diff options
116 files changed, 8743 insertions, 7209 deletions
diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam Binary files differindex 9412148a16..fb71997f32 100644 --- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam +++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 8c438b0bd7..30e3b02a0a 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -65,14 +65,14 @@ <funcs> <func> - <name>abs(Number) -> integer() | float()</name> + <name name="abs" arity="1" clause_i="1"/> + <name name="abs" arity="1" clause_i="2"/> + <type variable="Float" name_i="1"/> + <type variable="Int" name_i="2"/> <fsummary>Arithmetical absolute value</fsummary> - <type> - <v>Number = number()</v> - </type> <desc> <p>Returns an integer or float which is the arithmetical - absolute value of <c>Number</c>.</p> + absolute value of <c><anno>Float</anno></c> or <c><anno>Int</anno></c>.</p> <pre> > <input>abs(-3.33).</input> 3.33 @@ -82,26 +82,19 @@ </desc> </func> <func> - <name>erlang:adler32(Data) -> integer()</name> + <name name="adler32" arity="1"/> <fsummary>Compute adler32 checksum</fsummary> - <type> - <v>Data = iodata()</v> - </type> <desc> - <p>Computes and returns the adler32 checksum for <c>Data</c>.</p> + <p>Computes and returns the adler32 checksum for <c><anno>Data</anno></c>.</p> </desc> </func> <func> - <name>erlang:adler32(OldAdler, Data) -> integer()</name> + <name name="adler32" arity="2"/> <fsummary>Compute adler32 checksum</fsummary> - <type> - <v>OldAdler = integer()</v> - <v>Data = iodata()</v> - </type> <desc> <p>Continue computing the adler32 checksum by combining - the previous checksum, <c>OldAdler</c>, with the checksum of - <c>Data</c>.</p> + the previous checksum, <c><anno>OldAdler</anno></c>, with the checksum of + <c><anno>Data</anno></c>.</p> <p>The following code:</p> <code> X = erlang:adler32(Data1), @@ -114,12 +107,8 @@ </desc> </func> <func> - <name>erlang:adler32_combine(FirstAdler, SecondAdler, SecondSize) -> integer()</name> + <name name="adler32_combine" arity="3"/> <fsummary>Combine two adler32 checksums</fsummary> - <type> - <v>FirstAdler = SecondAdler = integer()</v> - <v>SecondSize = integer()</v> - </type> <desc> <p>Combines two previously computed adler32 checksums. This computation requires the size of the data object for @@ -138,18 +127,14 @@ </desc> </func> <func> - <name>erlang:append_element(Tuple1, Term) -> Tuple2</name> + <name name="append_element" arity="2"/> <fsummary>Append an extra element to a tuple</fsummary> - <type> - <v>Tuple1 = Tuple2 = tuple()</v> - <v>Term = term()</v> - </type> <desc> <p>Returns a new tuple which has one element more than - <c>Tuple1</c>, and contains the elements in <c>Tuple1</c> - followed by <c>Term</c> as the last element. Semantically + <c><anno>Tuple1</anno></c>, and contains the elements in <c><anno>Tuple1</anno></c> + followed by <c><anno>Term</anno></c> as the last element. Semantically equivalent to - <c>list_to_tuple(tuple_to_list(Tuple) ++ [Term])</c>, but much + <c>list_to_tuple(tuple_to_list(<anno>Tuple1</anno>) ++ [<anno>Term</anno>])</c>, but much faster.</p> <pre> > <input>erlang:append_element({one, two}, three).</input> @@ -204,27 +189,24 @@ </desc> </func> <func> - <name>atom_to_binary(Atom, Encoding) -> binary()</name> + <name name="atom_to_binary" arity="2"/> <fsummary>Return the binary representation of an atom</fsummary> - <type> - <v>Atom = atom()</v> - <v>Encoding = latin1 | utf8 | unicode</v> - </type> <desc> <p>Returns a binary which corresponds to the text - representation of <c>Atom</c>. If <c>Encoding</c> + representation of <c><anno>Atom</anno></c>. If <c><anno>Encoding</anno></c> is <c>latin1</c>, there will be one byte for each character - in the text representation. If <c>Encoding</c> is <c>utf8</c> or + in the text representation. If <c><anno>Encoding</anno></c> is + <c>utf8</c> or <c>unicode</c>, the characters will be encoded using UTF-8 (meaning that characters from 16#80 up to 0xFF will be encoded in two bytes).</p> - <note><p>Currently, <c>atom_to_binary(Atom, latin1)</c> can + <note><p>Currently, <c>atom_to_binary(<anno>Atom</anno>, latin1)</c> can never fail because the text representation of an atom can only contain characters from 0 to 16#FF. In a future release, the text representation of atoms might be allowed to contain any Unicode character - and <c>atom_to_binary(Atom, latin1)</c> will fail if the - text representation for the <c>Atom</c> contains a Unicode + and <c>atom_to_binary(<anno>Atom</anno>, latin1)</c> will fail if the + text representation for the <c><anno>Atom</anno></c> contains a Unicode character greater than 16#FF.</p></note> <pre> @@ -233,30 +215,21 @@ </desc> </func> <func> - <name>atom_to_list(Atom) -> string()</name> + <name name="atom_to_list" arity="1"/> <fsummary>Text representation of an atom</fsummary> - <type> - <v>Atom = atom()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of <c>Atom</c>.</p> + representation of <c><anno>Atom</anno></c>.</p> <pre> > <input>atom_to_list('Erlang').</input> "Erlang"</pre> </desc> </func> <func> - <name>binary_part(Subject, PosLen) -> binary()</name> + <name name="binary_part" arity="2"/> <fsummary>Extracts a part of a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>PosLen = {Start,Length}</v> - <v>Start = integer() >= 0</v> - <v>Length = integer() >= 0</v> - </type> - <desc> - <p>Extracts the part of the binary described by <c>PosLen</c>.</p> + <desc> + <p>Extracts the part of the binary described by <c><anno>PosLen</anno></c>.</p> <p>Negative length can be used to extract bytes at the end of a binary:</p> @@ -266,53 +239,44 @@ <<6,7,8,9,10>> </code> - <p>If <c>PosLen</c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> + <p>If <c><anno>PosLen</anno></c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> - <p><c>Start</c> is zero-based, i.e.:</p> + <p><c><anno>Start</anno></c> is zero-based, i.e.:</p> <code> 1> Bin = <<1,2,3>> 2> binary_part(Bin,{0,2}). <<1,2>> </code> - <p>See the STDLIB module <c>binary</c> for details about the <c>PosLen</c> semantics.</p> + <p>See the STDLIB module <c>binary</c> for details about the <c><anno>PosLen</anno></c> semantics.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>binary_part(Subject, Start, Length) -> binary()</name> + <name name="binary_part" arity="3"/> <fsummary>Extracts a part of a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Start = integer() >= 0</v> - <v>Length = integer() >= 0</v> - </type> <desc> - <p>The same as <c>binary_part(Subject, {Pos, Len})</c>.</p> + <p>The same as <c>binary_part(<anno>Subject</anno>, {<anno>Start</anno>, <anno>Length</anno>})</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>binary_to_atom(Binary, Encoding) -> atom()</name> + <name name="binary_to_atom" arity="2"/> <fsummary>Convert from text representation to an atom</fsummary> - <type> - <v>Binary = binary()</v> - <v>Encoding = latin1 | utf8 | unicode</v> - </type> <desc> <p>Returns the atom whose text representation is - <c>Binary</c>. If <c>Encoding</c> is <c>latin1</c>, no - translation of bytes in the binary is done. If <c>Encoding</c> + <c><anno>Binary</anno></c>. If <c><anno>Encoding</anno></c> is <c>latin1</c>, no + translation of bytes in the binary is done. If <c><anno>Encoding</anno></c> is <c>utf8</c> or <c>unicode</c>, the binary must contain valid UTF-8 sequences; furthermore, only Unicode characters up to 0xFF are allowed.</p> - <note><p><c>binary_to_atom(Binary, utf8)</c> will fail if + <note><p><c>binary_to_atom(<anno>Binary</anno>, utf8)</c> will fail if the binary contains Unicode characters greater than 16#FF. In a future release, such Unicode characters might be allowed - and <c>binary_to_atom(Binary, utf8)</c> + and <c>binary_to_atom(<anno>Binary</anno>, utf8)</c> will not fail in that case.</p></note> <pre> @@ -325,12 +289,8 @@ </desc> </func> <func> - <name>binary_to_existing_atom(Binary, Encoding) -> atom()</name> + <name name="binary_to_existing_atom" arity="2"/> <fsummary>Convert from text representation to an atom</fsummary> - <type> - <v>Binary = binary()</v> - <v>Encoding = latin1 | utf8 | unicode</v> - </type> <desc> <p>Works like <seealso marker="#binary_to_atom/2">binary_to_atom/2</seealso>, but the atom must already exist.</p> @@ -338,27 +298,21 @@ </desc> </func> <func> - <name>binary_to_list(Binary) -> [char()]</name> + <name name="binary_to_list" arity="1"/> <fsummary>Convert a binary to a list</fsummary> - <type> - <v>Binary = binary()</v> - </type> <desc> <p>Returns a list of integers which correspond to the bytes of - <c>Binary</c>.</p> + <c><anno>Binary</anno></c>.</p> </desc> </func> <func> - <name>binary_to_list(Binary, Start, Stop) -> [char()]</name> + <name name="binary_to_list" arity="3"/> <fsummary>Convert part of a binary to a list</fsummary> - <type> - <v>Binary = binary()</v> - <v>Start = Stop = 1..byte_size(Binary)</v> - </type> + <type_desc variable="Start">1..byte_size(<anno>Binary</anno>)</type_desc> <desc> <p>As <c>binary_to_list/1</c>, but returns a list of integers - corresponding to the bytes from position <c>Start</c> to - position <c>Stop</c> in <c>Binary</c>. Positions in the + corresponding to the bytes from position <c><anno>Start</anno></c> to + position <c><anno>Stop</anno></c> in <c><anno>Binary</anno></c>. Positions in the binary are numbered starting from 1.</p> <note><p>This function's indexing style of using one-based indices for @@ -368,27 +322,21 @@ </desc> </func> <func> - <name>bitstring_to_list(Bitstring) -> [char()|bitstring()]</name> + <name name="bitstring_to_list" arity="1"/> <fsummary>Convert a bitstring to a list</fsummary> - <type> - <v>Bitstring = bitstring()</v> - </type> <desc> <p>Returns a list of integers which correspond to the bytes of - <c>Bitstring</c>. If the number of bits in the binary is not + <c><anno>Bitstring</anno></c>. If the number of bits in the binary is not divisible by 8, the last element of the list will be a bitstring containing the remaining bits (1 up to 7 bits).</p> </desc> </func> <func> - <name>binary_to_term(Binary) -> term()</name> + <name name="binary_to_term" arity="1"/> <fsummary>Decode an Erlang external term format binary</fsummary> - <type> - <v>Binary = <seealso marker="#type-ext_binary">ext_binary()</seealso></v> - </type> <desc> <p>Returns an Erlang term which is the result of decoding - the binary object <c>Binary</c>, which must be encoded + the binary object <c><anno>Binary</anno></c>, which must be encoded according to the Erlang external term format.</p> <warning> <p>When decoding binaries from untrusted sources, consider using @@ -401,12 +349,8 @@ </desc> </func> <func> - <name>binary_to_term(Binary, Opts) -> term()</name> + <name name="binary_to_term" arity="2"/> <fsummary>Decode an Erlang external term format binary</fsummary> - <type> - <v>Opts = [safe]</v> - <v>Binary = <seealso marker="#type-ext_binary">ext_binary()</seealso></v> - </type> <desc> <p>As <c>binary_to_term/1</c>, but takes options that affect decoding of the binary.</p> @@ -436,13 +380,10 @@ </desc> </func> <func> - <name>bit_size(Bitstring) -> integer() >= 0</name> + <name name="bit_size" arity="1"/> <fsummary>Return the size of a bitstring</fsummary> - <type> - <v>Bitstring = bitstring()</v> - </type> <desc> - <p>Returns an integer which is the size in bits of <c>Bitstring</c>.</p> + <p>Returns an integer which is the size in bits of <c><anno>Bitstring</anno></c>.</p> <pre> > <input>bit_size(<<433:16,3:3>>).</input> 19 @@ -452,11 +393,8 @@ </desc> </func> <func> - <name>erlang:bump_reductions(Reductions) -> void()</name> + <name name="bump_reductions" arity="1"/> <fsummary>Increment the reduction counter</fsummary> - <type> - <v>Reductions = integer() >= 0</v> - </type> <desc> <p>This implementation-dependent function increments the reduction counter for the calling process. In the Beam @@ -472,14 +410,11 @@ </desc> </func> <func> - <name>byte_size(Bitstring) -> integer() >= 0</name> + <name name="byte_size" arity="1"/> <fsummary>Return the size of a bitstring (or binary)</fsummary> - <type> - <v>Bitstring = bitstring()</v> - </type> <desc> <p>Returns an integer which is the number of bytes needed to contain - <c>Bitstring</c>. (That is, if the number of bits in <c>Bitstring</c> is not + <c><anno>Bitstring</anno></c>. (That is, if the number of bits in <c><anno>Bitstring</anno></c> is not divisible by 8, the resulting number of bytes will be rounded <em>up</em>.)</p> <pre> > <input>byte_size(<<433:16,3:3>>).</input> @@ -490,21 +425,17 @@ </desc> </func> <func> - <name>erlang:cancel_timer(TimerRef) -> Time | false</name> + <name name="cancel_timer" arity="1"/> <fsummary>Cancel a timer</fsummary> - <type> - <v>TimerRef = reference()</v> - <v>Time = integer() >= 0</v> - </type> <desc> - <p>Cancels a timer, where <c>TimerRef</c> was returned by + <p>Cancels a timer, where <c><anno>TimerRef</anno></c> was returned by either <seealso marker="#send_after/3">erlang:send_after/3</seealso> or <seealso marker="#start_timer/3">erlang:start_timer/3</seealso>. If the timer is there to be removed, the function returns the time in milliseconds left until the timer would have expired, - otherwise <c>false</c> (which means that <c>TimerRef</c> was + otherwise <c>false</c> (which means that <c><anno>TimerRef</anno></c> was never a timer, that it has already been cancelled, or that it has already delivered its message).</p> <p>See also @@ -518,27 +449,20 @@ </func> <func> - <name>check_old_code(Module) -> boolean()</name> + <name name="check_old_code" arity="1"/> <fsummary>Check if a module has old code</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> - <p>Returns <c>true</c> if the <c>Module</c> has old code, + <p>Returns <c>true</c> if the <c><anno>Module</anno></c> has old code, and <c>false</c> otherwise.</p> <p>See also <seealso marker="kernel:code">code(3)</seealso>.</p> </desc> </func> <func> - <name>check_process_code(Pid, Module) -> boolean()</name> + <name name="check_process_code" arity="2"/> <fsummary>Check if a process is executing old code for a module</fsummary> - <type> - <v>Pid = pid()</v> - <v>Module = atom()</v> - </type> <desc> - <p>Returns <c>true</c> if the process <c>Pid</c> is executing - old code for <c>Module</c>. That is, if the current call of + <p>Returns <c>true</c> if the process <c><anno>Pid</anno></c> is executing + old code for <c><anno>Module</anno></c>. That is, if the current call of the process executes old code for this module, or if the process has references to old code for this module, or if the process contains funs that references old code for this @@ -550,26 +474,19 @@ false</pre> </desc> </func> <func> - <name>erlang:crc32(Data) -> integer() >= 0</name> + <name name="crc32" arity="1"/> <fsummary>Compute crc32 (IEEE 802.3) checksum</fsummary> - <type> - <v>Data = iodata()</v> - </type> <desc> - <p>Computes and returns the crc32 (IEEE 802.3 style) checksum for <c>Data</c>.</p> + <p>Computes and returns the crc32 (IEEE 802.3 style) checksum for <c><anno>Data</anno></c>.</p> </desc> </func> <func> - <name>erlang:crc32(OldCrc, Data) -> integer() >= 0</name> + <name name="crc32" arity="2"/> <fsummary>Compute crc32 (IEEE 802.3) checksum</fsummary> - <type> - <v>OldCrc = integer() >= 0</v> - <v>Data = iodata()</v> - </type> <desc> <p>Continue computing the crc32 checksum by combining - the previous checksum, <c>OldCrc</c>, with the checksum of - <c>Data</c>.</p> + the previous checksum, <c><anno>OldCrc</anno></c>, with the checksum of + <c><anno>Data</anno></c>.</p> <p>The following code:</p> <code> X = erlang:crc32(Data1), @@ -582,12 +499,8 @@ false</pre> </desc> </func> <func> - <name>erlang:crc32_combine(FirstCrc, SecondCrc, SecondSize) -> integer() >= 0</name> + <name name="crc32_combine" arity="3"/> <fsummary>Combine two crc32 (IEEE 802.3) checksums</fsummary> - <type> - <v>FirstCrc = SecondCrc = integer() >= 0</v> - <v>SecondSize = integer() >= 0</v> - </type> <desc> <p>Combines two previously computed crc32 checksums. This computation requires the size of the data object for @@ -606,11 +519,8 @@ false</pre> </desc> </func> <func> - <name>date() -> Date</name> + <name name="date" arity="0"/> <fsummary>Current date</fsummary> - <type> - <v>Date = <seealso marker="calendar#type-date">calendar:date()</seealso></v> - </type> <desc> <p>Returns the current date as <c>{Year, Month, Day}</c>.</p> <p>The time zone and daylight saving time correction depend on @@ -621,47 +531,24 @@ false</pre> </desc> </func> <func> - <name>erlang:decode_packet(Type,Bin,Options) -> {ok,Packet,Rest} | {more,Length} | {error,Reason}</name> + <name name="decode_packet" arity="3"/> <fsummary>Extracts a protocol packet from a binary</fsummary> - <type> - <v>Bin = binary()</v> - <v>Options = [Opt]</v> - <v>Packet = binary() | HttpPacket</v> - <v>Rest = binary()</v> - <v>Length = integer() > 0 | undefined</v> - <v>Reason = term()</v> - <v> Type, Opt -- see below</v> - <v></v> - <v>HttpPacket = HttpRequest | HttpResponse | HttpHeader | http_eoh | HttpError</v> - <v>HttpRequest = {http_request, HttpMethod, HttpUri, HttpVersion}</v> - <v>HttpResponse = {http_response, HttpVersion, integer(), HttpString}</v> - <v>HttpHeader = {http_header, integer(), HttpField, Reserved=term(), Value=HttpString}</v> - <v>HttpError = {http_error, HttpString}</v> - <v>HttpMethod = HttpMethodAtom | HttpString</v> - <v>HttpMethodAtom = 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'TRACE'</v> - <v>HttpUri = '*' | {absoluteURI, http|https, Host=HttpString, Port=integer()|undefined, Path=HttpString} | - {scheme, Scheme=HttpString, HttpString} | {abs_path, HttpString} | HttpString</v> - <v>HttpVersion = {Major=integer(), Minor=integer()}</v> - <v>HttpString = string() | binary()</v> - <v>HttpField = HttpFieldAtom | HttpString</v> - <v>HttpFieldAtom = 'Cache-Control' | 'Connection' | 'Date' | 'Pragma' | 'Transfer-Encoding' | 'Upgrade' | 'Via' | 'Accept' | 'Accept-Charset' | 'Accept-Encoding' | 'Accept-Language' | 'Authorization' | 'From' | 'Host' | 'If-Modified-Since' | 'If-Match' | 'If-None-Match' | 'If-Range' | 'If-Unmodified-Since' | 'Max-Forwards' | 'Proxy-Authorization' | 'Range' | 'Referer' | 'User-Agent' | 'Age' | 'Location' | 'Proxy-Authenticate' | 'Public' | 'Retry-After' | 'Server' | 'Vary' | 'Warning' | 'Www-Authenticate' | 'Allow' | 'Content-Base' | 'Content-Encoding' | 'Content-Language' | 'Content-Length' | 'Content-Location' | 'Content-Md5' | 'Content-Range' | 'Content-Type' | 'Etag' | 'Expires' | 'Last-Modified' | 'Accept-Ranges' | 'Set-Cookie' | 'Set-Cookie2' | 'X-Forwarded-For' | 'Cookie' | 'Keep-Alive' | 'Proxy-Connection'</v> - <v></v> - </type> - <desc> - <p>Decodes the binary <c>Bin</c> according to the packet - protocol specified by <c>Type</c>. Very similar to the packet - handling done by sockets with the option {packet,Type}.</p> - <p>If an entire packet is contained in <c>Bin</c> it is + <desc> + + <p>Decodes the binary <c><anno>Bin</anno></c> according to the packet + protocol specified by <c><anno>Type</anno></c>. Very similar to the packet + handling done by sockets with the option {packet,<anno>Type</anno>}.</p> + <p>If an entire packet is contained in <c><anno>Bin</anno></c> it is returned together with the remainder of the binary as - <c>{ok,Packet,Rest}</c>.</p> - <p>If <c>Bin</c> does not contain the entire packet, - <c>{more,Length}</c> is returned. <c>Length</c> is either the + <c>{ok,<anno>Packet</anno>,<anno>Rest</anno>}</c>.</p> + <p>If <c><anno>Bin</anno></c> does not contain the entire packet, + <c>{more,<anno>Length</anno>}</c> is returned. <c><anno>Length</anno></c> is either the expected <em>total size</em> of the packet or <c>undefined</c> if the expected packet size is not known. <c>decode_packet</c> can then be called again with more data added.</p> <p>If the packet does not conform to the protocol format - <c>{error,Reason}</c> is returned.</p> - <p>The following values of <c>Type</c> are valid:</p> + <c>{error,<anno>Reason</anno>}</c> is returned.</p> + <p>The following values of <c><anno>Type</anno></c> are valid:</p> <taglist> <tag><c>raw | 0</c></tag> <item> @@ -699,15 +586,15 @@ false</pre> <item> <p>The Hypertext Transfer Protocol. The packets are returned with the format according to - <c>HttpPacket</c> described above. A packet is either a + <c><anno>HttpPacket</anno></c> described above. A packet is either a request, a response, a header or an end of header - mark. Invalid lines are returned as <c>HttpError</c>.</p> + mark. Invalid lines are returned as <c><anno>HttpError</anno></c>.</p> <p>Recognized request methods and header fields are returned as atoms. Others are returned as strings.</p> <p>The protocol type <c>http</c> should only be used for - the first line when a <c>HttpRequest</c> or a - <c>HttpResponse</c> is expected. The following calls - should use <c>httph</c> to get <c>HttpHeader</c>'s until + the first line when a <c><anno>HttpRequest</anno></c> or a + <c><anno>HttpResponse</anno></c> is expected. The following calls + should use <c>httph</c> to get <c><anno>HttpHeader</anno></c>'s until <c>http_eoh</c> is returned that marks the end of the headers and the beginning of any following message body.</p> <p>The variants <c>http_bin</c> and <c>httph_bin</c> will return @@ -716,14 +603,14 @@ false</pre> </taglist> <p>The following options are available:</p> <taglist> - <tag><c>{packet_size, integer()}</c></tag> + <tag><c>{packet_size, integer() >= 0}</c></tag> <item><p>Sets the max allowed size of the packet body. If the packet header indicates that the length of the packet is longer than the max allowed length, the packet is considered invalid. Default is 0 which means no size limit.</p> </item> - <tag><c>{line_length, integer()}</c></tag> + <tag><c>{line_length, integer() >= 0}</c></tag> <item><p>For packet type <c>line</c>, truncate lines longer than the indicated length.</p> <p>Option <c>line_length</c> also applies to <c>http*</c> @@ -740,13 +627,10 @@ false</pre> </desc> </func> <func> - <name>delete_module(Module) -> true | undefined</name> + <name name="delete_module" arity="1"/> <fsummary>Make the current code for a module old</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> - <p>Makes the current code for <c>Module</c> become old code, and + <p>Makes the current code for <c><anno>Module</anno></c> become old code, and deletes all references for this module from the export table. Returns <c>undefined</c> if the module does not exist, otherwise <c>true</c>.</p> @@ -760,27 +644,24 @@ false</pre> </desc> </func> <func> - <name>demonitor(MonitorRef) -> true</name> + <name name="demonitor" arity="1"/> <fsummary>Stop monitoring</fsummary> - <type> - <v>MonitorRef = reference()</v> - </type> <desc> - <p>If <c>MonitorRef</c> is a reference which the calling process + <p>If <c><anno>MonitorRef</anno></c> is a reference which the calling process obtained by calling <seealso marker="#monitor/2">monitor/2</seealso>, this monitoring is turned off. If the monitoring is already turned off, nothing happens.</p> - <p>Once <c>demonitor(MonitorRef)</c> has returned it is - guaranteed that no <c>{'DOWN', MonitorRef, _, _, _}</c> message + <p>Once <c>demonitor(<anno>MonitorRef</anno>)</c> has returned it is + guaranteed that no <c>{'DOWN', <anno>MonitorRef</anno>, _, _, _}</c> message due to the monitor will be placed in the caller's message queue - in the future. A <c>{'DOWN', MonitorRef, _, _, _}</c> message + in the future. A <c>{'DOWN', <anno>MonitorRef</anno>, _, _, _}</c> message might have been placed in the caller's message queue prior to the call, though. Therefore, in most cases, it is advisable to remove such a <c>'DOWN'</c> message from the message queue after monitoring has been stopped. - <seealso marker="#demonitor/2">demonitor(MonitorRef, [flush])</seealso> can be used instead of - <c>demonitor(MonitorRef)</c> if this cleanup is wanted.</p> + <seealso marker="#demonitor/2">demonitor(<anno>MonitorRef</anno>, [flush])</seealso> can be used instead of + <c>demonitor(<anno>MonitorRef</anno>)</c> if this cleanup is wanted.</p> <note> <p>Prior to OTP release R11B (erts version 5.5) <c>demonitor/1</c> behaved completely asynchronous, i.e., the monitor was active @@ -792,35 +673,30 @@ false</pre> asynchronously send a "demonitor signal" to the monitored entity and ignore any future results of the monitor. </p> </note> - <p>Failure: It is an error if <c>MonitorRef</c> refers to a + <p>Failure: It is an error if <c><anno>MonitorRef</anno></c> refers to a monitoring started by another process. Not all such cases are cheap to check; if checking is cheap, the call fails with - <c>badarg</c> (for example if <c>MonitorRef</c> is a remote + <c>badarg</c> (for example if <c><anno>MonitorRef</anno></c> is a remote reference).</p> </desc> </func> <func> - <name>demonitor(MonitorRef, OptionList) -> boolean()</name> + <name name="demonitor" arity="2"/> <fsummary>Stop monitoring</fsummary> - <type> - <v>MonitorRef = reference()</v> - <v>OptionList = [Option]</v> - <v> Option = flush | info</v> - </type> <desc> <p>The returned value is <c>true</c> unless <c>info</c> is part - of <c>OptionList</c>. + of <c><anno>OptionList</anno></c>. </p> - <p><c>demonitor(MonitorRef, [])</c> is equivalent to - <seealso marker="#demonitor/1">demonitor(MonitorRef)</seealso>.</p> - <p>Currently the following <c>Option</c>s are valid:</p> + <p><c>demonitor(<anno>MonitorRef</anno>, [])</c> is equivalent to + <seealso marker="#demonitor/1">demonitor(<anno>MonitorRef</anno>)</seealso>.</p> + <p>Currently the following <c><anno>Option</anno></c>s are valid:</p> <taglist> <tag><c>flush</c></tag> <item> - <p>Remove (one) <c>{_, MonitorRef, _, _, _}</c> message, + <p>Remove (one) <c>{_, <anno>MonitorRef</anno>, _, _, _}</c> message, if there is one, from the caller's message queue after monitoring has been stopped.</p> - <p>Calling <c>demonitor(MonitorRef, [flush])</c> + <p>Calling <c>demonitor(<anno>MonitorRef</anno>, [flush])</c> is equivalent to the following, but more efficient:</p> <code type="none"> @@ -860,8 +736,8 @@ false</pre> <note> <p>More options may be added in the future.</p> </note> - <p>Failure: <c>badarg</c> if <c>OptionList</c> is not a list, or - if <c>Option</c> is not a valid option, or the same failure as for + <p>Failure: <c>badarg</c> if <c><anno>OptionList</anno></c> is not a list, or + if <c><anno>Option</anno></c> is not a valid option, or the same failure as for <seealso marker="#demonitor/1">demonitor/1</seealso></p> </desc> </func> @@ -878,13 +754,10 @@ false</pre> </desc> </func> <func> - <name>erlang:display(Term) -> true</name> + <name name="display" arity="1"/> <fsummary>Print a term on standard output</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Prints a text representation of <c>Term</c> on the standard + <p>Prints a text representation of <c><anno>Term</anno></c> on the standard output.</p> <warning> <p>This BIF is intended for debugging only.</p> @@ -892,15 +765,12 @@ false</pre> </desc> </func> <func> - <name>element(N, Tuple) -> term()</name> + <name name="element" arity="2"/> + <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <fsummary>Get Nth element of a tuple</fsummary> - <type> - <v>N = 1..tuple_size(Tuple)</v> - <v>Tuple = tuple()</v> - </type> <desc> - <p>Returns the <c>N</c>th element (numbering from 1) of - <c>Tuple</c>.</p> + <p>Returns the <c><anno>N</anno></c>th element (numbering from 1) of + <c><anno>Tuple</anno></c>.</p> <pre> > <input>element(2, {a, b, c}).</input> b</pre> @@ -908,11 +778,8 @@ b</pre> </desc> </func> <func> - <name>erase() -> [{Key, Val}]</name> + <name name="erase" arity="0"/> <fsummary>Return and delete the process dictionary</fsummary> - <type> - <v>Key = Val = term()</v> - </type> <desc> <p>Returns the process dictionary and deletes it.</p> <pre> @@ -923,15 +790,12 @@ b</pre> </desc> </func> <func> - <name>erase(Key) -> Val | undefined</name> + <name name="erase" arity="1"/> <fsummary>Return and delete a value from the process dictionary</fsummary> - <type> - <v>Key = Val = term()</v> - </type> <desc> - <p>Returns the value <c>Val</c> associated with <c>Key</c> and + <p>Returns the value <c><anno>Val</anno></c> associated with <c><anno>Key</anno></c> and deletes it from the process dictionary. Returns - <c>undefined</c> if no value is associated with <c>Key</c>.</p> + <c>undefined</c> if no value is associated with <c><anno>Key</anno></c>.</p> <pre> > <input>put(key1, {merry, lambs, are, playing}),</input> <input>X = erase(key1),</input> @@ -940,15 +804,12 @@ b</pre> </desc> </func> <func> - <name>error(Reason)</name> + <name name="error" arity="1"/> <fsummary>Stop execution with a given reason</fsummary> - <type> - <v>Reason = term()</v> - </type> <desc> <p>Stops the execution of the calling process with the reason - <c>Reason</c>, where <c>Reason</c> is any term. The actual - exit reason will be <c>{Reason, Where}</c>, where <c>Where</c> + <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> is any term. The actual + exit reason will be <c>{<anno>Reason</anno>, Where}</c>, where <c>Where</c> is a list of the functions most recently called (the current function first). Since evaluating this function causes the process to terminate, it has no return value.</p> @@ -962,18 +823,14 @@ b</pre> </desc> </func> <func> - <name>error(Reason, Args)</name> + <name name="error" arity="2"/> <fsummary>Stop execution with a given reason</fsummary> - <type> - <v>Reason = term()</v> - <v>Args = [term()]</v> - </type> <desc> <p>Stops the execution of the calling process with the reason - <c>Reason</c>, where <c>Reason</c> is any term. The actual - exit reason will be <c>{Reason, Where}</c>, where <c>Where</c> + <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> is any term. The actual + exit reason will be <c>{<anno>Reason</anno>, Where}</c>, where <c>Where</c> is a list of the functions most recently called (the current - function first). <c>Args</c> is expected to be the list of + function first). <c><anno>Args</anno></c> is expected to be the list of arguments for the current function; in Beam it will be used to provide the actual arguments for the current function in the <c>Where</c> term. Since evaluating this function causes @@ -981,14 +838,11 @@ b</pre> </desc> </func> <func> - <name>exit(Reason)</name> + <name name="exit" arity="1"/> <fsummary>Stop execution with a given reason</fsummary> - <type> - <v>Reason = term()</v> - </type> <desc> <p>Stops the execution of the calling process with the exit - reason <c>Reason</c>, where <c>Reason</c> is any term. Since + reason <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> is any term. Since evaluating this function causes the process to terminate, it has no return value.</p> <pre> @@ -999,78 +853,67 @@ b</pre> </desc> </func> <func> - <name>exit(Pid, Reason) -> true</name> + <name name="exit" arity="2"/> <fsummary>Send an exit signal to a process</fsummary> - <type> - <v>Pid = pid()</v> - <v>Reason = term()</v> - </type> - <desc> - <p>Sends an exit signal with exit reason <c>Reason</c> to - the process <c>Pid</c>.</p> - <p>The following behavior apply if <c>Reason</c> is any term + <desc> + <p>Sends an exit signal with exit reason <c><anno>Reason</anno></c> to + the process <c><anno>Pid</anno></c>.</p> + <p>The following behavior apply if <c><anno>Reason</anno></c> is any term except <c>normal</c> or <c>kill</c>:</p> - <p>If <c>Pid</c> is not trapping exits, <c>Pid</c> itself will - exit with exit reason <c>Reason</c>. If <c>Pid</c> is trapping + <p>If <c><anno>Pid</anno></c> is not trapping exits, <c><anno>Pid</anno></c> itself will + exit with exit reason <c><anno>Reason</anno></c>. If <c><anno>Pid</anno></c> is trapping exits, the exit signal is transformed into a message - <c>{'EXIT', From, Reason}</c> and delivered to the message - queue of <c>Pid</c>. <c>From</c> is the pid of the process + <c>{'EXIT', From, <anno>Reason</anno>}</c> and delivered to the message + queue of <c><anno>Pid</anno></c>. <c>From</c> is the pid of the process which sent the exit signal. See also <seealso marker="#process_flag/2">process_flag/2</seealso>.</p> - <p>If <c>Reason</c> is the atom <c>normal</c>, <c>Pid</c> will + <p>If <c><anno>Reason</anno></c> is the atom <c>normal</c>, <c><anno>Pid</anno></c> will not exit. If it is trapping exits, the exit signal is transformed into a message <c>{'EXIT', From, normal}</c> and delivered to its message queue.</p> - <p>If <c>Reason</c> is the atom <c>kill</c>, that is if - <c>exit(Pid, kill)</c> is called, an untrappable exit signal - is sent to <c>Pid</c> which will unconditionally exit with + <p>If <c><anno>Reason</anno></c> is the atom <c>kill</c>, that is if + <c>exit(<anno>Pid</anno>, kill)</c> is called, an untrappable exit signal + is sent to <c><anno>Pid</anno></c> which will unconditionally exit with exit reason <c>killed</c>.</p> </desc> </func> <func> - <name>erlang:external_size(Term) -> integer() >= 0</name> + <name name="external_size" arity="1"/> <fsummary>Calculate the maximum size for a term encoded in the Erlang external term format</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> <p>Calculates, without doing the encoding, the maximum byte size for a term encoded in the Erlang external term format. The following condition applies always:</p> <p> <pre> -> <input>Size1 = byte_size(term_to_binary(Term)),</input> -> <input>Size2 = erlang:external_size(Term),</input> +> <input>Size1 = byte_size(term_to_binary(<anno>Term</anno>)),</input> +> <input>Size2 = erlang:external_size(<anno>Term</anno>),</input> > <input>true = Size1 =< Size2.</input> true </pre> </p> - <p>This is equivalent to a call to: <code>erlang:external_size(Term, []) + <p>This is equivalent to a call to: <code>erlang:external_size(<anno>Term</anno>, []) </code></p> </desc> </func> <func> - <name>erlang:external_size(Term, [Option]) -> integer() >= 0</name> + <name name="external_size" arity="2"/> <fsummary>Calculate the maximum size for a term encoded in the Erlang external term format</fsummary> - <type> - <v>Term = term()</v> - <v>Option = {minor_version, Version}</v> - </type> <desc> <p>Calculates, without doing the encoding, the maximum byte size for a term encoded in the Erlang external term format. The following condition applies always:</p> <p> <pre> -> <input>Size1 = byte_size(term_to_binary(Term, Options)),</input> -> <input>Size2 = erlang:external_size(Term, Options),</input> +> <input>Size1 = byte_size(term_to_binary(<anno>Term</anno>, <anno>Options</anno>)),</input> +> <input>Size2 = erlang:external_size(<anno>Term</anno>, <anno>Options</anno>),</input> > <input>true = Size1 =< Size2.</input> true </pre> </p> - <p>The option <c>{minor_version, Version}</c> specifies how floats + <p>The option <c>{minor_version, <anno>Version</anno>}</c> specifies how floats are encoded. See <seealso marker="#term_to_binary/2">term_to_binary/2</seealso> for a more detailed description. @@ -1078,13 +921,10 @@ true </desc> </func> <func> - <name>float(Number) -> float()</name> + <name name="float" arity="1"/> <fsummary>Convert a number to a float</fsummary> - <type> - <v>Number = number()</v> - </type> <desc> - <p>Returns a float by converting <c>Number</c> to a float.</p> + <p>Returns a float by converting <c><anno>Number</anno></c> to a float.</p> <pre> > <input>float(55).</input> 55.0</pre> @@ -1101,14 +941,11 @@ true </desc> </func> <func> - <name>float_to_list(Float) -> string()</name> + <name name="float_to_list" arity="1"/> <fsummary>Text representation of a float</fsummary> - <type> - <v>Float = float()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of <c>Float</c>.</p> + representation of <c><anno>Float</anno></c>.</p> <pre> > <input>float_to_list(7.0).</input> "7.00000000000000000000e+00"</pre> @@ -1213,18 +1050,15 @@ true </desc> </func> <func> - <name>erlang:fun_info(Fun, Item) -> {Item, Info}</name> + <name name="fun_info" arity="2"/> + <type name="fun_info_item"/> <fsummary>Information about a fun</fsummary> - <type> - <v>Fun = fun()</v> - <v>Item, Info -- see below</v> - </type> - <desc> - <p>Returns information about <c>Fun</c> as specified by - <c>Item</c>, in the form <c>{Item,Info}</c>.</p> - <p>For any fun, <c>Item</c> can be any of the atoms + <desc> + <p>Returns information about <c><anno>Fun</anno></c> as specified by + <c><anno>Item</anno></c>, in the form <c>{<anno>Item</anno>,<anno>Info</anno>}</c>.</p> + <p>For any fun, <c><anno>Item</anno></c> can be any of the atoms <c>module</c>, <c>name</c>, <c>arity</c>, <c>env</c>, or <c>type</c>.</p> - <p>For a local fun, <c>Item</c> can also be any of the atoms + <p>For a local fun, <c><anno>Item</anno></c> can also be any of the atoms <c>index</c>, <c>new_index</c>, <c>new_uniq</c>, <c>uniq</c>, and <c>pid</c>. For an external fun, the value of any of these items is always the atom <c>undefined</c>.</p> @@ -1233,33 +1067,26 @@ true </desc> </func> <func> - <name>erlang:fun_to_list(Fun) -> string()</name> + <name name="fun_to_list" arity="1"/> <fsummary>Text representation of a fun</fsummary> - <type> - <v>Fun = fun()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of <c>Fun</c>.</p> + representation of <c><anno>Fun</anno></c>.</p> </desc> </func> <func> - <name>erlang:function_exported(Module, Function, Arity) -> boolean()</name> + <name name="function_exported" arity="3"/> <fsummary>Check if a function is exported and loaded</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Arity = arity()</v> - </type> <desc> - <p>Returns <c>true</c> if the module <c>Module</c> is loaded - and contains an exported function <c>Function/Arity</c>; + <p>Returns <c>true</c> if the module <c><anno>Module</anno></c> is loaded + and contains an exported function <c><anno>Function</anno>/<anno>Arity</anno></c>; otherwise <c>false</c>.</p> <p>Returns <c>false</c> for any BIF (functions implemented in C rather than in Erlang).</p> </desc> </func> <func> - <name>garbage_collect() -> true</name> + <name name="garbage_collect" arity="0"/> <fsummary>Force an immediate garbage collection of the calling process</fsummary> <desc> <p>Forces an immediate garbage collection of the currently @@ -1276,26 +1103,20 @@ true </desc> </func> <func> - <name>garbage_collect(Pid) -> boolean()</name> + <name name="garbage_collect" arity="1"/> <fsummary>Force an immediate garbage collection of a process</fsummary> - <type> - <v>Pid = pid()</v> - </type> <desc> <p>Works like <c>erlang:garbage_collect()</c> but on any process. The same caveats apply. Returns <c>false</c> if - <c>Pid</c> refers to a dead process; <c>true</c> otherwise.</p> + <c><anno>Pid</anno></c> refers to a dead process; <c>true</c> otherwise.</p> </desc> </func> <func> - <name>get() -> [{Key, Val}]</name> + <name name="get" arity="0"/> <fsummary>Return the process dictionary</fsummary> - <type> - <v>Key = Val = term()</v> - </type> <desc> <p>Returns the process dictionary as a list of - <c>{Key, Val}</c> tuples.</p> + <c>{<anno>Key</anno>, <anno>Val</anno>}</c> tuples.</p> <pre> > <input>put(key1, merry),</input> <input>put(key2, lambs),</input> @@ -1305,14 +1126,11 @@ true </desc> </func> <func> - <name>get(Key) -> Val | undefined</name> + <name name="get" arity="1"/> <fsummary>Return a value from the process dictionary</fsummary> - <type> - <v>Key = Val = term()</v> - </type> <desc> - <p>Returns the value <c>Val</c>associated with <c>Key</c> in - the process dictionary, or <c>undefined</c> if <c>Key</c> + <p>Returns the value <c><anno>Val</anno></c>associated with <c><anno>Key</anno></c> in + the process dictionary, or <c>undefined</c> if <c><anno>Key</anno></c> does not exist.</p> <pre> > <input>put(key1, merry),</input> @@ -1331,14 +1149,11 @@ true </desc> </func> <func> - <name>get_keys(Val) -> [Key]</name> + <name name="get_keys" arity="1"/> <fsummary>Return a list of keys from the process dictionary</fsummary> - <type> - <v>Val = Key = term()</v> - </type> <desc> <p>Returns a list of keys which are associated with the value - <c>Val</c> in the process dictionary.</p> + <c><anno>Val</anno></c> in the process dictionary.</p> <pre> > <input>put(mary, {1, 2}),</input> <input>put(had, {1, 2}),</input> @@ -1351,28 +1166,23 @@ true </desc> </func> <func> - <name>erlang:get_stacktrace() -> [{Module, Function, Arity | Args, Location}]</name> + <name name="get_stacktrace" arity="0"/> <fsummary>Get the call stack back-trace of the last exception</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Arity = arity()</v> - <v>Args = [term()]</v> - <v>Location = [{atom(),term()}]</v> - </type> + <type name="stack_item"/> <desc> <p>Get the call stack back-trace (<em>stacktrace</em>) of the last exception in the calling process as a list of - <c>{Module,Function,Arity,Location}</c> tuples. - The <c>Arity</c> field in the first tuple may be the argument + <c>{<anno>Module</anno>,<anno>Function</anno>,<anno>Arity</anno>,<anno>Location</anno>}</c> tuples. + The <c><anno>Arity</anno></c> field in the first tuple may be the argument list of that function call instead of an arity integer, depending on the exception.</p> <p>If there has not been any exceptions in a process, the - stacktrace is []. After a code change for the process, + stacktrace is <c>[]</c>. After a code change for the process, the stacktrace may also be reset to [].</p> <p>The stacktrace is the same data as the <c>catch</c> operator returns, for example:</p> <p><c>{'EXIT',{badarg,Stacktrace}} = catch abs(x)</c></p> - <p><c>Location</c> is a (possibly empty) list of two-tuples that + <p><c><anno>Location</anno></c> is a (possibly empty) list of two-tuples that may indicate the location in the source code of the function. The first element is an atom that describes the type of information in the second element. Currently the following @@ -1397,11 +1207,8 @@ true </desc> </func> <func> - <name>group_leader() -> GroupLeader</name> + <name name="group_leader" arity="0"/> <fsummary>Get the group leader for the calling process</fsummary> - <type> - <v>GroupLeader = pid()</v> - </type> <desc> <p>Returns the pid of the group leader for the process which evaluates the function.</p> @@ -1414,13 +1221,10 @@ true </desc> </func> <func> - <name>group_leader(GroupLeader, Pid) -> true</name> + <name name="group_leader" arity="2"/> <fsummary>Set the group leader for a process</fsummary> - <type> - <v>GroupLeader = Pid = pid()</v> - </type> <desc> - <p>Sets the group leader of <c>Pid</c> to <c>GroupLeader</c>. + <p>Sets the group leader of <c><anno>Pid</anno></c> to <c><anno>GroupLeader</anno></c>. Typically, this is used when a processes started from a certain shell should have another group leader than <c>init</c>.</p> @@ -1429,7 +1233,7 @@ true </desc> </func> <func> - <name>halt()</name> + <name name="halt" arity="0"/> <fsummary>Halt the Erlang runtime system and indicate normal exit to the calling environment</fsummary> <desc> <p>Halts the Erlang runtime system and indicates normal exit to @@ -1440,29 +1244,26 @@ os_prompt%</pre> </desc> </func> <func> - <name>halt(Status)</name> + <name name="halt" arity="1"/> <fsummary>Halt the Erlang runtime system</fsummary> - <type> - <v>Status = integer() >= 0 | string()</v> - </type> <desc> - <p><c>Status</c> must be a non-negative integer, or a string. + <p><c><anno>Status</anno></c> must be a non-negative integer, or a string. Halts the Erlang runtime system. Has no return value. - If <c>Status</c> is an integer, it is returned as an exit + If <c><anno>Status</anno></c> is an integer, it is returned as an exit status of Erlang to the calling environment. - If <c>Status</c> is a string, produces an Erlang crash dump - with <c>String</c> as slogan, and then exits with a non-zero + If <c><anno>Status</anno></c> is a string, produces an Erlang crash dump + with <c><anno>Status</anno></c> as slogan, and then exits with a non-zero status code.</p> <p>Note that on many platforms, only the status codes 0-255 are supported by the operating system.</p> </desc> </func> <func> - <name>erlang:hash(Term, Range) -> Hash</name> + <name name="hash" arity="2"/> <fsummary>Hash function (deprecated)</fsummary> <desc> - <p>Returns a hash value for <c>Term</c> within the range - <c>1..Range</c>. The allowed range is 1..2^27-1.</p> + <p>Returns a hash value for <c><anno>Term</anno></c> within the range + <c>1..<anno>Range</anno></c>. The allowed range is 1..2^27-1.</p> <warning> <p>This BIF is deprecated as the hash value may differ on different architectures. Also the hash values for integer @@ -1475,35 +1276,28 @@ os_prompt%</pre> </desc> </func> <func> - <name>hd(List) -> term()</name> + <name name="hd" arity="1"/> <fsummary>Head of a list</fsummary> - <type> - <v>List = [term()]</v> - </type> <desc> - <p>Returns the head of <c>List</c>, that is, the first element.</p> + <p>Returns the head of <c><anno>List</anno></c>, that is, the first element.</p> <pre> > <input>hd([1,2,3,4,5]).</input> 1</pre> <p>Allowed in guard tests.</p> - <p>Failure: <c>badarg</c> if <c>List</c> is the empty list [].</p> + <p>Failure: <c>badarg</c> if <c><anno>List</anno></c> is the empty list [].</p> </desc> </func> <func> - <name>erlang:hibernate(Module, Function, Args)</name> + <name name="hibernate" arity="3"/> <fsummary>Hibernate a process until a message is sent to it</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - </type> <desc> <p>Puts the calling process into a wait state where its memory allocation has been reduced as much as possible, which is useful if the process does not expect to receive any messages in the near future.</p> <p>The process will be awaken when a message is sent to it, and - control will resume in <c>Module:Function</c> with - the arguments given by <c>Args</c> with the call stack + control will resume in <c><anno>Module</anno>:<anno>Function</anno></c> with + the arguments given by <c><anno>Args</anno></c> with the call stack emptied, meaning that the process will terminate when that function returns. Thus <c>erlang:hibernate/3</c> will never return to its caller.</p> @@ -1533,14 +1327,11 @@ os_prompt%</pre> </desc> </func> <func> - <name>integer_to_list(Integer) -> string()</name> + <name name="integer_to_list" arity="1"/> <fsummary>Text representation of an integer</fsummary> - <type> - <v>Integer = integer()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of <c>Integer</c>.</p> + representation of <c><anno>Integer</anno></c>.</p> <pre> > <input>integer_to_list(77).</input> "77"</pre> @@ -1558,14 +1349,11 @@ os_prompt%</pre> </desc> </func> <func> - <name>iolist_to_binary(IoListOrBinary) -> binary()</name> + <name name="iolist_to_binary" arity="1"/> <fsummary>Convert an iolist to a binary</fsummary> - <type> - <v>IoListOrBinary = iolist() | binary()</v> - </type> <desc> <p>Returns a binary which is made from the integers and - binaries in <c>IoListOrBinary</c>.</p> + binaries in <c><anno>IoListOrBinary</anno></c>.</p> <pre> > <input>Bin1 = <<1,2,3>>.</input> <<1,2,3>> @@ -1578,22 +1366,19 @@ os_prompt%</pre> </desc> </func> <func> - <name>iolist_size(Item) -> integer() >= 0</name> + <name name="iolist_size" arity="1"/> <fsummary>Size of an iolist</fsummary> - <type> - <v>Item = iolist() | binary()</v> - </type> <desc> <p>Returns an integer which is the size in bytes of the binary that would be the result of - <c>iolist_to_binary(Item)</c>.</p> + <c>iolist_to_binary(<anno>Item</anno>)</c>.</p> <pre> > <input>iolist_size([1,2|<<3,4>>]).</input> 4</pre> </desc> </func> <func> - <name>is_alive() -> boolean()</name> + <name name="is_alive" arity="0"/> <fsummary>Check whether the local node is alive</fsummary> <desc> <p>Returns <c>true</c> if the local node is alive; that is, if @@ -1602,25 +1387,19 @@ os_prompt%</pre> </desc> </func> <func> - <name>is_atom(Term) -> boolean()</name> + <name name="is_atom" arity="1"/> <fsummary>Check whether a term is an atom</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is an atom; + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an atom; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_binary(Term) -> boolean()</name> + <name name="is_binary" arity="1"/> <fsummary>Check whether a term is a binary</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a binary; + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a binary; otherwise returns <c>false</c>.</p> <p>A binary always contains a complete number of bytes.</p> @@ -1629,78 +1408,58 @@ os_prompt%</pre> </desc> </func> <func> - <name>is_bitstring(Term) -> boolean()</name> + <name name="is_bitstring" arity="1"/> <fsummary>Check whether a term is a bitstring</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a bitstring (including a binary); + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a bitstring (including a binary); otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_boolean(Term) -> boolean()</name> + <name name="is_boolean" arity="1"/> <fsummary>Check whether a term is a boolean</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is either the atom <c>true</c> or the atom <c>false</c> (i.e. a boolean); otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>erlang:is_builtin(Module, Function, Arity) -> boolean()</name> + <name name="is_builtin" arity="3"/> <fsummary>Check if a function is a BIF implemented in C</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Arity = arity()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Module:Function/Arity</c> is + <p>Returns <c>true</c> if <c><anno>Module</anno>:<anno>Function</anno>/<anno>Arity</anno></c> is a BIF implemented in C; otherwise returns <c>false</c>. This BIF is useful for builders of cross reference tools.</p> </desc> </func> <func> - <name>is_float(Term) -> boolean()</name> + <name name="is_float" arity="1"/> <fsummary>Check whether a term is a float</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a floating point + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a floating point number; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_function(Term) -> boolean()</name> + <name name="is_function" arity="1"/> <fsummary>Check whether a term is a fun</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a fun; otherwise + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a fun; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_function(Term, Arity) -> boolean()</name> + <name name="is_function" arity="2"/> <fsummary>Check whether a term is a fun with a given arity</fsummary> - <type> - <v>Term = term()</v> - <v>Arity = arity()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a fun that can be - applied with <c>Arity</c> number of arguments; otherwise + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a fun that can be + applied with <c><anno>Arity</anno></c> number of arguments; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> <warning> @@ -1713,74 +1472,56 @@ os_prompt%</pre> </desc> </func> <func> - <name>is_integer(Term) -> boolean()</name> + <name name="is_integer" arity="1"/> <fsummary>Check whether a term is an integer</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is an integer; + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an integer; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_list(Term) -> boolean()</name> + <name name="is_list" arity="1"/> <fsummary>Check whether a term is a list</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a list with + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a list with zero or more elements; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_number(Term) -> boolean()</name> + <name name="is_number" arity="1"/> <fsummary>Check whether a term is a number</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is either an integer or a + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is either an integer or a floating point number; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_pid(Term) -> boolean()</name> + <name name="is_pid" arity="1"/> <fsummary>Check whether a term is a pid</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a pid (process + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a pid (process identifier); otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_port(Term) -> boolean()</name> + <name name="is_port" arity="1"/> <fsummary>Check whether a term is a port</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a port identifier; + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a port identifier; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_process_alive(Pid) -> boolean()</name> + <name name="is_process_alive" arity="1"/> <fsummary>Check whether a process is alive</fsummary> - <type> - <v>Pid = pid()</v> - </type> <desc> <p> - <c>Pid</c> must refer to a process at the local node. + <c><anno>Pid</anno></c> must refer to a process at the local node. Returns <c>true</c> if the process exists and is alive, that is, is not exiting and has not exited. Otherwise, returns <c>false</c>. @@ -1788,41 +1529,32 @@ os_prompt%</pre> </desc> </func> <func> - <name>is_record(Term, RecordTag) -> boolean()</name> + <name name="is_record" arity="2"/> <fsummary>Check whether a term appears to be a record</fsummary> - <type> - <v>Term = term()</v> - <v>RecordTag = atom()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a tuple and its first - element is <c>RecordTag</c>. Otherwise, returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a tuple and its first + element is <c><anno>RecordTag</anno></c>. Otherwise, returns <c>false</c>.</p> <note> <p>Normally the compiler treats calls to <c>is_record/2</c> - specially. It emits code to verify that <c>Term</c> is a - tuple, that its first element is <c>RecordTag</c>, and that - the size is correct. However, if the <c>RecordTag</c> is + specially. It emits code to verify that <c><anno>Term</anno></c> is a + tuple, that its first element is <c><anno>RecordTag</anno></c>, and that + the size is correct. However, if the <c><anno>RecordTag</anno></c> is not a literal atom, the <c>is_record/2</c> BIF will be called instead and the size of the tuple will not be verified.</p> </note> - <p>Allowed in guard tests, if <c>RecordTag</c> is a literal + <p>Allowed in guard tests, if <c><anno>RecordTag</anno></c> is a literal atom.</p> </desc> </func> <func> - <name>is_record(Term, RecordTag, Size) -> boolean()</name> + <name name="is_record" arity="3"/> <fsummary>Check whether a term appears to be a record</fsummary> - <type> - <v>Term = term()</v> - <v>RecordTag = atom()</v> - <v>Size = integer()</v> - </type> - <desc> - <p><c>RecordTag</c> must be an atom. Returns <c>true</c> if - <c>Term</c> is a tuple, its first element is <c>RecordTag</c>, - and its size is <c>Size</c>. Otherwise, returns <c>false</c>.</p> - <p>Allowed in guard tests, provided that <c>RecordTag</c> is + <desc> + <p><c><anno>RecordTag</anno></c> must be an atom. Returns <c>true</c> if + <c><anno>Term</anno></c> is a tuple, its first element is <c><anno>RecordTag</anno></c>, + and its size is <c><anno>Size</anno></c>. Otherwise, returns <c>false</c>.</p> + <p>Allowed in guard tests, provided that <c><anno>RecordTag</anno></c> is a literal atom and <c>Size</c> is a literal integer.</p> <note> <p>This BIF is documented for completeness. In most cases @@ -1831,37 +1563,28 @@ os_prompt%</pre> </desc> </func> <func> - <name>is_reference(Term) -> boolean()</name> + <name name="is_reference" arity="1"/> <fsummary>Check whether a term is a reference</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a reference; + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a reference; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>is_tuple(Term) -> boolean()</name> + <name name="is_tuple" arity="1"/> <fsummary>Check whether a term is a tuple</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Term</c> is a tuple; + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a tuple; otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> <func> - <name>length(List) -> integer() >= 0</name> + <name name="length" arity="1"/> <fsummary>Length of a list</fsummary> - <type> - <v>List = [term()]</v> - </type> <desc> - <p>Returns the length of <c>List</c>.</p> + <p>Returns the length of <c><anno>List</anno></c>.</p> <pre> > <input>length([1,2,3,4,5,6,7,8,9]).</input> 9</pre> @@ -1869,52 +1592,47 @@ os_prompt%</pre> </desc> </func> <func> - <name>link(Pid) -> true</name> + <name name="link" arity="1"/> <fsummary>Create a link to another process (or port)</fsummary> - <type> - <v>Pid = pid() | port()</v> - </type> <desc> <p>Creates a link between the calling process and another - process (or port) <c>Pid</c>, if there is not such a link + process (or port) <c><anno>PidOrPort</anno></c>, if there is not such a link already. If a process attempts to create a link to itself, nothing is done. Returns <c>true</c>.</p> - <p>If <c>Pid</c> does not exist, the behavior of the BIF depends + <p>If <c><anno>PidOrPort</anno></c> does not exist, the behavior of the BIF depends on if the calling process is trapping exits or not (see <seealso marker="#process_flag/2">process_flag/2</seealso>):</p> <list type="bulleted"> <item>If the calling process is not trapping exits, and - checking <c>Pid</c> is cheap -- that is, if <c>Pid</c> is + checking <c><anno>PidOrPort</anno></c> is cheap -- that is, if <c><anno>PidOrPort</anno></c> is local -- <c>link/1</c> fails with reason <c>noproc</c>.</item> <item>Otherwise, if the calling process is trapping exits, - and/or <c>Pid</c> is remote, <c>link/1</c> returns + and/or <c><anno>PidOrPort</anno></c> is remote, <c>link/1</c> returns <c>true</c>, but an exit signal with reason <c>noproc</c> is sent to the calling process.</item> </list> </desc> </func> <func> - <name>list_to_atom(String) -> atom()</name> + <name name="list_to_atom" arity="1"/> <fsummary>Convert from text representation to an atom</fsummary> - <type> - <v>String = string()</v> - </type> <desc> - <p>Returns the atom whose text representation is <c>String</c>.</p> + <p>Returns the atom whose text representation is <c><anno>String</anno></c>.</p> + <p><c><anno>String</anno></c> may only contain ISO-latin-1 + characterns (i.e. numbers below 256) as the current + implementation does not allow unicode characters >= 256 in + atoms.</p> <pre> > <input>list_to_atom("Erlang").</input> 'Erlang'</pre> </desc> </func> <func> - <name>list_to_binary(IoList) -> binary()</name> + <name name="list_to_binary" arity="1"/> <fsummary>Convert a list to a binary</fsummary> - <type> - <v>IoList = iolist()</v> - </type> <desc> <p>Returns a binary which is made from the integers and - binaries in <c>IoList</c>.</p> + binaries in <c><anno>IoList</anno></c>.</p> <pre> > <input>Bin1 = <<1,2,3>>.</input> <<1,2,3>> @@ -1927,14 +1645,12 @@ os_prompt%</pre> </desc> </func> <func> - <name>list_to_bitstring(BitstringList) -> bitstring()</name> + <name name="list_to_bitstring" arity="1"/> + <type name="bitstring_list"/> <fsummary>Convert a list to a bitstring</fsummary> - <type> - <v>BitstringList = [BitstringList | bitstring() | char()]</v> - </type> <desc> <p>Returns a bitstring which is made from the integers and - bitstrings in <c>BitstringList</c>. (The last tail in <c>BitstringList</c> + bitstrings in <c><anno>BitstringList</anno></c>. (The last tail in <c><anno>BitstringList</anno></c> is allowed to be a bitstring.)</p> <pre> > <input>Bin1 = <<1,2,3>>.</input> @@ -1943,51 +1659,42 @@ os_prompt%</pre> <<4,5>> > <input>Bin3 = <<6,7:4,>>.</input> <<6>> -> <input>list_to_binary([Bin1,1,[2,3,Bin2],4|Bin3]).</input> +> <input>list_to_bitstring([Bin1,1,[2,3,Bin2],4|Bin3]).</input> <<1,2,3,1,2,3,4,5,4,6,7:46>></pre> </desc> </func> <func> - <name>list_to_existing_atom(String) -> atom()</name> + <name name="list_to_existing_atom" arity="1"/> <fsummary>Convert from text representation to an atom</fsummary> - <type> - <v>String = string()</v> - </type> <desc> - <p>Returns the atom whose text representation is <c>String</c>, + <p>Returns the atom whose text representation is <c><anno>String</anno></c>, but only if there already exists such atom.</p> <p>Failure: <c>badarg</c> if there does not already exist an atom - whose text representation is <c>String</c>.</p> + whose text representation is <c><anno>String</anno></c>.</p> </desc> </func> <func> - <name>list_to_float(String) -> float()</name> + <name name="list_to_float" arity="1"/> <fsummary>Convert from text representation to a float</fsummary> - <type> - <v>String = string()</v> - </type> <desc> - <p>Returns the float whose text representation is <c>String</c>.</p> + <p>Returns the float whose text representation is <c><anno>String</anno></c>.</p> <pre> > <input>list_to_float("2.2017764e+0").</input> 2.2017764</pre> - <p>Failure: <c>badarg</c> if <c>String</c> contains a bad + <p>Failure: <c>badarg</c> if <c><anno>String</anno></c> contains a bad representation of a float.</p> </desc> </func> <func> - <name>list_to_integer(String) -> integer()</name> + <name name="list_to_integer" arity="1"/> <fsummary>Convert from text representation to an integer</fsummary> - <type> - <v>String = string()</v> - </type> <desc> <p>Returns an integer whose text representation is - <c>String</c>.</p> + <c><anno>String</anno></c>.</p> <pre> > <input>list_to_integer("123").</input> 123</pre> - <p>Failure: <c>badarg</c> if <c>String</c> contains a bad + <p>Failure: <c>badarg</c> if <c><anno>String</anno></c> contains a bad representation of an integer.</p> </desc> </func> @@ -2005,13 +1712,10 @@ os_prompt%</pre> </desc> </func> <func> - <name>list_to_pid(String) -> pid()</name> + <name name="list_to_pid" arity="1"/> <fsummary>Convert from text representation to a pid</fsummary> - <type> - <v>String = string()</v> - </type> <desc> - <p>Returns a pid whose text representation is <c>String</c>.</p> + <p>Returns a pid whose text representation is <c><anno>String</anno></c>.</p> <warning> <p>This BIF is intended for debugging and for use in the Erlang operating system. It should not be used in @@ -2020,18 +1724,15 @@ os_prompt%</pre> <pre> > <input>list_to_pid("<0.4.1>").</input> <0.4.1></pre> - <p>Failure: <c>badarg</c> if <c>String</c> contains a bad + <p>Failure: <c>badarg</c> if <c><anno>String</anno></c> contains a bad representation of a pid.</p> </desc> </func> <func> - <name>list_to_tuple(List) -> tuple()</name> + <name name="list_to_tuple" arity="1"/> <fsummary>Convert a list to a tuple</fsummary> - <type> - <v>List = [term()]</v> - </type> <desc> - <p>Returns a tuple which corresponds to <c>List</c>. <c>List</c> + <p>Returns a tuple which corresponds to <c><anno>List</anno></c>. <c><anno>List</anno></c> can contain any Erlang terms.</p> <pre> > <input>list_to_tuple([share, ['Ericsson_B', 163]]).</input> @@ -2039,38 +1740,30 @@ os_prompt%</pre> </desc> </func> <func> - <name>load_module(Module, Binary) -> {module, Module} | {error, Reason}</name> + <name name="load_module" arity="2"/> <fsummary>Load object code for a module</fsummary> - <type> - <v>Module = atom()</v> - <v>Binary = binary()</v> - <v>Reason = badfile | not_purged | badfile</v> - </type> - <desc> - <p>If <c>Binary</c> contains the object code for the module - <c>Module</c>, this BIF loads that object code. Also, if - the code for the module <c>Module</c> already exists, all + <desc> + <p>If <c><anno>Binary</anno></c> contains the object code for the module + <c><anno>Module</anno></c>, this BIF loads that object code. Also, if + the code for the module <c><anno>Module</anno></c> already exists, all export references are replaced so they point to the newly loaded code. The previously loaded code is kept in the system as old code, as there may still be processes which are executing that code. It returns either - <c>{module, Module}</c>, or <c>{error, Reason}</c> if loading - fails. <c>Reason</c> is one of the following:</p> + <c>{module, <anno>Module</anno>}</c>, or <c>{error, <anno>Reason</anno>}</c> if loading + fails. <c><anno>Reason</anno></c> is one of the following:</p> <taglist> <tag><c>badfile</c></tag> <item> - <p>The object code in <c>Binary</c> has an incorrect format.</p> + <p>The object code in <c><anno>Binary</anno></c> has an + incorrect format <em>or</em> the object code contains code + for another module than <c><anno>Module</anno></c>.</p> </item> <tag><c>not_purged</c></tag> <item> - <p><c>Binary</c> contains a module which cannot be loaded + <p><c><anno>Binary</anno></c> contains a module which cannot be loaded because old code for this module already exists.</p> </item> - <tag><c>badfile</c></tag> - <item> - <p>The object code contains code for another module than - <c>Module</c></p> - </item> </taglist> <warning> <p>This BIF is intended for the code server (see @@ -2080,15 +1773,8 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:load_nif(Path, LoadInfo) -> ok | {error, {Reason, Text}}</name> + <name name="load_nif" arity="2"/> <fsummary>Load NIF library</fsummary> - <type> - <v>Path = string()</v> - <v>LoadInfo = term()</v> - <v>Reason = load_failed | bad_lib | load | reload | - upgrade | old_code</v> - <v>Text = string()</v> - </type> <desc> <note> <p>In releases older than OTP R14B, NIFs were an @@ -2099,21 +1785,21 @@ os_prompt%</pre> <c>{error,Reason,Text}</c>.</p> </note> <p>Loads and links a dynamic library containing native - implemented functions (NIFs) for a module. <c>Path</c> is a + implemented functions (NIFs) for a module. <c><anno>Path</anno></c> is a file path to the sharable object/dynamic library file minus the OS-dependent file extension (.so for Unix and .dll for Windows). See <seealso marker="erl_nif">erl_nif</seealso> on how to implement a NIF library.</p> - <p><c>LoadInfo</c> can be any term. It will be passed on to + <p><c><anno>LoadInfo</anno></c> can be any term. It will be passed on to the library as part of the initialization. A good practice is to include a module version number to support future code upgrade scenarios.</p> <p>The call to <c>load_nif/2</c> must be made <em>directly</em> from the Erlang code of the module that the NIF library belongs to.</p> - <p>It returns either <c>ok</c>, or <c>{error,{Reason,Text}}</c> - if loading fails. <c>Reason</c> is one of the atoms below, - while <c>Text</c> is a human readable string that may give + <p>It returns either <c>ok</c>, or <c>{error,{<anno>Reason</anno>,Text}}</c> + if loading fails. <c><anno>Reason</anno></c> is one of the atoms below, + while <c><anno>Text</anno></c> is a human readable string that may give some more information about the failure.</p> <taglist> <tag><c>load_failed</c></tag> @@ -2139,11 +1825,8 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:loaded() -> [Module]</name> + <name name="loaded" arity="0"/> <fsummary>List of all loaded modules</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> <p>Returns a list of all loaded Erlang modules (current and/or old code), including preloaded modules.</p> @@ -2151,11 +1834,8 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:localtime() -> DateTime</name> + <name name="localtime" arity="0"/> <fsummary>Current local date and time</fsummary> - <type> - <v>DateTime = <seealso marker="calendar#type-datetime">calendar:datetime()</seealso></v> - </type> <desc> <p>Returns the current local date and time <c>{{Year, Month, Day}, {Hour, Minute, Second}}</c>.</p> @@ -2172,32 +1852,27 @@ os_prompt%</pre> <desc> <p>Converts local date and time to Universal Time Coordinated (UTC), if this is supported by the underlying OS. Otherwise, - no conversion is done and <c>{<anno>Date1</anno>, <anno>Time1</anno>}</c> is returned.</p> + no conversion is done and <c><anno>Localtime</anno></c> is returned.</p> <pre> > <input>erlang:localtime_to_universaltime({{1996,11,6},{14,45,17}}).</input> {{1996,11,6},{13,45,17}}</pre> - <p>Failure: <c>badarg</c> if <c>Date1</c> or <c>Time1</c> do - not denote a valid date or time.</p> + <p>Failure: <c>badarg</c> if <c><anno>Localtime</anno></c> does not denote + a valid date and time.</p> </desc> </func> <func> - <name>erlang:localtime_to_universaltime({Date1, Time1}, IsDst) -> {Date2, Time2}</name> + <name name="localtime_to_universaltime" arity="2"/> <fsummary>Convert from local to Universal Time Coordinated (UTC) date and time</fsummary> - <type> - <v>Date1 = Date2 = <seealso marker="calendar#type-date">calendar:date()</seealso></v> - <v>Time1 = Time2 = <seealso marker="calendar#type-time">calendar:time()</seealso></v> - <v>IsDst = true | false | undefined</v> - </type> <desc> <p>Converts local date and time to Universal Time Coordinated (UTC) just like <c>erlang:localtime_to_universaltime/1</c>, but the caller decides if daylight saving time is active or not.</p> - <p>If <c>IsDst == true</c> the <c>{Date1, Time1}</c> is during - daylight saving time, if <c>IsDst == false</c> it is not, - and if <c>IsDst == undefined</c> the underlying OS may + <p>If <c><anno>IsDst</anno> == true</c> the <c><anno>Localtime</anno></c> is during + daylight saving time, if <c><anno>IsDst</anno> == false</c> it is not, + and if <c><anno>IsDst</anno> == undefined</c> the underlying OS may guess, which is the same as calling - <c>erlang:localtime_to_universaltime({Date1, Time1})</c>.</p> + <c>erlang:localtime_to_universaltime(<anno>Localtime</anno>)</c>.</p> <pre> > <input>erlang:localtime_to_universaltime({{1996,11,6},{14,45,17}}, true).</input> {{1996,11,6},{12,45,17}} @@ -2205,12 +1880,12 @@ os_prompt%</pre> {{1996,11,6},{13,45,17}} > <input>erlang:localtime_to_universaltime({{1996,11,6},{14,45,17}}, undefined).</input> {{1996,11,6},{13,45,17}}</pre> - <p>Failure: <c>badarg</c> if <c>Date1</c> or <c>Time1</c> do - not denote a valid date or time.</p> + <p>Failure: <c>badarg</c> if <c><anno>Localtime</anno></c> does not denote + a valid date and time.</p> </desc> </func> <func> - <name>make_ref() -> reference()</name> + <name name="make_ref" arity="0"/> <fsummary>Return an almost unique reference</fsummary> <desc> <p>Returns an almost unique reference.</p> @@ -2222,33 +1897,23 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:make_tuple(Arity, InitialValue) -> tuple()</name> + <name name="make_tuple" arity="2"/> <fsummary>Create a new tuple of a given arity</fsummary> - <type> - <v>Arity = arity()</v> - <v>InitialValue = term()</v> - </type> <desc> - <p>Returns a new tuple of the given <c>Arity</c>, where all - elements are <c>InitialValue</c>.</p> + <p>Returns a new tuple of the given <c><anno>Arity</anno></c>, where all + elements are <c><anno>InitialValue</anno></c>.</p> <pre> > <input>erlang:make_tuple(4, []).</input> {[],[],[],[]}</pre> </desc> </func> <func> - <name>erlang:make_tuple(Arity, Default, InitList) -> tuple()</name> + <name name="make_tuple" arity="3"/> <fsummary>Create a new tuple with given arity and contents</fsummary> - <type> - <v>Arity = arity()</v> - <v>Default = term()</v> - <v>InitList = [{Position,term()}]</v> - <v>Position = integer()</v> - </type> - <desc> - <p><c>erlang:make_tuple</c> first creates a tuple of size <c>Arity</c> - where each element has the value <c>Default</c>. It then fills - in values from <c>InitList</c>. Each list element in <c>InitList</c> + <desc> + <p><c>erlang:make_tuple</c> first creates a tuple of size <c><anno>Arity</anno></c> + where each element has the value <c><anno>DefaultValue</anno></c>. It then fills + in values from <c><anno>InitList</anno></c>. Each list element in <c><anno>InitList</anno></c> must be a two-tuple where the first element is a position in the newly created tuple and the second element is any term. If a position occurs more than once in the list, the term corresponding to @@ -2267,15 +1932,11 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:md5(Data) -> Digest</name> + <name name="md5" arity="1"/> <fsummary>Compute an MD5 message digest</fsummary> - <type> - <v>Data = iodata()</v> - <v>Digest = binary()</v> - </type> <desc> - <p>Computes an <c>MD5</c> message digest from <c>Data</c>, where - the length of the digest is 128 bits (16 bytes). <c>Data</c> + <p>Computes an <c>MD5</c> message digest from <c><anno>Data</anno></c>, where + the length of the digest is 128 bits (16 bytes). <c><anno>Data</anno></c> is a binary or a list of small integers and binaries.</p> <p>See The MD5 Message Digest Algorithm (RFC 1321) for more information about MD5.</p> @@ -2284,51 +1945,39 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:md5_final(Context) -> Digest</name> + <name name="md5_final" arity="1"/> <fsummary>Finish the update of an MD5 context and return the computed MD5 message digest</fsummary> - <type> - <v>Context = Digest = binary()</v> - </type> <desc> - <p>Finishes the update of an MD5 <c>Context</c> and returns + <p>Finishes the update of an MD5 <c><anno>Context</anno></c> and returns the computed <c>MD5</c> message digest.</p> </desc> </func> <func> - <name>erlang:md5_init() -> Context</name> + <name name="md5_init" arity="0"/> <fsummary>Create an MD5 context</fsummary> - <type> - <v>Context = binary()</v> - </type> <desc> <p>Creates an MD5 context, to be used in subsequent calls to <c>md5_update/2</c>.</p> </desc> </func> <func> - <name>erlang:md5_update(Context, Data) -> NewContext</name> + <name name="md5_update" arity="2"/> <fsummary>Update an MD5 context with data, and return a new context</fsummary> - <type> - <v>Data = iodata()</v> - <v>Context = NewContext = binary()</v> - </type> <desc> - <p>Updates an MD5 <c>Context</c> with <c>Data</c>, and returns - a <c>NewContext</c>.</p> + <p>Updates an MD5 <c><anno>Context</anno></c> with <c><anno>Data</anno></c>, and returns + a <c><anno>NewContext</anno></c>.</p> </desc> </func> <func> - <name>erlang:memory() -> [{Type, Size}]</name> + <name name="memory" arity="0"/> + <type name="memory_type"/> <fsummary>Information about dynamically allocated memory</fsummary> - <type> - <v>Type, Size -- see below</v> - </type> <desc> <p>Returns a list containing information about memory dynamically allocated by the Erlang emulator. Each element of the list is a tuple <c>{Type, Size}</c>. The first element - <c>Type</c>is an atom describing memory type. The second - element <c>Size</c>is memory size in bytes. A description of + <c><anno>Type</anno></c>is an atom describing memory type. The second + element <c><anno>Size</anno></c>is memory size in bytes. A description of each memory type follows:</p> <taglist> <tag><c>total</c></tag> @@ -2390,6 +2039,14 @@ os_prompt%</pre> <p>This memory is part of the memory presented as <c>system</c> memory.</p> </item> + <tag><c>low</c></tag> + <item> + <p>Only on 64-bit halfword emulator.</p> + <p>The total amount of memory allocated in low memory areas + that are restricted to less than 4 Gb even though + the system may have more physical memory.</p> + <p>May be removed in future releases of halfword emulator.</p> + </item> <tag><c>maximum</c></tag> <item> <p>The maximum total amount of memory allocated since @@ -2401,14 +2058,6 @@ os_prompt%</pre> <seealso marker="tools:instrument">instrument(3)</seealso> and/or <seealso marker="erts:erl">erl(1)</seealso>.</p> </item> - <tag><c>low</c></tag> - <item> - <p>Only on 64-bit halfword emulator.</p> - <p>The total amount of memory allocated in low memory areas - that are restricted to less than 4 Gb even though - the system may have more physical memory.</p> - <p>May be removed in future releases of halfword emulator.</p> - </item> </taglist> <note> <p>The <c>system</c> value is not complete. Some allocated @@ -2472,16 +2121,15 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:memory(Type | [Type]) -> Size | [{Type, Size}]</name> + <name name="memory" arity="1" clause_i="1"/> + <name name="memory" arity="1" clause_i="2"/> + <type name="memory_type"/> <fsummary>Information about dynamically allocated memory</fsummary> - <type> - <v>Type, Size -- see below</v> - </type> <desc> <p>Returns the memory size in bytes allocated for memory of - type <c>Type</c>. The argument can also be given as a list - of <c>Type</c> atoms, in which case a corresponding list of - <c>{Type, Size}</c> tuples is returned.</p> + type <c><anno>Type</anno></c>. The argument can also be given as a list + of <c>memory_type()</c> atoms, in which case a corresponding list of + <c>{memory_type(), Size :: integer >= 0}</c> tuples is returned.</p> <note> <p> Since erts version 5.6.4 <c>erlang:memory/1</c> requires that @@ -2493,13 +2141,13 @@ os_prompt%</pre> <taglist> <tag><c>badarg</c></tag> <item> - If <c>Type</c> is not one of the memory types listed in the + If <c><anno>Type</anno></c> is not one of the memory types listed in the documentation of <seealso marker="#memory/0">erlang:memory/0</seealso>. </item> <tag><c>badarg</c></tag> <item> - If <c>maximum</c> is passed as <c>Type</c> and the emulator + If <c>maximum</c> is passed as <c><anno>Type</anno></c> and the emulator is not run in instrumented mode. </item> <tag><c>notsup</c></tag> @@ -2521,13 +2169,10 @@ os_prompt%</pre> </desc> </func> <func> - <name>module_loaded(Module) -> boolean()</name> + <name name="module_loaded" arity="1"/> <fsummary>Check if a module is loaded</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> - <p>Returns <c>true</c> if the module <c>Module</c> is loaded, + <p>Returns <c>true</c> if the module <c><anno>Module</anno></c> is loaded, otherwise returns <c>false</c>. It does not attempt to load the module.</p> <warning> @@ -2538,22 +2183,15 @@ os_prompt%</pre> </desc> </func> <func> - <name>monitor(Type, Item) -> MonitorRef</name> + <name name="monitor" arity="2"/> <fsummary>Start monitoring</fsummary> - <type> - <v>Type = process</v> - <v>Item = pid() | {RegName, Node} | RegName</v> - <v> RegName = atom()</v> - <v> Node = node()</v> - <v>MonitorRef = reference()</v> - </type> - <desc> - <p>The calling process starts monitoring <c>Item</c> which is - an object of type <c>Type</c>.</p> + <desc> + <p>The calling process starts monitoring <c><anno>Item</anno></c> which is + an object of type <c><anno>Type</anno></c>.</p> <p>Currently only processes can be monitored, i.e. the only - allowed <c>Type</c> is <c>process</c>, but other types may be + allowed <c><anno>Type</anno></c> is <c>process</c>, but other types may be allowed in the future.</p> - <p><c>Item</c> can be:</p> + <p><c><anno>Item</anno></c> can be:</p> <taglist> <tag><c>pid()</c></tag> <item> @@ -2579,8 +2217,8 @@ os_prompt%</pre> unregistered.</p> </note> <p>A <c>'DOWN'</c> message will be sent to the monitoring - process if <c>Item</c> dies, if <c>Item</c> does not exist, - or if the connection is lost to the node which <c>Item</c> + process if <c><anno>Item</anno></c> dies, if <c><anno>Item</anno></c> does not exist, + or if the connection is lost to the node which <c><anno>Item</anno></c> resides on. A <c>'DOWN'</c> message has the following pattern:</p> <code type="none"> {'DOWN', MonitorRef, Type, Object, Info}</code> @@ -2591,11 +2229,11 @@ os_prompt%</pre> <item> <p>A reference to the monitored object:</p> <list type="bulleted"> - <item>the pid of the monitored process, if <c>Item</c> was + <item>the pid of the monitored process, if <c><anno>Item</anno></c> was specified as a pid.</item> - <item><c>{RegName, Node}</c>, if <c>Item</c> was specified as + <item><c>{RegName, Node}</c>, if <c><anno>Item</anno></c> was specified as <c>{RegName, Node}</c>.</item> - <item><c>{RegName, Node}</c>, if <c>Item</c> was specified as + <item><c>{RegName, Node}</c>, if <c><anno>Item</anno></c> was specified as <c>RegName</c>. <c>Node</c> will in this case be the name of the local node (<c>node()</c>).</item> </list> @@ -2604,7 +2242,7 @@ os_prompt%</pre> <item> <p>Either the exit reason of the process, <c>noproc</c> (non-existing process), or <c>noconnection</c> (no - connection to <c>Node</c>).</p> + connection to <c><anno>Node</anno></c>).</p> </item> </taglist> <note> @@ -2622,7 +2260,7 @@ os_prompt%</pre> where remote process monitoring by registered name is not implemented), the call fails with <c>badarg</c>.</p> <p>Making several calls to <c>monitor/2</c> for the same - <c>Item</c> is not an error; it results in as many, completely + <c><anno>Item</anno></c> is not an error; it results in as many, completely independent, monitorings.</p> <note> <p>The format of the <c>'DOWN'</c> message changed in the 5.2 @@ -2640,25 +2278,21 @@ os_prompt%</pre> </desc> </func> <func> - <name>monitor_node(Node, Flag) -> true</name> + <name name="monitor_node" arity="2"/> <fsummary>Monitor the status of a node</fsummary> - <type> - <v>Node = node()</v> - <v>Flag = boolean()</v> - </type> <desc> - <p>Monitors the status of the node <c>Node</c>. If <c>Flag</c> - is <c>true</c>, monitoring is turned on; if <c>Flag</c> is + <p>Monitors the status of the node <c><anno>Node</anno></c>. If <c><anno>Flag</anno></c> + is <c>true</c>, monitoring is turned on; if <c><anno>Flag</anno></c> is <c>false</c>, monitoring is turned off.</p> <p>Making several calls to <c>monitor_node(Node, true)</c> for - the same <c>Node</c> is not an error; it results in as many, + the same <c><anno>Node</anno></c> is not an error; it results in as many, completely independent, monitorings.</p> - <p>If <c>Node</c> fails or does not exist, the message + <p>If <c><anno>Node</anno></c> fails or does not exist, the message <c>{nodedown, Node}</c> is delivered to the process. If a process has made two calls to <c>monitor_node(Node, true)</c> - and <c>Node</c> terminates, two <c>nodedown</c> messages are + and <c><anno>Node</anno></c> terminates, two <c>nodedown</c> messages are delivered to the process. If there is no connection to - <c>Node</c>, there will be an attempt to create one. If this + <c><anno>Node</anno></c>, there will be an attempt to create one. If this fails, a <c>nodedown</c> message is delivered.</p> <p>Nodes connected through hidden connections can be monitored as any other node.</p> @@ -2666,14 +2300,8 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:monitor_node(Node, Flag, Options) -> true</name> + <name name="monitor_node" arity="3"/> <fsummary>Monitor the status of a node</fsummary> - <type> - <v>Node = node()</v> - <v>Flag = boolean()</v> - <v>Options = [Option]</v> - <v>Option = allow_passive_connect</v> - </type> <desc> <p>Behaves as <c>monitor_node/2</c> except that it allows an extra option to be given, namely <c>allow_passive_connect</c>. @@ -2696,11 +2324,8 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:nif_error(Reason)</name> + <name name="nif_error" arity="1"/> <fsummary>Stop execution with a given reason</fsummary> - <type> - <v>Reason = term()</v> - </type> <desc> <p>Works exactly like <seealso marker="#error/1">erlang:error/1</seealso>, @@ -2711,12 +2336,8 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:nif_error(Reason, Args)</name> + <name name="nif_error" arity="2"/> <fsummary>Stop execution with a given reason</fsummary> - <type> - <v>Reason = term()</v> - <v>Args = [term()]</v> - </type> <desc> <p>Works exactly like <seealso marker="#error/2">erlang:error/2</seealso>, @@ -2727,11 +2348,8 @@ os_prompt%</pre> </desc> </func> <func> - <name>node() -> Node</name> + <name name="node" arity="0"/> <fsummary>Name of the local node</fsummary> - <type> - <v>Node = node()</v> - </type> <desc> <p>Returns the name of the local node. If the node is not alive, <c>nonode@nohost</c> is returned instead.</p> @@ -2739,14 +2357,10 @@ os_prompt%</pre> </desc> </func> <func> - <name>node(Arg) -> Node</name> + <name name="node" arity="1"/> <fsummary>At which node is a pid, port or reference located</fsummary> - <type> - <v>Arg = pid() | port() | reference()</v> - <v>Node = node()</v> - </type> <desc> - <p>Returns the node where <c>Arg</c> is located. <c>Arg</c> can + <p>Returns the node where <c><anno>Arg</anno></c> is located. <c><anno>Arg</anno></c> can be a pid, a reference, or a port. If the local node is not alive, <c>nonode@nohost</c> is returned.</p> <p>Allowed in guard tests.</p> @@ -2761,17 +2375,13 @@ os_prompt%</pre> </desc> </func> <func> - <name>nodes(Arg | [Arg]) -> Nodes</name> + <name name="nodes" arity="1"/> <fsummary>All nodes of a certain type in the system</fsummary> - <type> - <v>Arg = visible | hidden | connected | this | known</v> - <v>Nodes = [node()]</v> - </type> <desc> <p>Returns a list of nodes according to argument given. The result returned when the argument is a list, is the list of nodes satisfying the disjunction(s) of the list elements.</p> - <p><c>Arg</c> can be any of the following:</p> + <p><c><anno>NodeType</anno></c> can be any of the following:</p> <taglist> <tag><c>visible</c></tag> <item> @@ -2800,15 +2410,12 @@ os_prompt%</pre> <c>nodes() = nodes(visible)</c>.</p> <p>If the local node is not alive, <c>nodes(this) == nodes(known) == [nonode@nohost]</c>, for - any other <c>Arg</c> the empty list [] is returned.</p> + any other <c><anno>Arg</anno></c> the empty list [] is returned.</p> </desc> </func> <func> - <name>now() -> timestamp()</name> - <type> - <v>timestamp() = {MegaSecs, Secs, MicroSecs}</v> - <v>MegaSecs = Secs = MicroSecs = integer() >= 0</v> - </type> + <name name="now" arity="0"/> + <type name="timestamp"/> <fsummary>Elapsed time since 00:00 GMT</fsummary> <desc> <p>Returns the tuple <c>{MegaSecs, Secs, MicroSecs}</c> which is @@ -2826,35 +2433,19 @@ os_prompt%</pre> </desc> </func> <func> - <name>open_port(PortName, PortSettings) -> port()</name> + <name name="open_port" arity="2"/> <fsummary>Open a port</fsummary> - <type> - <v>PortName = {spawn, Command} | {spawn_driver, Command} | {spawn_executable, FileName} | {fd, In, Out}</v> - <v> Command = string()</v> - <v> FileName = [ FileNameChar ] | binary()</v> - <v> FileNameChar = integer() (1..255 or any Unicode codepoint, see description)</v> - <v> In = Out = integer()</v> - <v>PortSettings = [Opt]</v> - <v> Opt = {packet, N} | stream | {line, L} | {cd, Dir} | {env, Env} | {args, [ ArgString ]} | {arg0, ArgString} | exit_status | use_stdio | nouse_stdio | stderr_to_stdout | in | out | binary | eof</v> - <v> N = 1 | 2 | 4</v> - <v> L = integer()</v> - <v> Dir = string()</v> - <v> ArgString = [ FileNameChar ] | binary()</v> - <v> Env = [{Name, Val}]</v> - <v> Name = string()</v> - <v> Val = string() | false</v> - </type> <desc> <p>Returns a port identifier as the result of opening a new Erlang port. A port can be seen as an external Erlang - process. <c>PortName</c> is one of the following:</p> + process. <c><anno>PortName</anno></c> is one of the following:</p> <taglist> - <tag><c>{spawn, Command}</c></tag> + <tag><c>{spawn, <anno>Command</anno>}</c></tag> <item> - <p>Starts an external program. <c>Command</c> is the name - of the external program which will be run. <c>Command</c> + <p>Starts an external program. <c><anno>Command</anno></c> is the name + of the external program which will be run. <c><anno>Command</anno></c> runs outside the Erlang work space unless an Erlang - driver with the name <c>Command</c> is found. If found, + driver with the name <c><anno>Command</anno></c> is found. If found, that driver will be started. A driver runs in the Erlang workspace, which means that it is linked with the Erlang runtime system.</p> @@ -2874,24 +2465,24 @@ os_prompt%</pre> name of the executable (or driver). This (among other things) makes this option unsuitable for running programs having spaces in file or directory names. Use - {spawn_executable, Command} instead if spaces in executable + {spawn_executable, <anno>Command</anno>} instead if spaces in executable file names is desired.</p> </item> - <tag><c>{spawn_driver, Command}</c></tag> + <tag><c>{spawn_driver, <anno>Command</anno>}</c></tag> <item> - <p>Works like <c>{spawn, Command}</c>, but demands the + <p>Works like <c>{spawn, <anno>Command</anno>}</c>, but demands the first (space separated) token of the command to be the name of a loaded driver. If no driver with that name is loaded, a <c>badarg</c> error is raised.</p> </item> - <tag><c>{spawn_executable, Command}</c></tag> + <tag><c>{spawn_executable, <anno>FileName</anno>}</c></tag> <item> - <p>Works like <c>{spawn, Command}</c>, but only runs - external executables. The <c>Command</c> in its whole + <p>Works like <c>{spawn, <anno>FileName</anno>}</c>, but only runs + external executables. The <c><anno>FileName</anno></c> in its whole is used as the name of the executable, including any spaces. If arguments are to be passed, the - <c>args</c> and <c>arg0</c> <c>PortSettings</c> can be used.</p> + <c>args</c> and <c>arg0</c> <c><anno>PortSettings</anno></c> can be used.</p> <p>The shell is not usually invoked to start the program, it's executed directly. Neither is the @@ -2922,7 +2513,7 @@ os_prompt%</pre> of the executable is limited to the ISO-latin-1 character set.</p></note> - <p>If the <c>Command</c> cannot be run, an error + <p>If the <c><anno>FileName</anno></c> cannot be run, an error exception, with the posix error code as the reason, is raised. The error reason may differ between operating systems. Typically the error <c>enoent</c> is raised @@ -2930,23 +2521,23 @@ os_prompt%</pre> <c>eaccess</c> is raised when the given file is not executable.</p> </item> - <tag><c>{fd, In, Out}</c></tag> + <tag><c>{fd, <anno>In</anno>, <anno>Out</anno>}</c></tag> <item> <p>Allows an Erlang process to access any currently opened file descriptors used by Erlang. The file descriptor - <c>In</c> can be used for standard input, and the file - descriptor <c>Out</c> for standard output. It is only + <c><anno>In</anno></c> can be used for standard input, and the file + descriptor <c><anno>Out</anno></c> for standard output. It is only used for various servers in the Erlang operating system (<c>shell</c> and <c>user</c>). Hence, its use is very limited.</p> </item> </taglist> - <p><c>PortSettings</c> is a list of settings for the port. + <p><c><anno>PortSettings</anno></c> is a list of settings for the port. Valid settings are:</p> <taglist> - <tag><c>{packet, N}</c></tag> + <tag><c>{packet, <anno>N</anno>}</c></tag> <item> - <p>Messages are preceded by their length, sent in <c>N</c> + <p>Messages are preceded by their length, sent in <c><anno>N</anno></c> bytes, with the most significant byte first. Valid values for <c>N</c> are 1, 2, or 4.</p> </item> @@ -2956,7 +2547,7 @@ os_prompt%</pre> user-defined protocol must be used between the Erlang process and the external object.</p> </item> - <tag><c>{line, L}</c></tag> + <tag><c>{line, <anno>L</anno>}</c></tag> <item> <p>Messages are delivered on a per line basis. Each line (delimited by the OS-dependent newline sequence) is @@ -2964,7 +2555,7 @@ os_prompt%</pre> is <c>{Flag, Line}</c>, where <c>Flag</c> is either <c>eol</c> or <c>noeol</c> and <c>Line</c> is the actual data delivered (without the newline sequence).</p> - <p><c>L</c> specifies the maximum line length in bytes. + <p><c><anno>L</anno></c> specifies the maximum line length in bytes. Lines longer than this will be delivered in more than one message, with the <c>Flag</c> set to <c>noeol</c> for all but the last message. If end of file is encountered @@ -2972,36 +2563,36 @@ os_prompt%</pre> sequence, the last line will also be delivered with the <c>Flag</c> set to <c>noeol</c>. In all other cases, lines are delivered with <c>Flag</c> set to <c>eol</c>.</p> - <p>The <c>{packet, N}</c> and <c>{line, L}</c> settings are + <p>The <c>{packet, <anno>N</anno>}</c> and <c>{line, <anno>L</anno>}</c> settings are mutually exclusive.</p> </item> - <tag><c>{cd, Dir}</c></tag> + <tag><c>{cd, <anno>Dir</anno>}</c></tag> <item> - <p>This is only valid for <c>{spawn, Command}</c> and - <c>{spawn_executable, Command}</c>. - The external program starts using <c>Dir</c> as its - working directory. <c>Dir</c> must be a string. Not + <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> and + <c>{spawn_executable, <anno>FileName</anno>}</c>. + The external program starts using <c><anno>Dir</anno></c> as its + working directory. <c><anno>Dir</anno></c> must be a string. Not available on VxWorks.</p> </item> - <tag><c>{env, Env}</c></tag> + <tag><c>{env, <anno>Env</anno>}</c></tag> <item> - <p>This is only valid for <c>{spawn, Command}</c> and - <c>{spawn_executable, Command}</c>. + <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> and + <c>{spawn_executable, <anno>FileName</anno>}</c>. The environment of the started process is extended using - the environment specifications in <c>Env</c>.</p> - <p><c>Env</c> should be a list of tuples <c>{Name, Val}</c>, - where <c>Name</c> is the name of an environment variable, - and <c>Val</c> is the value it is to have in the spawned - port process. Both <c>Name</c> and <c>Val</c> must be - strings. The one exception is <c>Val</c> being the atom + the environment specifications in <c><anno>Env</anno></c>.</p> + <p><c><anno>Env</anno></c> should be a list of tuples <c>{<anno>Name</anno>, <anno>Val</anno>}</c>, + where <c><anno>Name</anno></c> is the name of an environment variable, + and <c><anno>Val</anno></c> is the value it is to have in the spawned + port process. Both <c><anno>Name</anno></c> and <c><anno>Val</anno></c> must be + strings. The one exception is <c><anno>Val</anno></c> being the atom <c>false</c> (in analogy with <c>os:getenv/1</c>), which removes the environment variable. Not available on VxWorks.</p> </item> - <tag><c>{args, [ string() ]}</c></tag> + <tag><c>{args, [ string() | binary() ]}</c></tag> <item> - <p>This option is only valid for <c>{spawn_executable, Command}</c> + <p>This option is only valid for <c>{spawn_executable, <anno>FileName</anno>}</c> and specifies arguments to the executable. Each argument is given as a separate string and (on Unix) eventually ends up as one element each in the argument vector. On @@ -3044,10 +2635,10 @@ os_prompt%</pre> option can be used.</p> </item> - <tag><c>{arg0, string()}</c></tag> + <tag><c>{arg0, string() | binary()}</c></tag> <item> - <p>This option is only valid for <c>{spawn_executable, Command}</c> + <p>This option is only valid for <c>{spawn_executable, <anno>FileName</anno>}</c> and explicitly specifies the program name argument when running an executable. This might in some circumstances, on some operating systems, be desirable. How the program @@ -3061,9 +2652,9 @@ os_prompt%</pre> <tag><c>exit_status</c></tag> <item> - <p>This is only valid for <c>{spawn, Command}</c> where - <c>Command</c> refers to an external program, and for - <c>{spawn_executable, Command}</c>.</p> + <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> where + <c><anno>Command</anno></c> refers to an external program, and for + <c>{spawn_executable, <anno>FileName</anno>}</c>.</p> <p>When the external process connected to the port exits, a message of the form <c>{Port,{exit_status,Status}}</c> is sent to the connected process, where <c>Status</c> is the @@ -3078,8 +2669,8 @@ os_prompt%</pre> </item> <tag><c>use_stdio</c></tag> <item> - <p>This is only valid for <c>{spawn, Command}</c> and - <c>{spawn_executable, Command}</c>. It + <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> and + <c>{spawn_executable, <anno>FileName</anno>}</c>. It allows the standard input and output (file descriptors 0 and 1) of the spawned (UNIX) process for communication with Erlang.</p> @@ -3176,7 +2767,7 @@ os_prompt%</pre> </item> <tag><c>enoent</c></tag> <item> - <p>The <c>Command</c> given in <c>{spawn_executable, Command}</c> does not point out an existing file.</p> + <p>The <c><anno>FileName</anno></c> given in <c>{spawn_executable, <anno>FileName</anno>}</c> does not point out an existing file.</p> </item> </taglist> <p>During use of a port opened using <c>{spawn, Name}</c>, @@ -3192,56 +2783,47 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:phash(Term, Range) -> Hash</name> + <name name="phash" arity="2"/> + <type_desc variable="Range">Range = 1..2^32, Hash = 1..Range</type_desc> <fsummary>Portable hash function</fsummary> - <type> - <v>Term = term()</v> - <v>Range = 1..2^32</v> - <v>Hash = 1..Range</v> - </type> <desc> <p>Portable hash function that will give the same hash for the same Erlang term regardless of machine architecture and ERTS version (the BIF was introduced in ERTS 4.9.1.1). Range can be between 1 and 2^32, the function returns a hash value - for <c>Term</c> within the range <c>1..Range</c>.</p> + for <c><anno>Term</anno></c> within the range <c>1..<anno>Range</anno></c>.</p> <p>This BIF could be used instead of the old deprecated <c>erlang:hash/2</c> BIF, as it calculates better hashes for all data-types, but consider using <c>phash2/1,2</c> instead.</p> </desc> </func> <func> - <name>erlang:phash2(Term [, Range]) -> Hash</name> + <name name="phash2" arity="1"/> + <name name="phash2" arity="2"/> + <type_desc variable="Range">1..2^32</type_desc> + <type_desc variable="Hash">0..Range-1</type_desc> <fsummary>Portable hash function</fsummary> - <type> - <v>Term = term()</v> - <v>Range = 1..2^32</v> - <v>Hash = 0..Range-1</v> - </type> <desc> <p>Portable hash function that will give the same hash for the same Erlang term regardless of machine architecture and ERTS version (the BIF was introduced in ERTS 5.2). Range can be between 1 and 2^32, the function returns a hash value for - <c>Term</c> within the range <c>0..Range-1</c>. When called - without the <c>Range</c> argument, a value in the range + <c><anno>Term</anno></c> within the range <c>0..<anno>Range</anno>-1</c>. When called + without the <c><anno>Range</anno></c> argument, a value in the range <c>0..2^27-1</c> is returned.</p> <p>This BIF should always be used for hashing terms. It distributes small integers better than <c>phash/2</c>, and it is faster for bignums and binaries.</p> - <p>Note that the range <c>0..Range-1</c> is different from - the range of <c>phash/2</c> (<c>1..Range</c>).</p> + <p>Note that the range <c>0..<anno>Range</anno>-1</c> is different from + the range of <c>phash/2</c> (<c>1..<anno>Range</anno></c>).</p> </desc> </func> <func> - <name>pid_to_list(Pid) -> string()</name> + <name name="pid_to_list" arity="1"/> <fsummary>Text representation of a pid</fsummary> - <type> - <v>Pid = pid()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of <c>Pid</c>.</p> + representation of <c><anno>Pid</anno></c>.</p> <warning> <p>This BIF is intended for debugging and for use in the Erlang operating system. It should not be used in @@ -3250,88 +2832,74 @@ os_prompt%</pre> </desc> </func> <func> - <name>port_close(Port) -> true</name> + <name name="port_close" arity="1"/> <fsummary>Close an open port</fsummary> - <type> - <v>Port = port() | atom()</v> - </type> <desc> <p>Closes an open port. Roughly the same as - <c>Port ! {self(), close}</c> except for the error behaviour + <c><anno>Port</anno> ! {self(), close}</c> except for the error behaviour (see below), and that the port does <em>not</em> reply with <c>{Port, closed}</c>. Any process may close a port with <c>port_close/1</c>, not only the port owner (the connected process).</p> - <p>For comparison: <c>Port ! {self(), close}</c> fails with - <c>badarg</c> if <c>Port</c> cannot be sent to (i.e., - <c>Port</c> refers neither to a port nor to a process). If - <c>Port</c> is a closed port nothing happens. If <c>Port</c> + <p>For comparison: <c><anno>Port</anno> ! {self(), close}</c> fails with + <c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to (i.e., + <c><anno>Port</anno></c> refers neither to a port nor to a process). If + <c><anno>Port</anno></c> is a closed port nothing happens. If <c><anno>Port</anno></c> is an open port and the calling process is the port owner, the port replies with <c>{Port, closed}</c> when all buffers have been flushed and the port really closes, but if the calling process is not the port owner the <em>port owner</em> fails with <c>badsig</c>.</p> <p>Note that any process can close a port using - <c>Port ! {PortOwner, close}</c> just as if it itself was + <c><anno>Port</anno> ! {PortOwner, close}</c> just as if it itself was the port owner, but the reply always goes to the port owner.</p> <p>In short: <c>port_close(Port)</c> has a cleaner and more - logical behaviour than <c>Port ! {self(), close}</c>.</p> - <p>Failure: <c>badarg</c> if <c>Port</c> is not an open port or + logical behaviour than <c><anno>Port</anno> ! {self(), close}</c>.</p> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port or the registered name of an open port.</p> </desc> </func> <func> - <name>port_command(Port, Data) -> true</name> + <name name="port_command" arity="2"/> <fsummary>Send data to a port</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Data = iodata()</v> - </type> <desc> <p>Sends data to a port. Same as - <c>Port ! {self(), {command, Data}}</c> except for the error + <c><anno>Port</anno> ! {self(), {command, Data}}</c> except for the error behaviour (see below). Any process may send data to a port with <c>port_command/2</c>, not only the port owner (the connected process).</p> - <p>For comparison: <c>Port ! {self(), {command, Data}}</c> - fails with <c>badarg</c> if <c>Port</c> cannot be sent to - (i.e., <c>Port</c> refers neither to a port nor to a process). - If <c>Port</c> is a closed port the data message disappears - without a sound. If <c>Port</c> is open and the calling + <p>For comparison: <c><anno>Port</anno> ! {self(), {command, Data}}</c> + fails with <c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to + (i.e., <c><anno>Port</anno></c> refers neither to a port nor to a process). + If <c><anno>Port</anno></c> is a closed port the data message disappears + without a sound. If <c><anno>Port</anno></c> is open and the calling process is not the port owner, the <em>port owner</em> fails with <c>badsig</c>. The port owner fails with <c>badsig</c> - also if <c>Data</c> is not a valid IO list.</p> + also if <c><anno>Data</anno></c> is not a valid IO list.</p> <p>Note that any process can send to a port using - <c>Port ! {PortOwner, {command, Data}}</c> just as if it + <c><anno>Port</anno> ! {PortOwner, {command, <anno>Data</anno>}}</c> just as if it itself was the port owner.</p> - <p>In short: <c>port_command(Port, Data)</c> has a cleaner and + <p>In short: <c>port_command(<anno>Port</anno>, <anno>Data</anno>)</c> has a cleaner and more logical behaviour than - <c>Port ! {self(), {command, Data}}</c>.</p> + <c><anno>Port</anno> ! {self(), {command, Data}}</c>.</p> <p>If the port is busy, the calling process will be suspended until the port is not busy anymore.</p> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> <item> - If <c>Port</c> is not an open port or the registered name + If <c><anno>Port</anno></c> is not an open port or the registered name of an open port. </item> <tag><c>badarg</c></tag> <item> - If <c>Data</c> is not a valid io list. + If <c><anno>Data</anno></c> is not a valid io list. </item> </taglist> </desc> </func> <func> - <name>port_command(Port, Data, OptionList) -> boolean()</name> + <name name="port_command" arity="3"/> <fsummary>Send data to a port</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Data = iodata()</v> - <v>OptionList = [Option]</v> - <v>Option = force</v> - <v>Option = nosuspend</v> - </type> <desc> <p>Sends data to a port. <c>port_command(Port, Data, [])</c> equals <c>port_command(Port, Data)</c>.</p> @@ -3339,7 +2907,7 @@ os_prompt%</pre> otherwise, <c>true</c> is returned.</p> <p>If the port is busy, the calling process will be suspended until the port is not busy anymore.</p> - <p>Currently the following <c>Option</c>s are valid:</p> + <p>Currently the following <c><anno>Option</anno></c>s are valid:</p> <taglist> <tag><c>force</c></tag> <item>The calling process will not be suspended if the port is @@ -3363,16 +2931,16 @@ os_prompt%</pre> <taglist> <tag><c>badarg</c></tag> <item> - If <c>Port</c> is not an open port or the registered name + If <c><anno>Port</anno></c> is not an open port or the registered name of an open port. </item> <tag><c>badarg</c></tag> <item> - If <c>Data</c> is not a valid io list. + If <c><anno>Data</anno></c> is not a valid io list. </item> <tag><c>badarg</c></tag> <item> - If <c>OptionList</c> is not a valid option list. + If <c><anno>OptionList</anno></c> is not a valid option list. </item> <tag><c>notsup</c></tag> <item> @@ -3384,15 +2952,11 @@ os_prompt%</pre> </desc> </func> <func> - <name>port_connect(Port, Pid) -> true</name> + <name name="port_connect" arity="2"/> <fsummary>Set the owner of a port</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Pid = pid()</v> - </type> <desc> - <p>Sets the port owner (the connected port) to <c>Pid</c>. - Roughly the same as <c>Port ! {self(), {connect, Pid}}</c> + <p>Sets the port owner (the connected port) to <c><anno>Pid</anno></c>. + Roughly the same as <c><anno>Port</anno> ! {self(), {connect, <anno>Pid</anno>}}</c> except for the following:</p> <list type="bulleted"> <item> @@ -3410,160 +2974,142 @@ os_prompt%</pre> <c>unlink(Port)</c> if this is not desired. Any process may set the port owner to be any process with <c>port_connect/2</c>.</p> - <p>For comparison: <c>Port ! {self(), {connect, Pid}}</c> fails - with <c>badarg</c> if <c>Port</c> cannot be sent to (i.e., - <c>Port</c> refers neither to a port nor to a process). If - <c>Port</c> is a closed port nothing happens. If <c>Port</c> + <p>For comparison: <c><anno>Port</anno> ! {self(), {connect, <anno>Pid</anno>}}</c> fails + with <c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to (i.e., + <c><anno>Port</anno></c> refers neither to a port nor to a process). If + <c><anno>Port</anno></c> is a closed port nothing happens. If <c><anno>Port</anno></c> is an open port and the calling process is the port owner, the port replies with <c>{Port, connected}</c> to the old port owner. Note that the old port owner is still linked to - the port, and that the new is not. If <c>Port</c> is an open + the port, and that the new is not. If <c><anno>Port</anno></c> is an open port and the calling process is not the port owner, the <em>port owner</em> fails with <c>badsig</c>. The port - owner fails with <c>badsig</c> also if <c>Pid</c> is not an + owner fails with <c>badsig</c> also if <c><anno>Pid</anno></c> is not an existing local pid.</p> <p>Note that any process can set the port owner using - <c>Port ! {PortOwner, {connect, Pid}}</c> just as if it + <c><anno>Port</anno> ! {PortOwner, {connect, <anno>Pid</anno>}}</c> just as if it itself was the port owner, but the reply always goes to the port owner.</p> - <p>In short: <c>port_connect(Port, Pid)</c> has a cleaner and + <p>In short: <c>port_connect(<anno>Port</anno>, <anno>Pid</anno>)</c> has a cleaner and more logical behaviour than - <c>Port ! {self(),{connect,Pid}}</c>.</p> - <p>Failure: <c>badarg</c> if <c>Port</c> is not an open port - or the registered name of an open port, or if <c>Pid</c> is + <c><anno>Port</anno> ! {self(),{connect,<anno>Pid</anno>}}</c>.</p> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port + or the registered name of an open port, or if <c><anno>Pid</anno></c> is not an existing local pid.</p> </desc> </func> <func> - <name>port_control(Port, Operation, Data) -> Res</name> + <name name="port_control" arity="3"/> <fsummary>Perform a synchronous control operation on a port</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Operation = integer()</v> - <v>Data = Res = iodata()</v> - </type> <desc> <p>Performs a synchronous control operation on a port. - The meaning of <c>Operation</c> and <c>Data</c> depends on + The meaning of <c><anno>Operation</anno></c> and <c><anno>Data</anno></c> depends on the port, i.e., on the port driver. Not all port drivers support this control feature.</p> <p>Returns: a list of integers in the range 0 through 255, or a binary, depending on the port driver. The meaning of the returned data also depends on the port driver.</p> - <p>Failure: <c>badarg</c> if <c>Port</c> is not an open port or - the registered name of an open port, if <c>Operation</c> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port or + the registered name of an open port, if <c><anno>Operation</anno></c> cannot fit in a 32-bit integer, if the port driver does not support synchronous control operations, or if the port driver so decides for any reason (probably something wrong with - <c>Operation</c> or <c>Data</c>).</p> + <c><anno>Operation</anno></c> or <c><anno>Data</anno></c>).</p> </desc> </func> <func> - <name>erlang:port_call(Port, Operation, Data) -> term()</name> + <name name="port_call" arity="3"/> <fsummary>Synchronous call to a port with term data</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Operation = integer()</v> - <v>Data = term()</v> - </type> <desc> <p>Performs a synchronous call to a port. The meaning of - <c>Operation</c> and <c>Data</c> depends on the port, i.e., + <c><anno>Operation</anno></c> and <c><anno>Data</anno></c> depends on the port, i.e., on the port driver. Not all port drivers support this feature.</p> - <p><c>Port</c> is a port identifier, referring to a driver.</p> - <p><c>Operation</c> is an integer, which is passed on to + <p><c><anno>Port</anno></c> is a port identifier, referring to a driver.</p> + <p><c><anno>Operation</anno></c> is an integer, which is passed on to the driver.</p> - <p><c>Data</c> is any Erlang term. This data is converted to + <p><c><anno>Data</anno></c> is any Erlang term. This data is converted to binary term format and sent to the port.</p> <p>Returns: a term from the driver. The meaning of the returned data also depends on the port driver.</p> - <p>Failure: <c>badarg</c> if <c>Port</c> is not an open port or - the registered name of an open port, if <c>Operation</c> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port or + the registered name of an open port, if <c><anno>Operation</anno></c> cannot fit in a 32-bit integer, if the port driver does not support synchronous control operations, or if the port driver so decides for any reason (probably something wrong with - <c>Operation</c> or <c>Data</c>).</p> + <c><anno>Operation</anno></c> or <c><anno>Data</anno></c>).</p> </desc> </func> <func> - <name>erlang:port_info(Port) -> [{Item, Info}] | undefined</name> + <name name="port_info" arity="1"/> + <type name="port_info_result_item"/> <fsummary>Information about a port</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Item, Info -- see below</v> - </type> <desc> <p>Returns a list containing tuples with information about - the <c>Port</c>, or <c>undefined</c> if the port is not open. + the <c><anno>Port</anno></c>, or <c>undefined</c> if the port is not open. The order of the tuples is not defined, nor are all the tuples mandatory.</p> <taglist> - <tag><c>{registered_name, RegName}</c></tag> + <tag><c>{registered_name, <anno>RegName</anno>}</c></tag> <item> - <p><c>RegName</c> (an atom) is the registered name of + <p><c><anno>RegName</anno></c> (an atom) is the registered name of the port. If the port has no registered name, this tuple is not present in the list.</p> </item> - <tag><c>{id, Index}</c></tag> + <tag><c>{id, <anno>Index</anno>}</c></tag> <item> - <p><c>Index</c> (an integer) is the internal index of the + <p><c><anno>Index</anno></c> (an integer) is the internal index of the port. This index may be used to separate ports.</p> </item> - <tag><c>{connected, Pid}</c></tag> + <tag><c>{connected, <anno>Pid</anno>}</c></tag> <item> - <p><c>Pid</c> is the process connected to the port.</p> + <p><c><anno>Pid</anno></c> is the process connected to the port.</p> </item> - <tag><c>{links, Pids}</c></tag> + <tag><c>{links, <anno>Pids</anno>}</c></tag> <item> - <p><c>Pids</c> is a list of pids to which processes the + <p><c><anno>Pids</anno></c> is a list of pids to which processes the port is linked.</p> </item> - <tag><c>{name, String}</c></tag> + <tag><c>{name, <anno>String</anno>}</c></tag> <item> - <p><c>String</c> is the command name set by + <p><c><anno>String</anno></c> is the command name set by <c>open_port</c>.</p> </item> - <tag><c>{input, Bytes}</c></tag> + <tag><c>{input, <anno>Bytes</anno>}</c></tag> <item> - <p><c>Bytes</c> is the total number of bytes read from + <p><c><anno>Bytes</anno></c> is the total number of bytes read from the port.</p> </item> - <tag><c>{output, Bytes}</c></tag> + <tag><c>{output, <anno>Bytes</anno>}</c></tag> <item> - <p><c>Bytes</c> is the total number of bytes written to + <p><c><anno>Bytes</anno></c> is the total number of bytes written to the port.</p> </item> </taglist> - <p>Failure: <c>badarg</c> if <c>Port</c> is not a local port.</p> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port.</p> </desc> </func> <func> - <name>erlang:port_info(Port, Item) -> {Item, Info} | undefined | []</name> + <name name="port_info" arity="2"/> + <type name="port_info_item"/> + <type name="port_info_result_item"/> <fsummary>Information about a port</fsummary> - <type> - <v>Port = port() | atom()</v> - <v>Item, Info -- see below</v> - </type> - <desc> - <p>Returns information about <c>Port</c> as specified - by <c>Item</c>, or <c>undefined</c> if the port is not open. - Also, if <c>Item == registered_name</c> and the port has no - registered name, [] is returned.</p> - <p>For valid values of <c>Item</c>, and corresponding - values of <c>Info</c>, see + <desc> + <p>Returns information about <c><anno>Port</anno></c> as specified + by <c><anno>Item</anno></c>, or <c>undefined</c> if the port is not open. + Also, if <c>Item =:= registered_name</c> and the port has no + registered name, <c>[]</c> is returned.</p> + <p>For valid values of <c><anno>Item</anno></c>, and corresponding + values of <c><anno>Result</anno></c>, see <seealso marker="#port_info/1">erlang:port_info/1</seealso>.</p> - <p>Failure: <c>badarg</c> if <c>Port</c> is not a local port.</p> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port.</p> </desc> </func> <func> - <name>erlang:port_to_list(Port) -> string()</name> + <name name="port_to_list" arity="1"/> <fsummary>Text representation of a port identifier</fsummary> - <type> - <v>Port = port()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of the port identifier <c>Port</c>.</p> + representation of the port identifier <c><anno>Port</anno></c>.</p> <warning> <p>This BIF is intended for debugging and for use in the Erlang operating system. It should not be used in @@ -3572,18 +3118,15 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:ports() -> [port()]</name> + <name name="ports" arity="0"/> <fsummary>All open ports</fsummary> <desc> <p>Returns a list of all ports on the local node.</p> </desc> </func> <func> - <name>pre_loaded() -> [Module]</name> + <name name="pre_loaded" arity="0"/> <fsummary>List of all pre-loaded modules</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> <p>Returns a list of Erlang modules which are pre-loaded in the system. As all loading of code is done through the file @@ -3592,220 +3135,222 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:process_display(Pid, Type) -> void()</name> + <name name="process_display" arity="2"/> <fsummary>Write information about a local process on standard error</fsummary> - <type> - <v>Pid = pid()</v> - <v>Type = backtrace</v> - </type> <desc> - <p>Writes information about the local process <c>Pid</c> on + <p>Writes information about the local process <c><anno>Pid</anno></c> on standard error. The currently allowed value for the atom - <c>Type</c> is <c>backtrace</c>, which shows the contents of + <c><anno>Type</anno></c> is <c>backtrace</c>, which shows the contents of the call stack, including information about the call chain, with the current function printed first. The format of the output is not further defined.</p> </desc> </func> <func> - <name>process_flag(Flag, Value) -> OldValue</name> - <fsummary>Set process flags for the calling process</fsummary> - <type> - <v>Flag, Value, OldValue -- see below</v> - </type> + <name name="process_flag" arity="2" clause_i="1"/> + <fsummary>Set process flag trap_exit for the calling process</fsummary> <desc> - <p>Sets certain flags for the process which calls this - function. Returns the old value of the flag.</p> - <taglist> - <tag><c>process_flag(trap_exit, Boolean)</c></tag> - <item> - <p>When <c>trap_exit</c> is set to <c>true</c>, exit signals - arriving to a process are converted to <c>{'EXIT', From, Reason}</c> messages, which can be received as ordinary - messages. If <c>trap_exit</c> is set to <c>false</c>, the - process exits if it receives an exit signal other than - <c>normal</c> and the exit signal is propagated to its - linked processes. Application processes should normally - not trap exits.</p> - <p>See also <seealso marker="#exit/2">exit/2</seealso>.</p> - </item> - <tag><c>process_flag(error_handler, Module)</c></tag> - <item> - <p>This is used by a process to redefine the error handler - for undefined function calls and undefined registered - processes. Inexperienced users should not use this flag - since code auto-loading is dependent on the correct - operation of the error handling module.</p> - </item> - <tag><c>process_flag(min_heap_size, MinHeapSize)</c></tag> - <item> - <p>This changes the minimum heap size for the calling - process.</p> - </item> - <tag><c>process_flag(min_bin_vheap_size, MinBinVHeapSize)</c></tag> - <item> - <p>This changes the minimum binary virtual heap size for the calling - process.</p> - </item> - <tag><marker id="process_flag_priority"><c>process_flag(priority, Level)</c></marker></tag> - <item> - <p>This sets the process priority. <c>Level</c> is an atom. - There are currently four priority levels: <c>low</c>, - <c>normal</c>, <c>high</c>, and <c>max</c>. The default - priority level is <c>normal</c>. <em>NOTE</em>: The - <c>max</c> priority level is reserved for internal use in - the Erlang runtime system, and should <em>not</em> be used - by others. - </p> - <p>Internally in each priority level processes are scheduled - in a round robin fashion. - </p> - <p>Execution of processes on priority <c>normal</c> and - priority <c>low</c> will be interleaved. Processes on - priority <c>low</c> will be selected for execution less - frequently than processes on priority <c>normal</c>. - </p> - <p>When there are runnable processes on priority <c>high</c> - no processes on priority <c>low</c>, or <c>normal</c> will - be selected for execution. Note, however, that this does - <em>not</em> mean that no processes on priority <c>low</c>, - or <c>normal</c> will be able to run when there are - processes on priority <c>high</c> running. On the runtime - system with SMP support there might be more processes running - in parallel than processes on priority <c>high</c>, i.e., - a <c>low</c>, and a <c>high</c> priority process might - execute at the same time. - </p> - <p>When there are runnable processes on priority <c>max</c> - no processes on priority <c>low</c>, <c>normal</c>, or - <c>high</c> will be selected for execution. As with the - <c>high</c> priority, processes on lower priorities might - execute in parallel with processes on priority <c>max</c>. - </p> - <p>Scheduling is preemptive. Regardless of priority, a process - is preempted when it has consumed more than a certain amount - of reductions since the last time it was selected for - execution. - </p> - <p><em>NOTE</em>: You should not depend on the scheduling - to remain exactly as it is today. Scheduling, at least on - the runtime system with SMP support, is very likely to be - modified in the future in order to better utilize available - processor cores. - </p> - <p>There is currently <em>no</em> automatic mechanism for - avoiding priority inversion, such as priority inheritance, - or priority ceilings. When using priorities you have - to take this into account and handle such scenarios by - yourself. - </p> - <p>Making calls from a <c>high</c> priority process into code - that you don't have control over may cause the <c>high</c> - priority process to wait for a processes with lower - priority, i.e., effectively decreasing the priority of the - <c>high</c> priority process during the call. Even if this - isn't the case with one version of the code that you don't - have under your control, it might be the case in a future - version of it. This might, for example, happen if a - <c>high</c> priority process triggers code loading, since - the code server runs on priority <c>normal</c>. - </p> - <p>Other priorities than <c>normal</c> are normally not needed. - When other priorities are used, they need to be used - with care, especially the <c>high</c> priority <em>must</em> - be used with care. A process on <c>high</c> priority should - only perform work for short periods of time. Busy looping for - long periods of time in a <c>high</c> priority process will - most likely cause problems, since there are important servers - in OTP running on priority <c>normal</c>. - </p> - </item> - - <tag><c>process_flag(save_calls, N)</c></tag> - <item> - <p><c>N</c> must be an integer in the interval 0..10000. - If <c>N</c> > 0, call saving is made active for the - process, which means that information about the <c>N</c> - most recent global function calls, BIF calls, sends and - receives made by the process are saved in a list, which - can be retrieved with - <c>process_info(Pid, last_calls)</c>. A global function - call is one in which the module of the function is - explicitly mentioned. Only a fixed amount of information - is saved: a tuple <c>{Module, Function, Arity}</c> for - function calls, and the mere atoms <c>send</c>, - <c>'receive'</c> and <c>timeout</c> for sends and receives - (<c>'receive'</c> when a message is received and - <c>timeout</c> when a receive times out). If <c>N</c> = 0, - call saving is disabled for the process, which is the - default. Whenever the size of the call saving list is set, - its contents are reset.</p> - </item> - <tag><c>process_flag(sensitive, Boolean)</c></tag> - <item> - <p>Set or clear the <c>sensitive</c> flag for the current process. - When a process has been marked as sensitive by calling - <c>process_flag(sensitive, true)</c>, features in the run-time - system that can be used for examining the data and/or inner working - of the process are silently disabled.</p> - <p>Features that are disabled include (but are not limited to) - the following:</p> - <p>Tracing: Trace flags can still be set for the process, but no - trace messages of any kind will be generated. - (If the <c>sensitive</c> flag is turned off, trace messages will - again be generated if there are any trace flags set.)</p> - <p>Sequential tracing: The sequential trace token will be propagated - as usual, but no sequential trace messages will be generated.</p> - <p><c>process_info/1,2</c> cannot be used to read out the message - queue or the process dictionary (both will be returned as empty lists).</p> - <p>Stack back-traces cannot be displayed for the process.</p> - <p>In crash dumps, the stack, messages, and the process dictionary - will be omitted.</p> - <p>If <c>{save_calls,N}</c> has been set for the process, no - function calls will be saved to the call saving list. - (The call saving list will not be cleared; furthermore, send, receive, - and timeout events will still be added to the list.)</p> - </item> - </taglist> + <p>When <c>trap_exit</c> is set to <c>true</c>, exit signals + arriving to a process are converted to <c>{'EXIT', From, Reason}</c> messages, which can be received as ordinary + messages. If <c>trap_exit</c> is set to <c>false</c>, the + process exits if it receives an exit signal other than + <c>normal</c> and the exit signal is propagated to its + linked processes. Application processes should normally + not trap exits.</p> + <p>Returns the old value of the flag.</p> + <p>See also <seealso marker="#exit/2">exit/2</seealso>.</p> + </desc> + </func> + <func> + <name name="process_flag" arity="2" clause_i="2"/> + <fsummary>Set process flag error_handler for the calling process</fsummary> + <desc> + <p>This is used by a process to redefine the error handler + for undefined function calls and undefined registered + processes. Inexperienced users should not use this flag + since code auto-loading is dependent on the correct + operation of the error handling module.</p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="process_flag" arity="2" clause_i="3"/> + <fsummary>Set process flag min_heap_size for the calling process</fsummary> + <desc> + <p>This changes the minimum heap size for the calling + process.</p> + <p>Returns the old value of the flag.</p> </desc> </func> <func> - <name>process_flag(Pid, Flag, Value) -> OldValue</name> + <name name="process_flag" arity="2" clause_i="4"/> + <fsummary>Set process flag min_bin_vheap_size for the calling process</fsummary> + <desc> + <p>This changes the minimum binary virtual heap size for the calling + process.</p> + <p>Returns the old value of the flag.</p> </desc> + </func> + <func> + <name name="process_flag" arity="2" clause_i="5"/> + <type name="priority_level"/> + <fsummary>Set process flag priority for the calling process</fsummary> + <desc> + <p><marker id="process_flag_priority"></marker> + This sets the process priority. <c><anno>Level</anno></c> is an atom. + There are currently four priority levels: <c>low</c>, + <c>normal</c>, <c>high</c>, and <c>max</c>. The default + priority level is <c>normal</c>. <em>NOTE</em>: The + <c>max</c> priority level is reserved for internal use in + the Erlang runtime system, and should <em>not</em> be used + by others. + </p> + <p>Internally in each priority level processes are scheduled + in a round robin fashion. + </p> + <p>Execution of processes on priority <c>normal</c> and + priority <c>low</c> will be interleaved. Processes on + priority <c>low</c> will be selected for execution less + frequently than processes on priority <c>normal</c>. + </p> + <p>When there are runnable processes on priority <c>high</c> + no processes on priority <c>low</c>, or <c>normal</c> will + be selected for execution. Note, however, that this does + <em>not</em> mean that no processes on priority <c>low</c>, + or <c>normal</c> will be able to run when there are + processes on priority <c>high</c> running. On the runtime + system with SMP support there might be more processes running + in parallel than processes on priority <c>high</c>, i.e., + a <c>low</c>, and a <c>high</c> priority process might + execute at the same time. + </p> + <p>When there are runnable processes on priority <c>max</c> + no processes on priority <c>low</c>, <c>normal</c>, or + <c>high</c> will be selected for execution. As with the + <c>high</c> priority, processes on lower priorities might + execute in parallel with processes on priority <c>max</c>. + </p> + <p>Scheduling is preemptive. Regardless of priority, a process + is preempted when it has consumed more than a certain amount + of reductions since the last time it was selected for + execution. + </p> + <p><em>NOTE</em>: You should not depend on the scheduling + to remain exactly as it is today. Scheduling, at least on + the runtime system with SMP support, is very likely to be + modified in the future in order to better utilize available + processor cores. + </p> + <p>There is currently <em>no</em> automatic mechanism for + avoiding priority inversion, such as priority inheritance, + or priority ceilings. When using priorities you have + to take this into account and handle such scenarios by + yourself. + </p> + <p>Making calls from a <c>high</c> priority process into code + that you don't have control over may cause the <c>high</c> + priority process to wait for a processes with lower + priority, i.e., effectively decreasing the priority of the + <c>high</c> priority process during the call. Even if this + isn't the case with one version of the code that you don't + have under your control, it might be the case in a future + version of it. This might, for example, happen if a + <c>high</c> priority process triggers code loading, since + the code server runs on priority <c>normal</c>. + </p> + <p>Other priorities than <c>normal</c> are normally not needed. + When other priorities are used, they need to be used + with care, especially the <c>high</c> priority <em>must</em> + be used with care. A process on <c>high</c> priority should + only perform work for short periods of time. Busy looping for + long periods of time in a <c>high</c> priority process will + most likely cause problems, since there are important servers + in OTP running on priority <c>normal</c>. + </p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="process_flag" arity="2" clause_i="6"/> + <fsummary>Set process flag save_calls for the calling process</fsummary> + <desc> + <p><c><anno>N</anno></c> must be an integer in the interval 0..10000. + If <c><anno>N</anno></c> > 0, call saving is made active for the + process, which means that information about the <c><anno>N</anno></c> + most recent global function calls, BIF calls, sends and + receives made by the process are saved in a list, which + can be retrieved with + <c>process_info(Pid, last_calls)</c>. A global function + call is one in which the module of the function is + explicitly mentioned. Only a fixed amount of information + is saved: a tuple <c>{Module, Function, Arity}</c> for + function calls, and the mere atoms <c>send</c>, + <c>'receive'</c> and <c>timeout</c> for sends and receives + (<c>'receive'</c> when a message is received and + <c>timeout</c> when a receive times out). If <c>N</c> = 0, + call saving is disabled for the process, which is the + default. Whenever the size of the call saving list is set, + its contents are reset.</p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="process_flag" arity="2" clause_i="7"/> + <fsummary>Set process flag sensitive for the calling process</fsummary> + <desc> + <p>Set or clear the <c>sensitive</c> flag for the current process. + When a process has been marked as sensitive by calling + <c>process_flag(sensitive, true)</c>, features in the run-time + system that can be used for examining the data and/or inner working + of the process are silently disabled.</p> + <p>Features that are disabled include (but are not limited to) + the following:</p> + <p>Tracing: Trace flags can still be set for the process, but no + trace messages of any kind will be generated. + (If the <c>sensitive</c> flag is turned off, trace messages will + again be generated if there are any trace flags set.)</p> + <p>Sequential tracing: The sequential trace token will be propagated + as usual, but no sequential trace messages will be generated.</p> + <p><c>process_info/1,2</c> cannot be used to read out the message + queue or the process dictionary (both will be returned as empty lists).</p> + <p>Stack back-traces cannot be displayed for the process.</p> + <p>In crash dumps, the stack, messages, and the process dictionary + will be omitted.</p> + <p>If <c>{save_calls,N}</c> has been set for the process, no + function calls will be saved to the call saving list. + (The call saving list will not be cleared; furthermore, send, receive, + and timeout events will still be added to the list.)</p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="process_flag" arity="3"/> <fsummary>Set process flags for a process</fsummary> - <type> - <v>Pid = pid()</v> - <v>Flag, Value, OldValue -- see below</v> - </type> <desc> - <p>Sets certain flags for the process <c>Pid</c>, in the same + <p>Sets certain flags for the process <c><anno>Pid</anno></c>, in the same manner as <seealso marker="#process_flag/2">process_flag/2</seealso>. Returns the old value of the flag. The allowed values for - <c>Flag</c> are only a subset of those allowed in + <c><anno>Flag</anno></c> are only a subset of those allowed in <c>process_flag/2</c>, namely: <c>save_calls</c>.</p> - <p>Failure: <c>badarg</c> if <c>Pid</c> is not a local process.</p> + <p>Failure: <c>badarg</c> if <c><anno>Pid</anno></c> is not a local process.</p> </desc> </func> <func> - <name>process_info(Pid) -> InfoResult</name> + <name name="process_info" arity="1"/> + <type name="process_info_result_item"/> + <type name="priority_level"/> + <type name="stack_item"/> <fsummary>Information about a process</fsummary> - <type> - <v>Pid = pid()</v> - <v>Item = atom()</v> - <v>Info = term()</v> - <v>InfoTuple = {Item, Info}</v> - <v>InfoTupleList = [InfoTuple]</v> - <v>InfoResult = InfoTupleList | undefined</v> - </type> - <desc> - <p>Returns a list containing <c>InfoTuple</c>s with + <desc> + <p>Returns a list containing <c><anno>InfoTuple</anno></c>s with miscellaneous information about the process identified by <c>Pid</c>, or <c>undefined</c> if the process is not alive. </p> <p> - The order of the <c>InfoTuple</c>s is not defined, nor - are all the <c>InfoTuple</c>s mandatory. The <c>InfoTuple</c>s + The order of the <c><anno>InfoTuple</anno></c>s is not defined, nor + are all the <c><anno>InfoTuple</anno></c>s mandatory. The <c><anno>InfoTuple</anno></c>s part of the result may be changed without prior notice. - Currently <c>InfoTuple</c>s with the following <c>Item</c>s + Currently <c><anno>InfoTuple</anno></c>s with the following items are part of the result: <c>current_function</c>, <c>initial_call</c>, <c>status</c>, <c>message_queue_len</c>, <c>messages</c>, <c>links</c>, @@ -3813,12 +3358,12 @@ os_prompt%</pre> <c>priority</c>, <c>group_leader</c>, <c>total_heap_size</c>, <c>heap_size</c>, <c>stack_size</c>, <c>reductions</c>, and <c>garbage_collection</c>. - If the process identified by <c>Pid</c> has a registered name - also an <c>InfoTuple</c> with <c>Item == registered_name</c> + If the process identified by <c><anno>Pid</anno></c> has a registered name + also an <c><anno>InfoTuple</anno></c> with the item <c>registered_name</c> will appear. </p> <p>See <seealso marker="#process_info/2">process_info/2</seealso> - for information about specific <c>InfoTuple</c>s.</p> + for information about specific <c><anno>InfoTuple</anno></c>s.</p> <warning> <p>This BIF is intended for <em>debugging only</em>, use <seealso marker="#process_info/2">process_info/2</seealso> @@ -3829,113 +3374,108 @@ os_prompt%</pre> </desc> </func> <func> - <name>process_info(Pid, ItemSpec) -> InfoResult</name> + <name name="process_info" arity="2" clause_i="1"/> + <name name="process_info" arity="2" clause_i="2"/> + <type name="process_info_item"/> + <type name="process_info_result_item"/> + <type name="stack_item"/> + <type name="priority_level"/> <fsummary>Information about a process</fsummary> - <type> - <v>Pid = pid()</v> - <v>Item = atom()</v> - <v>Info = term()</v> - <v>ItemList = [Item]</v> - <v>ItemSpec = Item | ItemList</v> - <v>InfoTuple = {Item, Info}</v> - <v>InfoTupleList = [InfoTuple]</v> - <v>InfoResult = InfoTuple | InfoTupleList | undefined | []</v> - </type> - <desc> - <p>Returns information about the process identified by <c>Pid</c> - as specified by the <c>ItemSpec</c>, or <c>undefined</c> if the + <desc> + <p>Returns information about the process identified by <c><anno>Pid</anno></c> + as specified by the <c><anno>Item</anno></c> or the <c><anno>ItemList</anno></c>, or <c>undefined</c> if the process is not alive. </p> - <p>If the process is alive and <c>ItemSpec</c> is a single - <c>Item</c>, the returned value is the corresponding - <c>InfoTuple</c> unless <c>ItemSpec == registered_name</c> + <p>If the process is alive and a single <c><anno>Item</anno></c> is given, + the returned value is the corresponding + <c><anno>InfoTuple</anno></c> unless <c>Item =:= registered_name</c> and the process has no registered name. In this case <c>[]</c> is returned. This strange behavior is due to historical reasons, and is kept for backward compatibility. </p> - <p>If <c>ItemSpec</c> is an <c>ItemList</c>, the result is an - <c>InfoTupleList</c>. The <c>InfoTuple</c>s in the - <c>InfoTupleList</c> will appear with the corresponding - <c>Item</c>s in the same order as the <c>Item</c>s appeared - in the <c>ItemList</c>. Valid <c>Item</c>s may appear multiple - times in the <c>ItemList</c>. + <p>If an <c>ItemList</c> is given, the result is an + <c><anno>InfoTupleList</anno></c>. The <c><anno>InfoTuple</anno></c>s in the + <c><anno>InfoTupleList</anno></c> will appear with the corresponding + <c><anno>Item</anno></c>s in the same order as the <c><anno>Item</anno></c>s appeared + in the <c><anno>ItemList</anno></c>. Valid <c><anno>Item</anno></c>s may appear multiple + times in the <c><anno>ItemList</anno></c>. </p> - <note><p>If <c>registered_name</c> is part of an <c>ItemList</c> + <note><p>If <c>registered_name</c> is part of an <c><anno>ItemList</anno></c> and the process has no name registered a - <c>{registered_name, []}</c> <c>InfoTuple</c> <em>will</em> - appear in the resulting <c>InfoTupleList</c>. This - behavior is different than when - <c>ItemSpec == registered_name</c>, and than when + <c>{registered_name, []}</c> <c><anno>InfoTuple</anno></c> <em>will</em> + appear in the resulting <c><anno>InfoTupleList</anno></c>. This + behavior is different than when a single + <c>Item =:= registered_name</c> is given, and than when <c>process_info/1</c> is used. </p></note> - <p>Currently the following <c>InfoTuple</c>s with corresponding - <c>Item</c>s are valid:</p> + <p>Currently the following <c><anno>InfoTuple</anno></c>s with corresponding + <c><anno>Item</anno></c>s are valid:</p> <taglist> - <tag><c>{backtrace, Bin}</c></tag> + <tag><c>{backtrace, <anno>Bin</anno>}</c></tag> <item> - <p>The binary <c>Bin</c> contains the same information as + <p>The binary <c><anno>Bin</anno></c> contains the same information as the output from - <c>erlang:process_display(Pid, backtrace)</c>. Use + <c>erlang:process_display(<anno>Pid</anno>, backtrace)</c>. Use <c>binary_to_list/1</c> to obtain the string of characters from the binary.</p> </item> - <tag><c>{binary, BinInfo}</c></tag> + <tag><c>{binary, <anno>BinInfo</anno>}</c></tag> <item> - <p><c>BinInfo</c> is a list containing miscellaneous information + <p><c><anno>BinInfo</anno></c> is a list containing miscellaneous information about binaries currently being referred to by this process. - This <c>InfoTuple</c> may be changed or removed without prior + This <c><anno>InfoTuple</anno></c> may be changed or removed without prior notice.</p> </item> - <tag><c>{catchlevel, CatchLevel}</c></tag> + <tag><c>{catchlevel, <anno>CatchLevel</anno>}</c></tag> <item> - <p><c>CatchLevel</c> is the number of currently active - catches in this process. This <c>InfoTuple</c> may be + <p><c><anno>CatchLevel</anno></c> is the number of currently active + catches in this process. This <c><anno>InfoTuple</anno></c> may be changed or removed without prior notice.</p> </item> - <tag><c>{current_function, {Module, Function, Arity}}</c></tag> + <tag><c>{current_function, {<anno>Module</anno>, <anno>Function</anno>, <anno>Arity</anno>}}</c></tag> <item> - <p><c>Module</c>, <c>Function</c>, <c>Arity</c> is + <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, <c><anno>Arity</anno></c> is the current function call of the process.</p> </item> - <tag><c>{current_location, {Module, Function, Arity, Location}}</c></tag> + <tag><c>{current_location, {<anno>Module</anno>, <anno>Function</anno>, <anno>Arity</anno>, <anno>Location</anno>}}</c></tag> <item> - <p><c>Module</c>, <c>Function</c>, <c>Arity</c> is + <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, <c><anno>Arity</anno></c> is the current function call of the process. - <c>Location</c> is a list of two-tuples that describes the + <c><anno>Location</anno></c> is a list of two-tuples that describes the location in the source code. </p> </item> - <tag><c>{current_stacktrace, Stack}</c></tag> + <tag><c>{current_stacktrace, <anno>Stack</anno>}</c></tag> <item> <p>Return the current call stack back-trace (<em>stacktrace</em>) of the process. The stack has the same format as returned by <seealso marker="#get_stacktrace/0">erlang:get_stacktrace/0</seealso>. </p> </item> - <tag><c>{dictionary, Dictionary}</c></tag> + <tag><c>{dictionary, <anno>Dictionary</anno>}</c></tag> <item> - <p><c>Dictionary</c> is the dictionary of the process.</p> + <p><c><anno>Dictionary</anno></c> is the dictionary of the process.</p> </item> - <tag><c>{error_handler, Module}</c></tag> + <tag><c>{error_handler, <anno>Module</anno>}</c></tag> <item> - <p><c>Module</c> is the error handler module used by + <p><c><anno>Module</anno></c> is the error handler module used by the process (for undefined function calls, for example).</p> </item> - <tag><c>{garbage_collection, GCInfo}</c></tag> + <tag><c>{garbage_collection, <anno>GCInfo</anno>}</c></tag> <item> - <p><c>GCInfo</c> is a list which contains miscellaneous + <p><c><anno>GCInfo</anno></c> is a list which contains miscellaneous information about garbage collection for this process. - The content of <c>GCInfo</c> may be changed without + The content of <c><anno>GCInfo</anno></c> may be changed without prior notice.</p> </item> - <tag><c>{group_leader, GroupLeader}</c></tag> + <tag><c>{group_leader, <anno>GroupLeader</anno>}</c></tag> <item> - <p><c>GroupLeader</c> is group leader for the IO of + <p><c><anno>GroupLeader</anno></c> is group leader for the IO of the process.</p> </item> - <tag><c>{heap_size, Size}</c></tag> + <tag><c>{heap_size, <anno>Size</anno>}</c></tag> <item> - <p><c>Size</c> is the size in words of youngest heap generation + <p><c><anno>Size</anno></c> is the size in words of youngest heap generation of the process. This generation currently include the stack of the process. This information is highly implementation dependent, and may change if the implementation change. @@ -3947,9 +3487,9 @@ os_prompt%</pre> the initial function call with which the process was spawned.</p> </item> - <tag><c>{links, Pids}</c></tag> + <tag><c>{links, <anno>Pids</anno>}</c></tag> <item> - <p><c>Pids</c> is a list of pids, with processes to + <p><c><anno>Pids</anno></c> is a list of pids, with processes to which the process has a link.</p> </item> <tag><c>{last_calls, false|Calls}</c></tag> @@ -3960,139 +3500,139 @@ os_prompt%</pre> If call saving is active, a list is returned, in which the last element is the most recent called.</p> </item> - <tag><c>{memory, Size}</c></tag> + <tag><c>{memory, <anno>Size</anno>}</c></tag> <item> - <p><c>Size</c> is the size in bytes of the process. This + <p><c><anno>Size</anno></c> is the size in bytes of the process. This includes call stack, heap and internal structures.</p> </item> - <tag><c>{message_binary, BinInfo}</c></tag> + <tag><c>{message_binary, <anno>BinInfo</anno>}</c></tag> <item> - <p><c>BinInfo</c> is a list containing miscellaneous information + <p><c><anno>BinInfo</anno></c> is a list containing miscellaneous information about binaries currently being referred to by the message - area. This <c>InfoTuple</c> is only valid on an emulator - using the hybrid heap type. This <c>InfoTuple</c> may be + area. This <c><anno>InfoTuple</anno></c> is only valid on an emulator + using the hybrid heap type. This <c><anno>InfoTuple</anno></c> may be changed or removed without prior notice.</p> </item> - <tag><c>{message_queue_len, MessageQueueLen}</c></tag> + <tag><c>{message_queue_len, <anno>MessageQueueLen</anno>}</c></tag> <item> - <p><c>MessageQueueLen</c> is the number of messages + <p><c><anno>MessageQueueLen</anno></c> is the number of messages currently in the message queue of the process. This is - the length of the list <c>MessageQueue</c> returned as + the length of the list <c><anno>MessageQueue</anno></c> returned as the info item <c>messages</c> (see below).</p> </item> - <tag><c>{messages, MessageQueue}</c></tag> + <tag><c>{messages, <anno>MessageQueue</anno>}</c></tag> <item> - <p><c>MessageQueue</c> is a list of the messages to + <p><c><anno>MessageQueue</anno></c> is a list of the messages to the process, which have not yet been processed.</p> </item> - <tag><c>{min_heap_size, MinHeapSize}</c></tag> + <tag><c>{min_heap_size, <anno>MinHeapSize</anno>}</c></tag> <item> - <p><c>MinHeapSize</c> is the minimum heap size for the process.</p> + <p><c><anno>MinHeapSize</anno></c> is the minimum heap size for the process.</p> </item> - <tag><c>{min_bin_vheap_size, MinBinVHeapSize}</c></tag> + <tag><c>{min_bin_vheap_size, <anno>MinBinVHeapSize</anno>}</c></tag> <item> - <p><c>MinBinVHeapSize</c> is the minimum binary virtual heap size for the process.</p> + <p><c><anno>MinBinVHeapSize</anno></c> is the minimum binary virtual heap size for the process.</p> </item> - <tag><c>{monitored_by, Pids}</c></tag> + <tag><c>{monitored_by, <anno>Pids</anno>}</c></tag> <item> <p>A list of pids that are monitoring the process (with <c>monitor/2</c>).</p> </item> - <tag><c>{monitors, Monitors}</c></tag> + <tag><c>{monitors, <anno>Monitors</anno>}</c></tag> <item> <p>A list of monitors (started by <c>monitor/2</c>) that are active for the process. For a local process monitor or a remote process monitor by pid, the list item - is <c>{process, Pid}</c>, and for a remote process + is <c>{process, <anno>Pid</anno>}</c>, and for a remote process monitor by name, the list item is - <c>{process, {RegName, Node}}</c>.</p> + <c>{process, {<anno>RegName</anno>, <anno>Node</anno>}}</c>.</p> </item> <tag><c>{priority, Level}</c></tag> <item> - <p><c>Level</c> is the current priority level for + <p><c><anno>Level</anno></c> is the current priority level for the process. For more information on priorities see <seealso marker="#process_flag_priority">process_flag(priority, Level)</seealso>.</p> </item> - <tag><c>{reductions, Number}</c></tag> + <tag><c>{reductions, <anno>Number</anno>}</c></tag> <item> - <p><c>Number</c> is the number of reductions executed by + <p><c><anno>Number</anno></c> is the number of reductions executed by the process.</p> </item> - <tag><c>{registered_name, Atom}</c></tag> + <tag><c>{registered_name, <anno>Atom</anno>}</c></tag> <item> - <p><c>Atom</c> is the registered name of the process. If + <p><c><anno>Atom</anno></c> is the registered name of the process. If the process has no registered name, this tuple is not present in the list.</p> </item> - <tag><c>{sequential_trace_token, [] | SequentialTraceToken}</c></tag> + <tag><c>{sequential_trace_token, [] | <anno>SequentialTraceToken</anno>}</c></tag> <item> - <p><c>SequentialTraceToken</c> the sequential trace token for - the process. This <c>InfoTuple</c> may be changed or removed + <p><c><anno>SequentialTraceToken</anno></c> the sequential trace token for + the process. This <c><anno>InfoTuple</anno></c> may be changed or removed without prior notice.</p> </item> - <tag><c>{stack_size, Size}</c></tag> + <tag><c>{stack_size, <anno>Size</anno>}</c></tag> <item> - <p><c>Size</c> is the stack size of the process in words.</p> + <p><c><anno>Size</anno></c> is the stack size of the process in words.</p> </item> - <tag><c>{status, Status}</c></tag> + <tag><c>{status, <anno>Status</anno>}</c></tag> <item> - <p><c>Status</c> is the status of the process. <c>Status</c> + <p><c><anno>Status</anno></c> is the status of the process. <c><anno>Status</anno></c> is <c>exiting</c>, <c>garbage_collecting</c>, <c>waiting</c> (for a message), <c>running</c>, <c>runnable</c> (ready to run, but another process is running), or <c>suspended</c> (suspended on a "busy" port or by the <c>erlang:suspend_process/[1,2]</c> BIF).</p> </item> - <tag><c>{suspending, SuspendeeList}</c></tag> + <tag><c>{suspending, <anno>SuspendeeList</anno>}</c></tag> <item> - <p><c>SuspendeeList</c> is a list of <c>{Suspendee, - ActiveSuspendCount, OutstandingSuspendCount}</c> tuples. - <c>Suspendee</c> is the pid of a process that have been or is to - be suspended by the process identified by <c>Pid</c> via the + <p><c><anno>SuspendeeList</anno></c> is a list of <c>{<anno>Suspendee</anno>, + <anno>ActiveSuspendCount</anno>, <anno>OutstandingSuspendCount</anno>}</c> tuples. + <c><anno>Suspendee</anno></c> is the pid of a process that have been or is to + be suspended by the process identified by <c><anno>Pid</anno></c> via the <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso> BIF, or the <seealso marker="#suspend_process/1">erlang:suspend_process/1</seealso> - BIF. <c>ActiveSuspendCount</c> is the number of times the - <c>Suspendee</c> has been suspended by <c>Pid</c>. - <c>OutstandingSuspendCount</c> is the number of not yet - completed suspend requests sent by <c>Pid</c>. That is, - if <c>ActiveSuspendCount /= 0</c>, <c>Suspendee</c> is + BIF. <c><anno>ActiveSuspendCount</anno></c> is the number of times the + <c><anno>Suspendee</anno></c> has been suspended by <c><anno>Pid</anno></c>. + <c><anno>OutstandingSuspendCount</anno></c> is the number of not yet + completed suspend requests sent by <c><anno>Pid</anno></c>. That is, + if <c><anno>ActiveSuspendCount</anno> =/= 0</c>, <c><anno>Suspendee</anno></c> is currently in the suspended state, and if - <c>OutstandingSuspendCount /= 0</c> the <c>asynchronous</c> + <c><anno>OutstandingSuspendCount</anno> =/= 0</c> the <c>asynchronous</c> option of <c>erlang:suspend_process/2</c> has been used and - the suspendee has not yet been suspended by <c>Pid</c>. - Note that the <c>ActiveSuspendCount</c> and - <c>OutstandingSuspendCount</c> are not the total suspend count - on <c>Suspendee</c>, only the parts contributed by <c>Pid</c>. + the suspendee has not yet been suspended by <c><anno>Pid</anno></c>. + Note that the <c><anno>ActiveSuspendCount</anno></c> and + <c><anno>OutstandingSuspendCount</anno></c> are not the total suspend count + on <c><anno>Suspendee</anno></c>, only the parts contributed by <c>Pid</c>. </p> </item> - <tag><c>{total_heap_size, Size}</c></tag> + <tag><c>{total_heap_size, <anno>Size</anno>}</c></tag> <item> - <p><c>Size</c> is the total size in words of all heap + <p><c><anno>Size</anno></c> is the total size in words of all heap fragments of the process. This currently include the stack of the process. </p> </item> - <tag><c>{trace, InternalTraceFlags}</c></tag> + <tag><c>{trace, <anno>InternalTraceFlags</anno>}</c></tag> <item> - <p><c>InternalTraceFlags</c> is an integer representing - internal trace flag for this process. This <c>InfoTuple</c> + <p><c><anno>InternalTraceFlags</anno></c> is an integer representing + internal trace flag for this process. This <c><anno>InfoTuple</anno></c> may be changed or removed without prior notice.</p> </item> - <tag><c>{trap_exit, Boolean}</c></tag> + <tag><c>{trap_exit, <anno>Boolean</anno>}</c></tag> <item> - <p><c>Boolean</c> is <c>true</c> if the process is trapping + <p><c><anno>Boolean</anno></c> is <c>true</c> if the process is trapping exits, otherwise it is <c>false</c>.</p> </item> </taglist> <p>Note however, that not all implementations support every one - of the above <c>Items</c>.</p> - <p>Failure: <c>badarg</c> if <c>Pid</c> is not a local process, - or if <c>Item</c> is not a valid <c>Item</c>.</p> + of the above <c><anno>Item</anno></c>s.</p> + <p>Failure: <c>badarg</c> if <c><anno>Pid</anno></c> is not a local process, + or if <c><anno>Item</anno></c> is not a valid <c><anno>Item</anno></c>.</p> </desc> </func> <func> - <name>processes() -> [pid()]</name> + <name name="processes" arity="0"/> <fsummary>All processes</fsummary> <desc> <p>Returns a list of process identifiers corresponding to @@ -4109,13 +3649,10 @@ os_prompt%</pre> </desc> </func> <func> - <name>purge_module(Module) -> void()</name> + <name name="purge_module" arity="1"/> <fsummary>Remove old code for a module</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> - <p>Removes old code for <c>Module</c>. Before this BIF is used, + <p>Removes old code for <c><anno>Module</anno></c>. Before this BIF is used, <c>erlang:check_process_code/2</c> should be called to check that no processes are executing old code in the module.</p> <warning> @@ -4124,20 +3661,17 @@ os_prompt%</pre> used elsewhere.</p> </warning> <p>Failure: <c>badarg</c> if there is no old code for - <c>Module</c>.</p> + <c><anno>Module</anno></c>.</p> </desc> </func> <func> - <name>put(Key, Val) -> OldVal | undefined</name> + <name name="put" arity="2"/> <fsummary>Add a new value to the process dictionary</fsummary> - <type> - <v>Key = Val = OldVal = term()</v> - </type> - <desc> - <p>Adds a new <c>Key</c> to the process dictionary, associated - with the value <c>Val</c>, and returns <c>undefined</c>. If - <c>Key</c> already exists, the old value is deleted and - replaced by <c>Val</c> and the function returns the old value.</p> + <desc> + <p>Adds a new <c><anno>Key</anno></c> to the process dictionary, associated + with the value <c><anno>Val</anno></c>, and returns <c>undefined</c>. If + <c><anno>Key</anno></c> already exists, the old value is deleted and + replaced by <c><anno>Val</anno></c> and the function returns the old value.</p> <note> <p>The values stored when <c>put</c> is evaluated within the scope of a <c>catch</c> will not be retracted if a @@ -4151,17 +3685,9 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:raise(Class, Reason, Stacktrace)</name> + <name name="raise" arity="3"/> + <type name="raise_stacktrace"/> <fsummary>Stop execution with an exception of given class, reason and call stack backtrace</fsummary> - <type> - <v>Class = error | exit | throw</v> - <v>Reason = term()</v> - <v>Stacktrace = [{Module, Function, Arity | Args} | {Fun, Args}]</v> - <v> Module = Function = atom()</v> - <v> Arity = arity()</v> - <v> Args = [term()]</v> - <v> Fun = [fun()]</v> - </type> <desc> <p>Stops the execution of the calling process with an exception of given class, reason and call stack backtrace @@ -4172,11 +3698,11 @@ os_prompt%</pre> be avoided in applications, unless you know very well what you are doing.</p> </warning> - <p><c>Class</c> is one of <c>error</c>, <c>exit</c> or + <p><c><anno>Class</anno></c> is one of <c>error</c>, <c>exit</c> or <c>throw</c>, so if it were not for the stacktrace - <c>erlang:raise(Class, Reason, Stacktrace)</c> is - equivalent to <c>erlang:Class(Reason)</c>. - <c>Reason</c> is any term and <c>Stacktrace</c> is a list as + <c>erlang:raise(<anno>Class</anno>, <anno>Reason</anno>, <anno>Stacktrace</anno>)</c> is + equivalent to <c>erlang:<anno>Class</anno>(<anno>Reason</anno>)</c>. + <c><anno>Reason</anno></c> is any term and <c><anno>Stacktrace</anno></c> is a list as returned from <c>get_stacktrace()</c>, that is a list of 4-tuples <c>{Module, Function, Arity | Args, Location}</c> where <c>Module</c> and <c>Function</c> @@ -4193,24 +3719,21 @@ os_prompt%</pre> terminate, it has no return value - unless the arguments are invalid, in which case the function <em>returns the error reason</em>, that is <c>badarg</c>. If you want to be really sure not to return you can call - <c>error(erlang:raise(Class, Reason, Stacktrace))</c> + <c>error(erlang:raise(<anno>Class</anno>, <anno>Reason</anno>, <anno>Stacktrace</anno>))</c> and hope to distinguish exceptions later.</p> </desc> </func> <func> - <name>erlang:read_timer(TimerRef) -> integer() >= 0 | false</name> + <name name="read_timer" arity="1"/> <fsummary>Number of milliseconds remaining for a timer</fsummary> - <type> - <v>TimerRef = reference()</v> - </type> <desc> - <p><c>TimerRef</c> is a timer reference returned by + <p><c><anno>TimerRef</anno></c> is a timer reference returned by <seealso marker="#send_after/3">erlang:send_after/3</seealso> or <seealso marker="#start_timer/3">erlang:start_timer/3</seealso>. If the timer is active, the function returns the time in milliseconds left until the timer will expire, otherwise - <c>false</c> (which means that <c>TimerRef</c> was never a + <c>false</c> (which means that <c><anno>TimerRef</anno></c> was never a timer, that it has been cancelled, or that it has already delivered its message).</p> <p>See also @@ -4221,14 +3744,11 @@ os_prompt%</pre> </desc> </func> <func> - <name>erlang:ref_to_list(Ref) -> string()</name> + <name name="ref_to_list" arity="1"/> <fsummary>Text representation of a reference</fsummary> - <type> - <v>Ref = reference()</v> - </type> <desc> <p>Returns a string which corresponds to the text - representation of <c>Ref</c>.</p> + representation of <c><anno>Ref</anno></c>.</p> <warning> <p>This BIF is intended for debugging and for use in the Erlang operating system. It should not be used in @@ -4237,33 +3757,25 @@ os_prompt%</pre> </desc> </func> <func> - <name>register(RegName, Pid | Port) -> true</name> + <name name="register" arity="2"/> <fsummary>Register a name for a pid (or port)</fsummary> - <type> - <v>RegName = atom()</v> - <v>Pid = pid()</v> - <v>Port = port()</v> - </type> - <desc> - <p>Associates the name <c>RegName</c> with a pid or a port - identifier. <c>RegName</c>, which must be an atom, can be used + <desc> + <p>Associates the name <c><anno>RegName</anno></c> with a pid or a port + identifier. <c><anno>RegName</anno></c>, which must be an atom, can be used instead of the pid / port identifier in the send operator - (<c>RegName ! Message</c>).</p> + (<c><anno>RegName</anno> ! Message</c>).</p> <pre> > <input>register(db, Pid).</input> true</pre> - <p>Failure: <c>badarg</c> if <c>Pid</c> is not an existing, - local process or port, if <c>RegName</c> is already in use, + <p>Failure: <c>badarg</c> if <c><anno>PidOrPort</anno></c> is not an existing, + local process or port, if <c><anno>RegName</anno></c> is already in use, if the process or port is already registered (already has a - name), or if <c>RegName</c> is the atom <c>undefined</c>.</p> + name), or if <c><anno>RegName</anno></c> is the atom <c>undefined</c>.</p> </desc> </func> <func> - <name>registered() -> [RegName]</name> + <name name="registered" arity="0"/> <fsummary>All registered names</fsummary> - <type> - <v>RegName = atom()</v> - </type> <desc> <p>Returns a list of names which have been registered using <seealso marker="#register/2">register/2</seealso>.</p> @@ -4273,22 +3785,19 @@ true</pre> </desc> </func> <func> - <name>erlang:resume_process(Suspendee) -> true</name> + <name name="resume_process" arity="1"/> <fsummary>Resume a suspended process</fsummary> - <type> - <v>Suspendee = pid()</v> - </type> <desc> <p>Decreases the suspend count on the process identified by - <c>Suspendee</c>. <c>Suspendee</c> should previously have been + <c><anno>Suspendee</anno></c>. <c><anno>Suspendee</anno></c> should previously have been suspended via <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso>, or <seealso marker="#suspend_process/1">erlang:suspend_process/1</seealso> - by the process calling <c>erlang:resume_process(Suspendee)</c>. When - the suspend count on <c>Suspendee</c> reach zero, <c>Suspendee</c> + by the process calling <c>erlang:resume_process(<anno>Suspendee</anno>)</c>. When + the suspend count on <c><anno>Suspendee</anno></c> reach zero, <c><anno>Suspendee</anno></c> will be resumed, i.e., the state of the <c>Suspendee</c> is changed - from suspended into the state <c>Suspendee</c> was in before it was + from suspended into the state <c><anno>Suspendee</anno></c> was in before it was suspended. </p> <warning> @@ -4298,29 +3807,26 @@ true</pre> <taglist> <tag><c>badarg</c></tag> <item> - If <c>Suspendee</c> isn't a process identifier. + If <c><anno>Suspendee</anno></c> isn't a process identifier. </item> <tag><c>badarg</c></tag> <item> If the process calling <c>erlang:resume_process/1</c> had not previously increased the suspend count on the process - identified by <c>Suspendee</c>. + identified by <c><anno>Suspendee</anno></c>. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c>Suspendee</c> is not alive. + If the process identified by <c><anno>Suspendee</anno></c> is not alive. </item> </taglist> </desc> </func> <func> - <name>round(Number) -> integer()</name> + <name name="round" arity="1"/> <fsummary>Return an integer by rounding a number</fsummary> - <type> - <v>Number = number()</v> - </type> <desc> - <p>Returns an integer by rounding <c>Number</c>.</p> + <p>Returns an integer by rounding <c><anno>Number</anno></c>.</p> <pre> > <input>round(5.5).</input> 6</pre> @@ -4328,7 +3834,7 @@ true</pre> </desc> </func> <func> - <name>self() -> pid()</name> + <name name="self" arity="0"/> <fsummary>Pid of the calling process</fsummary> <desc> <p>Returns the pid (process identifier) of the calling process.</p> @@ -4339,33 +3845,21 @@ true</pre> </desc> </func> <func> - <name>erlang:send(Dest, Msg) -> Msg</name> + <name name="send" arity="2"/> <fsummary>Send a message</fsummary> - <type> - <v>Dest = pid() | port() | RegName | {RegName, Node}</v> - <v>Msg = term()</v> - <v> RegName = atom()</v> - <v> Node = node()</v> - </type> - <desc> - <p>Sends a message and returns <c>Msg</c>. This is the same as - <c>Dest ! Msg</c>.</p> - <p><c>Dest</c> may be a remote or local pid, a (local) port, a - locally registered name, or a tuple <c>{RegName, Node}</c> + <type name="dst"/> + <desc> + <p>Sends a message and returns <c><anno>Msg</anno></c>. This is the same as + <c><anno>Dest</anno> ! <anno>Msg</anno></c>.</p> + <p><c><anno>Dest</anno></c> may be a remote or local pid, a (local) port, a + locally registered name, or a tuple <c>{<anno>RegName</anno>, <anno>Node</anno>}</c> for a registered name at another node.</p> </desc> </func> <func> - <name>erlang:send(Dest, Msg, [Option]) -> Res</name> + <name name="send" arity="3"/> + <type name="dst"/> <fsummary>Send a message conditionally</fsummary> - <type> - <v>Dest = pid() | port() | RegName | {RegName, Node}</v> - <v> RegName = atom()</v> - <v> Node = node()</v> - <v>Msg = term()</v> - <v>Option = nosuspend | noconnect</v> - <v>Res = ok | nosuspend | noconnect</v> - </type> <desc> <p>Sends a message and returns <c>ok</c>, or does not send the message but returns something else (see below). Otherwise @@ -4395,28 +3889,24 @@ true</pre> </desc> </func> <func> - <name>erlang:send_after(Time, Dest, Msg) -> TimerRef</name> + <name name="send_after" arity="3"/> + <type_desc variable="Time">0 <= Time <= 4294967295</type_desc> <fsummary>Start a timer</fsummary> - <type> - <v>Time = integer() >= 0</v> - <v> 0 <= Time <= 4294967295</v> - <v>Dest = pid() | RegName </v> - <v> LocalPid = pid() (of a process, alive or dead, on the local node)</v> - <v>Msg = term()</v> - <v>TimerRef = reference()</v> - </type> <desc> <p>Starts a timer which will send the message <c>Msg</c> - to <c>Dest</c> after <c>Time</c> milliseconds.</p> - <p>If <c>Dest</c> is an atom, it is supposed to be the name of + to <c><anno>Dest</anno></c> after <c><anno>Time</anno></c> milliseconds.</p> + <p>If <c><anno>Dest</anno></c> is a <c>pid()</c> it has to be a <c>pid()</c> of a local process, dead or alive.</p> + <p>The <c><anno>Time</anno></c> value can, in the current implementation, not be greater than 4294967295.</p> + <p>If <c><anno>Dest</anno></c> is an <c>atom()</c>, it is supposed to be the name of a registered process. The process referred to by the name is looked up at the time of delivery. No error is given if the name does not refer to a process.</p> - <p>If <c>Dest</c> is a pid, the timer will be automatically - canceled if the process referred to by the pid is not alive, + + <p>If <c><anno>Dest</anno></c> is a <c>pid()</c>, the timer will be automatically + canceled if the process referred to by the <c>pid()</c> is not alive, or when the process exits. This feature was introduced in erts version 5.4.11. Note that timers will not be - automatically canceled when <c>Dest</c> is an atom.</p> + automatically canceled when <c><anno>Dest</anno></c> is an <c>atom</c>.</p> <p>See also <seealso marker="#start_timer/3">erlang:start_timer/3</seealso>, <seealso marker="#cancel_timer/1">erlang:cancel_timer/1</seealso>, @@ -4516,32 +4006,25 @@ true</pre> </desc> </func> <func> - <name>setelement(Index, Tuple1, Value) -> Tuple2</name> + <name name="setelement" arity="3"/> + <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno>)</type_desc> <fsummary>Set Nth element of a tuple</fsummary> - <type> - <v>Index = 1..tuple_size(Tuple1)</v> - <v>Tuple1 = Tuple2 = tuple()</v> - <v>Value = term()</v> - </type> - <desc> - <p>Returns a tuple which is a copy of the argument <c>Tuple1</c> - with the element given by the integer argument <c>Index</c> + <desc> + <p>Returns a tuple which is a copy of the argument <c><anno>Tuple1</anno></c> + with the element given by the integer argument <c><anno>Index</anno></c> (the first element is the element with index 1) replaced by - the argument <c>Value</c>.</p> + the argument <c><anno>Value</anno></c>.</p> <pre> > <input>setelement(2, {10, green, bottles}, red).</input> {10,red,bottles}</pre> </desc> </func> <func> - <name>size(Item) -> integer() >= 0</name> + <name name="size" arity="1"/> <fsummary>Size of a tuple or binary</fsummary> - <type> - <v>Item = tuple() | binary()</v> - </type> <desc> <p>Returns an integer which is the size of the argument - <c>Item</c>, which must be either a tuple or a binary.</p> + <c><anno>Item</anno></c>, which must be either a tuple or a binary.</p> <pre> > <input>size({morni, mulle, bwange}).</input> 3</pre> @@ -4569,20 +4052,16 @@ true</pre> </desc> </func> <func> - <name>spawn(Module, Function, Args) -> pid()</name> + <name name="spawn" arity="3"/> <fsummary>Create a new process with a function as entry point</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - </type> <desc> <p>Returns the pid of a new process started by the application - of <c>Module:Function</c> to <c>Args</c>. The new process + of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c>. The new process created will be placed in the system scheduler queue and be run some time later.</p> - <p><c>error_handler:undefined_function(Module, Function, Args)</c> is evaluated by the new process if - <c>Module:Function/Arity</c> does not exist (where - <c>Arity</c> is the length of <c>Args</c>). The error handler + <p><c>error_handler:undefined_function(<anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c> is evaluated by the new process if + <c><anno>Module</anno>:<anno>Function</anno>/Arity</c> does not exist (where + <c>Arity</c> is the length of <c><anno>Args</anno></c>). The error handler can be redefined (see <seealso marker="#process_flag/2">process_flag/2</seealso>). If <c>error_handler</c> is undefined, or the user has @@ -4629,15 +4108,11 @@ true</pre> </desc> </func> <func> - <name>spawn_link(Module, Function, Args) -> pid()</name> + <name name="spawn_link" arity="3"/> <fsummary>Create and link to a new process with a function as entry point</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - </type> <desc> <p>Returns the pid of a new process started by the application - of <c>Module:Function</c> to <c>Args</c>. A link is created + of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c>. A link is created between the calling process and the new process, atomically. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> @@ -4816,15 +4291,12 @@ true</pre> </desc> </func> <func> - <name>split_binary(Bin, Pos) -> {Bin1, Bin2}</name> + <name name="split_binary" arity="2"/> + <type_desc variable="Pos">0..byte_size(Bin)</type_desc> <fsummary>Split a binary into two</fsummary> - <type> - <v>Bin = Bin1 = Bin2 = binary()</v> - <v>Pos = 0..byte_size(Bin)</v> - </type> <desc> <p>Returns a tuple containing the binaries which are the result - of splitting <c>Bin</c> into two parts at position <c>Pos</c>. + of splitting <c><anno>Bin</anno></c> into two parts at position <c><anno>Pos</anno></c>. This is not a destructive operation. After the operation, there will be three binaries altogether.</p> <pre> @@ -4841,30 +4313,24 @@ true</pre> </desc> </func> <func> - <name>erlang:start_timer(Time, Dest, Msg) -> TimerRef</name> + <name name="start_timer" arity="3"/> + <type_desc variable="Time">0 <= Time <= 4294967295</type_desc> <fsummary>Start a timer</fsummary> - <type> - <v>Time = integer() >= 0</v> - <v> 0 <= Time <= 4294967295</v> - <v>Dest = LocalPid | RegName </v> - <v> LocalPid = pid() (of a process, alive or dead, on the local node)</v> - <v> RegName = atom()</v> - <v>Msg = term()</v> - <v>TimerRef = reference()</v> - </type> <desc> <p>Starts a timer which will send the message - <c>{timeout, TimerRef, Msg}</c> to <c>Dest</c> - after <c>Time</c> milliseconds.</p> - <p>If <c>Dest</c> is an atom, it is supposed to be the name of + <c>{timeout, <anno>TimerRef</anno>, <anno>Msg</anno>}</c> to <c><anno>Dest</anno></c> + after <c><anno>Time</anno></c> milliseconds.</p> + <p>If <c><anno>Dest</anno></c> is a <c>pid()</c> it has to be a <c>pid()</c> of a local process, dead or alive.</p> + <p>The <c><anno>Time</anno></c> value can, in the current implementation, not be greater than 4294967295.</p> + <p>If <c><anno>Dest</anno></c> is an <c>atom()</c>, it is supposed to be the name of a registered process. The process referred to by the name is looked up at the time of delivery. No error is given if the name does not refer to a process.</p> - <p>If <c>Dest</c> is a pid, the timer will be automatically - canceled if the process referred to by the pid is not alive, + <p>If <c><anno>Dest</anno></c> is a <c>pid()</c>, the timer will be automatically + canceled if the process referred to by the <c>pid()</c> is not alive, or when the process exits. This feature was introduced in erts version 5.4.11. Note that timers will not be - automatically canceled when <c>Dest</c> is an atom.</p> + automatically canceled when <c><anno>Dest</anno></c> is an <c>atom()</c>.</p> <p>See also <seealso marker="#send_after/3">erlang:send_after/3</seealso>, <seealso marker="#cancel_timer/1">erlang:cancel_timer/1</seealso>, @@ -4875,54 +4341,52 @@ true</pre> </desc> </func> <func> - <name>statistics(Type) -> Res</name> - <fsummary>Information about the system</fsummary> - <type> - <v>Type, Res -- see below</v> - </type> + <name name="statistics" arity="1" clause_i="1"/> + <fsummary>Information about context switches</fsummary> <desc> - <p>All times are in milliseconds unless otherwise specified.</p> - <p>Returns information about the system as specified by - <c>Type</c>:</p> - <taglist> - <tag><c>context_switches</c></tag> - <item> - <p>Returns <c>{ContextSwitches, 0}</c>, where - <c>ContextSwitches</c> is the total number of context - switches since the system started.</p> - </item> - <tag><marker id="statistics_exact_reductions"><c>exact_reductions</c></marker></tag> - <item> - <p>Returns - <c>{Total_Exact_Reductions, Exact_Reductions_Since_Last_Call}</c>.</p> - <note><p><c>statistics(exact_reductions)</c> is - a more expensive operation than - <seealso marker="#statistics_reductions">statistics(reductions)</seealso> - especially on an Erlang machine with SMP support.</p> - </note> - </item> - <tag><c>garbage_collection</c></tag> - <item> - <p>Returns <c>{Number_of_GCs, Words_Reclaimed, 0}</c>. This - information may not be valid for all implementations.</p> - <pre> + <p><c><anno>ContextSwitches</anno></c> is the total number of context + switches since the system started.</p> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="2"/> + <fsummary>Information about exact reductions</fsummary> + <desc> + <marker id="statistics_exact_reductions"></marker> + <note><p><c>statistics(exact_reductions)</c> is + a more expensive operation than + <seealso marker="#statistics_reductions">statistics(reductions)</seealso> + especially on an Erlang machine with SMP support.</p> + </note> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="3"/> + <fsummary>Information about garbage collection</fsummary> + <desc> + <p>This information may not be valid for all implementations.</p> + <pre> > <input>statistics(garbage_collection).</input> {85,23961,0} </pre> - </item> - <tag><c>io</c></tag> - <item> - <p>Returns <c>{{input, Input}, {output, Output}}</c>, - where <c>Input</c> is the total number of bytes received - through ports, and <c>Output</c> is the total number of - bytes output to ports.</p> - </item> - <tag><marker id="statistics_reductions"><c>reductions</c></marker></tag> - <item> - <p>Returns - <c>{Total_Reductions, Reductions_Since_Last_Call}</c>.</p> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="4"/> + <fsummary>Information about io</fsummary> + <desc> + <p><c><anno>Input</anno></c> is the total number of bytes received + through ports, and <c><anno>Output</anno></c> is the total number of + bytes output to ports.</p> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="5"/> + <fsummary>Information about reductions</fsummary> + <desc> + <marker id="statistics_reductions"></marker> <note> - <p>From erts version 5.5 (OTP release R11B) + <p>Since erts-5.5 (OTP release R11B) this value does not include reductions performed in current time slices of currently scheduled processes. If an exact value is wanted, use @@ -4932,53 +4396,65 @@ true</pre> > <input>statistics(reductions).</input> {2046,11} </pre> - </item> - <tag><c>run_queue</c></tag> - <item> - <p>Returns the length of the run queue, that is, the number - of processes that are ready to run.</p> - </item> - <tag><c>runtime</c></tag> - <item> - <p>Returns <c>{Total_Run_Time, Time_Since_Last_Call}</c>. - Note that the run-time is the sum of the run-time for all - threads in the Erlang run-time system and may therefore be greater - than the wall-clock time.</p> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="6"/> + <fsummary>Information about the run-queue</fsummary> + <desc> + <p>Returns the length of the run queue, that is, the number + of processes that are ready to run.</p> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="7"/> + <fsummary>Information about run-time</fsummary> + <desc> + <p>Note that the run-time is the sum of the run-time for all + threads in the Erlang run-time system and may therefore be greater + than the wall-clock time.</p> <pre> > <input>statistics(runtime).</input> {1690,1620} </pre> - </item> - <tag><marker id="statistics_scheduler_wall_time"><c>scheduler_wall_time</c></marker></tag> - <item> - <p>Returns a list of tuples with - <c>{SchedulerId, ActiveTime, TotalTime}</c>, where <c>SchedulerId</c> is an integer id of the scheduler, <c>ActiveTime</c> is - the duration the scheduler has been busy, <c>TotalTime</c> is the total time duration since - <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> - activation. The time unit is not defined and may be subject to change - between releases, operating systems and system restarts. - <c>scheduler_wall_time</c> should only be used to calculate relative - values for scheduler-utilization. <c>ActiveTime</c> can never exceed <c>TotalTime</c>. - </p> + </desc> + </func> + <func> + <name name="statistics" arity="1" clause_i="8"/> + <fsummary>Information about each schedulers work time</fsummary> + <desc> + <marker id="statistics_scheduler_wall_time"></marker> + <p> + Returns a list of tuples with <c>{<anno>SchedulerId</anno>, + <anno>ActiveTime</anno>, <anno>TotalTime</anno>}</c>, where + <c>SchedulerId</c> is an integer id of the scheduler, <c>ActiveTime</c> is + the duration the scheduler has been busy, <c>TotalTime</c> is the total time duration since + <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> + activation. The time unit is not defined and may be subject to change + between releases, operating systems and system restarts. + <c>scheduler_wall_time</c> should only be used to calculate relative + values for scheduler-utilization. <c>ActiveTime</c> can never exceed <c>TotalTime</c>. + </p> - <p>The definition of a busy scheduler is when it is not idle or not - scheduling (selecting) a process or port, meaning; executing process - code, executing linked-in-driver or NIF code, executing - built-in-functions or any other runtime handling, garbage collecting - or handling any other memory management. Note, a scheduler may also be - busy even if the operating system has scheduled out the scheduler - thread. - </p> + <p>The definition of a busy scheduler is when it is not idle or not + scheduling (selecting) a process or port, meaning; executing process + code, executing linked-in-driver or NIF code, executing + built-in-functions or any other runtime handling, garbage collecting + or handling any other memory management. Note, a scheduler may also be + busy even if the operating system has scheduled out the scheduler + thread. + </p> - <p> - Returns <c>undefined</c> if the system flag <seealso marker="#system_flag_scheduler_wall_time"> - scheduler_wall_time</seealso> is turned off. - </p> + <p> + Returns <c>undefined</c> if the system flag + <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> + is turned off. + </p> - <p>The list of scheduler information is unsorted and may appear in different order - between calls. - </p> - <p>Using <c>scheduler_wall_time</c> to calculate scheduler utilization.</p> + <p>The list of scheduler information is unsorted and may appear in different order + between calls. + </p> + <p>Using <c>scheduler_wall_time</c> to calculate scheduler utilization.</p> <pre> > <input>erlang:system_flag(scheduler_wall_time, true).</input> false @@ -5006,34 +4482,26 @@ ok {Ai + (A1 - A0), Ti + (T1 - T0)} end, {0, 0}, lists:zip(Ts0,Ts1)), A/T.</input> 0.9769136803764825 </pre> - <note> <p><c>scheduler_wall_time</c> is by default disabled. Use <c>erlang:system_flag(scheduler_wall_time, true)</c> to enable it. </p> </note> - </item> - - <tag><c>wall_clock</c></tag> - <item> - <p>Returns - <c>{Total_Wallclock_Time, Wallclock_Time_Since_Last_Call}</c>. - <c>wall_clock</c> can be used in the same manner as - <c>runtime</c>, except that real time is measured as - opposed to runtime or CPU time.</p> - </item> - </taglist> </desc> </func> <func> - <name>erlang:suspend_process(Suspendee, OptList) -> boolean()</name> + <name name="statistics" arity="1" clause_i="9"/> + <fsummary>Information about wall-clock</fsummary> + <desc> + <p><c>wall_clock</c> can be used in the same manner as + <c>runtime</c>, except that real time is measured as + opposed to runtime or CPU time.</p> + </desc> + </func> + <func> + <name name="suspend_process" arity="2"/> <fsummary>Suspend a process</fsummary> - <type> - <v>Suspendee = pid()</v> - <v>OptList = [Opt]</v> - <v>Opt = atom()</v> - </type> <desc> <p>Increases the suspend count on the process identified by - <c>Suspendee</c> and puts it in the suspended state if it isn't + <c><anno>Suspendee</anno></c> and puts it in the suspended state if it isn't already in the suspended state. A suspended process will not be scheduled for execution until the process has been resumed. </p> @@ -5041,49 +4509,49 @@ ok <p>A process can be suspended by multiple processes and can be suspended multiple times by a single process. A suspended process will not leave the suspended state until its suspend - count reach zero. The suspend count of <c>Suspendee</c> is - decreased when - <seealso marker="#resume_process/1">erlang:resume_process(Suspendee)</seealso> + count reach zero. The suspend count of <c><anno>Suspendee</anno></c> + is decreased when + <seealso marker="#resume_process/1">erlang:resume_process(<anno>Suspendee</anno>)</seealso> is called by the same process that called - <c>erlang:suspend_process(Suspendee)</c>. All increased suspend + <c>erlang:suspend_process(<anno>Suspendee</anno>)</c>. All increased suspend counts on other processes acquired by a process will automatically be decreased when the process terminates.</p> - <p>Currently the following options (<c>Opt</c>s) are available:</p> + <p>Currently the following options (<c><anno>Opt</anno></c>s) are available:</p> <taglist> <tag><c>asynchronous</c></tag> <item> A suspend request is sent to the process identified by - <c>Suspendee</c>. <c>Suspendee</c> will eventually suspend + <c><anno>Suspendee</anno></c>. <c><anno>Suspendee</anno></c> will eventually suspend unless it is resumed before it was able to suspend. The caller of <c>erlang:suspend_process/2</c> will return immediately, - regardless of whether the <c>Suspendee</c> has suspended yet - or not. Note that the point in time when the <c>Suspendee</c> + regardless of whether the <c><anno>Suspendee</anno></c> has suspended yet + or not. Note that the point in time when the <c><anno>Suspendee</anno></c> will actually suspend cannot be deduced from other events in the system. The only guarantee given is that the - <c>Suspendee</c> will <em>eventually</em> suspend (unless it + <c><anno>Suspendee</anno></c> will <em>eventually</em> suspend (unless it is resumed). If the <c>asynchronous</c> option has <em>not</em> been passed, the caller of <c>erlang:suspend_process/2</c> will - be blocked until the <c>Suspendee</c> has actually suspended. + be blocked until the <c><anno>Suspendee</anno></c> has actually suspended. </item> <tag><c>unless_suspending</c></tag> <item> - The process identified by <c>Suspendee</c> will be suspended + The process identified by <c><anno>Suspendee</anno></c> will be suspended unless the calling process already is suspending the - <c>Suspendee</c>. If <c>unless_suspending</c> is combined + <c><anno>Suspendee</anno></c>. If <c>unless_suspending</c> is combined with the <c>asynchronous</c> option, a suspend request will be sent unless the calling process already is suspending the - <c>Suspendee</c> or if a suspend request already has been sent + <c><anno>Suspendee</anno></c> or if a suspend request already has been sent and is in transit. If the calling process already is suspending - the <c>Suspendee</c>, or if combined with the <c>asynchronous</c> + the <c><anno>Suspendee</anno></c>, or if combined with the <c>asynchronous</c> option and a send request already is in transit, - <c>false</c> is returned and the suspend count on <c>Suspendee</c> + <c>false</c> is returned and the suspend count on <c><anno>Suspendee</anno></c> will remain unchanged. </item> </taglist> <p>If the suspend count on the process identified by - <c>Suspendee</c> was increased, <c>true</c> is returned; otherwise, + <c><anno>Suspendee</anno></c> was increased, <c>true</c> is returned; otherwise, <c>false</c> is returned.</p> <warning> @@ -5093,28 +4561,28 @@ ok <taglist> <tag><c>badarg</c></tag> <item> - If <c>Suspendee</c> isn't a process identifier. + If <c><anno>Suspendee</anno></c> isn't a process identifier. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c>Suspendee</c> is same the process as + If the process identified by <c><anno>Suspendee</anno></c> is same the process as the process calling <c>erlang:suspend_process/2</c>. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c>Suspendee</c> is not alive. + If the process identified by <c><anno>Suspendee</anno></c> is not alive. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c>Suspendee</c> resides on another node. + If the process identified by <c><anno>Suspendee</anno></c> resides on another node. </item> <tag><c>badarg</c></tag> <item> - If <c>OptList</c> isn't a proper list of valid <c>Opt</c>s. + If <c><anno>OptList</anno></c> isn't a proper list of valid <c><anno>Opt</anno></c>s. </item> <tag><c>system_limit</c></tag> <item> - If the process identified by <c>Suspendee</c> has been suspended more + If the process identified by <c><anno>Suspendee</anno></c> has been suspended more times by the calling process than can be represented by the currently used internal data structures. The current system limit is larger than 2 000 000 000 suspends, and it will never be less @@ -5137,292 +4605,322 @@ ok </desc> </func> <func> - <name>erlang:system_flag(Flag, Value) -> OldValue</name> - <fsummary>Set system flags</fsummary> - <type> - <v>Flag, Value, OldValue -- see below</v> - </type> + <name name="system_flag" arity="2" clause_i="1"/> + <fsummary>Set system flag backtrace_depth</fsummary> + <desc> + <p>Sets the maximum depth of call stack back-traces in the + exit reason element of <c>'EXIT'</c> tuples.</p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="2"/> + <type name="cpu_topology"/> + <type name="level_entry"/> + <type name="level_tag"/> + <type name="sub_level"/> + <type name="info_list"/> + <fsummary>Set system flag cpu_topology</fsummary> + <desc> + <warning> + <p><marker id="system_flag_cpu_topology"></marker> + This argument is <em>deprecated</em> and + scheduled for removal in erts-5.10/OTP-R16. Instead of using + this argument you are advised to use the <c>erl</c> command + line argument <seealso marker="erts:erl#+sct">+sct</seealso>. + When this argument has been removed a final CPU topology to use + will be determined at emulator boot time.</p> + </warning> + <p>Sets the user defined <c><anno>CpuTopology</anno></c>. The user defined + CPU topology will override any automatically detected + CPU topology. By passing <c>undefined</c> as <c><anno>CpuTopology</anno></c> + the system will revert back to the CPU topology automatically + detected. The returned value equals the value returned + from <c>erlang:system_info(cpu_topology)</c> before the + change was made. + </p> + <p>Returns the old value of the flag.</p> + <p>The CPU topology is used when binding schedulers to logical + processors. If schedulers are already bound when the CPU + topology is changed, the schedulers will be sent a request + to rebind according to the new CPU topology. + </p> + <p>The user defined CPU topology can also be set by passing + the <seealso marker="erts:erl#+sct">+sct</seealso> command + line argument to <c>erl</c>. + </p> + <p>For information on the <c><anno>CpuTopology</anno></c> type + and more, see the documentation of + <seealso marker="#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso>, + and the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> + and <seealso marker="erts:erl#+sbt">+sbt</seealso> + command line flags. + </p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="3"/> + <fsummary>Set system flag fullsweep_after</fsummary> + <desc> + <p><c><anno>Number</anno></c> is a non-negative integer which indicates + how many times generational garbage collections can be + done without forcing a fullsweep collection. The value + applies to new processes; processes already running are + not affected.</p> + <p>Returns the old value of the flag.</p> + <p>In low-memory systems (especially without virtual + memory), setting the value to 0 can help to conserve + memory.</p> + <p>An alternative way to set this value is through the + (operating system) environment variable + <c>ERL_FULLSWEEP_AFTER</c>.</p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="4"/> + <fsummary>Set system flag min_heap_size</fsummary> + <desc> + <p>Sets the default minimum heap size for processes. The + size is given in words. The new <c>min_heap_size</c> only + effects processes spawned after the change of + <c>min_heap_size</c> has been made. + The <c>min_heap_size</c> can be set for individual + processes by use of + <seealso marker="#spawn_opt/4">spawn_opt/N</seealso> or + <seealso marker="#process_flag/2">process_flag/2</seealso>. </p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="5"/> + <fsummary>Set system flag min_bin_vheap_size</fsummary> + <desc> + <p>Sets the default minimum binary virtual heap size for processes. The + size is given in words. The new <c>min_bin_vhheap_size</c> only + effects processes spawned after the change of + <c>min_bin_vhheap_size</c> has been made. + The <c>min_bin_vheap_size</c> can be set for individual + processes by use of + <seealso marker="#spawn_opt/4">spawn_opt/N</seealso> or + <seealso marker="#process_flag/2">process_flag/2</seealso>. </p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="6"/> + <fsummary>Set system flag multi_scheduling</fsummary> + <desc> + <p><marker id="system_flag_multi_scheduling"></marker> + If multi-scheduling is enabled, more than one scheduler + thread is used by the emulator. Multi-scheduling can be + blocked. When multi-scheduling has been blocked, only + one scheduler thread will schedule Erlang processes.</p> + <p>If <c><anno>BlockState</anno> =:= block</c>, multi-scheduling will + be blocked. If <c><anno>BlockState</anno> =:= unblock</c> and no-one + else is blocking multi-scheduling and this process has + only blocked one time, multi-scheduling will be unblocked. + One process can block multi-scheduling multiple times. + If a process has blocked multiple times, it has to + unblock exactly as many times as it has blocked before it + has released its multi-scheduling block. If a process that + has blocked multi-scheduling exits, it will release its + blocking of multi-scheduling.</p> + <p>The return values are <c>disabled</c>, <c>blocked</c>, + or <c>enabled</c>. The returned value describes the + state just after the call to + <c>erlang:system_flag(multi_scheduling, <anno>BlockState</anno>)</c> + has been made. The return values are described in the + documentation of <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>.</p> + <p><em>NOTE</em>: Blocking of multi-scheduling should normally + not be needed. If you feel that you need to + block multi-scheduling, think through the + problem at least a couple of times again. + Blocking multi-scheduling should only be used + as a last resort since it will most likely be + a <em>very inefficient</em> way to solve the + problem.</p> + <p>See also <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, + <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>, and + <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="7"/> + <type name="scheduler_bind_type"/> + <fsummary>Set system flag scheduler_bind_type</fsummary> <desc> <warning> - <p>The - <seealso marker="#system_flag_cpu_topology">cpu_topology</seealso>, - and - <seealso marker="#system_flag_scheduler_bind_type">scheduler_bind_type</seealso> - <c>Flag</c>s are <em>deprecated</em> and have been scheduled for - removal in erts-5.10/OTP-R16.</p> + <p><marker id="system_flag_scheduler_bind_type"></marker> + This argument is <em>deprecated</em> and + scheduled for removal in erts-5.10/OTP-R16. Instead of using + this argument you are advised to use the <c>erl</c> command + line argument <seealso marker="erts:erl#+sbt">+sbt</seealso>. + When this argument has been removed a final scheduler bind type + to use will be determined at emulator boot time.</p> </warning> - <p>Sets various system properties of the Erlang node. Returns - the old value of the flag.</p> + <p>Controls if and how schedulers are bound to logical + processors.</p> + <p>When <c>erlang:system_flag(scheduler_bind_type, <anno>How</anno>)</c> is + called, an asynchronous signal is sent to all schedulers + online which causes them to try to bind or unbind as requested. + <em>NOTE:</em> If a scheduler fails to bind, this + will often be silently ignored. This since it isn't always + possible to verify valid logical processor identifiers. If + an error is reported, it will be reported to the + <c>error_logger</c>. If you want to verify that the + schedulers actually have bound as requested, call + <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. + </p> + <p>Schedulers can currently only be bound on newer Linux, + Solaris, FreeBSD, and Windows systems, but more systems will be + supported in the future. + </p> + <p>In order for the runtime system to be able to bind schedulers, + the CPU topology needs to be known. If the runtime system fails + to automatically detect the CPU topology, it can be defined. + For more information on how to define the CPU topology, see + the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> command + line flag. + </p> + <p>The runtime system will by default <em>not</em> bind schedulers + to logical processors. + </p> + <p><em>NOTE:</em> If the Erlang runtime system is the only + operating system process that binds threads to logical processors, + this improves the performance of the runtime system. However, + if other operating system processes (as for example another Erlang + runtime system) also bind threads to logical processors, there + might be a performance penalty instead. In some cases this + performance penalty might be severe. If this is the case, you + are advised to not bind the schedulers.</p> + <p>Schedulers can be bound in different ways. The <c><anno>How</anno></c> + argument determines how schedulers are bound. <c><anno>How</anno></c> can + currently be one of:</p> <taglist> - <tag><c>erlang:system_flag(backtrace_depth, Depth)</c></tag> - <item> - <p>Sets the maximum depth of call stack back-traces in the - exit reason element of <c>'EXIT'</c> tuples.</p> - </item> - <tag><marker id="system_flag_cpu_topology"><c>erlang:system_flag(cpu_topology, CpuTopology)</c></marker></tag> - <item> - <p><em>NOTE:</em> This argument is <em>deprecated</em> and - scheduled for removal in erts-5.10/OTP-R16. Instead of using - this argument you are advised to use the <c>erl</c> command - line argument <seealso marker="erts:erl#+sct">+sct</seealso>. - When this argument has been removed a final CPU topology to use - will be determined at emulator boot time.</p> - <p>Sets the user defined <c>CpuTopology</c>. The user defined - CPU topology will override any automatically detected - CPU topology. By passing <c>undefined</c> as <c>CpuTopology</c> - the system will revert back to the CPU topology automatically - detected. The returned value equals the value returned - from <c>erlang:system_info(cpu_topology)</c> before the - change was made. - </p> - <p>The CPU topology is used when binding schedulers to logical - processors. If schedulers are already bound when the CPU - topology is changed, the schedulers will be sent a request - to rebind according to the new CPU topology. - </p> - <p>The user defined CPU topology can also be set by passing - the <seealso marker="erts:erl#+sct">+sct</seealso> command - line argument to <c>erl</c>. - </p> - <p>For information on the <c>CpuTopology</c> type - and more, see the documentation of - <seealso marker="#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso>, - and the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> - and <seealso marker="erts:erl#+sbt">+sbt</seealso> - command line flags. - </p> - </item> - <tag><c>erlang:system_flag(fullsweep_after, Number)</c></tag> - <item> - <p><c>Number</c> is a non-negative integer which indicates - how many times generational garbage collections can be - done without forcing a fullsweep collection. The value - applies to new processes; processes already running are - not affected.</p> - <p>In low-memory systems (especially without virtual - memory), setting the value to 0 can help to conserve - memory.</p> - <p>An alternative way to set this value is through the - (operating system) environment variable - <c>ERL_FULLSWEEP_AFTER</c>.</p> - </item> - <tag><c>erlang:system_flag(min_heap_size, MinHeapSize)</c></tag> - <item> - <p>Sets the default minimum heap size for processes. The - size is given in words. The new <c>min_heap_size</c> only - effects processes spawned after the change of - <c>min_heap_size</c> has been made. - The <c>min_heap_size</c> can be set for individual - processes by use of - <seealso marker="#spawn_opt/4">spawn_opt/N</seealso> or - <seealso marker="#process_flag/2">process_flag/2</seealso>. </p> - </item> - <tag><c>erlang:system_flag(min_bin_vheap_size, MinBinVHeapSize)</c></tag> - <item> - <p>Sets the default minimum binary virtual heap size for processes. The - size is given in words. The new <c>min_bin_vhheap_size</c> only - effects processes spawned after the change of - <c>min_bin_vhheap_size</c> has been made. - The <c>min_bin_vheap_size</c> can be set for individual - processes by use of - <seealso marker="#spawn_opt/4">spawn_opt/N</seealso> or - <seealso marker="#process_flag/2">process_flag/2</seealso>. </p> - </item> - <tag><marker id="system_flag_multi_scheduling"><c>erlang:system_flag(multi_scheduling, BlockState)</c></marker></tag> - <item> - <p><c>BlockState = block | unblock</c></p> - <p>If multi-scheduling is enabled, more than one scheduler - thread is used by the emulator. Multi-scheduling can be - blocked. When multi-scheduling has been blocked, only - one scheduler thread will schedule Erlang processes.</p> - <p>If <c>BlockState =:= block</c>, multi-scheduling will - be blocked. If <c>BlockState =:= unblock</c> and no-one - else is blocking multi-scheduling and this process has - only blocked one time, multi-scheduling will be unblocked. - One process can block multi-scheduling multiple times. - If a process has blocked multiple times, it has to - unblock exactly as many times as it has blocked before it - has released its multi-scheduling block. If a process that - has blocked multi-scheduling exits, it will release its - blocking of multi-scheduling.</p> - <p>The return values are <c>disabled</c>, <c>blocked</c>, - or <c>enabled</c>. The returned value describes the - state just after the call to - <c>erlang:system_flag(multi_scheduling, BlockState)</c> - has been made. The return values are described in the - documentation of <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>.</p> - <p><em>NOTE</em>: Blocking of multi-scheduling should normally - not be needed. If you feel that you need to - block multi-scheduling, think through the - problem at least a couple of times again. - Blocking multi-scheduling should only be used - as a last resort since it will most likely be - a <em>very inefficient</em> way to solve the - problem.</p> - <p>See also <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, - <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>, and - <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> - </item> - <tag><marker id="system_flag_scheduler_bind_type"><c>erlang:system_flag(scheduler_bind_type, How)</c></marker></tag> - <item> - <p><em>NOTE:</em> This argument is <em>deprecated</em> and - scheduled for removal in erts-5.10/OTP-R16. Instead of using - this argument you are advised to use the <c>erl</c> command - line argument <seealso marker="erts:erl#+sbt">+sbt</seealso>. - When this argument has been removed a final scheduler bind type - to use will be determined at emulator boot time.</p> - <p>Controls if and how schedulers are bound to logical - processors.</p> - <p>When <c>erlang:system_flag(scheduler_bind_type, How)</c> is - called, an asynchronous signal is sent to all schedulers - online which causes them to try to bind or unbind as requested. - <em>NOTE:</em> If a scheduler fails to bind, this - will often be silently ignored. This since it isn't always - possible to verify valid logical processor identifiers. If - an error is reported, it will be reported to the - <c>error_logger</c>. If you want to verify that the - schedulers actually have bound as requested, call - <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. - </p> - <p>Schedulers can currently only be bound on newer Linux, - Solaris, FreeBSD, and Windows systems, but more systems will be - supported in the future. - </p> - <p>In order for the runtime system to be able to bind schedulers, - the CPU topology needs to be known. If the runtime system fails - to automatically detect the CPU topology, it can be defined. - For more information on how to define the CPU topology, see - the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> command - line flag. - </p> - <p>The runtime system will by default <em>not</em> bind schedulers - to logical processors. - </p> - <p><em>NOTE:</em> If the Erlang runtime system is the only - operating system process that binds threads to logical processors, - this improves the performance of the runtime system. However, - if other operating system processes (as for example another Erlang - runtime system) also bind threads to logical processors, there - might be a performance penalty instead. In some cases this - performance penalty might be severe. If this is the case, you - are advised to not bind the schedulers.</p> - <p>Schedulers can be bound in different ways. The <c>How</c> - argument determines how schedulers are bound. <c>How</c> can - currently be one of:</p> - <taglist> - <tag><c>unbound</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt u</seealso>. - </p></item> - <tag><c>no_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt ns</seealso>. - </p></item> - <tag><c>thread_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt ts</seealso>. - </p></item> - <tag><c>processor_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt ps</seealso>. - </p></item> - <tag><c>spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt s</seealso>. - </p></item> - <tag><c>no_node_thread_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt nnts</seealso>. - </p></item> - <tag><c>no_node_processor_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt nnps</seealso>. - </p></item> - <tag><c>thread_no_node_processor_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt tnnps</seealso>. - </p></item> - <tag><c>default_bind</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt db</seealso>. - </p></item> - </taglist> - <p>The value returned equals <c>How</c> before the - <c>scheduler_bind_type</c> flag was changed.</p> - <p>Failure:</p> - <taglist> - <tag><c>notsup</c></tag> - <item> - <p>If binding of schedulers is not supported.</p> - </item> - <tag><c>badarg</c></tag> - <item> - <p>If <c>How</c> isn't one of the documented alternatives.</p> - </item> - <tag><c>badarg</c></tag> - <item> - <p>If no CPU topology information is available.</p> - </item> - </taglist> - <p>The scheduler bind type can also be set by passing - the <seealso marker="erts:erl#+sbt">+sbt</seealso> command - line argument to <c>erl</c>. - </p> - <p>For more information, see - <seealso marker="#system_info_scheduler_bind_type">erlang:system_info(scheduler_bind_type)</seealso>, - <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>, - the <c>erl</c> <seealso marker="erts:erl#+sbt">+sbt</seealso> - and <seealso marker="erts:erl#+sct">+sct</seealso> command line - flags. - </p> - </item> - <tag><marker id="system_flag_scheduler_wall_time"><c>erlang:system_flag(scheduler_wall_time, Boolean)</c></marker></tag> + <tag><c>unbound</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt u</seealso>. + </p></item> + <tag><c>no_spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt ns</seealso>. + </p></item> + <tag><c>thread_spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt ts</seealso>. + </p></item> + <tag><c>processor_spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt ps</seealso>. + </p></item> + <tag><c>spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt s</seealso>. + </p></item> + <tag><c>no_node_thread_spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt nnts</seealso>. + </p></item> + <tag><c>no_node_processor_spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt nnps</seealso>. + </p></item> + <tag><c>thread_no_node_processor_spread</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt tnnps</seealso>. + </p></item> + <tag><c>default_bind</c></tag> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt db</seealso>. + </p></item> + </taglist> + <p>The value returned equals <c><anno>How</anno></c> before the + <c>scheduler_bind_type</c> flag was changed.</p> + <p>Failure:</p> + <taglist> + <tag><c>notsup</c></tag> <item> - <p>Turns on/off scheduler wall time measurements. </p> - <p>For more information see, - <seealso marker="#statistics_scheduler_wall_time">erlang:statistics(scheduler_wall_time)</seealso>. - </p> + <p>If binding of schedulers is not supported.</p> </item> - - <tag><marker id="system_flag_schedulers_online"><c>erlang:system_flag(schedulers_online, SchedulersOnline)</c></marker></tag> + <tag><c>badarg</c></tag> <item> - <p>Sets the amount of schedulers online. Valid range is - <![CDATA[1 <= SchedulerId <= erlang:system_info(schedulers)]]>. - </p> - <p>For more information see, - <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>, - and - <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>. - </p> + <p>If <c>How</c> isn't one of the documented alternatives.</p> </item> - - <tag><c>erlang:system_flag(trace_control_word, TCW)</c></tag> + <tag><c>badarg</c></tag> <item> - <p>Sets the value of the node's trace control word to - <c>TCW</c>. <c>TCW</c> should be an unsigned integer. For - more information see documentation of the - <seealso marker="erts:match_spec#set_tcw">set_tcw</seealso> - function in the match specification documentation in the - ERTS User's Guide.</p> + <p>If no CPU topology information is available.</p> </item> </taglist> - <note> - <p>The <c>schedulers</c> option has been removed as - of erts version 5.5.3. The number of scheduler - threads is determined at emulator boot time, and - cannot be changed after that.</p> - </note> + <p>The scheduler bind type can also be set by passing + the <seealso marker="erts:erl#+sbt">+sbt</seealso> command + line argument to <c>erl</c>. + </p> + <p>For more information, see + <seealso marker="#system_info_scheduler_bind_type">erlang:system_info(scheduler_bind_type)</seealso>, + <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>, + the <c>erl</c> <seealso marker="erts:erl#+sbt">+sbt</seealso> + and <seealso marker="erts:erl#+sct">+sct</seealso> command line + flags. + </p> </desc> </func> <func> - <name>erlang:system_info(Type) -> Res</name> - <fsummary>Information about the system</fsummary> - <type> - <v>Type, Res -- see below</v> - </type> + <name name="system_flag" arity="2" clause_i="8"/> + <fsummary>Set system flag scheduler_wall_time</fsummary> + <desc><p><marker id="system_flag_scheduler_wall_time"></marker> + Turns on/off scheduler wall time measurements. </p> + <p>For more information see, + <seealso marker="#statistics_scheduler_wall_time">erlang:statistics(scheduler_wall_time)</seealso>. + </p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="9"/> + <fsummary>Set system flag schedulers_online</fsummary> <desc> - <p>Returns various information about the current system - (emulator) as specified by <c>Type</c>:</p> + <p><marker id="system_flag_schedulers_online"></marker> + Sets the amount of schedulers online. Valid range is + <![CDATA[1 <= SchedulersOnline <= erlang:system_info(schedulers)]]>. + </p> + <p>Returns the old value of the flag.</p> + <p>For more information see, + <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>, + and + <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>. + </p> + </desc> + </func> + <func> + <name name="system_flag" arity="2" clause_i="10"/> + <fsummary>Set system flag trace_control_word</fsummary> + <desc> + <p>Sets the value of the node's trace control word to + <c><anno>TCW</anno></c>. <c><anno>TCW</anno></c> should be an unsigned integer. For + more information see documentation of the + <seealso marker="erts:match_spec#set_tcw">set_tcw</seealso> + function in the match specification documentation in the + ERTS User's Guide.</p> + <p>Returns the old value of the flag.</p> + </desc> + </func> + <func> + <name name="system_info" arity="1" clause_i="1"/> + <name name="system_info" arity="1" clause_i="2"/> + <name name="system_info" arity="1" clause_i="3"/> + <name name="system_info" arity="1" clause_i="4"/> + <name name="system_info" arity="1" clause_i="5"/> + <type variable="Allocator" name_i="2"/> + <type variable="Version" name_i="2"/> + <type variable="Features" name_i="2"/> + <type variable="Settings" name_i="2"/> + <type variable="Alloc" name_i="3"/> + <fsummary>Information about the allocators of the system</fsummary> + <desc> + <p> + Returns various information about the + <marker id="system_info_allocator_tags">allocators</marker> of the + current system (emulator) as specified by + <c><anno>Item</anno></c>:</p> <taglist> <tag><marker id="system_info_allocated_areas"><c>allocated_areas</c></marker></tag> <item> @@ -5447,37 +4945,27 @@ ok </item> <tag><marker id="system_info_allocator"><c>allocator</c></marker></tag> <item> - <p>Returns <c>{Allocator, Version, Features, Settings}.</c></p> - <p>Types:</p> - <list type="bulleted"> - <item><c>Allocator = undefined | glibc</c></item> - <item><c>Version = [integer()]</c></item> - <item><c>Features = [atom()]</c></item> - <item><c>Settings = [{Subsystem, [{Parameter, Value}]}]</c></item> - <item><c>Subsystem = atom()</c></item> - <item><c>Parameter = atom()</c></item> - <item><c>Value = term()</c></item> - </list> + <p>Returns <c>{<anno>Allocator</anno>, <anno>Version</anno>, <anno>Features</anno>, <anno>Settings</anno>}.</c></p> <p>Explanation:</p> <list type="bulleted"> <item> - <p><c>Allocator</c> corresponds to the <c>malloc()</c> - implementation used. If <c>Allocator</c> equals + <p><c><anno>Allocator</anno></c> corresponds to the <c>malloc()</c> + implementation used. If <c><anno>Allocator</anno></c> equals <c>undefined</c>, the <c>malloc()</c> implementation used could not be identified. Currently <c>glibc</c> can be identified.</p> </item> <item> - <p><c>Version</c> is a list of integers (but not a + <p><c><anno>Version</anno></c> is a list of integers (but not a string) representing the version of the <c>malloc()</c> implementation used.</p> </item> <item> - <p><c>Features</c> is a list of atoms representing + <p><c><anno>Features</anno></c> is a list of atoms representing allocation features used.</p> </item> <item> - <p><c>Settings</c> is a list of subsystems, their + <p><c><anno>Settings</anno></c> is a list of subsystems, their configurable parameters, and used values. Settings may differ between different combinations of platforms, allocators, and allocation features. @@ -5497,15 +4985,15 @@ ok erts_alloc(3)</seealso> documentation. </p> </item> - <tag><marker id="system_info_allocator_tuple"><c>{allocator, Alloc}</c></marker></tag> + <tag><marker id="system_info_allocator_tuple"><c>{allocator, <anno>Alloc</anno>}</c></marker></tag> <item> <p>Returns information about the specified allocator. As of erts version 5.6.1 the return value is a list of <c>{instance, InstanceNo, InstanceInfo}</c> tuples where <c>InstanceInfo</c> contains information about a specific instance of the allocator. - If <c>Alloc</c> is not a recognized allocator, - <c>undefined</c> is returned. If <c>Alloc</c> is disabled, + If <c><anno>Alloc</anno></c> is not a recognized allocator, + <c>undefined</c> is returned. If <c><anno>Alloc</anno></c> is disabled, <c>false</c> is returned.</p> <p><em>Note:</em> The information returned is highly implementation dependent and may be changed, or removed @@ -5534,54 +5022,51 @@ ok values. The first value is memory pool size and the second value used memory size.</p> </item> - <tag><marker id="system_info_allocator_sizes"><c>{allocator_sizes, Alloc}</c></marker></tag> + <tag><marker id="system_info_allocator_sizes"><c>{allocator_sizes, <anno>Alloc</anno>}</c></marker></tag> <item> <p>Returns various size information for the specified allocator. The information returned is a subset of the information returned by - <seealso marker="#system_info_allocator_tuple">erlang:system_info({allocator, Alloc})</seealso>. + <seealso marker="#system_info_allocator_tuple">erlang:system_info({allocator, <anno>Alloc</anno>})</seealso>. </p> </item> - <tag><c>build_type</c></tag> - <item> - <p>Returns an atom describing the build type of the runtime - system. This is normally the atom <c>opt</c> for optimized. - Other possible return values are <c>debug</c>, <c>purify</c>, - <c>quantify</c>, <c>purecov</c>, <c>gcov</c>, <c>valgrind</c>, - <c>gprof</c>, and <c>lcnt</c>. Possible return values - may be added and/or removed at any time without prior notice. - </p> - </item> - <tag><c>c_compiler_used</c></tag> - <item> - <p>Returns a two-tuple describing the C compiler used when - compiling the runtime system. The first element is an - atom describing the name of the compiler, or <c>undefined</c> - if unknown. The second element is a term describing the - version of the compiler, or <c>undefined</c> if unknown. - </p> - </item> - <tag><c>check_io</c></tag> - <item> - <p>Returns a list containing miscellaneous information - regarding the emulators internal I/O checking. Note, - the content of the returned list may vary between - platforms and over time. The only thing guaranteed is - that a list is returned.</p> - </item> - <tag><c>compat_rel</c></tag> - <item> - <p>Returns the compatibility mode of the local node as - an integer. The integer returned represents the - Erlang/OTP release which the current emulator has been - set to be backward compatible with. The compatibility - mode can be configured at startup by using the command - line flag <c>+R</c>, see - <seealso marker="erts:erl#compat_rel">erl(1)</seealso>.</p> - </item> - <tag><marker id="system_info_cpu_topology"><c>cpu_topology</c></marker></tag> + </taglist> + </desc> + </func> + <func> + <name name="system_info" arity="1" clause_i="10"/> + <name name="system_info" arity="1" clause_i="11"/> + <type name="cpu_topology"/> + <type name="level_entry"/> + <type_desc name="cpu_topology"> + <marker id="system_info_cpu_topology"></marker> + All <c><anno>LevelEntry</anno></c>s of a list + must contain the same <c><anno>LevelTag</anno></c>, except + on the top level where both <c>node</c> and + <c>processor</c> <c><anno>LevelTag</anno></c>s may co-exist. + </type_desc> + <type_desc name="level_entry"> + <c>{<anno>LevelTag</anno>, <anno>SubLevel</anno>} == {<anno>LevelTag</anno>, [], <anno>SubLevel</anno>}</c> + </type_desc> + <type name="level_tag"/> + <type_desc name="level_tag"> + More <c><anno>LevelTag</anno></c>s may be introduced in the future. + </type_desc> + <type name="sub_level"/> + <type name="info_list"/> + <type_desc name="info_list"> + The <c>info_list()</c> may be extended in the future. + </type_desc> + <fsummary>Information about the CPU topology of the system</fsummary> + <desc> + <p>Returns various information about the + <marker id="system_info_cpu_topology_tags">CPU topology</marker> + of the current system + (emulator) as specified by <c><anno>Item</anno></c>:</p> + <taglist> + <tag><c>cpu_topology</c></tag> <item> - <p>Returns the <c>CpuTopology</c> which currently is used by the + <p>Returns the <c><anno>CpuTopology</anno></c> which currently is used by the emulator. The CPU topology is used when binding schedulers to logical processors. The CPU topology used is the <seealso marker="erlang#system_info_cpu_topology_defined">user @@ -5589,31 +5074,11 @@ ok <seealso marker="erlang#system_info_cpu_topology_detected">automatically detected CPU topology</seealso> if such exists. If no CPU topology exists, <c>undefined</c> is returned.</p> - <p>Types:</p> - <list type="bulleted"> - <item><c>CpuTopology = LevelEntryList | undefined</c></item> - <item><c>LevelEntryList = [LevelEntry]</c> (all - <c>LevelEntry</c>s of a <c>LevelEntryList</c> - must contain the same <c>LevelTag</c>, except - on the top level where both <c>node</c> and - <c>processor</c> <c>LevelTag</c>s may co-exist)</item> - <item><c>LevelEntry = {LevelTag, SubLevel} - | {LevelTag, InfoList, SubLevel}</c> - (<c>{LevelTag, SubLevel} - == {LevelTag, [], SubLevel}</c>)</item> - <item><c>LevelTag = node|processor|core|thread</c> - (more <c>LevelTag</c>s may be introduced in - the future)</item> - <item><c>SubLevel = [LevelEntry] | LogicalCpuId</c></item> - <item><c>LogicalCpuId = {logical, integer()}</c></item> - <item><c>InfoList = []</c> (the <c>InfoList</c> - may be extended in the future)</item> - </list> <p><c>node</c> refers to NUMA (non-uniform memory access) nodes, and <c>thread</c> refers to hardware threads (e.g. Intels hyper-threads).</p> - <p>A level in the <c>CpuTopology</c> term can be omitted if - only one entry exists and the <c>InfoList</c> is empty. + <p>A level in the <c><anno>CpuTopology</anno></c> term can be omitted if + only one entry exists and the <c><anno>InfoList</anno></c> is empty. </p> <p><c>thread</c> can only be a sub level to <c>core</c>. <c>core</c> can be a sub level to either <c>processor</c> @@ -5625,15 +5090,15 @@ ok consist of a mix of processor internal and external NUMA nodes, as long as each logical CPU belongs to one and only one NUMA node. Cache hierarchy is not part of - the <c>CpuTopology</c> type yet, but will be in the + the <c><anno>CpuTopology</anno></c> type yet, but will be in the future. Other things may also make it into the CPU topology in the future. In other words, expect the - <c>CpuTopology</c> type to change. + <c><anno>CpuTopology</anno></c> type to change. </p> </item> <tag><marker id="system_info_cpu_topology_defined"><c>{cpu_topology, defined}</c></marker></tag> <item> - <p>Returns the user defined <c>CpuTopology</c>. For more + <p>Returns the user defined <c><anno>CpuTopology</anno></c>. For more information see the documentation of the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> command line flag, and the documentation of the @@ -5643,7 +5108,7 @@ ok </item> <tag><marker id="system_info_cpu_topology_detected"><c>{cpu_topology, detected}</c></marker></tag> <item> - <p>Returns the automatically detected <c>CpuTopology</c>. The + <p>Returns the automatically detected <c><anno>CpuTopology</anno></c>. The emulator currently only detects the CPU topology on some newer Linux, Solaris, FreeBSD, and Windows systems. On Windows system with more than 32 logical processors the CPU topology is not detected. @@ -5655,13 +5120,111 @@ ok </item> <tag><c>{cpu_topology, used}</c></tag> <item> - <p>Returns the <c>CpuTopology</c> which is used by the + <p>Returns the <c><anno>CpuTopology</anno></c> which is used by the emulator. For more information see the documentation of the <seealso marker="#system_info_cpu_topology">cpu_topology</seealso> argument. </p> </item> + </taglist> + </desc> + </func> + <func> + <name name="system_info" arity="1" clause_i="6"/> + <name name="system_info" arity="1" clause_i="7"/> + <name name="system_info" arity="1" clause_i="8"/> + <name name="system_info" arity="1" clause_i="9"/> + <name name="system_info" arity="1" clause_i="12"/> + <name name="system_info" arity="1" clause_i="13"/> + <name name="system_info" arity="1" clause_i="14"/> + <name name="system_info" arity="1" clause_i="15"/> + <name name="system_info" arity="1" clause_i="16"/> + <name name="system_info" arity="1" clause_i="17"/> + <name name="system_info" arity="1" clause_i="18"/> + <name name="system_info" arity="1" clause_i="19"/> + <name name="system_info" arity="1" clause_i="20"/> + <name name="system_info" arity="1" clause_i="21"/> + <name name="system_info" arity="1" clause_i="22"/> + <name name="system_info" arity="1" clause_i="23"/> + <name name="system_info" arity="1" clause_i="24"/> + <name name="system_info" arity="1" clause_i="25"/> + <name name="system_info" arity="1" clause_i="26"/> + <name name="system_info" arity="1" clause_i="27"/> + <name name="system_info" arity="1" clause_i="28"/> + <name name="system_info" arity="1" clause_i="29"/> + <name name="system_info" arity="1" clause_i="30"/> + <name name="system_info" arity="1" clause_i="31"/> + <name name="system_info" arity="1" clause_i="32"/> + <name name="system_info" arity="1" clause_i="33"/> + <name name="system_info" arity="1" clause_i="34"/> + <name name="system_info" arity="1" clause_i="35"/> + <name name="system_info" arity="1" clause_i="36"/> + <name name="system_info" arity="1" clause_i="37"/> + <name name="system_info" arity="1" clause_i="38"/> + <name name="system_info" arity="1" clause_i="39"/> + <name name="system_info" arity="1" clause_i="40"/> + <name name="system_info" arity="1" clause_i="41"/> + <name name="system_info" arity="1" clause_i="42"/> + <name name="system_info" arity="1" clause_i="43"/> + <name name="system_info" arity="1" clause_i="44"/> + <name name="system_info" arity="1" clause_i="45"/> + <name name="system_info" arity="1" clause_i="46"/> + <name name="system_info" arity="1" clause_i="47"/> + <name name="system_info" arity="1" clause_i="48"/> + <name name="system_info" arity="1" clause_i="49"/> + <name name="system_info" arity="1" clause_i="50"/> + <fsummary>Information about the system</fsummary> + <desc> + <p>Returns various information about the current system + (emulator) as specified by <c><anno>Item</anno></c>:</p> + <taglist> + <tag><c>allocated_areas</c>, <c>allocator</c>, + <c>alloc_util_allocators</c>, <c>allocator_sizes</c></tag> + <item> + <p>See <seealso marker="#system_info_allocator_tags">above</seealso>.</p> + </item> + <tag><c>build_type</c></tag> + <item> + <p>Returns an atom describing the build type of the runtime + system. This is normally the atom <c>opt</c> for optimized. + Other possible return values are <c>debug</c>, <c>purify</c>, + <c>quantify</c>, <c>purecov</c>, <c>gcov</c>, <c>valgrind</c>, + <c>gprof</c>, and <c>lcnt</c>. Possible return values + may be added and/or removed at any time without prior notice. + </p> + </item> + <tag><c>c_compiler_used</c></tag> + <item> + <p>Returns a two-tuple describing the C compiler used when + compiling the runtime system. The first element is an + atom describing the name of the compiler, or <c>undefined</c> + if unknown. The second element is a term describing the + version of the compiler, or <c>undefined</c> if unknown. + </p> + </item> + <tag><c>check_io</c></tag> + <item> + <p>Returns a list containing miscellaneous information + regarding the emulators internal I/O checking. Note, + the content of the returned list may vary between + platforms and over time. The only thing guaranteed is + that a list is returned.</p> + </item> + <tag><c>compat_rel</c></tag> + <item> + <p>Returns the compatibility mode of the local node as + an integer. The integer returned represents the + Erlang/OTP release which the current emulator has been + set to be backward compatible with. The compatibility + mode can be configured at startup by using the command + line flag <c>+R</c>, see + <seealso marker="erts:erl#compat_rel">erl(1)</seealso>.</p> + </item> + <tag><c>cpu_topology</c></tag> + <item> + <p>See <seealso marker="#system_info_cpu_topology_tags">above</seealso>.</p> + </item> <tag><c>creation</c></tag> <item> <p>Returns the creation of the local node as an integer. @@ -5691,10 +5254,10 @@ ok <item> <p>Returns a list of tuples <c>{Node, ControllingEntity}</c>, one entry for each - connected remote node. The <c>Node</c> is the name of the - node and the <c>ControllingEntity</c> is the port or pid + connected remote node. The <c><anno>Node</anno></c> is the name of the + node and the <c><anno>ControllingEntity</anno></c> is the port or pid responsible for the communication to that node. More - specifically, the <c>ControllingEntity</c> for nodes + specifically, the <c><anno>ControllingEntity</anno></c> for nodes connected via TCP/IP (the normal case) is the socket actually used in communication with the specific node.</p> </item> @@ -5719,7 +5282,7 @@ ok </item> <tag><c>fullsweep_after</c></tag> <item> - <p>Returns <c>{fullsweep_after, integer()}</c> which is the + <p>Returns <c>{fullsweep_after, integer() >= 0}</c> which is the <c>fullsweep_after</c> garbage collection setting used by default. For more information see <c>garbage_collection</c> described below.</p> @@ -5827,12 +5390,12 @@ ok </item> <tag><c>min_heap_size</c></tag> <item> - <p>Returns <c>{min_heap_size, MinHeapSize}</c> where <c>MinHeapSize</c> is the current system wide + <p>Returns <c>{min_heap_size, <anno>MinHeapSize</anno>}</c> where <c><anno>MinHeapSize</anno></c> is the current system wide minimum heap size for spawned processes.</p> </item> <tag><c>min_bin_vheap_size</c></tag> <item> - <p>Returns <c>{min_bin_vheap_size, MinBinVHeapSize}</c> where <c>MinBinVHeapSize</c> is the current system wide + <p>Returns <c>{min_bin_vheap_size, <anno>MinBinVHeapSize</anno>}</c> where <c><anno>MinBinVHeapSize</anno></c> is the current system wide minimum binary virtual heap size for spawned processes.</p> </item> <tag><c>modified_timing_level</c></tag> @@ -5876,10 +5439,10 @@ ok </item> <tag><marker id="system_info_multi_scheduling_blockers"><c>multi_scheduling_blockers</c></marker></tag> <item> - <p>Returns a list of <c>PID</c>s when multi-scheduling - is blocked; otherwise, the empty list. The <c>PID</c>s - in the list is <c>PID</c>s of the processes currently - blocking multi-scheduling. A <c>PID</c> will only be + <p>Returns a list of <c><anno>PID</anno></c>s when multi-scheduling + is blocked; otherwise, the empty list. The <c><anno>PID</anno></c>s + in the list is <c><anno>PID</anno></c>s of the processes currently + blocking multi-scheduling. A <c><anno>PID</anno></c> will only be present once in the list, even if the corresponding process has blocked multiple times.</p> <p>See also <seealso marker="#system_flag_multi_scheduling">erlang:system_flag(multi_scheduling, BlockState)</seealso>, @@ -5954,7 +5517,7 @@ ok <item> <p>Returns the scheduler id (<c>SchedulerId</c>) of the scheduler thread that the calling process is executing - on. <c>SchedulerId</c> is a positive integer; where + on. <c><anno>SchedulerId</anno></c> is a positive integer; where <c><![CDATA[1 <= SchedulerId <= erlang:system_info(schedulers)]]></c>. See also <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> </item> @@ -6080,53 +5643,39 @@ ok </func> <func> - <name>erlang:system_monitor() -> MonSettings</name> + <name name="system_monitor" arity="0"/> + <type name="system_monitor_option"/> <fsummary>Current system performance monitoring settings</fsummary> - <type> - <v>MonSettings -> {MonitorPid, Options} | undefined</v> - <v> MonitorPid = pid()</v> - <v> Options = [Option]</v> - <v> Option = {long_gc, Time} | {large_heap, Size} | busy_port | busy_dist_port</v> - <v> Time = Size = integer()</v> - </type> <desc> <p>Returns the current system monitoring settings set by <seealso marker="#system_monitor/2">erlang:system_monitor/2</seealso> - as <c>{MonitorPid, Options}</c>, or <c>undefined</c> if there + as <c>{<anno>MonitorPid</anno>, <anno>Options</anno>}</c>, or <c>undefined</c> if there are no settings. The order of the options may be different from the one that was set.</p> </desc> </func> <func> - <name>erlang:system_monitor(undefined | {MonitorPid, Options}) -> MonSettings</name> + <name name="system_monitor" arity="1"/> + <type name="system_monitor_option"/> <fsummary>Set or clear system performance monitoring options</fsummary> - <type> - <v>MonitorPid, Options, MonSettings -- see below</v> - </type> <desc> <p>When called with the argument <c>undefined</c>, all system performance monitoring settings are cleared.</p> - <p>Calling the function with <c>{MonitorPid, Options}</c> as + <p>Calling the function with <c>{<anno>MonitorPid</anno>, <anno>Options</anno>}</c> as argument, is the same as calling - <seealso marker="#system_monitor/2">erlang:system_monitor(MonitorPid, Options)</seealso>.</p> + <seealso marker="#system_monitor/2">erlang:system_monitor(<anno>MonitorPid</anno>, <anno>Options</anno>)</seealso>.</p> <p>Returns the previous system monitor settings just like <seealso marker="#system_monitor/0">erlang:system_monitor/0</seealso>.</p> </desc> </func> <func> - <name>erlang:system_monitor(MonitorPid, [Option]) -> MonSettings</name> + <name name="system_monitor" arity="2"/> + <type name="system_monitor_option"/> <fsummary>Set system performance monitoring options</fsummary> - <type> - <v>MonitorPid = pid()</v> - <v>Option = {long_gc, Time} | {large_heap, Size} | busy_port | busy_dist_port</v> - <v> Time = Size = integer()</v> - <v>MonSettings = {OldMonitorPid, [Option]}</v> - <v> OldMonitorPid = pid()</v> - </type> - <desc> - <p>Sets system performance monitoring options. <c>MonitorPid</c> + <desc> + <p>Sets system performance monitoring options. <c><anno>MonitorPid</anno></c> is a local pid that will receive system monitor messages, and the second argument is a list of monitoring options:</p> <taglist> @@ -6135,7 +5684,7 @@ ok <p>If a garbage collection in the system takes at least <c>Time</c> wallclock milliseconds, a message <c>{monitor, GcPid, long_gc, Info}</c> is sent to - <c>MonitorPid</c>. <c>GcPid</c> is the pid that was + <c><anno>MonitorPid</anno></c>. <c>GcPid</c> is the pid that was garbage collected and <c>Info</c> is a list of two-element tuples describing the result of the garbage collection. One of the tuples is <c>{timeout, GcTime}</c> where @@ -6158,7 +5707,7 @@ ok <p>If a garbage collection in the system results in the allocated size of a heap being at least <c>Size</c> words, a message <c>{monitor, GcPid, large_heap, Info}</c> - is sent to <c>MonitorPid</c>. <c>GcPid</c> and <c>Info</c> + is sent to <c><anno>MonitorPid</anno></c>. <c>GcPid</c> and <c>Info</c> are the same as for <c>long_gc</c> above, except that the tuple tagged with <c>timeout</c> is not present. <em>Note</em>: As of erts version 5.6 the monitor message @@ -6174,7 +5723,7 @@ ok <p>If a process in the system gets suspended because it sends to a busy port, a message <c>{monitor, SusPid, busy_port, Port}</c> is sent to - <c>MonitorPid</c>. <c>SusPid</c> is the pid that got + <c><anno>MonitorPid</anno></c>. <c>SusPid</c> is the pid that got suspended when sending to <c>Port</c>.</p> </item> <tag><c>busy_dist_port</c></tag> @@ -6183,7 +5732,7 @@ ok sends to a process on a remote node whose inter-node communication was handled by a busy port, a message <c>{monitor, SusPid, busy_dist_port, Port}</c> is sent to - <c>MonitorPid</c>. <c>SusPid</c> is the pid that got + <c><anno>MonitorPid</anno></c>. <c>SusPid</c> is the pid that got suspended when sending through the inter-node communication port <c>Port</c>.</p> </item> @@ -6198,48 +5747,48 @@ ok <p>Keep the monitoring process neat and do not set the system monitor limits too tight.</p> </note> - <p>Failure: <c>badarg</c> if <c>MonitorPid</c> does not exist.</p> + <p>Failure: <c>badarg</c> if <c><anno>MonitorPid</anno></c> does not exist or is not a local process.</p> </desc> </func> <func> - <name>erlang:system_profile() -> ProfilerSettings</name> + <name name="system_profile" arity="0"/> + <type name="system_profile_option"/> <fsummary>Current system profiling settings</fsummary> - <type> - <v>ProfilerSettings -> {ProfilerPid, Options} | undefined</v> - <v> ProfilerPid = pid() | port()</v> - <v> Options = [Option]</v> - <v> Option = runnable_procs | runnable_ports | scheduler | exclusive</v> - </type> <desc> <p>Returns the current system profiling settings set by <seealso marker="#system_profile/2">erlang:system_profile/2</seealso> - as <c>{ProfilerPid, Options}</c>, or <c>undefined</c> if there + as <c>{<anno>ProfilerPid</anno>, <anno>Options</anno>}</c>, or <c>undefined</c> if there are no settings. The order of the options may be different from the one that was set.</p> </desc> </func> <func> - <name>erlang:system_profile(ProfilerPid, Options) -> ProfilerSettings</name> + <name name="system_profile" arity="2"/> + <type name="system_profile_option"/> <fsummary>Current system profiling settings</fsummary> - <type> - <v>ProfilerSettings -> {ProfilerPid, Options} | undefined</v> - <v> ProfilerPid = pid() | port()</v> - <v> Options = [Option]</v> - <v> Option = runnable_procs | runnable_ports | scheduler | exclusive</v> - </type> - <desc> - <p>Sets system profiler options. <c>ProfilerPid</c> + <desc> + <p>Sets system profiler options. <c><anno>ProfilerPid</anno></c> is a local pid or port that will receive profiling messages. The receiver is excluded from all profiling. The second argument is a list of profiling options:</p> <taglist> + <tag><c>exclusive</c></tag> + <item> + <p> + If a synchronous call to a port from a process is done, the + calling process is considered not runnable during the call + runtime to the port. The calling process is notified as + <c>inactive</c> and subsequently <c>active</c> when the port + callback returns. + </p> + </item> <tag><c>runnable_procs</c></tag> <item> <p>If a process is put into or removed from the run queue a message, <c>{profile, Pid, State, Mfa, Ts}</c>, is sent to - <c>ProfilerPid</c>. Running processes that is reinserted into the + <c><anno>ProfilerPid</anno></c>. Running processes that is reinserted into the run queue after having been preemptively scheduled out will not trigger this message. </p> @@ -6248,24 +5797,14 @@ ok <item> <p>If a port is put into or removed from the run queue a message, <c>{profile, Port, State, 0, Ts}</c>, is sent to - <c>ProfilerPid</c>. + <c><anno>ProfilerPid</anno></c>. </p> </item> <tag><c>scheduler</c></tag> <item> <p>If a scheduler is put to sleep or awoken a message, <c>{profile, scheduler, Id, State, NoScheds, Ts}</c>, is sent - to <c>ProfilerPid</c>. - </p> - </item> - <tag><c>exclusive</c></tag> - <item> - <p> - If a synchronous call to a port from a process is done, the - calling process is considered not runnable during the call - runtime to the port. The calling process is notified as - <c>inactive</c> and subsequently <c>active</c> when the port - callback returns. + to <c><anno>ProfilerPid</anno></c>. </p> </item> </taglist> @@ -6276,14 +5815,11 @@ ok </func> <func> - <name>term_to_binary(Term) -> ext_binary()</name> + <name name="term_to_binary" arity="1"/> <fsummary>Encode a term to an Erlang external term format binary</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> <p>Returns a binary data object which is the result of encoding - <c>Term</c> according to the Erlang external term format.</p> + <c><anno>Term</anno></c> according to the Erlang external term format.</p> <p>This can be used for a variety of purposes, for example writing a term to a file in an efficient way, or sending an Erlang term to some type of communications channel not @@ -6293,20 +5829,16 @@ ok </desc> </func> <func> - <name>term_to_binary(Term, [Option]) -> ext_binary()</name> + <name name="term_to_binary" arity="2"/> <fsummary>Encode a term to en Erlang external term format binary</fsummary> - <type> - <v>Term = term()</v> - <v>Option = compressed | {compressed,Level} | {minor_version,Version}</v> - </type> <desc> <p>Returns a binary data object which is the result of encoding - <c>Term</c> according to the Erlang external term format.</p> + <c><anno>Term</anno></c> according to the Erlang external term format.</p> <p>If the option <c>compressed</c> is provided, the external term format will be compressed. The compressed format is automatically recognized by <c>binary_to_term/1</c> in R7B and later.</p> <p>It is also possible to specify a compression level by giving - the option <c>{compressed,Level}</c>, where <c>Level</c> is an + the option <c>{compressed, <anno>Level</anno>}</c>, where <c><anno>Level</anno></c> is an integer from 0 through 9. <c>0</c> means that no compression will be done (it is the same as not giving any <c>compressed</c> option); <c>1</c> will take the least time but may not compress as well as @@ -6315,16 +5847,16 @@ ok on the input term, level 9 compression may or may not produce a smaller result than level 1 compression.</p> <p>Currently, <c>compressed</c> gives the same result as - <c>{compressed,6}</c>.</p> - <p>The option <c>{minor_version,Version}</c> can be use to control + <c>{compressed, 6}</c>.</p> + <p>The option <c>{minor_version, <anno>Version</anno>}</c> can be use to control some details of the encoding. This option was - introduced in R11B-4. Currently, the allowed values for <c>Version</c> + introduced in R11B-4. Currently, the allowed values for <c><anno>Version</anno></c> are <c>0</c> and <c>1</c>.</p> - <p><c>{minor_version,1}</c> forces any floats in the term to be encoded + <p><c>{minor_version, 1}</c> forces any floats in the term to be encoded in a more space-efficient and exact way (namely in the 64-bit IEEE format, rather than converted to a textual representation). <c>binary_to_term/1</c> in R11B-4 and later is able decode the new representation.</p> - <p><c>{minor_version,0}</c> is currently the default, meaning that floats + <p><c>{minor_version, 0}</c> is currently the default, meaning that floats will be encoded using a textual representation; this option is useful if you want to ensure that releases prior to R11B-4 can decode resulting binary.</p> @@ -6333,14 +5865,11 @@ ok </desc> </func> <func> - <name>throw(Any)</name> + <name name="throw" arity="1"/> <fsummary>Throw an exception</fsummary> - <type> - <v>Any = term()</v> - </type> <desc> <p>A non-local return from a function. If evaluated within a - <c>catch</c>, <c>catch</c> will return the value <c>Any</c>.</p> + <c>catch</c>, <c>catch</c> will return the value <c><anno>Any</anno></c>.</p> <pre> > <input>catch throw({hello, there}).</input> {hello,there}</pre> @@ -6348,11 +5877,8 @@ ok </desc> </func> <func> - <name>time() -> {Hour, Minute, Second}</name> + <name name="time" arity="0"/> <fsummary>Current time</fsummary> - <type> - <v>Hour = Minute = Second = integer() >= 0</v> - </type> <desc> <p>Returns the current time as <c>{Hour, Minute, Second}</c>.</p> <p>The time zone and daylight saving time correction depend on @@ -6363,35 +5889,27 @@ ok </desc> </func> <func> - <name>tl(List1) -> List2</name> + <name name="tl" arity="1"/> <fsummary>Tail of a list</fsummary> - <type> - <v>List1 = List2 = [term()]</v> - </type> <desc> - <p>Returns the tail of <c>List1</c>, that is, the list minus + <p>Returns the tail of <c><anno>List</anno></c>, that is, the list minus the first element.</p> <pre> > <input>tl([geesties, guilies, beasties]).</input> [guilies, beasties]</pre> <p>Allowed in guard tests.</p> - <p>Failure: <c>badarg</c> if <c>List</c> is the empty list [].</p> + <p>Failure: <c>badarg</c> if <c><anno>List</anno></c> is the empty list [].</p> </desc> </func> <func> - <name>erlang:trace(PidSpec, How, FlagList) -> integer() >= 0</name> + <name name="trace" arity="3"/> + <type name="trace_flag"/> <fsummary>Set trace flags for a process or processes</fsummary> - <type> - <v>PidSpec = pid() | existing | new | all</v> - <v>How = boolean()</v> - <v>FlagList = [Flag]</v> - <v> Flag -- see below</v> - </type> - <desc> - <p>Turns on (if <c>How == true</c>) or off (if - <c>How == false</c>) the trace flags in <c>FlagList</c> for - the process or processes represented by <c>PidSpec</c>.</p> - <p><c>PidSpec</c> is either a pid for a local process, or one of + <desc> + <p>Turns on (if <c><anno>How</anno> == true</c>) or off (if + <c><anno>How</anno> == false</c>) the trace flags in <c><anno>FlagList</anno></c> for + the process or processes represented by <c><anno>PidSpec</anno></c>.</p> + <p><c><anno>PidSpec</anno></c> is either a pid for a local process, or one of the following atoms:</p> <taglist> <tag><c>existing</c></tag> @@ -6408,7 +5926,7 @@ ok will be created in the future.</p> </item> </taglist> - <p><c>FlagList</c> can contain any number of the following + <p><c><anno>FlagList</anno></c> can contain any number of the following flags (the "message tags" refers to the list of messages following below):</p> <taglist> @@ -6723,11 +6241,11 @@ ok <p>Only one process can trace a particular process. For this reason, attempts to trace an already traced process will fail.</p> <p>Returns: A number indicating the number of processes that - matched <c>PidSpec</c>. If <c>PidSpec</c> is a pid, - the return value will be <c>1</c>. If <c>PidSpec</c> is + matched <c><anno>PidSpec</anno></c>. If <c><anno>PidSpec</anno></c> is a pid, + the return value will be <c>1</c>. If <c><anno>PidSpec</anno></c> is <c>all</c> or <c>existing</c> the return value will be the number of processes running, excluding tracer processes. - If <c>PidSpec</c> is <c>new</c>, the return value will be + If <c><anno>PidSpec</anno></c> is <c>new</c>, the return value will be <c>0</c>.</p> <p>Failure: If specified arguments are not supported. For example <c>cpu_timestamp</c> is not supported on all @@ -6735,64 +6253,58 @@ ok </desc> </func> <func> - <name>erlang:trace_delivered(Tracee) -> Ref</name> + <name name="trace_delivered" arity="1"/> <fsummary>Notification when trace has been delivered</fsummary> - <type> - <v>Tracee = pid() | all</v> - <v>Ref = reference()</v> - </type> <desc> <p>The delivery of trace messages is dislocated on the time-line compared to other events in the system. If you know that the - <c>Tracee</c> has passed some specific point in its execution, + <c><anno>Tracee</anno></c> has passed some specific point in its execution, and you want to know when at least all trace messages corresponding to events up to this point have reached the tracer - you can use <c>erlang:trace_delivered(Tracee)</c>. A - <c>{trace_delivered, Tracee, Ref}</c> message is sent to - the caller of <c>erlang:trace_delivered(Tracee)</c> when it + you can use <c>erlang:trace_delivered(<anno>Tracee</anno>)</c>. A + <c>{trace_delivered, <anno>Tracee</anno>, <anno>Ref</anno>}</c> message is sent to + the caller of <c>erlang:trace_delivered(<anno>Tracee</anno>)</c> when it is guaranteed that all trace messages have been delivered to - the tracer up to the point that the <c>Tracee</c> had reached + the tracer up to the point that the <c><anno>Tracee</anno></c> had reached at the time of the call to - <c>erlang:trace_delivered(Tracee)</c>.</p> + <c>erlang:trace_delivered(<anno>Tracee</anno>)</c>.</p> <p>Note that the <c>trace_delivered</c> message does <em>not</em> imply that trace messages have been delivered; instead, it implies that all trace messages that <em>should</em> be delivered have - been delivered. It is not an error if <c>Tracee</c> isn't, and + been delivered. It is not an error if <c><anno>Tracee</anno></c> isn't, and hasn't been traced by someone, but if this is the case, <em>no</em> trace messages will have been delivered when the <c>trace_delivered</c> message arrives.</p> - <p>Note that <c>Tracee</c> has to refer to a process currently, + <p>Note that <c><anno>Tracee</anno></c> has to refer to a process currently, or previously existing on the same node as the caller of - <c>erlang:trace_delivered(Tracee)</c> resides on. - The special <c>Tracee</c> atom <c>all</c> denotes all processes + <c>erlang:trace_delivered(<anno>Tracee</anno>)</c> resides on. + The special <c><anno>Tracee</anno></c> atom <c>all</c> denotes all processes that currently are traced in the node.</p> - <p>An example: Process <c>A</c> is tracee, port <c>B</c> is + <p>An example: Process <c>A</c> is <c><anno>Tracee</anno></c>, port <c>B</c> is tracer, and process <c>C</c> is the port owner of <c>B</c>. <c>C</c> wants to close <c>B</c> when <c>A</c> exits. <c>C</c> can ensure that the trace isn't truncated by calling <c>erlang:trace_delivered(A)</c> when <c>A</c> exits and wait - for the <c>{trace_delivered, A, Ref}</c> message before closing + for the <c>{trace_delivered, A, <anno>Ref</anno>}</c> message before closing <c>B</c>.</p> - <p>Failure: <c>badarg</c> if <c>Tracee</c> does not refer to a + <p>Failure: <c>badarg</c> if <c><anno>Tracee</anno></c> does not refer to a process (dead or alive) on the same node as the caller of - <c>erlang:trace_delivered(Tracee)</c> resides on.</p> + <c>erlang:trace_delivered(<anno>Tracee</anno>)</c> resides on.</p> </desc> </func> <func> - <name>erlang:trace_info(PidOrFunc, Item) -> Res</name> + <name name="trace_info" arity="2"/> + <type name="trace_info_return"/> + <type name="trace_info_item_result"/> + <type name="trace_info_flag"/> + <type name="trace_match_spec"/> <fsummary>Trace information about a process or function</fsummary> - <type> - <v>PidOrFunc = pid() | new | {Module, Function, Arity} | on_load</v> - <v> Module = Function = atom()</v> - <v> Arity = arity()</v> - <v>Item, Res -- see below</v> - </type> <desc> <p>Returns trace information about a process or function.</p> - <p>To get information about a process, <c>PidOrFunc</c> should + <p>To get information about a process, <c><anno>PidOrFunc</anno></c> should be a pid or the atom <c>new</c>. The atom <c>new</c> means that the default trace state for processes to be created will - be returned. <c>Item</c> must have one of the following + be returned. <c><anno>Item</anno></c> must have one of the following values:</p> <taglist> <tag><c>flags</c></tag> @@ -6872,22 +6384,24 @@ ok <tag><c>all</c></tag> <item> - <p>Return a list containing the <c>{Item, Value}</c> tuples + <p>Return a list containing the <c>{<anno>Item</anno>, Value}</c> tuples for all other items, or return <c>false</c> if no tracing is active for this function.</p> </item> </taglist> - <p>The actual return value will be <c>{Item, Value}</c>, where + <p>The actual return value will be <c>{<anno>Item</anno>, Value}</c>, where <c>Value</c> is the requested information as described above. If a pid for a dead process was given, or the name of a non-existing function, <c>Value</c> will be <c>undefined</c>.</p> - <p>If <c>PidOrFunc</c> is the <c>on_load</c>, the information + <p>If <c><anno>PidOrFunc</anno></c> is the <c>on_load</c>, the information returned refers to the default value for code that will be loaded.</p> </desc> </func> <func> - <name>erlang:trace_pattern(MFA, MatchSpec) -> integer() >= 0</name> + <name name="trace_pattern" arity="2" clause_i="1"/> + <type name="trace_pattern_mfa"/> + <type name="trace_match_spec"/> <fsummary>Set trace patterns for global call tracing</fsummary> <desc> <p>The same as @@ -6896,11 +6410,11 @@ ok </desc> </func> <func> - <name>erlang:trace_pattern(MFA, MatchSpec, FlagList) -> integer() >= 0</name> + <name name="trace_pattern" arity="3"/> + <type name="trace_pattern_mfa"/> + <type name="trace_match_spec"/> + <type name="trace_pattern_flag"/> <fsummary>Set trace patterns for tracing of function calls</fsummary> - <type> - <v>MFA, MatchSpec, FlagList -- see below</v> - </type> <desc> <p>This BIF is used to enable or disable call tracing for exported functions. It must be combined with @@ -6925,7 +6439,7 @@ ok and an action to be performed. The default action is to send a trace message. If the pattern does not match or the guard fails, the action will not be executed.</p> - <p>The <c>MFA</c> argument should be a tuple like + <p>The <c><anno>MFA</anno></c> argument should be a tuple like <c>{Module, Function, Arity}</c> or the atom <c>on_load</c> (described below). It can be the module, function, and arity for an exported function (or a BIF in any module). @@ -6948,11 +6462,11 @@ ok </taglist> <p>Other combinations, such as <c>{Module,'_',Arity}</c>, are not allowed. Local functions will match wildcards only if - the <c>local</c> option is in the <c>FlagList</c>.</p> - <p>If the <c>MFA</c> argument is the atom <c>on_load</c>, + the <c>local</c> option is in the <c><anno>FlagList</anno></c>.</p> + <p>If the <c><anno>MFA</anno></c> argument is the atom <c>on_load</c>, the match specification and flag list will be used on all modules that are newly loaded.</p> - <p>The <c>MatchSpec</c> argument can take any of the following + <p>The <c><anno>MatchSpec</anno></c> argument can take any of the following forms:</p> <taglist> <tag><c>false</c></tag> @@ -6964,7 +6478,7 @@ ok <item> <p>Enable tracing for the matching function(s).</p> </item> - <tag><c>MatchSpecList</c></tag> + <tag><c><anno>MatchSpecList</anno></c></tag> <item> <p>A list of match specifications. An empty list is equivalent to <c>true</c>. See the ERTS User's Guide @@ -6972,18 +6486,18 @@ ok </item> <tag><c>restart</c></tag> <item> - <p>For the <c>FlagList</c> option <c>call_count</c> and <c>call_time</c>: + <p>For the <c><anno>FlagList</anno></c> option <c>call_count</c> and <c>call_time</c>: restart the existing counters. The behaviour is undefined - for other <c>FlagList</c> options.</p> + for other <c><anno>FlagList</anno></c> options.</p> </item> <tag><c>pause</c></tag> <item> - <p>For the <c>FlagList</c> option <c>call_count</c> and <c>call_time</c>: pause + <p>For the <c><anno>FlagList</anno></c> option <c>call_count</c> and <c>call_time</c>: pause the existing counters. The behaviour is undefined for other <c>FlagList</c> options.</p> </item> </taglist> - <p>The <c>FlagList</c> parameter is a list of options. + <p>The <c><anno>FlagList</anno></c> parameter is a list of options. The following options are allowed:</p> <taglist> <tag><c>global</c></tag> @@ -7002,13 +6516,13 @@ ok the process, a <c>return_to</c> message will also be sent when this function returns to its caller.</p> </item> - <tag><c>meta | {meta, Pid}</c></tag> + <tag><c>meta | {meta, <anno>Pid</anno>}</c></tag> <item> <p>Turn on or off meta tracing for all types of function calls. Trace messages will be sent to the tracer process - or port <c>Pid</c> whenever any of the specified + or port <c><anno>Pid</anno></c> whenever any of the specified functions are called, regardless of how they are called. - If no <c>Pid</c> is specified, <c>self()</c> is used as a + If no <c><anno>Pid</anno></c> is specified, <c>self()</c> is used as a default tracer process.</p> <p>Meta tracing traces all processes and does not care about the process trace flags set by <c>trace/3</c>, @@ -7020,32 +6534,32 @@ ok </item> <tag><c>call_count</c></tag> <item> - <p>Starts (<c>MatchSpec == true</c>) or stops - (<c>MatchSpec == false</c>) call count tracing for all + <p>Starts (<c><anno>MatchSpec</anno> == true</c>) or stops + (<c><anno>MatchSpec</anno> == false</c>) call count tracing for all types of function calls. For every function a counter is incremented when the function is called, in any process. No process trace flags need to be activated.</p> <p>If call count tracing is started while already running, the count is restarted from zero. Running counters can be - paused with <c>MatchSpec == pause</c>. Paused and running + paused with <c><anno>MatchSpec</anno> == pause</c>. Paused and running counters can be restarted from zero with - <c>MatchSpec == restart</c>.</p> + <c><anno>MatchSpec</anno> == restart</c>.</p> <p>The counter value can be read with <seealso marker="#trace_info/2">erlang:trace_info/2</seealso>.</p> </item> <tag><c>call_time</c></tag> <item> - <p>Starts (<c>MatchSpec == true</c>) or stops - (<c>MatchSpec == false</c>) call time tracing for all + <p>Starts (<c><anno>MatchSpec</anno> == true</c>) or stops + (<c><anno>MatchSpec</anno> == false</c>) call time tracing for all types of function calls. For every function a counter is incremented when the function is called. Time spent in the function is accumulated in two other counters, seconds and micro-seconds. The counters are stored for each call traced process.</p> <p>If call time tracing is started while already running, the count and time is restarted from zero. Running counters can be - paused with <c>MatchSpec == pause</c>. Paused and running + paused with <c><anno>MatchSpec</anno> == pause</c>. Paused and running counters can be restarted from zero with - <c>MatchSpec == restart</c>.</p> + <c><anno>MatchSpec</anno> == restart</c>.</p> <p>The counter value can be read with <seealso marker="#trace_info/2">erlang:trace_info/2</seealso>.</p> </item> @@ -7071,18 +6585,15 @@ ok <seealso marker="#trace_info/2">erlang:trace_info/2</seealso> BIF to retrieve the existing match specification.</p> <p>Returns the number of exported functions that matched - the <c>MFA</c> argument. This will be zero if none matched at + the <c><anno>MFA</anno></c> argument. This will be zero if none matched at all.</p> </desc> </func> <func> - <name>trunc(Number) -> integer()</name> + <name name="trunc" arity="1"/> <fsummary>Return an integer by the truncating a number</fsummary> - <type> - <v>Number = number()</v> - </type> <desc> - <p>Returns an integer by the truncating <c>Number</c>.</p> + <p>Returns an integer by the truncating <c><anno>Number</anno></c>.</p> <pre> > <input>trunc(5.5).</input> 5</pre> @@ -7090,13 +6601,10 @@ ok </desc> </func> <func> - <name>tuple_size(Tuple) -> integer() >= 0</name> + <name name="tuple_size" arity="1"/> <fsummary>Return the size of a tuple</fsummary> - <type> - <v>Tuple = tuple()</v> - </type> <desc> - <p>Returns an integer which is the number of elements in <c>Tuple</c>.</p> + <p>Returns an integer which is the number of elements in <c><anno>Tuple</anno></c>.</p> <pre> > <input>tuple_size({morni, mulle, bwange}).</input> 3</pre> @@ -7104,25 +6612,19 @@ ok </desc> </func> <func> - <name>tuple_to_list(Tuple) -> [term()]</name> + <name name="tuple_to_list" arity="1"/> <fsummary>Convert a tuple to a list</fsummary> - <type> - <v>Tuple = tuple()</v> - </type> <desc> - <p>Returns a list which corresponds to <c>Tuple</c>. - <c>Tuple</c> may contain any Erlang terms.</p> + <p>Returns a list which corresponds to <c><anno>Tuple</anno></c>. + <c><anno>Tuple</anno></c> may contain any Erlang terms.</p> <pre> > <input>tuple_to_list({share, {'Ericsson_B', 163}}).</input> [share,{'Ericsson_B',163}]</pre> </desc> </func> <func> - <name>erlang:universaltime() -> DateTime</name> + <name name="universaltime" arity="0"/> <fsummary>Current date and time according to Universal Time Coordinated (UTC)</fsummary> - <type> - <v>DateTime = <seealso marker="calendar#type-datetime">calendar:datetime()</seealso></v> - </type> <desc> <p>Returns the current date and time according to Universal Time Coordinated (UTC), also called GMT, in the form @@ -7136,46 +6638,39 @@ ok </desc> </func> <func> - <name>erlang:universaltime_to_localtime({Date1, Time1}) -> {Date2, Time2}</name> + <name name="universaltime_to_localtime" arity="1"/> <fsummary>Convert from Universal Time Coordinated (UTC) to local date and time</fsummary> - <type> - <v>Date1 = Date2 = <seealso marker="calendar#type-date">calendar:date()</seealso></v> - <v>Time1 = Time2 = <seealso marker="calendar#type-time">calendar:time()</seealso></v> - </type> <desc> <p>Converts Universal Time Coordinated (UTC) date and time to local date and time, if this is supported by the underlying OS. Otherwise, no conversion is done, and - <c>{Date1, Time1}</c> is returned.</p> + <c><anno>Universaltime</anno></c> is returned.</p> <pre> > <input>erlang:universaltime_to_localtime({{1996,11,6},{14,18,43}}).</input> {{1996,11,7},{15,18,43}}</pre> - <p>Failure: <c>badarg</c> if <c>Date1</c> or <c>Time1</c> do - not denote a valid date or time.</p> + <p>Failure: <c>badarg</c> if <c>Universaltime</c> does not denote + a valid date and time.</p> </desc> </func> <func> - <name>unlink(Id) -> true</name> + <name name="unlink" arity="1"/> <fsummary>Remove a link, if there is one, to another process or port</fsummary> - <type> - <v>Id = pid() | port()</v> - </type> <desc> <p>Removes the link, if there is one, between the calling - process and the process or port referred to by <c>Id</c>.</p> + process and the process or port referred to by <c><anno>Id</anno></c>.</p> <p>Returns <c>true</c> and does not fail, even if there is no - link to <c>Id</c>, or if <c>Id</c> does not exist.</p> - <p>Once <c>unlink(Id)</c> has returned it is guaranteed that + link to <c><anno>Id</anno></c>, or if <c><anno>Id</anno></c> does not exist.</p> + <p>Once <c>unlink(<anno>Id</anno>)</c> has returned it is guaranteed that the link between the caller and the entity referred to by - <c>Id</c> has no effect on the caller in the future (unless + <c><anno>Id</anno></c> has no effect on the caller in the future (unless the link is setup again). If caller is trapping exits, an - <c>{'EXIT', Id, _}</c> message due to the link might have + <c>{'EXIT', <anno>Id</anno>, _}</c> message due to the link might have been placed in the caller's message queue prior to the call, - though. Note, the <c>{'EXIT', Id, _}</c> message can be the - result of the link, but can also be the result of <c>Id</c> + though. Note, the <c>{'EXIT', <anno>Id</anno>, _}</c> message can be the + result of the link, but can also be the result of <c><anno>Id</anno></c> calling <c>exit/2</c>. Therefore, it <em>may</em> be appropriate to cleanup the message queue when trapping exits - after the call to <c>unlink(Id)</c>, as follow:</p> + after the call to <c>unlink(<anno>Id</anno>)</c>, as follow:</p> <code type="none"> unlink(Id), @@ -7198,13 +6693,10 @@ ok </desc> </func> <func> - <name>unregister(RegName) -> true</name> + <name name="unregister" arity="1"/> <fsummary>Remove the registered name for a process (or port)</fsummary> - <type> - <v>RegName = atom()</v> - </type> <desc> - <p>Removes the registered name <c>RegName</c>, associated with a + <p>Removes the registered name <c><anno>RegName</anno></c>, associated with a pid or a port identifier.</p> <pre> > <input>unregister(db).</input> @@ -7215,7 +6707,7 @@ true</pre> </desc> </func> <func> - <name>whereis(RegName) -> pid() | port() | undefined</name> + <name name="whereis" arity="1"/> <fsummary>Get the pid (or port) with a given registered name</fsummary> <desc> <p>Returns the pid or port identifier with the registered name diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index 279844adb2..379943c7a6 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -701,7 +701,9 @@ EMU_OBJS = \ $(OBJDIR)/beam_emu.o $(OBJDIR)/beam_opcodes.o \ $(OBJDIR)/beam_load.o $(OBJDIR)/beam_bif_load.o \ $(OBJDIR)/beam_debug.o $(OBJDIR)/beam_bp.o \ - $(OBJDIR)/beam_catches.o + $(OBJDIR)/beam_catches.o \ + $(OBJDIR)/code_ix.o \ + $(OBJDIR)/beam_ranges.o RUN_OBJS = \ $(OBJDIR)/erl_pbifs.o $(OBJDIR)/benchmark.o \ diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 78a9d76a20..768c38dae1 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -37,25 +37,83 @@ static void set_default_trace_pattern(Eterm module); static Eterm check_process_code(Process* rp, Module* modp); -static void delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp); -static void delete_export_references(Eterm module); -static int purge_module(int module); +static void delete_code(Module* modp); static void decrement_refc(BeamInstr* code); static int is_native(BeamInstr* code); static int any_heap_ref_ptrs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size); static int any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size); -static void remove_from_address_table(BeamInstr* code); -Eterm -load_module_2(BIF_ALIST_2) + + +BIF_RETTYPE code_is_module_native_1(BIF_ALIST_1) { - Eterm reason; - Eterm* hp; - int sz; - byte* code; + Module* modp; Eterm res; + ErtsCodeIndex code_ix; + + if (is_not_atom(BIF_ARG_1)) { + BIF_ERROR(BIF_P, BADARG); + } + code_ix = erts_active_code_ix(); + if ((modp = erts_get_module(BIF_ARG_1, code_ix)) == NULL) { + return am_undefined; + } + erts_rlock_old_code(code_ix); + res = ((modp->curr.code && is_native(modp->curr.code)) || + (modp->old.code != 0 && is_native(modp->old.code))) ? + am_true : am_false; + erts_runlock_old_code(code_ix); + return res; +} + +BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) +{ + Module* modp; + Eterm res; + + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD3(bif_export[BIF_code_make_stub_module_3], + BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); + } + + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + + modp = erts_get_module(BIF_ARG_1, erts_active_code_ix()); + + if (modp && modp->curr.num_breakpoints > 0) { + ASSERT(modp->curr.code != NULL); + erts_clear_module_break(modp); + ASSERT(modp->curr.num_breakpoints == 0); + } + + erts_start_staging_code_ix(); + + res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); + + if (res == BIF_ARG_1) { + erts_end_staging_code_ix(); + erts_commit_staging_code_ix(); + } + else { + erts_abort_staging_code_ix(); + } + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_release_code_write_permission(); + return res; +} + +BIF_RETTYPE +prepare_loading_2(BIF_ALIST_2) +{ byte* temp_alloc = NULL; - struct LoaderState* stp; + byte* code; + Uint sz; + Binary* magic; + Eterm reason; + Eterm* hp; + Eterm res; if (is_not_atom(BIF_ARG_1)) { error: @@ -65,108 +123,277 @@ load_module_2(BIF_ALIST_2) if ((code = erts_get_aligned_binary_bytes(BIF_ARG_2, &temp_alloc)) == NULL) { goto error; } - hp = HAlloc(BIF_P, 3); - /* - * Read the BEAM file and prepare the module for loading. - */ - stp = erts_alloc_loader_state(); + magic = erts_alloc_loader_state(); sz = binary_size(BIF_ARG_2); - reason = erts_prepare_loading(stp, BIF_P, BIF_P->group_leader, + reason = erts_prepare_loading(magic, BIF_P, BIF_P->group_leader, &BIF_ARG_1, code, sz); erts_free_aligned_binary_bytes(temp_alloc); if (reason != NIL) { + hp = HAlloc(BIF_P, 3); res = TUPLE2(hp, am_error, reason); BIF_RET(res); } + hp = HAlloc(BIF_P, PROC_BIN_SIZE); + res = erts_mk_magic_binary_term(&hp, &MSO(BIF_P), magic); + erts_refc_dec(&magic->refc, 1); + BIF_RET(res); +} - /* - * Stop all other processes and finish the loading of the module. - */ - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); +struct m { + Binary* code; + Eterm module; + Module* modp; + Uint exception; +}; - reason = erts_finish_loading(stp, BIF_P, 0, &BIF_ARG_1); - if (reason != NIL) { - res = TUPLE2(hp, am_error, reason); - } else { - set_default_trace_pattern(BIF_ARG_1); - res = TUPLE2(hp, am_module, BIF_ARG_1); - } +static Eterm staging_epilogue(Process* c_p, int, Eterm res, int, struct m*, int); - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - BIF_RET(res); +static Eterm +exception_list(Process* p, Eterm tag, struct m* mp, Sint exceptions) +{ + Eterm* hp = HAlloc(p, 3 + 2*exceptions); + Eterm res = NIL; + + mp += exceptions - 1; + while (exceptions > 0) { + if (mp->exception) { + res = CONS(hp, mp->module, res); + hp += 2; + exceptions--; + } + mp--; + } + return TUPLE2(hp, tag, res); } -BIF_RETTYPE purge_module_1(BIF_ALIST_1) + +BIF_RETTYPE +finish_loading_1(BIF_ALIST_1) { - int purge_res; + int i; + int n; + struct m* p = NULL; + Uint exceptions; + Eterm res; + int is_blocking = 0; + int do_commit = 0; - if (is_not_atom(BIF_ARG_1)) { - BIF_ERROR(BIF_P, BADARG); + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD1(bif_export[BIF_finish_loading_1], BIF_P, BIF_ARG_1); } - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); + /* + * Validate the argument before we start loading; it must be a + * proper list where each element is a magic binary containing + * prepared (not previously loaded) code. + * + * First count the number of elements and allocate an array + * to keep the elements in. + */ - erts_export_consolidate(); - purge_res = purge_module(atom_val(BIF_ARG_1)); + n = list_length(BIF_ARG_1); + if (n == -1) { + ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG); + goto done; + } + p = erts_alloc(ERTS_ALC_T_LOADER_TMP, n*sizeof(struct m)); - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + /* + * We now know that the argument is a proper list. Validate + * and collect the binaries into the array. + */ - if (purge_res < 0) { - BIF_ERROR(BIF_P, BADARG); + for (i = 0; i < n; i++) { + Eterm* cons = list_val(BIF_ARG_1); + Eterm term = CAR(cons); + ProcBin* pb; + + if (!ERTS_TERM_IS_MAGIC_BINARY(term)) { + ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG); + goto done; + } + pb = (ProcBin*) binary_val(term); + p[i].code = pb->val; + p[i].module = erts_module_for_prepared_code(p[i].code); + if (p[i].module == NIL) { + ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG); + goto done; + } + BIF_ARG_1 = CDR(cons); } - BIF_RET(am_true); -} -BIF_RETTYPE code_is_module_native_1(BIF_ALIST_1) -{ - Module* modp; + /* + * Since we cannot handle atomic loading of a group of modules + * if one or more of them uses on_load, we will only allow one + * element in the list. This limitation is intended to be + * lifted in the future. + */ - if (is_not_atom(BIF_ARG_1)) { - BIF_ERROR(BIF_P, BADARG); + if (n > 1) { + ERTS_BIF_PREP_ERROR(res, BIF_P, SYSTEM_LIMIT); + goto done; } - if ((modp = erts_get_module(BIF_ARG_1)) == NULL) { - return am_undefined; + + /* + * All types are correct. There cannot be a BADARG from now on. + * Before we can start loading, we must check whether any of + * the modules already has old code. To avoid a race, we must + * not allow other process to initiate a code loading operation + * from now on. + */ + + res = am_ok; + erts_start_staging_code_ix(); + + for (i = 0; i < n; i++) { + p[i].modp = erts_put_module(p[i].module); + } + for (i = 0; i < n; i++) { + if (p[i].modp->curr.num_breakpoints > 0 || + p[i].modp->curr.num_traced_exports > 0 || + erts_is_default_trace_enabled()) { + /* tracing involved, fallback with thread blocking */ + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + is_blocking = 1; + break; + } } - return ((modp->code && is_native(modp->code)) || - (modp->old_code != 0 && is_native(modp->old_code))) ? - am_true : am_false; -} -BIF_RETTYPE code_make_stub_module_3(BIF_ALIST_3) -{ - Eterm res; + if (is_blocking) { + for (i = 0; i < n; i++) { + if (p[i].modp->curr.num_breakpoints) { + erts_clear_module_break(p[i].modp); + ASSERT(p[i].modp->curr.num_breakpoints == 0); + } + } + } - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); + exceptions = 0; + for (i = 0; i < n; i++) { + p[i].exception = 0; + if (p[i].modp->curr.code && p[i].modp->old.code) { + p[i].exception = 1; + exceptions++; + } + } - erts_export_consolidate(); - res = erts_make_stub_module(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); + if (exceptions) { + res = exception_list(BIF_P, am_not_purged, p, exceptions); + } else { + /* + * Now we can load all code. This can't fail. + */ - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - return res; + exceptions = 0; + for (i = 0; i < n; i++) { + Eterm mod; + Eterm retval; + + erts_refc_inc(&p[i].code->refc, 1); + retval = erts_finish_loading(p[i].code, BIF_P, 0, &mod); + ASSERT(retval == NIL || retval == am_on_load); + if (retval == am_on_load) { + p[i].exception = 1; + exceptions++; + } + } + + /* + * Check whether any module has an on_load_handler. + */ + + if (exceptions) { + res = exception_list(BIF_P, am_on_load, p, exceptions); + } + do_commit = 1; + } + +done: + return staging_epilogue(BIF_P, do_commit, res, is_blocking, p, n); +} + +static Eterm +staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking, + struct m* loaded, int nloaded) +{ +#ifdef ERTS_SMP + if (is_blocking || !commit) +#endif + { + if (commit) { + erts_end_staging_code_ix(); + erts_commit_staging_code_ix(); + if (loaded) { + int i; + for (i=0; i < nloaded; i++) { + set_default_trace_pattern(loaded[i].module); + } + } + } + else { + erts_abort_staging_code_ix(); + } + if (loaded) { + erts_free(ERTS_ALC_T_LOADER_TMP, loaded); + } + if (is_blocking) { + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); + } + erts_release_code_write_permission(); + return res; + } +#ifdef ERTS_SMP + else { + ErtsThrPrgrVal later; + ASSERT(is_value(res)); + + if (loaded) { + erts_free(ERTS_ALC_T_LOADER_TMP, loaded); + } + erts_end_staging_code_ix(); + /* + * Now we must wait for all schedulers to do a memory barrier before + * we can activate and let them access the new staged code. This allows + * schedulers to read active code_ix in a safe way while executing + * without any memory barriers at all. + */ + + later = erts_thr_progress_later(); + erts_thr_progress_wakeup(c_p->scheduler_data, later); + erts_notify_code_ix_activation(c_p, later); + erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); + /* + * handle_code_ix_activation() will do the rest "later" + * and resume this process to return 'res'. + */ + ERTS_BIF_YIELD_RETURN(c_p, res); + } +#endif } BIF_RETTYPE check_old_code_1(BIF_ALIST_1) { + ErtsCodeIndex code_ix; Module* modp; + Eterm res = am_false; if (is_not_atom(BIF_ARG_1)) { BIF_ERROR(BIF_P, BADARG); } - modp = erts_get_module(BIF_ARG_1); - if (modp == NULL) { /* Doesn't exist. */ - BIF_RET(am_false); - } else if (modp->old_code == NULL) { /* No old code. */ - BIF_RET(am_false); + code_ix = erts_active_code_ix(); + modp = erts_get_module(BIF_ARG_1, code_ix); + if (modp != NULL) { + erts_rlock_old_code(code_ix); + if (modp->old.code != NULL) { + res = am_true; + } + erts_runlock_old_code(code_ix); } - BIF_RET(am_true); + BIF_RET(res); } Eterm @@ -180,14 +407,20 @@ check_process_code_2(BIF_ALIST_2) } if (is_internal_pid(BIF_ARG_1)) { Eterm res; + ErtsCodeIndex code_ix; if (internal_pid_index(BIF_ARG_1) >= erts_max_processes) goto error; - modp = erts_get_module(BIF_ARG_2); + code_ix = erts_active_code_ix(); + modp = erts_get_module(BIF_ARG_2, code_ix); if (modp == NULL) { /* Doesn't exist. */ return am_false; - } else if (modp->old_code == NULL) { /* No old code. */ + } + erts_rlock_old_code(code_ix); + if (modp->old.code == NULL) { /* No old code. */ + erts_runlock_old_code(code_ix); return am_false; } + erts_runlock_old_code(code_ix); #ifdef ERTS_SMP rp = erts_pid2proc_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, @@ -202,7 +435,14 @@ check_process_code_2(BIF_ALIST_2) ERTS_BIF_YIELD2(bif_export[BIF_check_process_code_2], BIF_P, BIF_ARG_1, BIF_ARG_2); } - res = check_process_code(rp, modp); + erts_rlock_old_code(code_ix); + if (modp->old.code != NULL) { /* must check again */ + res = check_process_code(rp, modp); + } + else { + res = am_false; + } + erts_runlock_old_code(code_ix); #ifdef ERTS_SMP if (BIF_P != rp) { erts_resume(rp, ERTS_PROC_LOCK_MAIN); @@ -223,56 +463,71 @@ check_process_code_2(BIF_ALIST_2) BIF_RETTYPE delete_module_1(BIF_ALIST_1) { - int res; + ErtsCodeIndex code_ix; + Module* modp; + int is_blocking = 0; + int success = 0; + Eterm res = NIL; - if (is_not_atom(BIF_ARG_1)) - goto badarg; + if (is_not_atom(BIF_ARG_1)) { + BIF_ERROR(BIF_P, BADARG); + } - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD1(bif_export[BIF_delete_module_1], BIF_P, BIF_ARG_1); + } { - Module *modp = erts_get_module(BIF_ARG_1); + erts_start_staging_code_ix(); + code_ix = erts_staging_code_ix(); + modp = erts_get_module(BIF_ARG_1, code_ix); if (!modp) { res = am_undefined; } - else if (modp->old_code != 0) { + else if (modp->old.code != 0) { erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); erts_dsprintf(dsbufp, "Module %T must be purged before loading\n", BIF_ARG_1); erts_send_error_to_logger(BIF_P->group_leader, dsbufp); - res = am_badarg; + ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG); } else { - delete_export_references(BIF_ARG_1); - delete_code(BIF_P, 0, modp); + if (modp->curr.num_breakpoints > 0 || + modp->curr.num_traced_exports > 0) { + /* we have tracing, retry single threaded */ + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + is_blocking = 1; + if (modp->curr.num_breakpoints) { + erts_clear_module_break(modp); + ASSERT(modp->curr.num_breakpoints == 0); + } + } + delete_code(modp); res = am_true; + success = 1; } } - - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - - if (res == am_badarg) { - badarg: - BIF_ERROR(BIF_P, BADARG); - } - BIF_RET(res); + return staging_epilogue(BIF_P, success, res, is_blocking, NULL, 0); } BIF_RETTYPE module_loaded_1(BIF_ALIST_1) { Module* modp; + ErtsCodeIndex code_ix; + Eterm res = am_false; if (is_not_atom(BIF_ARG_1)) { BIF_ERROR(BIF_P, BADARG); } - if ((modp = erts_get_module(BIF_ARG_1)) == NULL || - modp->code == NULL || - modp->code[MI_ON_LOAD_FUNCTION_PTR] != 0) { - BIF_RET(am_false); + code_ix = erts_active_code_ix(); + if ((modp = erts_get_module(BIF_ARG_1, code_ix)) != NULL) { + if (modp->curr.code != NULL + && modp->curr.code[MI_ON_LOAD_FUNCTION_PTR] == 0) { + res = am_true; + } } - BIF_RET(am_true); + BIF_RET(res); } BIF_RETTYPE pre_loaded_0(BIF_ALIST_0) @@ -282,27 +537,28 @@ BIF_RETTYPE pre_loaded_0(BIF_ALIST_0) BIF_RETTYPE loaded_0(BIF_ALIST_0) { + ErtsCodeIndex code_ix = erts_active_code_ix(); + Module* modp; Eterm previous = NIL; Eterm* hp; int i; int j = 0; - - for (i = 0; i < module_code_size(); i++) { - if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { + + for (i = 0; i < module_code_size(code_ix); i++) { + if ((modp = module_code(i, code_ix)) != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { j++; } } if (j > 0) { hp = HAlloc(BIF_P, j*2); - for (i = 0; i < module_code_size(); i++) { - if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { - previous = CONS(hp, make_atom(module_code(i)->module), - previous); + for (i = 0; i < module_code_size(code_ix); i++) { + if ((modp=module_code(i,code_ix)) != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { + previous = CONS(hp, make_atom(modp->module), previous); hp += 2; } } @@ -312,54 +568,65 @@ BIF_RETTYPE loaded_0(BIF_ALIST_0) BIF_RETTYPE call_on_load_function_1(BIF_ALIST_1) { - Module* modp = erts_get_module(BIF_ARG_1); - Eterm on_load; + Module* modp = erts_get_module(BIF_ARG_1, erts_active_code_ix()); - if (!modp || modp->code == 0) { - error: - BIF_ERROR(BIF_P, BADARG); + if (modp && modp->curr.code) { + BIF_TRAP_CODE_PTR_0(BIF_P, modp->curr.code[MI_ON_LOAD_FUNCTION_PTR]); } - if ((on_load = modp->code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { - goto error; + else { + BIF_ERROR(BIF_P, BADARG); } - BIF_TRAP_CODE_PTR_0(BIF_P, on_load); } BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) { - Module* modp = erts_get_module(BIF_ARG_1); + ErtsCodeIndex code_ix; + Module* modp; Eterm on_load; - if (!modp || modp->code == 0) { + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD2(bif_export[BIF_finish_after_on_load_2], + BIF_P, BIF_ARG_1, BIF_ARG_2); + } + + /* ToDo: Use code_ix staging instead of thread blocking */ + + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + + code_ix = erts_active_code_ix(); + modp = erts_get_module(BIF_ARG_1, code_ix); + + if (!modp || modp->curr.code == 0) { error: + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_release_code_write_permission(); BIF_ERROR(BIF_P, BADARG); } - if ((on_load = modp->code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { + if ((on_load = modp->curr.code[MI_ON_LOAD_FUNCTION_PTR]) == 0) { goto error; } if (BIF_ARG_2 != am_false && BIF_ARG_2 != am_true) { goto error; } - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - if (BIF_ARG_2 == am_true) { int i; /* * The on_load function succeded. Fix up export entries. */ - for (i = 0; i < export_list_size(); i++) { - Export *ep = export_list(i); + for (i = 0; i < export_list_size(code_ix); i++) { + Export *ep = export_list(i,code_ix); if (ep != NULL && ep->code[0] == BIF_ARG_1 && ep->code[4] != 0) { - ep->address = (void *) ep->code[4]; + ep->addressv[code_ix] = (void *) ep->code[4]; ep->code[4] = 0; } } - modp->code[MI_ON_LOAD_FUNCTION_PTR] = 0; + modp->curr.code[MI_ON_LOAD_FUNCTION_PTR] = 0; set_default_trace_pattern(BIF_ARG_1); } else if (BIF_ARG_2 == am_false) { BeamInstr* code; @@ -370,19 +637,21 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2) * This is an combination of delete and purge. We purge * the current code; the old code is not touched. */ - erts_total_code_size -= modp->code_length; - code = modp->code; - end = (BeamInstr *)((char *)code + modp->code_length); + erts_total_code_size -= modp->curr.code_length; + code = modp->curr.code; + end = (BeamInstr *)((char *)code + modp->curr.code_length); erts_cleanup_funs_on_purge(code, end); - beam_catches_delmod(modp->catches, code, modp->code_length); + beam_catches_delmod(modp->curr.catches, code, modp->curr.code_length, + erts_active_code_ix()); erts_free(ERTS_ALC_T_CODE, (void *) code); - modp->code = NULL; - modp->code_length = 0; - modp->catches = BEAM_CATCHES_NIL; - remove_from_address_table(code); + modp->curr.code = NULL; + modp->curr.code_length = 0; + modp->curr.catches = BEAM_CATCHES_NIL; + erts_remove_from_ranges(code); } erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_release_code_write_permission(); BIF_RET(am_true); } @@ -429,10 +698,10 @@ check_process_code(Process* rp, Module* modp) /* * Pick up limits for the module. */ - start = modp->old_code; - end = (BeamInstr *)((char *)start + modp->old_code_length); + start = modp->old.code; + end = (BeamInstr *)((char *)start + modp->old.code_length); mod_start = (char *) start; - mod_size = modp->old_code_length; + mod_size = modp->old.code_length; /* * Check if current instruction or continuation pointer points into module. @@ -566,10 +835,10 @@ check_process_code(Process* rp, Module* modp) done_gc = 1; FLAGS(rp) |= F_NEED_FULLSWEEP; (void) erts_garbage_collect(rp, 0, rp->arg_reg, rp->arity); - literals = (Eterm *) modp->old_code[MI_LITERALS_START]; - lit_size = (Eterm *) modp->old_code[MI_LITERALS_END] - literals; + literals = (Eterm *) modp->old.code[MI_LITERALS_START]; + lit_size = (Eterm *) modp->old.code[MI_LITERALS_END] - literals; oh = (struct erl_off_heap_header *) - modp->old_code[MI_LITERALS_OFF_HEAP]; + modp->old.code[MI_LITERALS_OFF_HEAP]; erts_garbage_collect_literals(rp, literals, lit_size, oh); } } @@ -628,53 +897,82 @@ any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size) #undef in_area - -static int -purge_module(int module) +BIF_RETTYPE purge_module_1(BIF_ALIST_1) { + ErtsCodeIndex code_ix; BeamInstr* code; BeamInstr* end; Module* modp; + int is_blocking = 0; + Eterm ret; - /* - * Correct module? - */ - - if ((modp = erts_get_module(make_atom(module))) == NULL) { - return -2; + if (is_not_atom(BIF_ARG_1)) { + BIF_ERROR(BIF_P, BADARG); } - /* - * Any code to purge? - */ - if (modp->old_code == 0) { - return -1; + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD1(bif_export[BIF_purge_module_1], BIF_P, BIF_ARG_1); } + code_ix = erts_active_code_ix(); + /* - * Unload any NIF library + * Correct module? */ - if (modp->old_nif != NULL) { - erts_unload_nif(modp->old_nif); - modp->old_nif = NULL; + + if ((modp = erts_get_module(BIF_ARG_1, code_ix)) == NULL) { + ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG); } + else { + erts_rwlock_old_code(code_ix); - /* - * Remove the old code. - */ - ASSERT(erts_total_code_size >= modp->old_code_length); - erts_total_code_size -= modp->old_code_length; - code = modp->old_code; - end = (BeamInstr *)((char *)code + modp->old_code_length); - erts_cleanup_funs_on_purge(code, end); - beam_catches_delmod(modp->old_catches, code, modp->old_code_length); - decrement_refc(code); - erts_free(ERTS_ALC_T_CODE, (void *) code); - modp->old_code = NULL; - modp->old_code_length = 0; - modp->old_catches = BEAM_CATCHES_NIL; - remove_from_address_table(code); - return 0; + /* + * Any code to purge? + */ + if (modp->old.code == 0) { + ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG); + } + else { + /* + * Unload any NIF library + */ + if (modp->old.nif != NULL) { + /* ToDo: Do unload nif without blocking */ + erts_rwunlock_old_code(code_ix); + erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_smp_thr_progress_block(); + is_blocking = 1; + erts_rwlock_old_code(code_ix); + erts_unload_nif(modp->old.nif); + modp->old.nif = NULL; + } + + /* + * Remove the old code. + */ + ASSERT(erts_total_code_size >= modp->old.code_length); + erts_total_code_size -= modp->old.code_length; + code = modp->old.code; + end = (BeamInstr *)((char *)code + modp->old.code_length); + erts_cleanup_funs_on_purge(code, end); + beam_catches_delmod(modp->old.catches, code, modp->old.code_length, + code_ix); + decrement_refc(code); + erts_free(ERTS_ALC_T_CODE, (void *) code); + modp->old.code = NULL; + modp->old.code_length = 0; + modp->old.catches = BEAM_CATCHES_NIL; + erts_remove_from_ranges(code); + ERTS_BIF_PREP_RET(ret, am_true); + } + erts_rwunlock_old_code(code_ix); + } + if (is_blocking) { + erts_smp_thr_progress_unblock(); + erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + } + erts_release_code_write_permission(); + return ret; } static void @@ -694,92 +992,50 @@ decrement_refc(BeamInstr* code) } } -static void -remove_from_address_table(BeamInstr* code) -{ - int i; - - for (i = 0; i < num_loaded_modules; i++) { - if (modules[i].start == code) { - num_loaded_modules--; - while (i < num_loaded_modules) { - modules[i] = modules[i+1]; - i++; - } - mid_module = &modules[num_loaded_modules/2]; - return; - } - } - ASSERT(0); /* Not found? */ -} - - /* - * Move code from current to old. + * Move code from current to old and null all export entries for the module */ -static void -delete_code(Process *c_p, ErtsProcLocks c_p_locks, Module* modp) -{ -#ifdef ERTS_ENABLE_LOCK_CHECK -#ifdef ERTS_SMP - if (c_p && c_p_locks) - erts_proc_lc_chk_only_proc_main(c_p); - else -#endif - erts_lc_check_exact(NULL, 0); -#endif - - /* - * Clear breakpoints if any - */ - if (modp->code != NULL && modp->code[MI_NUM_BREAKPOINTS] > 0) { - if (c_p && c_p_locks) - erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); - erts_clear_module_break(modp); - modp->code[MI_NUM_BREAKPOINTS] = 0; - erts_smp_thr_progress_unblock(); - if (c_p && c_p_locks) - erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); - } - modp->old_code = modp->code; - modp->old_code_length = modp->code_length; - modp->old_catches = modp->catches; - modp->old_nif = modp->nif; - modp->code = NULL; - modp->code_length = 0; - modp->catches = BEAM_CATCHES_NIL; - modp->nif = NULL; -} - - -/* null all references on the export table for the module called with the - atom index below */ - static void -delete_export_references(Eterm module) +delete_code(Module* modp) { + ErtsCodeIndex code_ix = erts_staging_code_ix(); + Eterm module = make_atom(modp->module); int i; - ASSERT(is_atom(module)); - - for (i = 0; i < export_list_size(); i++) { - Export *ep = export_list(i); + for (i = 0; i < export_list_size(code_ix); i++) { + Export *ep = export_list(i, code_ix); if (ep != NULL && (ep->code[0] == module)) { - if (ep->address == ep->code+3 && - (ep->code[3] == (BeamInstr) em_apply_bif)) { - continue; + if (ep->addressv[code_ix] == ep->code+3) { + if (ep->code[3] == (BeamInstr) em_apply_bif) { + continue; + } + else if (ep->code[3] == (BeamInstr) em_call_traced_function) { + ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking()); + ASSERT(modp->curr.num_traced_exports > 0); + --modp->curr.num_traced_exports; + MatchSetUnref(ep->match_prog_set); + ep->match_prog_set = NULL; + } + else ASSERT(ep->code[3] == (BeamInstr) em_call_error_handler + || !erts_initialized); } - ep->address = ep->code+3; + ep->addressv[code_ix] = ep->code+3; ep->code[3] = (BeamInstr) em_call_error_handler; ep->code[4] = 0; - MatchSetUnref(ep->match_prog_set); - ep->match_prog_set = NULL; + ASSERT(ep->match_prog_set == NULL); } } + + ASSERT(modp->curr.num_breakpoints == 0); + ASSERT(modp->curr.num_traced_exports == 0); + modp->old = modp->curr; + modp->curr.code = NULL; + modp->curr.code_length = 0; + modp->curr.catches = BEAM_CATCHES_NIL; + modp->curr.nif = NULL; } - + Eterm beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module) @@ -791,11 +1047,10 @@ beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module) * if not, delete old code; error if old code already exists. */ - if (modp->code != NULL && modp->old_code != NULL) { + if (modp->curr.code != NULL && modp->old.code != NULL) { return am_not_purged; - } else if (modp->old_code == NULL) { /* Make the current version old. */ - delete_code(c_p, c_p_locks, modp); - delete_export_references(module); + } else if (modp->old.code == NULL) { /* Make the current version old. */ + delete_code(modp); } return NIL; } diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index dd13cd179a..ef48d7d05e 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -478,15 +478,16 @@ erts_find_local_func(Eterm mfa[3]) { BeamInstr* code_ptr; Uint i,n; - if ((modp = erts_get_module(mfa[0])) == NULL) + if ((modp = erts_get_module(mfa[0], erts_active_code_ix())) == NULL) return NULL; - if ((code_base = (BeamInstr **) modp->code) == NULL) + if ((code_base = (BeamInstr **) modp->curr.code) == NULL) return NULL; n = (BeamInstr) code_base[MI_NUM_FUNCTIONS]; for (i = 0; i < n; ++i) { code_ptr = code_base[MI_FUNCTIONS+i]; ASSERT(((BeamInstr) BeamOp(op_i_func_info_IaaI)) == code_ptr[0]); - ASSERT(mfa[0] == ((Eterm) code_ptr[2])); + ASSERT(mfa[0] == ((Eterm) code_ptr[2]) || + is_nil((Eterm) code_ptr[2])); if (mfa[1] == ((Eterm) code_ptr[3]) && ((BeamInstr) mfa[2]) == code_ptr[4]) { return code_ptr + 5; @@ -849,12 +850,13 @@ static int set_break(Eterm mfa[3], int specified, { Module *modp; int num_processed = 0; + ErtsCodeIndex code_ix = erts_active_code_ix(); if (!specified) { /* Find and process all modules in the system... */ int current; - int last = module_code_size(); + int last = module_code_size(code_ix); for (current = 0; current < last; current++) { - modp = module_code(current); + modp = module_code(current, code_ix); ASSERT(modp != NULL); num_processed += set_module_break(modp, mfa, specified, @@ -863,7 +865,7 @@ static int set_break(Eterm mfa[3], int specified, } } else { /* Process a single module */ - if ((modp = erts_get_module(mfa[0])) != NULL) { + if ((modp = erts_get_module(mfa[0], code_ix)) != NULL) { num_processed += set_module_break(modp, mfa, specified, match_spec, break_op, count_op, @@ -883,7 +885,7 @@ static int set_module_break(Module *modp, Eterm mfa[3], int specified, ASSERT(break_op); ASSERT(modp); - code_base = (BeamInstr **) modp->code; + code_base = (BeamInstr **) modp->curr.code; if (code_base == NULL) { return 0; } @@ -913,10 +915,10 @@ static int set_function_break(Module *modp, BeamInstr *pc, int bif, Uint ix = 0; if (bif == BREAK_IS_ERL) { - code_base = (BeamInstr **)modp->code; + code_base = (BeamInstr **)modp->curr.code; ASSERT(code_base); ASSERT(code_base <= (BeamInstr **)pc); - ASSERT((BeamInstr **)pc < code_base + (modp->code_length/sizeof(BeamInstr *))); + ASSERT((BeamInstr **)pc < code_base + (modp->curr.code_length/sizeof(BeamInstr *))); } else { ASSERT(*pc == (BeamInstr) em_apply_bif); ASSERT(modp == NULL); @@ -1097,29 +1099,30 @@ static int set_function_break(Module *modp, BeamInstr *pc, int bif, } if (bif == BREAK_IS_ERL) { - ++(*(BeamInstr*)&code_base[MI_NUM_BREAKPOINTS]); + ++modp->curr.num_breakpoints; } return 1; } static int clear_break(Eterm mfa[3], int specified, BeamInstr break_op) { + ErtsCodeIndex code_ix = erts_active_code_ix(); int num_processed = 0; Module *modp; if (!specified) { /* Iterate over all modules */ int current; - int last = module_code_size(); + int last = module_code_size(code_ix); for (current = 0; current < last; current++) { - modp = module_code(current); + modp = module_code(current, code_ix); ASSERT(modp != NULL); num_processed += clear_module_break(modp, mfa, specified, break_op); } } else { /* Process a single module */ - if ((modp = erts_get_module(mfa[0])) != NULL) { + if ((modp = erts_get_module(mfa[0], code_ix)) != NULL) { num_processed += clear_module_break(modp, mfa, specified, break_op); } @@ -1136,7 +1139,7 @@ static int clear_module_break(Module *m, Eterm mfa[3], int specified, BeamInstr n; ASSERT(m); - code_base = (BeamInstr **) m->code; + code_base = (BeamInstr **) m->curr.code; if (code_base == NULL) { return 0; } @@ -1160,10 +1163,10 @@ static int clear_function_break(Module *m, BeamInstr *pc, int bif, BeamInstr bre BeamInstr **code_base = NULL; if (bif == BREAK_IS_ERL) { - code_base = (BeamInstr **)m->code; + code_base = (BeamInstr **)m->curr.code; ASSERT(code_base); ASSERT(code_base <= (BeamInstr **)pc); - ASSERT((BeamInstr **)pc < code_base + (m->code_length/sizeof(BeamInstr *))); + ASSERT((BeamInstr **)pc < code_base + (m->curr.code_length/sizeof(BeamInstr *))); } else { ASSERT(*pc == (BeamInstr) em_apply_bif); ASSERT(m == NULL); @@ -1273,8 +1276,8 @@ static int clear_function_break(Module *m, BeamInstr *pc, int bif, BeamInstr bre } Free(bd); if (bif == BREAK_IS_ERL) { - ASSERT(((BeamInstr) code_base[MI_NUM_BREAKPOINTS]) > 0); - --(*(BeamInstr*)&code_base[MI_NUM_BREAKPOINTS]); + ASSERT(m->curr.num_breakpoints > 0); + --m->curr.num_breakpoints; } if (*rs) { for (ix = 1; ix < erts_no_schedulers; ++ix) { diff --git a/erts/emulator/beam/beam_catches.c b/erts/emulator/beam/beam_catches.c index 406ef1db5f..92f7ffe5a2 100644 --- a/erts/emulator/beam/beam_catches.c +++ b/erts/emulator/beam/beam_catches.c @@ -31,78 +31,144 @@ typedef struct { unsigned cdr; } beam_catch_t; -static int free_list; -static unsigned high_mark; -static unsigned tabsize; -static beam_catch_t *beam_catches; +#ifdef DEBUG +# define IF_DEBUG(x) x +#else +# define IF_DEBUG(x) +#endif + +struct bc_pool { + int free_list; + unsigned high_mark; + unsigned tabsize; + beam_catch_t *beam_catches; + /* + * Note that the 'beam_catches' area is shared by pools. Used slots + * are readonly as long as the module is not purgable. The free-list is + * protected by the code_ix lock. + */ + + IF_DEBUG(int is_staging;) +}; + +static struct bc_pool bccix[ERTS_NUM_CODE_IX]; void beam_catches_init(void) { - tabsize = DEFAULT_TABSIZE; - free_list = -1; - high_mark = 0; + int i; + + bccix[0].tabsize = DEFAULT_TABSIZE; + bccix[0].free_list = -1; + bccix[0].high_mark = 0; + bccix[0].beam_catches = erts_alloc(ERTS_ALC_T_CODE, + sizeof(beam_catch_t)*DEFAULT_TABSIZE); + IF_DEBUG(bccix[0].is_staging = 0); + for (i=1; i<ERTS_NUM_CODE_IX; i++) { + bccix[i] = bccix[i-1]; + } + /* For initial load: */ + IF_DEBUG(bccix[erts_staging_code_ix()].is_staging = 1); +} - beam_catches = erts_alloc(ERTS_ALC_T_CODE, sizeof(beam_catch_t)*DEFAULT_TABSIZE); + +static void gc_old_vec(beam_catch_t* vec) +{ + int i; + for (i=0; i<ERTS_NUM_CODE_IX; i++) { + if (bccix[i].beam_catches == vec) { + return; + } + } + erts_free(ERTS_ALC_T_CODE, vec); +} + + +void beam_catches_start_staging(void) +{ + ErtsCodeIndex dst = erts_staging_code_ix(); + ErtsCodeIndex src = erts_active_code_ix(); + beam_catch_t* prev_vec = bccix[dst].beam_catches; + + ASSERT(!bccix[src].is_staging && !bccix[dst].is_staging); + + bccix[dst] = bccix[src]; + gc_old_vec(prev_vec); + IF_DEBUG(bccix[dst].is_staging = 1); +} + +void beam_catches_end_staging(int commit) +{ + IF_DEBUG(bccix[erts_staging_code_ix()].is_staging = 0); } unsigned beam_catches_cons(BeamInstr *cp, unsigned cdr) { int i; + struct bc_pool* p = &bccix[erts_staging_code_ix()]; + ASSERT(p->is_staging); /* * Allocate from free_list while it is non-empty. * If free_list is empty, allocate at high_mark. - * - * This avoids the need to initialise the free list in - * beam_catches_init(), which would cost O(TABSIZ) time. */ - if( free_list >= 0 ) { - i = free_list; - free_list = beam_catches[i].cdr; - } else if( high_mark < tabsize ) { - i = high_mark; - high_mark++; - } else { - /* No free slots and table is full: realloc table */ - tabsize = 2*tabsize; - beam_catches = erts_realloc(ERTS_ALC_T_CODE, beam_catches, sizeof(beam_catch_t)*tabsize); - i = high_mark; - high_mark++; + if (p->free_list >= 0) { + i = p->free_list; + p->free_list = p->beam_catches[i].cdr; + } + else { + if (p->high_mark >= p->tabsize) { + /* No free slots and table is full: realloc table */ + beam_catch_t* prev_vec = p->beam_catches; + unsigned newsize = p->tabsize*2; + + p->beam_catches = erts_alloc(ERTS_ALC_T_CODE, + newsize*sizeof(beam_catch_t)); + sys_memcpy(p->beam_catches, prev_vec, + p->tabsize*sizeof(beam_catch_t)); + gc_old_vec(prev_vec); + p->tabsize = newsize; + } + i = p->high_mark++; } - beam_catches[i].cp = cp; - beam_catches[i].cdr = cdr; + p->beam_catches[i].cp = cp; + p->beam_catches[i].cdr = cdr; return i; } BeamInstr *beam_catches_car(unsigned i) { - if( i >= tabsize ) { + struct bc_pool* p = &bccix[erts_active_code_ix()]; + + if (i >= p->tabsize ) { erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); } - return beam_catches[i].cp; + return p->beam_catches[i].cp; } -void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes) +void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes, + ErtsCodeIndex code_ix) { + struct bc_pool* p = &bccix[code_ix]; unsigned i, cdr; + ASSERT((code_ix == erts_active_code_ix()) != bccix[erts_staging_code_ix()].is_staging); for(i = head; i != (unsigned)-1;) { - if( i >= tabsize ) { + if (i >= p->tabsize) { erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); } - if( (char*)beam_catches[i].cp - (char*)code >= code_bytes ) { + if( (char*)p->beam_catches[i].cp - (char*)code >= code_bytes ) { erl_exit(1, "beam_catches_delmod: item %#x has cp %#lx which is not " "in module's range [%#lx,%#lx[\r\n", - i, (long)beam_catches[i].cp, + i, (long)p->beam_catches[i].cp, (long)code, (long)((char*)code + code_bytes)); } - beam_catches[i].cp = 0; - cdr = beam_catches[i].cdr; - beam_catches[i].cdr = free_list; - free_list = i; + p->beam_catches[i].cp = 0; + cdr = p->beam_catches[i].cdr; + p->beam_catches[i].cdr = p->free_list; + p->free_list = i; i = cdr; } } diff --git a/erts/emulator/beam/beam_catches.h b/erts/emulator/beam/beam_catches.h index 6223427f0d..b2bd2351a5 100644 --- a/erts/emulator/beam/beam_catches.h +++ b/erts/emulator/beam/beam_catches.h @@ -20,12 +20,21 @@ #ifndef __BEAM_CATCHES_H #define __BEAM_CATCHES_H +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include "sys.h" +#include "code_ix.h" + #define BEAM_CATCHES_NIL (-1) void beam_catches_init(void); +void beam_catches_start_staging(void); +void beam_catches_end_staging(int commit); unsigned beam_catches_cons(BeamInstr* cp, unsigned cdr); BeamInstr *beam_catches_car(unsigned i); -void beam_catches_delmod(unsigned head, BeamInstr* code, unsigned code_bytes); +void beam_catches_delmod(unsigned head, BeamInstr* code, unsigned code_bytes, + ErtsCodeIndex); #define catch_pc(x) beam_catches_car(catch_val((x))) diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index 8041c92162..e69cbc3048 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -114,6 +114,10 @@ erts_debug_breakpoint_2(BIF_ALIST_2) mfa[2] = signed_val(mfa[2]); } + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD2(bif_export[BIF_erts_debug_breakpoint_2], + BIF_P, BIF_ARG_1, BIF_ARG_2); + } erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); @@ -125,7 +129,7 @@ erts_debug_breakpoint_2(BIF_ALIST_2) erts_smp_thr_progress_unblock(); erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); - + erts_release_code_write_permission(); return res; error: @@ -207,6 +211,7 @@ erts_debug_disassemble_1(BIF_ALIST_1) BIF_RET(am_false); } } else if (is_tuple(addr)) { + ErtsCodeIndex code_ix; Module* modp; Eterm mod; Eterm name; @@ -225,14 +230,14 @@ erts_debug_disassemble_1(BIF_ALIST_1) goto error; } arity = signed_val(tp[3]); - modp = erts_get_module(mod); + code_ix = erts_active_code_ix(); + modp = erts_get_module(mod, code_ix); /* * Try the export entry first to allow disassembly of special functions * such as erts_debug:apply/4. Then search for it in the module. */ - - if ((ep = erts_find_function(mod, name, arity)) != NULL) { + if ((ep = erts_find_function(mod, name, arity, code_ix)) != NULL) { /* XXX: add "&& ep->address != ep->code+3" condition? * Consider a traced function. * Its ep will have ep->address == ep->code+3. @@ -241,9 +246,9 @@ erts_debug_disassemble_1(BIF_ALIST_1) * But this code_ptr will point to the start of the Export, * not the function's func_info instruction. BOOM !? */ - code_ptr = ((BeamInstr *) ep->address) - 5; + code_ptr = ((BeamInstr *) ep->addressv[code_ix]) - 5; funcinfo = code_ptr+2; - } else if (modp == NULL || (code_base = modp->code) == NULL) { + } else if (modp == NULL || (code_base = modp->curr.code) == NULL) { BIF_RET(am_undef); } else { n = code_base[MI_NUM_FUNCTIONS]; diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index c65b2be106..d6189c6c65 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -541,7 +541,7 @@ extern int count_instructions; do { \ if (FCALLS > 0) { \ Eterm* dis_next; \ - SET_I(((Export *) Arg(0))->address); \ + SET_I(((Export *) Arg(0))->addressv[erts_active_code_ix()]); \ dis_next = (Eterm *) *I; \ FCALLS--; \ CHECK_ARGS(I); \ @@ -550,7 +550,7 @@ extern int count_instructions; && FCALLS > neg_o_reds) { \ goto save_calls1; \ } else { \ - SET_I(((Export *) Arg(0))->address); \ + SET_I(((Export *) Arg(0))->addressv[erts_active_code_ix()]); \ CHECK_ARGS(I); \ goto context_switch; \ } \ @@ -5065,7 +5065,7 @@ void process_main(void) save_calls(c_p, (Export *) Arg(0)); - SET_I(((Export *) Arg(0))->address); + SET_I(((Export *) Arg(0))->addressv[erts_active_code_ix()]); dis_next = (Eterm *) *I; FCALLS--; @@ -5742,7 +5742,8 @@ call_error_handler(Process* p, BeamInstr* fi, Eterm* reg, Eterm func) /* * Search for the error_handler module. */ - ep = erts_find_function(erts_proc_get_error_handler(p), func, 3); + ep = erts_find_function(erts_proc_get_error_handler(p), func, 3, + erts_active_code_ix()); if (ep == NULL) { /* No error handler */ p->current = fi; p->freason = EXC_UNDEF; @@ -5772,7 +5773,7 @@ call_error_handler(Process* p, BeamInstr* fi, Eterm* reg, Eterm func) reg[0] = fi[0]; reg[1] = fi[1]; reg[2] = args; - return ep->address; + return ep->addressv[erts_active_code_ix()]; } @@ -5786,7 +5787,7 @@ apply_setup_error_handler(Process* p, Eterm module, Eterm function, Uint arity, * there is no error handler module. */ - if ((ep = erts_find_export_entry(erts_proc_get_error_handler(p), + if ((ep = erts_active_export_entry(erts_proc_get_error_handler(p), am_undefined_function, 3)) == NULL) { return NULL; } else { @@ -5893,13 +5894,13 @@ apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg) * Note: All BIFs have export entries; thus, no special case is needed. */ - if ((ep = erts_find_export_entry(module, function, arity)) == NULL) { + if ((ep = erts_active_export_entry(module, function, arity)) == NULL) { if ((ep = apply_setup_error_handler(p, module, function, arity, reg)) == NULL) goto error; } else if (ERTS_PROC_GET_SAVED_CALLS_BUF(p)) { save_calls(p, ep); } - return ep->address; + return ep->addressv[erts_active_code_ix()]; } static BeamInstr* @@ -5941,14 +5942,14 @@ fixed_apply(Process* p, Eterm* reg, Uint arity) * Note: All BIFs have export entries; thus, no special case is needed. */ - if ((ep = erts_find_export_entry(module, function, arity)) == NULL) { + if ((ep = erts_active_export_entry(module, function, arity)) == NULL) { if ((ep = apply_setup_error_handler(p, module, function, arity, reg)) == NULL) goto error; } else if (ERTS_PROC_GET_SAVED_CALLS_BUF(p)) { save_calls(p, ep); } - return ep->address; + return ep->addressv[erts_active_code_ix()]; } int @@ -6118,7 +6119,7 @@ call_fun(Process* p, /* Current process. */ Export* ep; Module* modp; Eterm module; - + ErtsCodeIndex code_ix = erts_active_code_ix(); /* * No arity. There is no module loaded that defines the fun, @@ -6126,9 +6127,9 @@ call_fun(Process* p, /* Current process. */ * representation (the module has never been loaded), * or the module defining the fun has been unloaded. */ - module = fe->module; - if ((modp = erts_get_module(module)) != NULL && modp->code != NULL) { + if ((modp = erts_get_module(module, code_ix)) != NULL + && modp->curr.code != NULL) { /* * There is a module loaded, but obviously the fun is not * defined in it. We must not call the error_handler @@ -6143,7 +6144,7 @@ call_fun(Process* p, /* Current process. */ */ ep = erts_find_function(erts_proc_get_error_handler(p), - am_undefined_lambda, 3); + am_undefined_lambda, 3, code_ix); if (ep == NULL) { /* No error handler */ p->current = NULL; p->freason = EXC_UNDEF; @@ -6153,7 +6154,7 @@ call_fun(Process* p, /* Current process. */ reg[1] = fun; reg[2] = args; reg[3] = NIL; - return ep->address; + return ep->addressv[erts_active_code_ix()]; } } } else if (is_export_header(hdr)) { @@ -6164,7 +6165,7 @@ call_fun(Process* p, /* Current process. */ actual_arity = (int) ep->code[2]; if (arity == actual_arity) { - return ep->address; + return ep->addressv[erts_active_code_ix()]; } else { /* * Wrong arity. First build a list of the arguments. @@ -6215,8 +6216,8 @@ call_fun(Process* p, /* Current process. */ erts_send_warning_to_logger(p->group_leader, dsbufp); } - if ((ep = erts_find_export_entry(module, function, arity)) == NULL) { - ep = erts_find_export_entry(erts_proc_get_error_handler(p), + if ((ep = erts_active_export_entry(module, function, arity)) == NULL) { + ep = erts_active_export_entry(erts_proc_get_error_handler(p), am_undefined_function, 3); if (ep == NULL) { p->freason = EXC_UNDEF; @@ -6239,7 +6240,7 @@ call_fun(Process* p, /* Current process. */ reg[1] = function; reg[2] = args; } - return ep->address; + return ep->addressv[erts_active_code_ix()]; } else { badfun: p->current = NULL; @@ -6344,7 +6345,8 @@ erts_is_builtin(Eterm Mod, Eterm Name, int arity) if ((ep = export_get(&e)) == NULL) { return 0; } - return ep->address == ep->code+3 && (ep->code[3] == (BeamInstr) em_apply_bif); + return ep->addressv[erts_active_code_ix()] == ep->code+3 + && (ep->code[3] == (BeamInstr) em_apply_bif); } diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index dd788df6e4..d3f55a2ba4 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -352,27 +352,6 @@ typedef struct LoaderState { int loc_size; /* Size of location info in bytes (2/4) */ } LoaderState; -/* - * Layout of the line table. - */ - -#define MI_LINE_FNAME_PTR 0 -#define MI_LINE_LOC_TAB 1 -#define MI_LINE_LOC_SIZE 2 -#define MI_LINE_FUNC_TAB 3 - -#define LINE_INVALID_LOCATION (0) - -/* - * Macros for manipulating locations. - */ - -#define IS_VALID_LOCATION(File, Line) \ - ((unsigned) (File) < 255 && (unsigned) (Line) < ((1 << 24) - 1)) -#define MAKE_LOCATION(File, Line) (((File) << 24) | (Line)) -#define LOC_FILE(Loc) ((Loc) >> 24) -#define LOC_LINE(Loc) ((Loc) & ((1 << 24)-1)) - #define GetTagAndValue(Stp, Tag, Val) \ do { \ BeamInstr __w; \ @@ -496,7 +475,8 @@ typedef struct LoaderState { } while (0) -static void free_state(LoaderState* stp); +static void free_loader_state(Binary* magic); +static void loader_state_dtor(Binary* magic); static Eterm insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, Eterm group_leader, Eterm module, BeamInstr* code, Uint size); @@ -507,6 +487,7 @@ static int verify_chunks(LoaderState* stp); static int load_atom_table(LoaderState* stp); static int load_import_table(LoaderState* stp); static int read_export_table(LoaderState* stp); +static int is_bif(Eterm mod, Eterm func, unsigned arity); static int read_lambda_table(LoaderState* stp); static int read_literal_table(LoaderState* stp); static int read_line_table(LoaderState* stp); @@ -548,22 +529,9 @@ static Eterm native_addresses(Process* p, Eterm mod); int patch_funentries(Eterm Patchlist); int patch(Eterm Addresses, Uint fe); static int safe_mul(UWord a, UWord b, UWord* resp); -static void lookup_loc(FunctionInfo* fi, BeamInstr* pc, - BeamInstr* modp, int idx); - static int must_swap_floats; -/* - * The following variables keep a sorted list of address ranges for - * each module. It allows us to quickly find a function given an - * instruction pointer. - */ -Range* modules = NULL; /* Sorted lists of module addresses. */ -int num_loaded_modules; /* Number of loaded modules. */ -int allocated_modules; /* Number of slots allocated. */ -Range* mid_module = NULL; /* Cached search start point */ - Uint erts_total_code_size; /**********************************************************************/ @@ -579,11 +547,7 @@ void init_load(void) f.fd = 1.0; must_swap_floats = (f.fw[0] == 0); - allocated_modules = 128; - modules = (Range *) erts_alloc(ERTS_ALC_T_MODULE_REFS, - allocated_modules*sizeof(Range)); - mid_module = modules; - num_loaded_modules = 0; + erts_init_ranges(); } static void @@ -595,7 +559,7 @@ define_file(LoaderState* stp, char* name, int idx) } Eterm -erts_load_module(Process *c_p, +erts_preload_module(Process *c_p, ErtsProcLocks c_p_locks, Eterm group_leader, /* Group leader or NIL if none. */ Eterm* modp, /* @@ -605,15 +569,16 @@ erts_load_module(Process *c_p, byte* code, /* Points to the code to load */ Uint size) /* Size of code to load. */ { - LoaderState* stp = erts_alloc_loader_state(); + Binary* magic = erts_alloc_loader_state(); Eterm retval; - retval = erts_prepare_loading(stp, c_p, group_leader, modp, + ASSERT(!erts_initialized); + retval = erts_prepare_loading(magic, c_p, group_leader, modp, code, size); if (retval != NIL) { return retval; } - return erts_finish_loading(stp, c_p, c_p_locks, modp); + return erts_finish_loading(magic, c_p, c_p_locks, modp); } /* #define LOAD_MEMORY_HARD_DEBUG 1*/ @@ -629,11 +594,13 @@ extern void check_allocated_block(Uint type, void *blk); #endif Eterm -erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, +erts_prepare_loading(Binary* magic, Process *c_p, Eterm group_leader, Eterm* modp, byte* code, Uint unloaded_size) { Eterm retval = am_badfile; + LoaderState* stp; + stp = ERTS_MAGIC_BIN_DATA(magic); stp->module = *modp; stp->group_leader = group_leader; @@ -666,7 +633,7 @@ erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, /* * Initialize code area. */ - stp->code_buffer_size = erts_next_heap_size(2048 + stp->num_functions, 0); + stp->code_buffer_size = 2048 + stp->num_functions; stp->code = (BeamInstr *) erts_alloc(ERTS_ALC_T_CODE, sizeof(BeamInstr) * stp->code_buffer_size); @@ -679,8 +646,6 @@ erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, stp->code[MI_COMPILE_PTR] = 0; stp->code[MI_COMPILE_SIZE] = 0; stp->code[MI_COMPILE_SIZE_ON_HEAP] = 0; - stp->code[MI_NUM_BREAKPOINTS] = 0; - /* * Read the atom table. @@ -774,23 +739,24 @@ erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, load_error: if (retval != NIL) { - free_state(stp); + free_loader_state(magic); } return retval; } Eterm -erts_finish_loading(LoaderState* stp, Process* c_p, +erts_finish_loading(Binary* magic, Process* c_p, ErtsProcLocks c_p_locks, Eterm* modp) { Eterm retval; + LoaderState* stp = ERTS_MAGIC_BIN_DATA(magic); /* * No other process may run since we will update the export * table which is not protected by any locks. */ - ERTS_SMP_LC_ASSERT(erts_initialized == 0 || + ERTS_SMP_LC_ASSERT(erts_initialized == 0 || erts_is_code_ix_locked() || erts_smp_thr_progress_is_blocking()); /* @@ -811,7 +777,6 @@ erts_finish_loading(LoaderState* stp, Process* c_p, * exported and imported functions. This can't fail. */ - erts_export_consolidate(); CHKBLK(ERTS_ALC_T_CODE,stp->code); final_touch(stp); @@ -837,16 +802,20 @@ erts_finish_loading(LoaderState* stp, Process* c_p, } load_error: - free_state(stp); + free_loader_state(magic); return retval; } -LoaderState* +Binary* erts_alloc_loader_state(void) { LoaderState* stp; + Binary* magic; - stp = erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(LoaderState)); + magic = erts_create_magic_binary(sizeof(LoaderState), + loader_state_dtor); + erts_refc_inc(&magic->refc, 1); + stp = ERTS_MAGIC_BIN_DATA(magic); stp->bin = NULL; stp->function = THE_NON_VALUE; /* Function not known yet */ stp->arity = 0; @@ -875,76 +844,123 @@ erts_alloc_loader_state(void) stp->line_instr = 0; stp->func_line = 0; stp->fname = 0; - return stp; + return magic; +} + +/* + * Return the module name (a tagged atom) for the prepared code + * in the magic binary, or NIL if the binary does not contain + * prepared code. + */ +Eterm +erts_module_for_prepared_code(Binary* magic) +{ + LoaderState* stp; + + if (ERTS_MAGIC_BIN_DESTRUCTOR(magic) != loader_state_dtor) { + return NIL; + } + stp = ERTS_MAGIC_BIN_DATA(magic); + if (stp->code != 0) { + return stp->module; + } else { + return NIL; + } } static void -free_state(LoaderState* stp) +free_loader_state(Binary* magic) { + loader_state_dtor(magic); + if (erts_refc_dectest(&magic->refc, 0) == 0) { + erts_bin_free(magic); + } +} + +/* + * This destructor function can safely be called multiple times. + */ +static void +loader_state_dtor(Binary* magic) +{ + LoaderState* stp = ERTS_MAGIC_BIN_DATA(magic); + if (stp->bin != 0) { driver_free_binary(stp->bin); + stp->bin = 0; } if (stp->code != 0) { erts_free(ERTS_ALC_T_CODE, stp->code); + stp->code = 0; } - if (stp->labels != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->labels); + if (stp->labels != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->labels); + stp->labels = 0; } - if (stp->atom != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->atom); + if (stp->atom != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->atom); + stp->atom = 0; } - if (stp->import != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->import); + if (stp->import != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->import); + stp->import = 0; } - if (stp->export != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->export); + if (stp->export != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->export); + stp->export = 0; } if (stp->lambdas != stp->def_lambdas) { - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->lambdas); + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->lambdas); + stp->lambdas = stp->def_lambdas; } - if (stp->literals != NULL) { + if (stp->literals != 0) { int i; for (i = 0; i < stp->num_literals; i++) { - if (stp->literals[i].heap != NULL) { - erts_free(ERTS_ALC_T_LOADER_TMP, + if (stp->literals[i].heap != 0) { + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->literals[i].heap); + stp->literals[i].heap = 0; } } - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->literals); + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->literals); + stp->literals = 0; } - while (stp->literal_patches != NULL) { + while (stp->literal_patches != 0) { LiteralPatch* next = stp->literal_patches->next; - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->literal_patches); + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->literal_patches); stp->literal_patches = next; } - while (stp->string_patches != NULL) { + while (stp->string_patches != 0) { StringPatch* next = stp->string_patches->next; - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->string_patches); + erts_free(ERTS_ALC_T_PREPARED_CODE, (void *) stp->string_patches); stp->string_patches = next; } - while (stp->genop_blocks) { - GenOpBlock* next = stp->genop_blocks->next; - erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->genop_blocks); - stp->genop_blocks = next; - } if (stp->line_item != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, stp->line_item); + erts_free(ERTS_ALC_T_PREPARED_CODE, stp->line_item); + stp->line_item = 0; } if (stp->line_instr != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, stp->line_instr); + erts_free(ERTS_ALC_T_PREPARED_CODE, stp->line_instr); + stp->line_instr = 0; } if (stp->func_line != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, stp->func_line); + erts_free(ERTS_ALC_T_PREPARED_CODE, stp->func_line); + stp->func_line = 0; } if (stp->fname != 0) { - erts_free(ERTS_ALC_T_LOADER_TMP, stp->fname); + erts_free(ERTS_ALC_T_PREPARED_CODE, stp->fname); + stp->fname = 0; } - erts_free(ERTS_ALC_T_LOADER_TMP, stp); + /* + * The following data items should have been freed earlier. + */ + + ASSERT(stp->genop_blocks == 0); } static Eterm @@ -954,7 +970,6 @@ insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, { Module* modp; Eterm retval; - int i; if ((retval = beam_make_current_old(c_p, c_p_locks, module)) != NIL) { erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); @@ -971,30 +986,15 @@ insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, erts_total_code_size += size; modp = erts_put_module(module); - modp->code = code; - modp->code_length = size; - modp->catches = BEAM_CATCHES_NIL; /* Will be filled in later. */ + modp->curr.code = code; + modp->curr.code_length = size; + modp->curr.catches = BEAM_CATCHES_NIL; /* Will be filled in later. */ /* - * Update address table (used for finding a function from a PC value). + * Update ranges (used for finding a function from a PC value). */ - if (num_loaded_modules == allocated_modules) { - allocated_modules *= 2; - modules = (Range *) erts_realloc(ERTS_ALC_T_MODULE_REFS, - (void *) modules, - allocated_modules * sizeof(Range)); - } - for (i = num_loaded_modules; i > 0; i--) { - if (code > modules[i-1].start) { - break; - } - modules[i] = modules[i-1]; - } - modules[i].start = code; - modules[i].end = (BeamInstr *) (((byte *)code) + size); - num_loaded_modules++; - mid_module = &modules[num_loaded_modules/2]; + erts_update_ranges(code, size); return NIL; } @@ -1217,9 +1217,8 @@ load_atom_table(LoaderState* stp) GetInt(stp, 4, stp->num_atoms); stp->num_atoms++; - stp->atom = erts_alloc(ERTS_ALC_T_LOADER_TMP, - erts_next_heap_size((stp->num_atoms*sizeof(Eterm)), - 0)); + stp->atom = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + stp->num_atoms*sizeof(Eterm)); /* * Read all atoms. @@ -1263,10 +1262,8 @@ load_import_table(LoaderState* stp) int i; GetInt(stp, 4, stp->num_imports); - stp->import = erts_alloc(ERTS_ALC_T_LOADER_TMP, - erts_next_heap_size((stp->num_imports * - sizeof(ImportEntry)), - 0)); + stp->import = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + stp->num_imports * sizeof(ImportEntry)); for (i = 0; i < stp->num_imports; i++) { int n; Eterm mod; @@ -1296,7 +1293,7 @@ load_import_table(LoaderState* stp) * If the export entry refers to a BIF, get the pointer to * the BIF function. */ - if ((e = erts_find_export_entry(mod, func, arity)) != NULL) { + if ((e = erts_active_export_entry(mod, func, arity)) != NULL) { if (e->code[3] == (BeamInstr) em_apply_bif) { stp->import[i].bf = (BifFunction) e->code[4]; if (func == am_load_nif && mod == am_erlang && arity == 2) { @@ -1315,16 +1312,8 @@ load_import_table(LoaderState* stp) static int read_export_table(LoaderState* stp) { - static struct { - Eterm mod; - Eterm func; - int arity; - } allow_redef[] = { - /* The BIFs that are allowed to be redefined by Erlang code */ - {am_erlang,am_apply,2}, - {am_erlang,am_apply,3}, - }; int i; + BeamInstr* address; GetInt(stp, 4, stp->num_exps); if (stp->num_exps > stp->num_functions) { @@ -1332,7 +1321,7 @@ read_export_table(LoaderState* stp) stp->num_exps, stp->num_functions); } stp->export - = (ExportEntry *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + = (ExportEntry *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, (stp->num_exps * sizeof(ExportEntry))); for (i = 0; i < stp->num_exps; i++) { @@ -1340,7 +1329,6 @@ read_export_table(LoaderState* stp) Uint value; Eterm func; Uint arity; - Export* e; GetInt(stp, 4, n); GetAtom(stp, n, func); @@ -1358,29 +1346,34 @@ read_export_table(LoaderState* stp) if (value == 0) { LoadError2(stp, "export table entry %d: label %d not resolved", i, n); } - stp->export[i].address = stp->code + value; + stp->export[i].address = address = stp->code + value; /* - * Check that we are not redefining a BIF (except the ones allowed to - * redefine). + * Find out if there is a BIF with the same name. */ - if ((e = erts_find_export_entry(stp->module, func, arity)) != NULL) { - if (e->code[3] == (BeamInstr) em_apply_bif) { - int j; - for (j = 0; j < sizeof(allow_redef)/sizeof(allow_redef[0]); j++) { - if (stp->module == allow_redef[j].mod && - func == allow_redef[j].func && - arity == allow_redef[j].arity) { - break; - } - } - if (j == sizeof(allow_redef)/sizeof(allow_redef[0])) { - LoadError2(stp, "exported function %T/%d redefines BIF", - func, arity); - } - } + if (!is_bif(stp->module, func, arity)) { + continue; + } + + /* + * This is a stub for a BIF. + * + * It should not be exported, and the information in its + * func_info instruction should be invalidated so that it + * can be filtered out by module_info(functions) and by + * any other functions that walk through all local functions. + */ + + if (stp->labels[n].patches) { + LoadError3(stp, "there are local calls to the stub for " + "the BIF %T:%T/%d", + stp->module, func, arity); } + stp->export[i].address = NULL; + address[-1] = 0; + address[-2] = NIL; + address[-3] = NIL; } return 1; @@ -1388,15 +1381,39 @@ read_export_table(LoaderState* stp) return 0; } + +static int +is_bif(Eterm mod, Eterm func, unsigned arity) +{ + Export* e = erts_active_export_entry(mod, func, arity); + if (e == NULL) { + return 0; + } + if (e->code[3] != (BeamInstr) em_apply_bif) { + return 0; + } + if (mod == am_erlang && func == am_apply && arity == 3) { + /* + * erlang:apply/3 is a special case -- it is implemented + * as an instruction and it is OK to redefine it. + */ + return 0; + } + return 1; +} + static int read_lambda_table(LoaderState* stp) { int i; GetInt(stp, 4, stp->num_lambdas); - stp->lambdas_allocated = stp->num_lambdas; - stp->lambdas = (Lambda *) erts_alloc(ERTS_ALC_T_LOADER_TMP, - stp->num_lambdas * sizeof(Lambda)); + if (stp->num_lambdas > stp->lambdas_allocated) { + ASSERT(stp->lambdas == stp->def_lambdas); + stp->lambdas_allocated = stp->num_lambdas; + stp->lambdas = (Lambda *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, + stp->num_lambdas * sizeof(Lambda)); + } for (i = 0; i < stp->num_lambdas; i++) { Uint n; Uint32 Index; @@ -1446,7 +1463,7 @@ read_literal_table(LoaderState* stp) stp->file_p = uncompressed; stp->file_left = (unsigned) uncompressed_sz; GetInt(stp, 4, stp->num_literals); - stp->literals = (Literal *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->literals = (Literal *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_literals * sizeof(Literal)); stp->allocated_literals = stp->num_literals; @@ -1466,7 +1483,7 @@ read_literal_table(LoaderState* stp) if ((heap_size = erts_decode_ext_size(p, sz)) < 0) { LoadError1(stp, "literal %d: bad external format", i); } - hp = stp->literals[i].heap = erts_alloc(ERTS_ALC_T_LOADER_TMP, + hp = stp->literals[i].heap = erts_alloc(ERTS_ALC_T_PREPARED_CODE, heap_size*sizeof(Eterm)); stp->literals[i].off_heap.first = 0; stp->literals[i].off_heap.overhead = 0; @@ -1538,7 +1555,7 @@ read_line_table(LoaderState* stp) */ num_line_items++; - lp = (BeamInstr *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + lp = (BeamInstr *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, num_line_items * sizeof(BeamInstr)); stp->line_item = lp; stp->num_line_items = num_line_items; @@ -1594,7 +1611,7 @@ read_line_table(LoaderState* stp) */ if (stp->num_fnames != 0) { - stp->fname = (Eterm *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->fname = (Eterm *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_fnames * sizeof(Eterm)); for (i = 0; i < stp->num_fnames; i++) { @@ -1610,11 +1627,11 @@ read_line_table(LoaderState* stp) /* * Allocate the arrays to be filled while code is being loaded. */ - stp->line_instr = (LineInstr *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->line_instr = (LineInstr *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_line_instrs * sizeof(LineInstr)); stp->current_li = 0; - stp->func_line = (int *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->func_line = (int *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_functions * sizeof(int)); @@ -1677,7 +1694,7 @@ read_code_header(LoaderState* stp) * Initialize label table. */ - stp->labels = (Label *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->labels = (Label *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_labels * sizeof(Label)); for (i = 0; i < stp->num_labels; i++) { stp->labels[i].value = 0; @@ -1703,9 +1720,9 @@ read_code_header(LoaderState* stp) #define CodeNeed(w) do { \ ASSERT(ci <= code_buffer_size); \ if (code_buffer_size < ci+(w)) { \ - code_buffer_size = erts_next_heap_size(ci+(w), 0); \ - stp->code = code \ - = (BeamInstr *) erts_realloc(ERTS_ALC_T_CODE, \ + code_buffer_size = 2*ci+(w); \ + stp->code = code = \ + (BeamInstr *) erts_realloc(ERTS_ALC_T_CODE, \ (void *) code, \ code_buffer_size * sizeof(BeamInstr)); \ } \ @@ -1731,6 +1748,7 @@ load_code(LoaderState* stp) GenOp* last_op = NULL; GenOp** last_op_next = NULL; int arity; + int retval = 1; /* * The size of the loaded func_info instruction is needed @@ -2457,7 +2475,11 @@ load_code(LoaderState* stp) case op_int_code_end: stp->code_buffer_size = code_buffer_size; stp->ci = ci; - return 1; + stp->function = THE_NON_VALUE; + stp->genop = NULL; + stp->specific_op = -1; + retval = 1; + goto cleanup; } /* @@ -2471,9 +2493,20 @@ load_code(LoaderState* stp) } } - load_error: - return 0; + retval = 0; + + cleanup: + /* + * Clean up everything that is not needed any longer. + */ + + while (stp->genop_blocks) { + GenOpBlock* next = stp->genop_blocks->next; + erts_free(ERTS_ALC_T_LOADER_TMP, (void *) stp->genop_blocks); + stp->genop_blocks = next; + } + return retval; } @@ -4265,24 +4298,31 @@ final_touch(LoaderState* stp) index = next; } modp = erts_put_module(stp->module); - modp->catches = catches; + modp->curr.catches = catches; /* * Export functions. */ for (i = 0; i < stp->num_exps; i++) { - Export* ep = erts_export_put(stp->module, stp->export[i].function, - stp->export[i].arity); + Export* ep; + BeamInstr* address = stp->export[i].address; + + if (address == NULL) { + /* Skip stub for a BIF */ + continue; + } + ep = erts_export_put(stp->module, stp->export[i].function, + stp->export[i].arity); if (!on_load) { - ep->address = stp->export[i].address; + ep->addressv[erts_staging_code_ix()] = address; } else { /* * Don't make any of the exported functions * callable yet. */ - ep->address = ep->code+3; - ep->code[4] = (BeamInstr) stp->export[i].address; + ep->addressv[erts_staging_code_ix()] = ep->code+3; + ep->code[4] = (BeamInstr) address; } } @@ -4926,7 +4966,7 @@ new_label(LoaderState* stp) int num = stp->num_labels; stp->num_labels++; - stp->labels = (Label *) erts_realloc(ERTS_ALC_T_LOADER_TMP, + stp->labels = (Label *) erts_realloc(ERTS_ALC_T_PREPARED_CODE, (void *) stp->labels, stp->num_labels * sizeof(Label)); stp->labels[num].value = 0; @@ -4937,7 +4977,8 @@ new_label(LoaderState* stp) static void new_literal_patch(LoaderState* stp, int pos) { - LiteralPatch* p = erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(LiteralPatch)); + LiteralPatch* p = erts_alloc(ERTS_ALC_T_PREPARED_CODE, + sizeof(LiteralPatch)); p->pos = pos; p->next = stp->literal_patches; stp->literal_patches = p; @@ -4946,7 +4987,7 @@ new_literal_patch(LoaderState* stp, int pos) static void new_string_patch(LoaderState* stp, int pos) { - StringPatch* p = erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(StringPatch)); + StringPatch* p = erts_alloc(ERTS_ALC_T_PREPARED_CODE, sizeof(StringPatch)); p->pos = pos; p->next = stp->string_patches; stp->string_patches = p; @@ -4964,14 +5005,14 @@ new_literal(LoaderState* stp, Eterm** hpp, Uint heap_size) ASSERT(stp->num_literals == 0); stp->allocated_literals = 8; need = stp->allocated_literals * sizeof(Literal); - stp->literals = (Literal *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + stp->literals = (Literal *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, need); } else if (stp->allocated_literals <= stp->num_literals) { Uint need; stp->allocated_literals *= 2; need = stp->allocated_literals * sizeof(Literal); - stp->literals = (Literal *) erts_realloc(ERTS_ALC_T_LOADER_TMP, + stp->literals = (Literal *) erts_realloc(ERTS_ALC_T_PREPARED_CODE, (void *) stp->literals, need); } @@ -4980,7 +5021,7 @@ new_literal(LoaderState* stp, Eterm** hpp, Uint heap_size) lit = stp->literals + stp->num_literals; lit->offset = 0; lit->heap_size = heap_size; - lit->heap = erts_alloc(ERTS_ALC_T_LOADER_TMP, heap_size*sizeof(Eterm)); + lit->heap = erts_alloc(ERTS_ALC_T_PREPARED_CODE, heap_size*sizeof(Eterm)); lit->term = make_boxed(lit->heap); lit->off_heap.first = 0; lit->off_heap.overhead = 0; @@ -4999,7 +5040,7 @@ erts_module_info_0(Process* p, Eterm module) return THE_NON_VALUE; } - if (erts_get_module(module) == NULL) { + if (erts_get_module(module, erts_active_code_ix()) == NULL) { return THE_NON_VALUE; } @@ -5054,32 +5095,43 @@ functions_in_module(Process* p, /* Process whose heap to use. */ BeamInstr* code; int i; Uint num_functions; + Uint need; Eterm* hp; + Eterm* hp_end; Eterm result = NIL; if (is_not_atom(mod)) { return THE_NON_VALUE; } - modp = erts_get_module(mod); + modp = erts_get_module(mod, erts_active_code_ix()); if (modp == NULL) { return THE_NON_VALUE; } - code = modp->code; + code = modp->curr.code; num_functions = code[MI_NUM_FUNCTIONS]; - hp = HAlloc(p, 5*num_functions); + need = 5*num_functions; + hp = HAlloc(p, need); + hp_end = hp + need; for (i = num_functions-1; i >= 0 ; i--) { BeamInstr* func_info = (BeamInstr *) code[MI_FUNCTIONS+i]; Eterm name = (Eterm) func_info[3]; int arity = (int) func_info[4]; Eterm tuple; - ASSERT(is_atom(name)); - tuple = TUPLE2(hp, name, make_small(arity)); - hp += 3; - result = CONS(hp, tuple, result); - hp += 2; + /* + * If the function name is [], this entry is a stub for + * a BIF that should be ignored. + */ + ASSERT(is_atom(name) || is_nil(name)); + if (is_atom(name)) { + tuple = TUPLE2(hp, name, make_small(arity)); + hp += 3; + result = CONS(hp, tuple, result); + hp += 2; + } } + HRelease(p, hp_end, hp); return result; } @@ -5106,12 +5158,12 @@ native_addresses(Process* p, Eterm mod) return THE_NON_VALUE; } - modp = erts_get_module(mod); + modp = erts_get_module(mod, erts_active_code_ix()); if (modp == NULL) { return THE_NON_VALUE; } - code = modp->code; + code = modp->curr.code; num_functions = code[MI_NUM_FUNCTIONS]; need = (6+BIG_UINT_HEAP_SIZE)*num_functions; hp = HAlloc(p, need); @@ -5122,9 +5174,11 @@ native_addresses(Process* p, Eterm mod) int arity = (int) func_info[4]; Eterm tuple; - ASSERT(is_atom(name)); + ASSERT(is_atom(name) || is_nil(name)); /* [] if BIF stub */ if (func_info[1] != 0) { - Eterm addr = erts_bld_uint(&hp, NULL, func_info[1]); + Eterm addr; + ASSERT(is_atom(name)); + addr = erts_bld_uint(&hp, NULL, func_info[1]); tuple = erts_bld_tuple(&hp, NULL, 3, name, make_small(arity), addr); result = erts_bld_cons(&hp, NULL, tuple, result); } @@ -5149,18 +5203,20 @@ exported_from_module(Process* p, /* Process whose heap to use. */ Eterm* hp = NULL; Eterm* hend = NULL; Eterm result = NIL; + ErtsCodeIndex code_ix; if (is_not_atom(mod)) { return THE_NON_VALUE; } - for (i = 0; i < export_list_size(); i++) { - Export* ep = export_list(i); + code_ix = erts_active_code_ix(); + for (i = 0; i < export_list_size(code_ix); i++) { + Export* ep = export_list(i,code_ix); if (ep->code[0] == mod) { Eterm tuple; - if (ep->address == ep->code+3 && + if (ep->addressv[code_ix] == ep->code+3 && ep->code[3] == (BeamInstr) em_call_error_handler) { /* There is a call to the function, but it does not exist. */ continue; @@ -5204,11 +5260,11 @@ attributes_for_module(Process* p, /* Process whose heap to use. */ return THE_NON_VALUE; } - modp = erts_get_module(mod); + modp = erts_get_module(mod, erts_active_code_ix()); if (modp == NULL) { return THE_NON_VALUE; } - code = modp->code; + code = modp->curr.code; ext = (byte *) code[MI_ATTR_PTR]; if (ext != NULL) { hp = HAlloc(p, code[MI_ATTR_SIZE_ON_HEAP]); @@ -5244,11 +5300,11 @@ compilation_info_for_module(Process* p, /* Process whose heap to use. */ return THE_NON_VALUE; } - modp = erts_get_module(mod); + modp = erts_get_module(mod, erts_active_code_ix()); if (modp == NULL) { return THE_NON_VALUE; } - code = modp->code; + code = modp->curr.code; ext = (byte *) code[MI_COMPILE_PTR]; if (ext != NULL) { hp = HAlloc(p, code[MI_COMPILE_SIZE_ON_HEAP]); @@ -5263,113 +5319,6 @@ compilation_info_for_module(Process* p, /* Process whose heap to use. */ } /* - * Find a function from the given pc and fill information in - * the FunctionInfo struct. If the full_info is non-zero, fill - * in all available information (including location in the - * source code). If no function is found, the 'current' field - * will be set to NULL. - */ - -void -erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info) -{ - Range* low = modules; - Range* high = low + num_loaded_modules; - Range* mid = mid_module; - - fi->current = NULL; - fi->needed = 5; - fi->loc = LINE_INVALID_LOCATION; - while (low < high) { - if (pc < mid->start) { - high = mid; - } else if (pc > mid->end) { - low = mid + 1; - } else { - BeamInstr** low1 = (BeamInstr **) (mid->start + MI_FUNCTIONS); - BeamInstr** high1 = low1 + mid->start[MI_NUM_FUNCTIONS]; - BeamInstr** mid1; - - while (low1 < high1) { - mid1 = low1 + (high1-low1) / 2; - if (pc < mid1[0]) { - high1 = mid1; - } else if (pc < mid1[1]) { - mid_module = mid; - fi->current = mid1[0]+2; - if (full_info) { - BeamInstr** fp = (BeamInstr **) (mid->start + - MI_FUNCTIONS); - int idx = mid1 - fp; - lookup_loc(fi, pc, mid->start, idx); - } - return; - } else { - low1 = mid1 + 1; - } - } - return; - } - mid = low + (high-low) / 2; - } -} - -static void -lookup_loc(FunctionInfo* fi, BeamInstr* orig_pc, BeamInstr* modp, int idx) -{ - Eterm* line = (Eterm *) modp[MI_LINE_TABLE]; - Eterm* low; - Eterm* high; - Eterm* mid; - Eterm pc; - - if (line == 0) { - return; - } - - pc = (Eterm) (BeamInstr) orig_pc; - fi->fname_ptr = (Eterm *) (BeamInstr) line[MI_LINE_FNAME_PTR]; - low = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx]; - high = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx+1]; - while (high > low) { - mid = low + (high-low) / 2; - if (pc < mid[0]) { - high = mid; - } else if (pc < mid[1]) { - int file; - int index = mid - (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB]; - - if (line[MI_LINE_LOC_SIZE] == 2) { - Uint16* loc_table = - (Uint16 *) (BeamInstr) line[MI_LINE_LOC_TAB]; - fi->loc = loc_table[index]; - } else { - Uint32* loc_table = - (Uint32 *) (BeamInstr) line[MI_LINE_LOC_TAB]; - ASSERT(line[MI_LINE_LOC_SIZE] == 4); - fi->loc = loc_table[index]; - } - if (fi->loc == LINE_INVALID_LOCATION) { - return; - } - fi->needed += 3+2+3+2; - file = LOC_FILE(fi->loc); - if (file == 0) { - /* Special case: Module name with ".erl" appended */ - Atom* mod_atom = atom_tab(atom_val(fi->current[0])); - fi->needed += 2*(mod_atom->len+4); - } else { - Atom* ap = atom_tab(atom_val((fi->fname_ptr)[file-1])); - fi->needed += 2*ap->len; - } - return; - } else { - low = mid + 1; - } - } -} - -/* * Build a single {M,F,A,Loction} item to be part of * a stack trace. */ @@ -5449,6 +5398,7 @@ code_get_chunk_2(BIF_ALIST_2) Process* p = BIF_P; Eterm Bin = BIF_ARG_1; Eterm Chunk = BIF_ARG_2; + Binary* magic = 0; LoaderState* stp; Uint chunk = 0; ErlSubBin* sb; @@ -5461,12 +5411,13 @@ code_get_chunk_2(BIF_ALIST_2) Eterm real_bin; byte* temp_alloc = NULL; - stp = erts_alloc_loader_state(); + magic = erts_alloc_loader_state(); + stp = ERTS_MAGIC_BIN_DATA(magic); if ((start = erts_get_aligned_binary_bytes(Bin, &temp_alloc)) == NULL) { error: erts_free_aligned_binary_bytes(temp_alloc); - if (stp) { - free_state(stp); + if (magic) { + free_loader_state(magic); } BIF_ERROR(p, BADARG); } @@ -5511,7 +5462,7 @@ code_get_chunk_2(BIF_ALIST_2) done: erts_free_aligned_binary_bytes(temp_alloc); - free_state(stp); + free_loader_state(magic); return res; } @@ -5524,14 +5475,16 @@ code_module_md5_1(BIF_ALIST_1) { Process* p = BIF_P; Eterm Bin = BIF_ARG_1; + Binary* magic; LoaderState* stp; byte* bytes; byte* temp_alloc = NULL; Eterm res; - stp = erts_alloc_loader_state(); + magic = erts_alloc_loader_state(); + stp = ERTS_MAGIC_BIN_DATA(magic); if ((bytes = erts_get_aligned_binary_bytes(Bin, &temp_alloc)) == NULL) { - free_state(stp); + free_loader_state(magic); BIF_ERROR(p, BADARG); } stp->module = THE_NON_VALUE; /* Suppress diagnostiscs */ @@ -5545,7 +5498,7 @@ code_module_md5_1(BIF_ALIST_1) done: erts_free_aligned_binary_bytes(temp_alloc); - free_state(stp); + free_loader_state(magic); return res; } @@ -5601,7 +5554,7 @@ stub_read_export_table(LoaderState* stp) stp->num_exps, stp->num_functions); } stp->export - = (ExportEntry *) erts_alloc(ERTS_ALC_T_LOADER_TMP, + = (ExportEntry *) erts_alloc(ERTS_ALC_T_PREPARED_CODE, stp->num_exps * sizeof(ExportEntry)); for (i = 0; i < stp->num_exps; i++) { @@ -5627,20 +5580,29 @@ stub_final_touch(LoaderState* stp, BeamInstr* fp) { int i; int n = stp->num_exps; + Eterm mod = fp[2]; Eterm function = fp[3]; int arity = fp[4]; #ifdef HIPE Lambda* lp; #endif + if (is_bif(mod, function, arity)) { + fp[1] = 0; + fp[2] = 0; + fp[3] = 0; + fp[4] = 0; + return; + } + /* * Test if the function should be exported. */ for (i = 0; i < n; i++) { if (stp->export[i].function == function && stp->export[i].arity == arity) { - Export* ep = erts_export_put(fp[2], function, arity); - ep->address = fp+5; + Export* ep = erts_export_put(mod, function, arity); + ep->addressv[erts_staging_code_ix()] = fp+5; return; } } @@ -5819,6 +5781,7 @@ patch_funentries(Eterm Patchlist) Eterm erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) { + Binary* magic; LoaderState* stp; BeamInstr Funcs; BeamInstr Patchlist; @@ -5840,7 +5803,8 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) * Must initialize stp->lambdas here because the error handling code * at label 'error' uses it. */ - stp = erts_alloc_loader_state(); + magic = erts_alloc_loader_state(); + stp = ERTS_MAGIC_BIN_DATA(magic); if (is_not_atom(Mod)) { goto error; @@ -5920,7 +5884,6 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) code[MI_COMPILE_PTR] = 0; code[MI_COMPILE_SIZE] = 0; code[MI_COMPILE_SIZE_ON_HEAP] = 0; - code[MI_NUM_BREAKPOINTS] = 0; code[MI_LITERALS_START] = 0; code[MI_LITERALS_END] = 0; code[MI_LITERALS_OFF_HEAP] = 0; @@ -6028,13 +5991,13 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) if (patch_funentries(Patchlist)) { erts_free_aligned_binary_bytes(temp_alloc); - free_state(stp); + free_loader_state(magic); return Mod; } error: erts_free_aligned_binary_bytes(temp_alloc); - free_state(stp); + free_loader_state(magic); BIF_ERROR(p, BADARG); } @@ -6051,3 +6014,4 @@ static int safe_mul(UWord a, UWord b, UWord* resp) return (res / b) == a; } } + diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h index 997ba197db..f1506a8684 100644 --- a/erts/emulator/beam/beam_load.h +++ b/erts/emulator/beam/beam_load.h @@ -50,10 +50,6 @@ extern BeamInstr beam_debug_apply[]; extern BeamInstr* em_call_error_handler; extern BeamInstr* em_apply_bif; extern BeamInstr* em_call_traced_function; -typedef struct { - BeamInstr* start; /* Pointer to start of module. */ - BeamInstr* end; /* Points one word beyond last function in module. */ -} Range; /* * The following variables keep a sorted list of address ranges for @@ -61,11 +57,6 @@ typedef struct { * instruction pointer. */ -extern Range* modules; -extern int num_loaded_modules; -extern int allocated_modules; -extern Range* mid_module; - /* Total code size in bytes */ extern Uint erts_total_code_size; /* @@ -94,27 +85,22 @@ extern Uint erts_total_code_size; #define MI_COMPILE_SIZE_ON_HEAP 6 /* - * Number of breakpoints in module is stored in this word - */ -#define MI_NUM_BREAKPOINTS 7 - -/* * Literal area (constant pool). */ -#define MI_LITERALS_START 8 -#define MI_LITERALS_END 9 -#define MI_LITERALS_OFF_HEAP 10 +#define MI_LITERALS_START 7 +#define MI_LITERALS_END 8 +#define MI_LITERALS_OFF_HEAP 9 /* * Pointer to the on_load function (or NULL if none). */ -#define MI_ON_LOAD_FUNCTION_PTR 11 +#define MI_ON_LOAD_FUNCTION_PTR 10 /* * Pointer to the line table (or NULL if none). */ -#define MI_LINE_TABLE 12 +#define MI_LINE_TABLE 11 /* * Start of function pointer table. This table contains pointers to @@ -125,5 +111,27 @@ extern Uint erts_total_code_size; * this table. */ -#define MI_FUNCTIONS 13 +#define MI_FUNCTIONS 12 + +/* + * Layout of the line table. + */ + +#define MI_LINE_FNAME_PTR 0 +#define MI_LINE_LOC_TAB 1 +#define MI_LINE_LOC_SIZE 2 +#define MI_LINE_FUNC_TAB 3 + +#define LINE_INVALID_LOCATION (0) + +/* + * Macros for manipulating locations. + */ + +#define IS_VALID_LOCATION(File, Line) \ + ((unsigned) (File) < 255 && (unsigned) (Line) < ((1 << 24) - 1)) +#define MAKE_LOCATION(File, Line) (((File) << 24) | (Line)) +#define LOC_FILE(Loc) ((Loc) >> 24) +#define LOC_LINE(Loc) ((Loc) & ((1 << 24)-1)) + #endif /* _BEAM_LOAD_H */ diff --git a/erts/emulator/beam/beam_ranges.c b/erts/emulator/beam/beam_ranges.c new file mode 100644 index 0000000000..0f2d5d0c2a --- /dev/null +++ b/erts/emulator/beam/beam_ranges.c @@ -0,0 +1,349 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2012. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "sys.h" +#include "erl_vm.h" +#include "global.h" +#include "beam_load.h" + +typedef struct { + BeamInstr* start; /* Pointer to start of module. */ + erts_smp_atomic_t end; /* (BeamInstr*) Points one word beyond last function in module. */ +} Range; + +/* Range 'end' needs to be atomic as we purge module + by setting end=start in active code_ix */ +#define RANGE_END(R) ((BeamInstr*)erts_smp_atomic_read_nob(&(R)->end)) + +static Range* find_range(BeamInstr* pc); +static void lookup_loc(FunctionInfo* fi, BeamInstr* pc, + BeamInstr* modp, int idx); + +/* + * The following variables keep a sorted list of address ranges for + * each module. It allows us to quickly find a function given an + * instruction pointer. + */ +struct ranges { + Range* modules; /* Sorted lists of module addresses. */ + Sint n; /* Number of range entries. */ + Sint allocated; /* Number of allocated entries. */ + erts_smp_atomic_t mid; /* Cached search start point */ +}; +static struct ranges r[ERTS_NUM_CODE_IX]; +static erts_smp_atomic_t mem_used; + +#ifdef HARD_DEBUG +static void check_consistency(struct ranges* p) +{ + int i; + + ASSERT(p->n <= p->allocated); + ASSERT((Uint)(p->mid - p->modules) < p->n || + (p->mid == p->modules && p->n == 0)); + for (i = 0; i < p->n; i++) { + ASSERT(p->modules[i].start <= RANGE_END(&p->modules[i])); + ASSERT(!i || RANGE_END(&p->modules[i-1]) < p->modules[i].start); + } +} +# define CHECK(r) check_consistency(r) +#else +# define CHECK(r) +#endif /* HARD_DEBUG */ + + +void +erts_init_ranges(void) +{ + Sint i; + + erts_smp_atomic_init_nob(&mem_used, 0); + for (i = 0; i < ERTS_NUM_CODE_IX; i++) { + r[i].modules = 0; + r[i].n = 0; + r[i].allocated = 0; + erts_smp_atomic_init_nob(&r[i].mid, 0); + } +} + +void +erts_start_staging_ranges(void) +{ + ErtsCodeIndex dst = erts_staging_code_ix(); + + if (r[dst].modules) { + erts_smp_atomic_add_nob(&mem_used, -r[dst].allocated); + erts_free(ERTS_ALC_T_MODULE_REFS, r[dst].modules); + r[dst].modules = NULL; + } +} + +void +erts_end_staging_ranges(int commit) +{ + ErtsCodeIndex dst = erts_staging_code_ix(); + + if (commit && r[dst].modules == NULL) { + Sint i; + Sint n; + + /* No modules added, just clone src and remove purged code. */ + ErtsCodeIndex src = erts_active_code_ix(); + + erts_smp_atomic_add_nob(&mem_used, r[src].n); + r[dst].modules = erts_alloc(ERTS_ALC_T_MODULE_REFS, + r[src].n * sizeof(Range)); + r[dst].allocated = r[src].n; + n = 0; + for (i = 0; i < r[src].n; i++) { + Range* rp = r[src].modules+i; + if (rp->start < RANGE_END(rp)) { + /* Only insert a module that has not been purged. */ + r[dst].modules[n] = *rp; + n++; + } + } + r[dst].n = n; + erts_smp_atomic_set_nob(&r[dst].mid, + (erts_aint_t) (r[dst].modules + n / 2)); + } +} + +void +erts_update_ranges(BeamInstr* code, Uint size) +{ + ErtsCodeIndex dst = erts_staging_code_ix(); + ErtsCodeIndex src = erts_active_code_ix(); + Sint i; + Sint n; + Sint need; + + if (src == dst) { + ASSERT(!erts_initialized); + + /* + * During start-up of system, the indices are the same. + * Handle this by faking a source area. + */ + src = (src+1) % ERTS_NUM_CODE_IX; + if (r[src].modules) { + erts_smp_atomic_add_nob(&mem_used, -r[src].allocated); + erts_free(ERTS_ALC_T_MODULE_REFS, r[src].modules); + } + r[src] = r[dst]; + r[dst].modules = 0; + } + + CHECK(&r[src]); + + ASSERT(r[dst].modules == NULL); + need = r[dst].allocated = r[src].n + 1; + erts_smp_atomic_add_nob(&mem_used, need); + r[dst].modules = (Range *) erts_alloc(ERTS_ALC_T_MODULE_REFS, + need * sizeof(Range)); + n = 0; + for (i = 0; i < r[src].n; i++) { + Range* rp = r[src].modules+i; + if (code < rp->start) { + r[dst].modules[n].start = code; + erts_smp_atomic_init_nob(&r[dst].modules[n].end, + (erts_aint_t)(((byte *)code) + size)); + ASSERT(!n || RANGE_END(&r[dst].modules[n-1]) < code); + n++; + break; + } + if (rp->start < RANGE_END(rp)) { + /* Only insert a module that has not been purged. */ + r[dst].modules[n].start = rp->start; + erts_smp_atomic_init_nob(&r[dst].modules[n].end, + (erts_aint_t)(RANGE_END(rp))); + ASSERT(!n || RANGE_END(&r[dst].modules[n-1]) < rp->start); + n++; + } + } + + while (i < r[src].n) { + Range* rp = r[src].modules+i; + if (rp->start < RANGE_END(rp)) { + /* Only insert a module that has not been purged. */ + r[dst].modules[n].start = rp->start; + erts_smp_atomic_init_nob(&r[dst].modules[n].end, + (erts_aint_t)(RANGE_END(rp))); + ASSERT(!n || RANGE_END(&r[dst].modules[n-1]) < rp->start); + n++; + } + i++; + } + + if (n == 0 || code > r[dst].modules[n-1].start) { + r[dst].modules[n].start = code; + erts_smp_atomic_init_nob(&r[dst].modules[n].end, + (erts_aint_t)(((byte *)code) + size)); + ASSERT(!n || RANGE_END(&r[dst].modules[n-1]) < code); + n++; + } + + ASSERT(n <= r[src].n+1); + r[dst].n = n; + erts_smp_atomic_set_nob(&r[dst].mid, + (erts_aint_t) (r[dst].modules + n / 2)); + + CHECK(&r[dst]); + CHECK(&r[src]); +} + +void +erts_remove_from_ranges(BeamInstr* code) +{ + Range* rp = find_range(code); + erts_smp_atomic_set_nob(&rp->end, (erts_aint_t)rp->start); +} + +UWord +erts_ranges_sz(void) +{ + return erts_smp_atomic_read_nob(&mem_used) * sizeof(Range); +} + +/* + * Find a function from the given pc and fill information in + * the FunctionInfo struct. If the full_info is non-zero, fill + * in all available information (including location in the + * source code). If no function is found, the 'current' field + * will be set to NULL. + */ + +void +erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info) +{ + BeamInstr** low; + BeamInstr** high; + BeamInstr** mid; + Range* rp; + + fi->current = NULL; + fi->needed = 5; + fi->loc = LINE_INVALID_LOCATION; + rp = find_range(pc); + if (rp == 0) { + return; + } + + low = (BeamInstr **) (rp->start + MI_FUNCTIONS); + high = low + rp->start[MI_NUM_FUNCTIONS]; + while (low < high) { + mid = low + (high-low) / 2; + if (pc < mid[0]) { + high = mid; + } else if (pc < mid[1]) { + fi->current = mid[0]+2; + if (full_info) { + BeamInstr** fp = (BeamInstr **) (rp->start + + MI_FUNCTIONS); + int idx = mid - fp; + lookup_loc(fi, pc, rp->start, idx); + } + return; + } else { + low = mid + 1; + } + } +} + +static Range* +find_range(BeamInstr* pc) +{ + ErtsCodeIndex active = erts_active_code_ix(); + Range* low = r[active].modules; + Range* high = low + r[active].n; + Range* mid = (Range *) erts_smp_atomic_read_nob(&r[active].mid); + + CHECK(&r[active]); + while (low < high) { + if (pc < mid->start) { + high = mid; + } else if (pc > RANGE_END(mid)) { + low = mid + 1; + } else { + erts_smp_atomic_set_nob(&r[active].mid, (erts_aint_t) mid); + return mid; + } + mid = low + (high-low) / 2; + } + return 0; +} + +static void +lookup_loc(FunctionInfo* fi, BeamInstr* orig_pc, BeamInstr* modp, int idx) +{ + Eterm* line = (Eterm *) modp[MI_LINE_TABLE]; + Eterm* low; + Eterm* high; + Eterm* mid; + Eterm pc; + + if (line == 0) { + return; + } + + pc = (Eterm) (BeamInstr) orig_pc; + fi->fname_ptr = (Eterm *) (BeamInstr) line[MI_LINE_FNAME_PTR]; + low = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx]; + high = (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB+idx+1]; + while (high > low) { + mid = low + (high-low) / 2; + if (pc < mid[0]) { + high = mid; + } else if (pc < mid[1]) { + int file; + int index = mid - (Eterm *) (BeamInstr) line[MI_LINE_FUNC_TAB]; + + if (line[MI_LINE_LOC_SIZE] == 2) { + Uint16* loc_table = + (Uint16 *) (BeamInstr) line[MI_LINE_LOC_TAB]; + fi->loc = loc_table[index]; + } else { + Uint32* loc_table = + (Uint32 *) (BeamInstr) line[MI_LINE_LOC_TAB]; + ASSERT(line[MI_LINE_LOC_SIZE] == 4); + fi->loc = loc_table[index]; + } + if (fi->loc == LINE_INVALID_LOCATION) { + return; + } + fi->needed += 3+2+3+2; + file = LOC_FILE(fi->loc); + if (file == 0) { + /* Special case: Module name with ".erl" appended */ + Atom* mod_atom = atom_tab(atom_val(fi->current[0])); + fi->needed += 2*(mod_atom->len+4); + } else { + Atom* ap = atom_tab(atom_val((fi->fname_ptr)[file-1])); + fi->needed += 2*ap->len; + } + return; + } else { + low = mid + 1; + } + } +} diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index f8305944a4..9b2394d92f 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -3709,7 +3709,8 @@ BIF_RETTYPE function_exported_3(BIF_ALIST_3) is_not_small(BIF_ARG_3)) { BIF_ERROR(BIF_P, BADARG); } - if (erts_find_function(BIF_ARG_1, BIF_ARG_2, signed_val(BIF_ARG_3)) == NULL) { + if (erts_find_function(BIF_ARG_1, BIF_ARG_2, signed_val(BIF_ARG_3), + erts_active_code_ix()) == NULL) { BIF_RET(am_false); } BIF_RET(am_true); @@ -4434,6 +4435,21 @@ erts_bif_prep_await_proc_exit_apply_trap(Process *c_p, Export bif_return_trap_export; +void erts_init_trap_export(Export* ep, Eterm m, Eterm f, Uint a, + Eterm (*bif)(BIF_ALIST_0)) +{ + int i; + sys_memset((void *) ep, 0, sizeof(Export)); + for (i=0; i<ERTS_NUM_CODE_IX; i++) { + ep->addressv[i] = &ep->code[3]; + } + ep->code[0] = m; + ep->code[1] = f; + ep->code[2] = a; + ep->code[3] = (BeamInstr) em_apply_bif; + ep->code[4] = (BeamInstr) bif; +} + void erts_init_bif(void) { reference0 = 0; @@ -4449,17 +4465,13 @@ void erts_init_bif(void) * yield the calling process traps to. The only thing it does: * return the value passed as argument. */ - sys_memset((void *) &bif_return_trap_export, 0, sizeof(Export)); - bif_return_trap_export.address = &bif_return_trap_export.code[3]; - bif_return_trap_export.code[0] = am_erlang; - bif_return_trap_export.code[1] = am_bif_return_trap; + erts_init_trap_export(&bif_return_trap_export, am_erlang, am_bif_return_trap, #ifdef DEBUG - bif_return_trap_export.code[2] = 2; + 2 #else - bif_return_trap_export.code[2] = 1; + 1 #endif - bif_return_trap_export.code[3] = (BeamInstr) em_apply_bif; - bif_return_trap_export.code[4] = (BeamInstr) &bif_return_trap; + , &bif_return_trap); flush_monitor_message_trap = erts_export_put(am_erlang, am_flush_monitor_message, diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h index d20089a9fb..7cb2c78815 100644 --- a/erts/emulator/beam/bif.h +++ b/erts/emulator/beam/bif.h @@ -125,7 +125,7 @@ do { \ #define ERTS_BIF_PREP_TRAP0(Ret, Trap, Proc) \ do { \ (Proc)->arity = 0; \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ (Ret) = THE_NON_VALUE; \ } while (0) @@ -135,7 +135,7 @@ do { \ Eterm* reg = ERTS_PROC_GET_SCHDATA((Proc))->x_reg_array; \ (Proc)->arity = 1; \ reg[0] = (Eterm) (A0); \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ (Ret) = THE_NON_VALUE; \ } while (0) @@ -146,7 +146,7 @@ do { \ (Proc)->arity = 2; \ reg[0] = (Eterm) (A0); \ reg[1] = (Eterm) (A1); \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ (Ret) = THE_NON_VALUE; \ } while (0) @@ -158,7 +158,7 @@ do { \ reg[0] = (Eterm) (A0); \ reg[1] = (Eterm) (A1); \ reg[2] = (Eterm) (A2); \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ (Ret) = THE_NON_VALUE; \ } while (0) @@ -170,13 +170,13 @@ do { \ reg[0] = (Eterm) (A0); \ reg[1] = (Eterm) (A1); \ reg[2] = (Eterm) (A2); \ - (Proc)->i = (BeamInstr*) ((Trap)->address); \ + (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \ (Proc)->freason = TRAP; \ } while (0) #define BIF_TRAP0(p, Trap_) do { \ (p)->arity = 0; \ - (p)->i = (BeamInstr*) ((Trap_)->address); \ + (p)->i = (BeamInstr*) ((Trap_)->addressv[erts_active_code_ix()]); \ (p)->freason = TRAP; \ return THE_NON_VALUE; \ } while(0) @@ -185,7 +185,7 @@ do { \ Eterm* reg = ERTS_PROC_GET_SCHDATA((p))->x_reg_array; \ (p)->arity = 1; \ reg[0] = (A0); \ - (p)->i = (BeamInstr*) ((Trap_)->address); \ + (p)->i = (BeamInstr*) ((Trap_)->addressv[erts_active_code_ix()]); \ (p)->freason = TRAP; \ return THE_NON_VALUE; \ } while(0) @@ -195,7 +195,7 @@ do { \ (p)->arity = 2; \ reg[0] = (A0); \ reg[1] = (A1); \ - (p)->i = (BeamInstr*) ((Trap_)->address); \ + (p)->i = (BeamInstr*) ((Trap_)->addressv[erts_active_code_ix()]); \ (p)->freason = TRAP; \ return THE_NON_VALUE; \ } while(0) @@ -206,7 +206,7 @@ do { \ reg[0] = (A0); \ reg[1] = (A1); \ reg[2] = (A2); \ - (p)->i = (BeamInstr*) ((Trap_)->address); \ + (p)->i = (BeamInstr*) ((Trap_)->addressv[erts_active_code_ix()]); \ (p)->freason = TRAP; \ return THE_NON_VALUE; \ } while(0) diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 8cc568b16c..7f874a2d9c 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -142,8 +142,6 @@ bif erlang:list_to_pid/1 bif 'erl.lang.proc':string_to_pid/1 ebif_string_to_pid_1 list_to_pid_1 bif erlang:list_to_tuple/1 bif 'erl.lang.tuple':from_list/1 ebif_list_to_tuple_1 -bif erlang:load_module/2 -bif 'erl.system.code':load/2 ebif_load_module_2 bif erlang:loaded/0 bif 'erl.system.code':loaded/0 ebif_loaded_0 bif erlang:localtime/0 @@ -812,6 +810,13 @@ bif erlang:check_old_code/1 # bif erlang:universaltime_to_posixtime/1 bif erlang:posixtime_to_universaltime/1 + +# +# New in R16B. +# +bif erlang:prepare_loading/2 +bif erlang:finish_loading/1 + # # Obsolete # diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 6f5020dc14..39f91be7fc 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -377,17 +377,22 @@ loaded(int to, void *to_arg) int old = 0; int cur = 0; BeamInstr* code; + Module* modp; + ErtsCodeIndex code_ix; + + code_ix = erts_active_code_ix(); + erts_rlock_old_code(code_ix); /* * Calculate and print totals. */ - for (i = 0; i < module_code_size(); i++) { - if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { - cur += module_code(i)->code_length; - if (module_code(i)->old_code_length != 0) { - old += module_code(i)->old_code_length; + for (i = 0; i < module_code_size(code_ix); i++) { + if ((modp = module_code(i, code_ix)) != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { + cur += modp->curr.code_length; + if (modp->old.code_length != 0) { + old += modp->old.code_length; } } } @@ -398,21 +403,22 @@ loaded(int to, void *to_arg) * Print one line per module. */ - for (i = 0; i < module_code_size(); i++) { + for (i = 0; i < module_code_size(code_ix); i++) { + modp = module_code(i, code_ix); if (!ERTS_IS_CRASH_DUMPING) { /* * Interactive dump; keep it brief. */ - if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { - erts_print(to, to_arg, "%T", make_atom(module_code(i)->module)); - cur += module_code(i)->code_length; - erts_print(to, to_arg, " %d", module_code(i)->code_length ); - if (module_code(i)->old_code_length != 0) { + if (modp != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { + erts_print(to, to_arg, "%T", make_atom(modp->module)); + cur += modp->curr.code_length; + erts_print(to, to_arg, " %d", modp->curr.code_length ); + if (modp->old.code_length != 0) { erts_print(to, to_arg, " (%d old)", - module_code(i)->old_code_length ); - old += module_code(i)->old_code_length; + modp->old.code_length ); + old += modp->old.code_length; } erts_print(to, to_arg, "\n"); } @@ -420,15 +426,15 @@ loaded(int to, void *to_arg) /* * To crash dump; make it parseable. */ - if (module_code(i) != NULL && - ((module_code(i)->code_length != 0) || - (module_code(i)->old_code_length != 0))) { + if (modp != NULL && + ((modp->curr.code_length != 0) || + (modp->old.code_length != 0))) { erts_print(to, to_arg, "=mod:"); - erts_print(to, to_arg, "%T", make_atom(module_code(i)->module)); + erts_print(to, to_arg, "%T", make_atom(modp->module)); erts_print(to, to_arg, "\n"); erts_print(to, to_arg, "Current size: %d\n", - module_code(i)->code_length); - code = module_code(i)->code; + modp->curr.code_length); + code = modp->curr.code; if (code != NULL && code[MI_ATTR_PTR]) { erts_print(to, to_arg, "Current attributes: "); dump_attributes(to, to_arg, (byte *) code[MI_ATTR_PTR], @@ -440,9 +446,9 @@ loaded(int to, void *to_arg) code[MI_COMPILE_SIZE]); } - if (module_code(i)->old_code_length != 0) { - erts_print(to, to_arg, "Old size: %d\n", module_code(i)->old_code_length); - code = module_code(i)->old_code; + if (modp->old.code_length != 0) { + erts_print(to, to_arg, "Old size: %d\n", modp->old.code_length); + code = modp->old.code; if (code[MI_ATTR_PTR]) { erts_print(to, to_arg, "Old attributes: "); dump_attributes(to, to_arg, (byte *) code[MI_ATTR_PTR], @@ -457,6 +463,7 @@ loaded(int to, void *to_arg) } } } + erts_runlock_old_code(code_ix); } diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c new file mode 100644 index 0000000000..ae4cca1e58 --- /dev/null +++ b/erts/emulator/beam/code_ix.c @@ -0,0 +1,152 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2012. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "code_ix.h" +#include "global.h" +#include "beam_catches.h" + + + +#if 0 +# define CIX_TRACE(text) erts_fprintf(stderr, "CIX_TRACE: " text " act=%u load=%u\r\n", erts_active_code_ix(), erts_staging_code_ix()) +#else +# define CIX_TRACE(text) +#endif + +erts_smp_atomic32_t the_active_code_index; +erts_smp_atomic32_t the_staging_code_index; + +static int the_code_ix_lock = 0; +struct code_ix_queue_item { + Process *p; + struct code_ix_queue_item* next; +}; +static struct code_ix_queue_item* the_code_ix_queue = NULL; +static erts_smp_mtx_t the_code_ix_queue_lock; + +void erts_code_ix_init(void) +{ + /* We start emulator by initializing preloaded modules + * single threaded with active and staging set both to zero. + * Preloading is finished by a commit that will set things straight. + */ + erts_smp_atomic32_init_nob(&the_active_code_index, 0); + erts_smp_atomic32_init_nob(&the_staging_code_index, 0); + erts_smp_mtx_init(&the_code_ix_queue_lock, "code_ix_queue"); + CIX_TRACE("init"); +} + +void erts_start_staging_code_ix(void) +{ + beam_catches_start_staging(); + export_start_staging(); + module_start_staging(); + erts_start_staging_ranges(); + CIX_TRACE("start"); +} + + +void erts_end_staging_code_ix(void) +{ + beam_catches_end_staging(1); + export_end_staging(1); + module_end_staging(1); + erts_end_staging_ranges(1); + CIX_TRACE("end"); +} + +void erts_commit_staging_code_ix(void) +{ + ErtsCodeIndex ix; + /* We need to this lock as we are now making the staging export table active */ + export_staging_lock(); + ix = erts_staging_code_ix(); + erts_smp_atomic32_set_nob(&the_active_code_index, ix); + ix = (ix + 1) % ERTS_NUM_CODE_IX; + erts_smp_atomic32_set_nob(&the_staging_code_index, ix); + export_staging_unlock(); + CIX_TRACE("activate"); +} + +void erts_abort_staging_code_ix(void) +{ + beam_catches_end_staging(0); + export_end_staging(0); + module_end_staging(0); + erts_end_staging_ranges(0); + CIX_TRACE("abort"); +} + + +/* + * Calller _must_ yield if we return 0 + */ +int erts_try_seize_code_write_permission(Process* c_p) +{ + int success; +#ifdef ERTS_SMP + ASSERT(!erts_smp_thr_progress_is_blocking()); /* to avoid deadlock */ +#endif + + erts_smp_mtx_lock(&the_code_ix_queue_lock); + success = !the_code_ix_lock; + if (success) { + the_code_ix_lock = 1; + } + else { /* Already locked */ + struct code_ix_queue_item* qitem; + qitem = erts_alloc(ERTS_ALC_T_CODE_IX_LOCK_Q, sizeof(*qitem)); + qitem->p = c_p; + erts_smp_proc_inc_refc(c_p); + qitem->next = the_code_ix_queue; + the_code_ix_queue = qitem; + erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); + } + erts_smp_mtx_unlock(&the_code_ix_queue_lock); + return success; +} + +void erts_release_code_write_permission(void) +{ + erts_smp_mtx_lock(&the_code_ix_queue_lock); + while (the_code_ix_queue != NULL) { /* unleash the entire herd */ + struct code_ix_queue_item* qitem = the_code_ix_queue; + erts_smp_proc_lock(qitem->p, ERTS_PROC_LOCK_STATUS); + if (!ERTS_PROC_IS_EXITING(qitem->p)) { + erts_resume(qitem->p, ERTS_PROC_LOCK_STATUS); + } + erts_smp_proc_unlock(qitem->p, ERTS_PROC_LOCK_STATUS); + the_code_ix_queue = qitem->next; + erts_smp_proc_dec_refc(qitem->p); + erts_free(ERTS_ALC_T_CODE_IX_LOCK_Q, qitem); + } + the_code_ix_lock = 0; + erts_smp_mtx_unlock(&the_code_ix_queue_lock); +} + +#ifdef ERTS_ENABLE_LOCK_CHECK +int erts_is_code_ix_locked(void) +{ + return the_code_ix_lock; +} +#endif diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h new file mode 100644 index 0000000000..6b2680044e --- /dev/null +++ b/erts/emulator/beam/code_ix.h @@ -0,0 +1,141 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2012. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* Description: + * This is the interface that facilitate changing the beam code + * (load,upgrade,delete) while allowing executing Erlang processes to + * access the code without any locks or other expensive memory barriers. + * + * The basic idea is to maintain several "logical copies" of the code. These + * copies are identified by a global 'code index', an integer of 0, 1 or 2. + * The code index is used as argument to code access structures like + * export, module, beam_catches, beam_ranges. + * + * The current 'active' code index is used to access the current running + * code. The 'staging' code index is used by the process that performs + * a code change operation. When a code change operation completes + * succesfully, the staging code index becomes the new active code index. + * + * The third code index is not explicitly used. It can be thought of as + * the "previous active" or the "next staging" index. It is needed to make + * sure that we do not reuse a code index for staging until we are sure + * that no executing BIFs are still referring it. + * We could get by with only two (0 and 1), but that would require that we + * must wait for all schedulers to re-schedule before each code change + * operation can start staging. + * + * Note that the 'code index' is very loosely coupled to the concept of + * 'current' and 'old' module versions. You can almost say that they are + * orthogonal to each other. Code index is an emulator global concept while + * 'current' and 'old' is specific for each module. + */ + +#ifndef __CODE_IX_H__ +#define __CODE_IX_H__ + +#ifndef __SYS_H__ +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif +# include "sys.h" +#endif +struct process; + + +#define ERTS_NUM_CODE_IX 3 +typedef unsigned ErtsCodeIndex; + + +/* Called once at emulator initialization. + */ +void erts_code_ix_init(void); + +/* Return active code index. + * Is guaranteed to be valid until the calling BIF returns. + * To get a consistent view of the code, only one call to erts_active_code_ix() + * should be made and the returned ix reused within the same BIF call. + */ +ERTS_GLB_INLINE +ErtsCodeIndex erts_active_code_ix(void); + +/* Return staging code ix. + * Only used by a process performing code loading/upgrading/deleting/purging. + * code_ix must be locked. + */ +ERTS_GLB_INLINE +ErtsCodeIndex erts_staging_code_ix(void); + +/* Try seize exclusive code write permission. Needed for code staging. + * Main process lock (only) must be held. + * System thread progress must not be blocked. + * Caller is suspended and *must* yield if 0 is returned. + */ +int erts_try_seize_code_write_permission(struct process*); + +/* Release code write permission. + * Will resume any suspended waiters. + */ +void erts_release_code_write_permission(void); + +/* Prepare the "staging area" to be a complete copy of the active code. + * Code write permission must have been seized. + * Must be followed by calls to either "end" and "commit" or "abort" before + * code write permission can be released. + */ +void erts_start_staging_code_ix(void); + +/* End the staging. + * Preceded by "start" and must be followed by "commit". + */ +void erts_end_staging_code_ix(void); + +/* Set staging code index as new active code index. + * Preceded by "end". + */ +void erts_commit_staging_code_ix(void); + +/* Abort the staging. + * Preceded by "start". + */ +void erts_abort_staging_code_ix(void); + +#ifdef ERTS_ENABLE_LOCK_CHECK +int erts_is_code_ix_locked(void); +#endif + + + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +extern erts_smp_atomic32_t the_active_code_index; +extern erts_smp_atomic32_t the_staging_code_index; + +ERTS_GLB_INLINE ErtsCodeIndex erts_active_code_ix(void) +{ + return erts_smp_atomic32_read_nob(&the_active_code_index); +} +ERTS_GLB_INLINE ErtsCodeIndex erts_staging_code_ix(void) +{ + return erts_smp_atomic32_read_nob(&the_staging_code_index); +} + +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ + +#endif /* !__CODE_IX_H__ */ + diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index bee61e7273..00d57ceab5 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -2295,15 +2295,15 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2) goto error; /* Check that all trap functions are defined !! */ - if (dsend2_trap->address == NULL || - dsend3_trap->address == NULL || + if (dsend2_trap->addressv[0] == NULL || + dsend3_trap->addressv[0] == NULL || /* dsend_nosuspend_trap->address == NULL ||*/ - dlink_trap->address == NULL || - dunlink_trap->address == NULL || - dmonitor_node_trap->address == NULL || - dgroup_leader_trap->address == NULL || - dmonitor_p_trap->address == NULL || - dexit_trap->address == NULL) { + dlink_trap->addressv[0] == NULL || + dunlink_trap->addressv[0] == NULL || + dmonitor_node_trap->addressv[0] == NULL || + dgroup_leader_trap->addressv[0] == NULL || + dmonitor_p_trap->addressv[0] == NULL || + dexit_trap->addressv[0] == NULL) { goto error; } diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index df27186680..ac92822aca 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -2185,9 +2185,9 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) if (want.code) { size.code = module_table_sz(); size.code += export_table_sz(); - size.code += export_list_size() * sizeof(Export); + size.code += export_entries_sz(); size.code += erts_fun_table_sz(); - size.code += allocated_modules*sizeof(Range); + size.code += erts_ranges_sz(); size.code += erts_total_code_size; } @@ -2335,7 +2335,7 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc) values[i].arity = 2; values[i].name = "export_list"; - values[i].ui[0] = export_list_size() * sizeof(Export); + values[i].ui[0] = export_entries_sz(); i++; values[i].arity = 2; @@ -2350,7 +2350,7 @@ erts_allocated_areas(int *print_to_p, void *print_to_arg, void *proc) values[i].arity = 2; values[i].name = "module_refs"; - values[i].ui[0] = allocated_modules*sizeof(Range); + values[i].ui[0] = erts_ranges_sz(); i++; values[i].arity = 2; diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index 90a6c0cbee..de7d5599bb 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -164,6 +164,7 @@ type MSG_REF FIXED_SIZE PROCESSES msg_ref type MSG_ROOTS TEMPORARY PROCESSES msg_roots type ROOTSET TEMPORARY PROCESSES root_set type LOADER_TMP TEMPORARY CODE loader_tmp +type PREPARED_CODE SHORT_LIVED CODE prepared_code type BIF_TIMER_TABLE LONG_LIVED SYSTEM bif_timer_table type SL_BIF_TIMER SHORT_LIVED PROCESSES bif_timer_sl type LL_BIF_TIMER STANDARD PROCESSES bif_timer_ll @@ -263,6 +264,7 @@ type ZLIB STANDARD SYSTEM zlib type CPU_GRPS_MAP LONG_LIVED SYSTEM cpu_groups_map type AUX_WORK_TMO LONG_LIVED SYSTEM aux_work_timeouts type MISC_AUX_WORK_Q LONG_LIVED SYSTEM misc_aux_work_q +type CODE_IX_LOCK_Q SHORT_LIVED SYSTEM code_ix_lock_q +if threads_no_smp # Need thread safe allocs, but std_alloc and fix_alloc are not; diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c index cc4f2be8eb..474151d454 100644 --- a/erts/emulator/beam/erl_bif_binary.c +++ b/erts/emulator/beam/erl_bif_binary.c @@ -72,52 +72,29 @@ binary_matches(Process *p, Eterm arg1, Eterm arg2, Eterm arg3); void erts_init_bif_binary(void) { - sys_memset((void *) &binary_match_trap_export, 0, sizeof(Export)); - binary_match_trap_export.address = &binary_match_trap_export.code[3]; - binary_match_trap_export.code[0] = am_erlang; - binary_match_trap_export.code[1] = am_binary_match_trap; - binary_match_trap_export.code[2] = 3; - binary_match_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_match_trap_export.code[4] = (BeamInstr) &binary_match_trap; - - sys_memset((void *) &binary_matches_trap_export, 0, sizeof(Export)); - binary_matches_trap_export.address = &binary_matches_trap_export.code[3]; - binary_matches_trap_export.code[0] = am_erlang; - binary_matches_trap_export.code[1] = am_binary_matches_trap; - binary_matches_trap_export.code[2] = 3; - binary_matches_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_matches_trap_export.code[4] = (BeamInstr) &binary_matches_trap; - - sys_memset((void *) &binary_longest_prefix_trap_export, 0, sizeof(Export)); - binary_longest_prefix_trap_export.address = &binary_longest_prefix_trap_export.code[3]; - binary_longest_prefix_trap_export.code[0] = am_erlang; - binary_longest_prefix_trap_export.code[1] = am_binary_longest_prefix_trap; - binary_longest_prefix_trap_export.code[2] = 3; - binary_longest_prefix_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_longest_prefix_trap_export.code[4] = (BeamInstr) &binary_longest_prefix_trap; - - sys_memset((void *) &binary_longest_suffix_trap_export, 0, sizeof(Export)); - binary_longest_suffix_trap_export.address = &binary_longest_suffix_trap_export.code[3]; - binary_longest_suffix_trap_export.code[0] = am_erlang; - binary_longest_suffix_trap_export.code[1] = am_binary_longest_suffix_trap; - binary_longest_suffix_trap_export.code[2] = 3; - binary_longest_suffix_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_longest_suffix_trap_export.code[4] = (BeamInstr) &binary_longest_suffix_trap; - - sys_memset((void *) &binary_bin_to_list_trap_export, 0, sizeof(Export)); - binary_bin_to_list_trap_export.address = &binary_bin_to_list_trap_export.code[3]; - binary_bin_to_list_trap_export.code[0] = am_erlang; - binary_bin_to_list_trap_export.code[1] = am_binary_bin_to_list_trap; - binary_bin_to_list_trap_export.code[2] = 3; - binary_bin_to_list_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_bin_to_list_trap_export.code[4] = (BeamInstr) &binary_bin_to_list_trap; - sys_memset((void *) &binary_copy_trap_export, 0, sizeof(Export)); - binary_copy_trap_export.address = &binary_copy_trap_export.code[3]; - binary_copy_trap_export.code[0] = am_erlang; - binary_copy_trap_export.code[1] = am_binary_copy_trap; - binary_copy_trap_export.code[2] = 2; - binary_copy_trap_export.code[3] = (BeamInstr) em_apply_bif; - binary_copy_trap_export.code[4] = (BeamInstr) &binary_copy_trap; + erts_init_trap_export(&binary_match_trap_export, + am_erlang, am_binary_match_trap, 3, + &binary_match_trap); + + erts_init_trap_export(&binary_matches_trap_export, + am_erlang, am_binary_matches_trap, 3, + &binary_matches_trap); + + erts_init_trap_export(&binary_longest_prefix_trap_export, + am_erlang, am_binary_longest_prefix_trap, 3, + &binary_longest_prefix_trap); + + erts_init_trap_export(&binary_longest_suffix_trap_export, + am_erlang, am_binary_longest_suffix_trap, 3, + &binary_longest_suffix_trap); + + erts_init_trap_export(&binary_bin_to_list_trap_export, + am_erlang, am_binary_bin_to_list_trap, 3, + &binary_bin_to_list_trap); + + erts_init_trap_export(&binary_copy_trap_export, + am_erlang, am_binary_copy_trap, 2, + &binary_copy_trap); max_loop_limit = 0; return; diff --git a/erts/emulator/beam/erl_bif_chksum.c b/erts/emulator/beam/erl_bif_chksum.c index 06b7ffdf32..ff5ce3cc7a 100644 --- a/erts/emulator/beam/erl_bif_chksum.c +++ b/erts/emulator/beam/erl_bif_chksum.c @@ -42,16 +42,9 @@ static Export chksum_md5_2_exp; void erts_init_bif_chksum(void) { /* Non visual BIF to trap to. */ - memset(&chksum_md5_2_exp, 0, sizeof(Export)); - chksum_md5_2_exp.address = - &chksum_md5_2_exp.code[3]; - chksum_md5_2_exp.code[0] = am_erlang; - chksum_md5_2_exp.code[1] = am_atom_put("md5_trap",8); - chksum_md5_2_exp.code[2] = 2; - chksum_md5_2_exp.code[3] = - (BeamInstr) em_apply_bif; - chksum_md5_2_exp.code[4] = - (BeamInstr) &md5_2; + erts_init_trap_export(&chksum_md5_2_exp, + am_erlang, am_atom_put("md5_trap",8), 2, + &md5_2); } diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c index 6b843d2e08..b036c5ef5c 100644 --- a/erts/emulator/beam/erl_bif_re.c +++ b/erts/emulator/beam/erl_bif_re.c @@ -71,14 +71,9 @@ void erts_init_bif_re(void) erts_pcre_stack_free = &erts_erts_pcre_stack_free; default_table = NULL; /* ISO8859-1 default, forced into pcre */ max_loop_limit = CONTEXT_REDS * LOOP_FACTOR; - - sys_memset((void *) &re_exec_trap_export, 0, sizeof(Export)); - re_exec_trap_export.address = &re_exec_trap_export.code[3]; - re_exec_trap_export.code[0] = am_erlang; - re_exec_trap_export.code[1] = am_re_run_trap; - re_exec_trap_export.code[2] = 3; - re_exec_trap_export.code[3] = (BeamInstr) em_apply_bif; - re_exec_trap_export.code[4] = (BeamInstr) &re_exec_trap; + + erts_init_trap_export(&re_exec_trap_export, am_erlang, am_re_run_trap, 3, + &re_exec_trap); grun_trap_exportp = erts_export_put(am_re,am_grun,3); urun_trap_exportp = erts_export_put(am_re,am_urun,3); diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index b0a58c80ea..1c99fcdaa6 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -60,8 +60,8 @@ static Eterm trace_info_pid(Process* p, Eterm pid_spec, Eterm key); static Eterm trace_info_func(Process* p, Eterm pid_spec, Eterm key); static Eterm trace_info_on_load(Process* p, Eterm key); -static int setup_func_trace(Export* ep, void* match_prog); -static int reset_func_trace(Export* ep); +static int setup_func_trace(Export* ep, void* match_prog, ErtsCodeIndex); +static int reset_func_trace(Export* ep, ErtsCodeIndex); static void reset_bif_trace(int bif_index); static void setup_bif_trace(int bif_index); static void set_trace_bif(int bif_index, void* match_prog); @@ -98,7 +98,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) { DeclareTmpHeap(mfa,3,p); /* Not really heap here, but might be when setting pattern */ int i; - int matches = 0; + int matches = -1; int specified = 0; enum erts_break_op on; Binary* match_prog_set; @@ -108,6 +108,9 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) Process *meta_tracer_proc = p; Eterm meta_tracer_pid = p->id; + if (!erts_try_seize_code_write_permission(p)) { + ERTS_BIF_YIELD3(bif_export[BIF_trace_pattern_3], p, MFA, Pattern, flaglist); + } erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); @@ -241,7 +244,6 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) erts_default_meta_match_spec = NULL; erts_default_meta_tracer_pid = NIL; } - MatchSetUnref(match_prog_set); if (erts_default_trace_pattern_flags.breakpoint && flags.breakpoint) { /* Breakpoint trace -> breakpoint trace */ @@ -297,8 +299,7 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) erts_default_trace_pattern_is_on = !!flags.breakpoint; } } - - goto done; + matches = 0; } else if (is_tuple(MFA)) { Eterm *tp = tuple_val(MFA); if (tp[0] != make_arityval(3)) { @@ -322,35 +323,29 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist) if (is_small(mfa[2])) { mfa[2] = signed_val(mfa[2]); } - } else { - goto error; - } - if (meta_tracer_proc) { - meta_tracer_proc->trace_flags |= F_TRACER; - } - - - matches = erts_set_trace_pattern(mfa, specified, - match_prog_set, match_prog_set, - on, flags, meta_tracer_pid); - MatchSetUnref(match_prog_set); - - done: - UnUseTmpHeap(3,p); - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); + if (meta_tracer_proc) { + meta_tracer_proc->trace_flags |= F_TRACER; + } - return make_small(matches); + matches = erts_set_trace_pattern(mfa, specified, + match_prog_set, match_prog_set, + on, flags, meta_tracer_pid); + } error: - MatchSetUnref(match_prog_set); - UnUseTmpHeap(3,p); erts_smp_thr_progress_unblock(); erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); - BIF_ERROR(p, BADARG); + erts_release_code_write_permission(); + + if (matches >= 0) { + return make_small(matches); + } + else { + BIF_ERROR(p, BADARG); + } } void @@ -372,7 +367,10 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on, *meta_tracer_pid = erts_default_meta_tracer_pid; } - +int erts_is_default_trace_enabled(void) +{ + return erts_default_trace_pattern_is_on; +} Uint erts_trace_flag2bit(Eterm flag) @@ -466,6 +464,10 @@ Eterm trace_3(BIF_ALIST_3) BIF_ERROR(p, BADARG); } + if (!erts_try_seize_code_write_permission(BIF_P)) { + ERTS_BIF_YIELD3(bif_export[BIF_trace_3], BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3); + } + if (is_nil(tracer) || is_internal_pid(tracer)) { Process *tracer_proc = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN, @@ -730,6 +732,7 @@ Eterm trace_3(BIF_ALIST_3) erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); } #endif + erts_release_code_write_permission(); BIF_RET(make_small(matches)); @@ -745,6 +748,7 @@ Eterm trace_3(BIF_ALIST_3) erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); } #endif + erts_release_code_write_permission(); BIF_ERROR(p, BADARG); } @@ -990,7 +994,7 @@ static int function_is_traced(Process *p, e.code[1] = mfa[1]; e.code[2] = mfa[2]; if ((ep = export_get(&e)) != NULL) { - if (ep->address == ep->code+3 && + if (ep->addressv[erts_active_code_ix()] == ep->code+3 && ep->code[3] != (BeamInstr) em_call_error_handler) { if (ep->code[3] == (BeamInstr) em_call_traced_function) { *ms = ep->match_prog_set; @@ -1333,6 +1337,7 @@ erts_set_trace_pattern(Eterm* mfa, int specified, int on, struct trace_pattern_flags flags, Eterm meta_tracer_pid) { + const ErtsCodeIndex code_ix = erts_active_code_ix(); int matches = 0; int i; @@ -1340,8 +1345,8 @@ erts_set_trace_pattern(Eterm* mfa, int specified, * First work on normal functions (not real BIFs). */ - for (i = 0; i < export_list_size(); i++) { - Export* ep = export_list(i); + for (i = 0; i < export_list_size(code_ix); i++) { + Export* ep = export_list(i, code_ix); int j; if (ExportIsBuiltIn(ep)) { @@ -1355,11 +1360,11 @@ erts_set_trace_pattern(Eterm* mfa, int specified, if (j == specified) { if (on) { if (! flags.breakpoint) - matches += setup_func_trace(ep, match_prog_set); + matches += setup_func_trace(ep, match_prog_set, code_ix); else - reset_func_trace(ep); + reset_func_trace(ep, code_ix); } else if (! flags.breakpoint) { - matches += reset_func_trace(ep); + matches += reset_func_trace(ep, code_ix); } } } @@ -1522,9 +1527,11 @@ erts_set_trace_pattern(Eterm* mfa, int specified, */ static int -setup_func_trace(Export* ep, void* match_prog) +setup_func_trace(Export* ep, void* match_prog, ErtsCodeIndex code_ix) { - if (ep->address == ep->code+3) { + Module* modp; + + if (ep->addressv[code_ix] == ep->code+3) { if (ep->code[3] == (BeamInstr) em_call_error_handler) { return 0; } else if (ep->code[3] == (BeamInstr) em_call_traced_function) { @@ -1543,15 +1550,19 @@ setup_func_trace(Export* ep, void* match_prog) /* * Currently no trace support for native code. */ - if (erts_is_native_break(ep->address)) { + if (erts_is_native_break(ep->addressv[code_ix])) { return 0; } - + ep->code[3] = (BeamInstr) em_call_traced_function; - ep->code[4] = (BeamInstr) ep->address; - ep->address = ep->code+3; + ep->code[4] = (BeamInstr) ep->addressv[code_ix]; + ep->addressv[code_ix] = ep->code+3; ep->match_prog_set = match_prog; MatchSetRef(ep->match_prog_set); + + modp = erts_get_module(ep->code[0], code_ix); + ASSERT(modp); + modp->curr.num_traced_exports++; return 1; } @@ -1584,13 +1595,17 @@ static void set_trace_bif(int bif_index, void* match_prog) { */ static int -reset_func_trace(Export* ep) +reset_func_trace(Export* ep, ErtsCodeIndex code_ix) { - if (ep->address == ep->code+3) { + if (ep->addressv[code_ix] == ep->code+3) { if (ep->code[3] == (BeamInstr) em_call_error_handler) { return 0; } else if (ep->code[3] == (BeamInstr) em_call_traced_function) { - ep->address = (Uint *) ep->code[4]; + Module* modp = erts_get_module(ep->code[0], code_ix); + ASSERT(modp); + modp->curr.num_traced_exports--; + + ep->addressv[code_ix] = (Uint *) ep->code[4]; MatchSetUnref(ep->match_prog_set); ep->match_prog_set = NULL; return 1; @@ -1605,7 +1620,7 @@ reset_func_trace(Export* ep) /* * Currently no trace support for native code. */ - if (erts_is_native_break(ep->address)) { + if (erts_is_native_break(ep->addressv[code_ix])) { return 0; } diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 51bdf53823..5cbfa65378 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -2816,7 +2816,6 @@ void init_db(void) { DbTable init_tb; int i; - extern BeamInstr* em_apply_bif; Eterm *hp; unsigned bits; size_t size; @@ -2949,49 +2948,24 @@ void init_db(void) } /* Non visual BIF to trap to. */ - memset(&ets_select_delete_continue_exp, 0, sizeof(Export)); - ets_select_delete_continue_exp.address = - &ets_select_delete_continue_exp.code[3]; - ets_select_delete_continue_exp.code[0] = am_ets; - ets_select_delete_continue_exp.code[1] = am_atom_put("delete_trap",11); - ets_select_delete_continue_exp.code[2] = 1; - ets_select_delete_continue_exp.code[3] = - (BeamInstr) em_apply_bif; - ets_select_delete_continue_exp.code[4] = - (BeamInstr) &ets_select_delete_1; + erts_init_trap_export(&ets_select_delete_continue_exp, + am_ets, am_atom_put("delete_trap",11), 1, + &ets_select_delete_1); /* Non visual BIF to trap to. */ - memset(&ets_select_count_continue_exp, 0, sizeof(Export)); - ets_select_count_continue_exp.address = - &ets_select_count_continue_exp.code[3]; - ets_select_count_continue_exp.code[0] = am_ets; - ets_select_count_continue_exp.code[1] = am_atom_put("count_trap",11); - ets_select_count_continue_exp.code[2] = 1; - ets_select_count_continue_exp.code[3] = - (BeamInstr) em_apply_bif; - ets_select_count_continue_exp.code[4] = - (BeamInstr) &ets_select_count_1; + erts_init_trap_export(&ets_select_count_continue_exp, + am_ets, am_atom_put("count_trap",11), 1, + &ets_select_count_1); /* Non visual BIF to trap to. */ - memset(&ets_select_continue_exp, 0, sizeof(Export)); - ets_select_continue_exp.address = - &ets_select_continue_exp.code[3]; - ets_select_continue_exp.code[0] = am_ets; - ets_select_continue_exp.code[1] = am_atom_put("select_trap",11); - ets_select_continue_exp.code[2] = 1; - ets_select_continue_exp.code[3] = - (BeamInstr) em_apply_bif; - ets_select_continue_exp.code[4] = - (BeamInstr) &ets_select_trap_1; + erts_init_trap_export(&ets_select_continue_exp, + am_ets, am_atom_put("select_trap",11), 1, + &ets_select_trap_1); /* Non visual BIF to trap to. */ - memset(&ets_delete_continue_exp, 0, sizeof(Export)); - ets_delete_continue_exp.address = &ets_delete_continue_exp.code[3]; - ets_delete_continue_exp.code[0] = am_ets; - ets_delete_continue_exp.code[1] = am_atom_put("delete_trap",11); - ets_delete_continue_exp.code[2] = 1; - ets_delete_continue_exp.code[3] = (BeamInstr) em_apply_bif; - ets_delete_continue_exp.code[4] = (BeamInstr) &ets_delete_trap; + erts_init_trap_export(&ets_delete_continue_exp, + am_ets, am_atom_put("delete_trap",11), 1, + &ets_delete_trap); hp = ms_delete_all_buff; ms_delete_all = CONS(hp, am_true, NIL); diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c index 312050b931..faa7f31d99 100644 --- a/erts/emulator/beam/erl_db_tree.c +++ b/erts/emulator/beam/erl_db_tree.c @@ -452,16 +452,8 @@ DbTableMethod db_tree = void db_initialize_tree(void) { - memset(&ets_select_reverse_exp, 0, sizeof(Export)); - ets_select_reverse_exp.address = - &ets_select_reverse_exp.code[3]; - ets_select_reverse_exp.code[0] = am_ets; - ets_select_reverse_exp.code[1] = am_reverse; - ets_select_reverse_exp.code[2] = 3; - ets_select_reverse_exp.code[3] = - (BeamInstr) em_apply_bif; - ets_select_reverse_exp.code[4] = - (BeamInstr) &ets_select_reverse; + erts_init_trap_export(&ets_select_reverse_exp, am_ets, am_reverse, 3, + &ets_select_reverse); return; }; diff --git a/erts/emulator/beam/erl_fun.h b/erts/emulator/beam/erl_fun.h index 2f165afa06..6023fa0448 100644 --- a/erts/emulator/beam/erl_fun.h +++ b/erts/emulator/beam/erl_fun.h @@ -79,8 +79,6 @@ ErlFunEntry* erts_get_fun_entry(Eterm mod, int uniq, int index); ErlFunEntry* erts_put_fun_entry2(Eterm mod, int old_uniq, int old_index, byte* uniq, int index, int arity); -ErlFunEntry* erts_get_fun_entry2(Eterm mod, int old_uniq, int old_index, - byte* uniq, int index, int arity); void erts_erase_fun_entry(ErlFunEntry* fe); #ifndef HYBRID /* FIND ME! */ diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 717315d8bd..4db23a0a18 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -264,6 +264,7 @@ erl_init(int ncpu) erts_init_trace(); erts_init_binary(); erts_init_bits(); + erts_code_ix_init(); erts_init_fun_table(); init_atom_table(); init_export_table(); @@ -352,7 +353,8 @@ erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char** Eterm env; start_mod = am_atom_put(modname, sys_strlen(modname)); - if (erts_find_function(start_mod, am_start, 2) == NULL) { + if (erts_find_function(start_mod, am_start, 2, + erts_active_code_ix()) == NULL) { erl_exit(5, "No function %s:start/2\n", modname); } @@ -451,7 +453,7 @@ load_preloaded(void) if ((code = sys_preload_begin(&preload_p[i])) == 0) erl_exit(1, "Failed to find preloaded code for module %s\n", name); - res = erts_load_module(NULL, 0, NIL, &module_name, code, length); + res = erts_preload_module(NULL, 0, NIL, &module_name, code, length); sys_preload_end(&preload_p[i]); if (res != NIL) erl_exit(1,"Failed loading preloaded module %s (%T)\n", @@ -1471,6 +1473,8 @@ erl_start(int argc, char **argv) init_shared_memory(boot_argc, boot_argv); load_preloaded(); + erts_end_staging_code_ix(); + erts_commit_staging_code_ix(); erts_initialized = 1; diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c index 09e85893c3..8c7e1f36ee 100644 --- a/erts/emulator/beam/erl_lock_check.c +++ b/erts/emulator/beam/erl_lock_check.c @@ -84,6 +84,7 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "reg_tab", NULL }, { "migration_info_update", NULL }, { "proc_main", "pid" }, + { "old_code", "address" }, #ifdef HIPE { "hipe_mfait_lock", NULL }, #endif @@ -93,6 +94,7 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "proc_msgq", "pid" }, { "dist_entry", "address" }, { "dist_entry_links", "address" }, + { "code_ix_queue", NULL }, { "proc_status", "pid" }, { "proc_tab", NULL }, { "ports_snapshot", NULL }, @@ -443,7 +445,7 @@ print_lock2(char *prefix, Sint16 id, Wterm extra, Uint16 flags, char *suffix) "%s'%s:%p%s'%s%s", prefix, lname, - boxed_val(extra), + _unchecked_boxed_val(extra), lock_type(flags), rw_op_str(flags), suffix); diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 58a09986d2..bdbeb3bcf6 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -1513,6 +1513,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) if (len < 0) { BIF_ERROR(BIF_P, BADARG); } + lib_name = (char *) erts_alloc(ERTS_ALC_T_TMP, len + 1); if (intlist_to_buf(BIF_ARG_1, lib_name, len) != len) { @@ -1521,6 +1522,12 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) } lib_name[len] = '\0'; + if (!erts_try_seize_code_write_permission(BIF_P)) { + erts_free(ERTS_ALC_T_TMP, lib_name); + ERTS_BIF_YIELD2(bif_export[BIF_load_nif_2], + BIF_P, BIF_ARG_1, BIF_ARG_2); + } + /* Block system (is this the right place to do it?) */ erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); @@ -1534,11 +1541,11 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) ASSERT(caller != NULL); mod_atom = caller[0]; ASSERT(is_atom(mod_atom)); - mod=erts_get_module(mod_atom); + mod=erts_get_module(mod_atom, erts_active_code_ix()); ASSERT(mod != NULL); - if (!in_area(caller, mod->code, mod->code_length)) { - ASSERT(in_area(caller, mod->old_code, mod->old_code_length)); + if (!in_area(caller, mod->curr.code, mod->curr.code_length)) { + ASSERT(in_area(caller, mod->old.code, mod->old.code_length)); ret = load_nif_error(BIF_P, "old_code", "Calling load_nif from old " "module '%T' not allowed", mod_atom); @@ -1584,7 +1591,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) BeamInstr** code_pp; ErlNifFunc* f = &entry->funcs[i]; if (!erts_atom_get(f->name, sys_strlen(f->name), &f_atom) - || (code_pp = get_func_pp(mod->code, f_atom, f->arity))==NULL) { + || (code_pp = get_func_pp(mod->curr.code, f_atom, f->arity))==NULL) { ret = load_nif_error(BIF_P,bad_lib,"Function not found %T:%s/%u", mod_atom, f->name, f->arity); } @@ -1613,18 +1620,18 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) erts_refc_init(&lib->rt_dtor_cnt, 0); lib->mod = mod; env.mod_nif = lib; - if (mod->nif != NULL) { /* Reload */ + if (mod->curr.nif != NULL) { /* Reload */ int k; - lib->priv_data = mod->nif->priv_data; + lib->priv_data = mod->curr.nif->priv_data; - ASSERT(mod->nif->entry != NULL); + ASSERT(mod->curr.nif->entry != NULL); if (entry->reload == NULL) { ret = load_nif_error(BIF_P,reload,"Reload not supported by this NIF library."); goto error; } /* Check that no NIF is removed */ - for (k=0; k < mod->nif->entry->num_of_funcs; k++) { - ErlNifFunc* old_func = &mod->nif->entry->funcs[k]; + for (k=0; k < mod->curr.nif->entry->num_of_funcs; k++) { + ErlNifFunc* old_func = &mod->curr.nif->entry->funcs[k]; for (i=0; i < entry->num_of_funcs; i++) { if (old_func->arity == entry->funcs[i].arity && sys_strcmp(old_func->name, entry->funcs[i].name) == 0) { @@ -1645,24 +1652,24 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) ret = load_nif_error(BIF_P, reload, "Library reload-call unsuccessful."); } else { - mod->nif->entry = NULL; /* to prevent 'unload' callback */ - erts_unload_nif(mod->nif); + mod->curr.nif->entry = NULL; /* to prevent 'unload' callback */ + erts_unload_nif(mod->curr.nif); reload_warning = 1; } } else { lib->priv_data = NULL; - if (mod->old_nif != NULL) { /* Upgrade */ - void* prev_old_data = mod->old_nif->priv_data; + if (mod->old.nif != NULL) { /* Upgrade */ + void* prev_old_data = mod->old.nif->priv_data; if (entry->upgrade == NULL) { ret = load_nif_error(BIF_P, upgrade, "Upgrade not supported by this NIF library."); goto error; } erts_pre_nif(&env, BIF_P, lib); - veto = entry->upgrade(&env, &lib->priv_data, &mod->old_nif->priv_data, BIF_ARG_2); + veto = entry->upgrade(&env, &lib->priv_data, &mod->old.nif->priv_data, BIF_ARG_2); erts_post_nif(&env); if (veto) { - mod->old_nif->priv_data = prev_old_data; + mod->old.nif->priv_data = prev_old_data; ret = load_nif_error(BIF_P, upgrade, "Library upgrade-call unsuccessful."); } /*else if (mod->old_nif->priv_data != prev_old_data) { @@ -1682,12 +1689,12 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) /* ** Everything ok, patch the beam code with op_call_nif */ - mod->nif = lib; + mod->curr.nif = lib; for (i=0; i < entry->num_of_funcs; i++) { BeamInstr* code_ptr; erts_atom_get(entry->funcs[i].name, sys_strlen(entry->funcs[i].name), &f_atom); - code_ptr = *get_func_pp(mod->code, f_atom, entry->funcs[i].arity); + code_ptr = *get_func_pp(mod->curr.code, f_atom, entry->funcs[i].arity); if (code_ptr[1] == 0) { code_ptr[5+0] = (BeamInstr) BeamOp(op_call_nif); @@ -1715,6 +1722,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_release_code_write_permission(); erts_free(ERTS_ALC_T_TMP, lib_name); if (reload_warning) { diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c index 34da9cab84..2320b64295 100644 --- a/erts/emulator/beam/erl_printf_term.c +++ b/erts/emulator/beam/erl_printf_term.c @@ -437,7 +437,10 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, } break; case BINARY_DEF: - { + if (header_is_bin_matchstate(*boxed_val(wobj))) { + PRINT_STRING(res, fn, arg, "#MatchState"); + } + else { ProcBin* pb = (ProcBin *) binary_val(wobj); if (pb->size == 1) PRINT_STRING(res, fn, arg, "<<1 byte>>"); diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 138acfeb2c..6c136571d5 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -366,6 +366,9 @@ dbg_chk_aux_work_val(erts_aint32_t value) #ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN valid |= ERTS_SSI_AUX_WORK_CHECK_CHILDREN; #endif +#ifdef ERTS_SMP + valid |= ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION; +#endif if (~valid & value) erl_exit(ERTS_ABORT_EXIT, @@ -861,7 +864,7 @@ set_aux_work_flags_wakeup_nob(ErtsSchedulerSleepInfo *ssi, } } -#if 0 /* Currently not used */ +#ifdef ERTS_SMP static ERTS_INLINE void set_aux_work_flags_wakeup_relb(ErtsSchedulerSleepInfo *ssi, @@ -882,7 +885,7 @@ set_aux_work_flags_wakeup_relb(ErtsSchedulerSleepInfo *ssi, } } -#endif +#endif /* ERTS_SMP */ static ERTS_INLINE erts_aint32_t set_aux_work_flags(ErtsSchedulerSleepInfo *ssi, erts_aint32_t flgs) @@ -1145,7 +1148,45 @@ handle_async_ready_clean(ErtsAuxWorkData *awdp, } } +#endif /* ERTS_USE_ASYNC_READY_Q */ + +#ifdef ERTS_SMP +void +erts_notify_code_ix_activation(Process* p, ErtsThrPrgrVal later) +{ + ErtsAuxWorkData* awdp = &p->scheduler_data->aux_work_data; + ASSERT(awdp->code_ix_activation.code_stager == NULL); + awdp->code_ix_activation.code_stager = p; + awdp->code_ix_activation.thr_prgr = later; + erts_smp_proc_inc_refc(p); + set_aux_work_flags_wakeup_relb(p->scheduler_data->ssi, + ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION); +} + +static erts_aint32_t +handle_code_ix_activation(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) +{ + Process* p; + if (!erts_thr_progress_has_reached(awdp->code_ix_activation.thr_prgr)) { + return aux_work & ~ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION; + } + unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION); + p = awdp->code_ix_activation.code_stager; + ASSERT(p); +#ifdef DEBUG + awdp->code_ix_activation.code_stager = NULL; #endif + erts_commit_staging_code_ix(); + erts_release_code_write_permission(); + erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); + if (!ERTS_PROC_IS_EXITING(p)) { + erts_resume(p, ERTS_PROC_LOCK_STATUS); + } + erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + erts_smp_proc_dec_refc(p); + return aux_work & ~ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION; +} +#endif /* ERTS_SMP */ static ERTS_INLINE erts_aint32_t handle_fix_alloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) @@ -1451,6 +1492,10 @@ handle_aux_work(ErtsAuxWorkData *awdp, erts_aint32_t orig_aux_work) handle_mseg_cache_check); #endif +#ifdef ERTS_SMP + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION, + handle_code_ix_activation); +#endif ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); return aux_work; @@ -9599,13 +9644,8 @@ init_processes_bif(void) + 1); /* processes_trap/2 is a hidden BIF that the processes/0 BIF traps to. */ - sys_memset((void *) &processes_trap_export, 0, sizeof(Export)); - processes_trap_export.address = &processes_trap_export.code[3]; - processes_trap_export.code[0] = am_erlang; - processes_trap_export.code[1] = am_processes_trap; - processes_trap_export.code[2] = 2; - processes_trap_export.code[3] = (BeamInstr) em_apply_bif; - processes_trap_export.code[4] = (BeamInstr) &processes_trap; + erts_init_trap_export(&processes_trap_export, am_erlang, am_processes_trap, 2, + &processes_trap); #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST erts_get_emu_time(&debug_tv_start); diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index c23810f15a..3f19d92fcd 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -264,6 +264,7 @@ typedef enum { #define ERTS_SSI_AUX_WORK_CHECK_CHILDREN (((erts_aint32_t) 1) << 8) #define ERTS_SSI_AUX_WORK_SET_TMO (((erts_aint32_t) 1) << 9) #define ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK (((erts_aint32_t) 1) << 10) +#define ERTS_SSI_AUX_WORK_CODE_IX_ACTIVATION (((erts_aint32_t) 1) << 11) typedef struct ErtsSchedulerSleepInfo_ ErtsSchedulerSleepInfo; @@ -429,6 +430,12 @@ typedef struct { void *queue; } async_ready; #endif +#ifdef ERTS_SMP + struct { + Process* code_stager; + ErtsThrPrgrVal thr_prgr; + } code_ix_activation; +#endif } ErtsAuxWorkData; struct ErtsSchedulerData_ { @@ -1110,6 +1117,9 @@ void erts_smp_notify_check_children_needed(void); #if ERTS_USE_ASYNC_READY_Q void erts_notify_check_async_ready_queue(void *); #endif +#ifdef ERTS_SMP +void erts_notify_code_ix_activation(Process* p, ErtsThrPrgrVal later); +#endif void erts_schedule_misc_aux_work(int sched_id, void (*func)(void *), void *arg); diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c index 6d5eae73b0..049226ab7d 100644 --- a/erts/emulator/beam/erl_unicode.c +++ b/erts/emulator/beam/erl_unicode.c @@ -77,66 +77,25 @@ void erts_init_unicode(void) { max_loop_limit = CONTEXT_REDS * LOOP_FACTOR; /* Non visual BIFs to trap to. */ - memset(&characters_to_utf8_trap_exp, 0, sizeof(Export)); - characters_to_utf8_trap_exp.address = - &characters_to_utf8_trap_exp.code[3]; - characters_to_utf8_trap_exp.code[0] = am_erlang; - characters_to_utf8_trap_exp.code[1] = - am_atom_put("characters_to_utf8_trap",23); - characters_to_utf8_trap_exp.code[2] = 3; - characters_to_utf8_trap_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_utf8_trap_exp.code[4] = - (BeamInstr) &characters_to_utf8_trap; - - memset(&characters_to_list_trap_1_exp, 0, sizeof(Export)); - characters_to_list_trap_1_exp.address = - &characters_to_list_trap_1_exp.code[3]; - characters_to_list_trap_1_exp.code[0] = am_erlang; - characters_to_list_trap_1_exp.code[1] = - am_atom_put("characters_to_list_trap_1",25); - characters_to_list_trap_1_exp.code[2] = 3; - characters_to_list_trap_1_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_list_trap_1_exp.code[4] = - (BeamInstr) &characters_to_list_trap_1; - - memset(&characters_to_list_trap_2_exp, 0, sizeof(Export)); - characters_to_list_trap_2_exp.address = - &characters_to_list_trap_2_exp.code[3]; - characters_to_list_trap_2_exp.code[0] = am_erlang; - characters_to_list_trap_2_exp.code[1] = - am_atom_put("characters_to_list_trap_2",25); - characters_to_list_trap_2_exp.code[2] = 3; - characters_to_list_trap_2_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_list_trap_2_exp.code[4] = - (BeamInstr) &characters_to_list_trap_2; - - - memset(&characters_to_list_trap_3_exp, 0, sizeof(Export)); - characters_to_list_trap_3_exp.address = - &characters_to_list_trap_3_exp.code[3]; - characters_to_list_trap_3_exp.code[0] = am_erlang; - characters_to_list_trap_3_exp.code[1] = - am_atom_put("characters_to_list_trap_3",25); - characters_to_list_trap_3_exp.code[2] = 3; - characters_to_list_trap_3_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_list_trap_3_exp.code[4] = - (BeamInstr) &characters_to_list_trap_3; - - memset(&characters_to_list_trap_4_exp, 0, sizeof(Export)); - characters_to_list_trap_4_exp.address = - &characters_to_list_trap_4_exp.code[3]; - characters_to_list_trap_4_exp.code[0] = am_erlang; - characters_to_list_trap_4_exp.code[1] = - am_atom_put("characters_to_list_trap_4",25); - characters_to_list_trap_4_exp.code[2] = 1; - characters_to_list_trap_4_exp.code[3] = - (BeamInstr) em_apply_bif; - characters_to_list_trap_4_exp.code[4] = - (BeamInstr) &characters_to_list_trap_4; + erts_init_trap_export(&characters_to_utf8_trap_exp, + am_erlang, am_atom_put("characters_to_utf8_trap",23), 3, + &characters_to_utf8_trap); + + erts_init_trap_export(&characters_to_list_trap_1_exp, + am_erlang, am_atom_put("characters_to_list_trap_1",25), 3, + &characters_to_list_trap_1); + + erts_init_trap_export(&characters_to_list_trap_2_exp, + am_erlang, am_atom_put("characters_to_list_trap_2",25), 3, + &characters_to_list_trap_2); + + erts_init_trap_export(&characters_to_list_trap_3_exp, + am_erlang, am_atom_put("characters_to_list_trap_3",25), 3, + &characters_to_list_trap_3); + + erts_init_trap_export(&characters_to_list_trap_4_exp, + am_erlang, am_atom_put("characters_to_list_trap_4",25), 1, + &characters_to_list_trap_4); c_to_b_int_trap_exportp = erts_export_put(am_unicode,am_characters_to_binary_int,2); c_to_l_int_trap_exportp = erts_export_put(am_unicode,am_characters_to_list_int,2); diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index fb0ee99119..229641cb32 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -32,98 +32,163 @@ #define EXPORT_HASH(m,f,a) ((m)*(f)+(a)) -static IndexTable export_table; /* Not locked. */ -static Hash secondary_export_table; /* Locked. */ +#ifdef DEBUG +# define IF_DEBUG(x) x +#else +# define IF_DEBUG(x) +#endif -#include "erl_smp.h" +static IndexTable export_tables[ERTS_NUM_CODE_IX]; /* Active not locked */ -static erts_smp_rwmtx_t export_table_lock; /* Locks the secondary export table. */ +static erts_smp_atomic_t total_entries_bytes; -#define export_read_lock() erts_smp_rwmtx_rlock(&export_table_lock) -#define export_read_unlock() erts_smp_rwmtx_runlock(&export_table_lock) -#define export_write_lock() erts_smp_rwmtx_rwlock(&export_table_lock) -#define export_write_unlock() erts_smp_rwmtx_rwunlock(&export_table_lock) +#include "erl_smp.h" + +/* This lock protects the staging export table from concurrent access + * AND it protects the staging table from becoming active. + */ +erts_smp_mtx_t export_staging_lock; extern BeamInstr* em_call_error_handler; extern BeamInstr* em_call_traced_function; +struct export_entry +{ + IndexSlot slot; /* MUST BE LOCATED AT TOP OF STRUCT!!! */ + Export* ep; +}; + +/* Helper struct that brings things together in one allocation +*/ +struct export_blob +{ + Export exp; + struct export_entry entryv[ERTS_NUM_CODE_IX]; + /* Note that entryv is not indexed by "code_ix". + */ +}; + +/* Helper struct only used as template +*/ +struct export_templ +{ + struct export_entry entry; + Export exp; +}; + +static struct export_blob* entry_to_blob(struct export_entry* ee) +{ + return (struct export_blob*) + ((char*)ee->ep - offsetof(struct export_blob,exp)); +} + void export_info(int to, void *to_arg) { #ifdef ERTS_SMP int lock = !ERTS_IS_CRASH_DUMPING; if (lock) - export_read_lock(); + export_staging_lock(); #endif - index_info(to, to_arg, &export_table); - hash_info(to, to_arg, &secondary_export_table); + index_info(to, to_arg, &export_tables[erts_active_code_ix()]); + hash_info(to, to_arg, &export_tables[erts_staging_code_ix()].htable); #ifdef ERTS_SMP if (lock) - export_read_unlock(); + export_staging_unlock(); #endif } static HashValue -export_hash(Export* x) +export_hash(struct export_entry* ee) { + Export* x = ee->ep; return EXPORT_HASH(x->code[0], x->code[1], x->code[2]); } static int -export_cmp(Export* tmpl, Export* obj) +export_cmp(struct export_entry* tmpl_e, struct export_entry* obj_e) { + Export* tmpl = tmpl_e->ep; + Export* obj = obj_e->ep; return !(tmpl->code[0] == obj->code[0] && tmpl->code[1] == obj->code[1] && tmpl->code[2] == obj->code[2]); } -static Export* -export_alloc(Export* tmpl) +static struct export_entry* +export_alloc(struct export_entry* tmpl_e) { - Export* obj = (Export*) erts_alloc(ERTS_ALC_T_EXPORT, sizeof(Export)); - - obj->fake_op_func_info_for_hipe[0] = 0; - obj->fake_op_func_info_for_hipe[1] = 0; - obj->code[0] = tmpl->code[0]; - obj->code[1] = tmpl->code[1]; - obj->code[2] = tmpl->code[2]; - obj->slot.index = -1; - obj->address = obj->code+3; - obj->code[3] = (BeamInstr) em_call_error_handler; - obj->code[4] = 0; - obj->match_prog_set = NULL; - return obj; + struct export_blob* blob; + unsigned ix; + + if (tmpl_e->slot.index == -1) { /* Template, allocate blob */ + Export* tmpl = tmpl_e->ep; + Export* obj; + + blob = (struct export_blob*) erts_alloc(ERTS_ALC_T_EXPORT, sizeof(*blob)); + erts_smp_atomic_add_nob(&total_entries_bytes, sizeof(*blob)); + obj = &blob->exp; + obj->fake_op_func_info_for_hipe[0] = 0; + obj->fake_op_func_info_for_hipe[1] = 0; + obj->code[0] = tmpl->code[0]; + obj->code[1] = tmpl->code[1]; + obj->code[2] = tmpl->code[2]; + obj->code[3] = (BeamInstr) em_call_error_handler; + obj->code[4] = 0; + obj->match_prog_set = NULL; + + for (ix=0; ix<ERTS_NUM_CODE_IX; ix++) { + obj->addressv[ix] = obj->code+3; + + blob->entryv[ix].slot.index = -1; + blob->entryv[ix].ep = &blob->exp; + } + ix = 0; + } + else { /* Existing entry in another table, use free entry in blob */ + blob = entry_to_blob(tmpl_e); + for (ix = 0; blob->entryv[ix].slot.index >= 0; ix++) { + ASSERT(ix < ERTS_NUM_CODE_IX); + } + } + return &blob->entryv[ix]; } - -static void -export_free(Export* obj) +static void +export_free(struct export_entry* obj) { - erts_free(ERTS_ALC_T_EXPORT, (void*) obj); + struct export_blob* blob = entry_to_blob(obj); + int i; + obj->slot.index = -1; + for (i=0; i < ERTS_NUM_CODE_IX; i++) { + if (blob->entryv[i].slot.index >= 0) { + return; + } + } + erts_free(ERTS_ALC_T_EXPORT, blob); + erts_smp_atomic_add_nob(&total_entries_bytes, -sizeof(*blob)); } - void init_export_table(void) { HashFunctions f; - erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; - rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ; - rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED; + int i; - erts_smp_rwmtx_init_opt(&export_table_lock, &rwmtx_opt, "export_tab"); + erts_smp_mtx_init(&export_staging_lock, "export_tab"); + erts_smp_atomic_init_nob(&total_entries_bytes, 0); f.hash = (H_FUN) export_hash; f.cmp = (HCMP_FUN) export_cmp; f.alloc = (HALLOC_FUN) export_alloc; f.free = (HFREE_FUN) export_free; - erts_index_init(ERTS_ALC_T_EXPORT_TABLE, &export_table, "export_list", - EXPORT_INITIAL_SIZE, EXPORT_LIMIT, f); - hash_init(ERTS_ALC_T_EXPORT_TABLE, &secondary_export_table, - "secondary_export_table", 50, f); + for (i=0; i<ERTS_NUM_CODE_IX; i++) { + erts_index_init(ERTS_ALC_T_EXPORT_TABLE, &export_tables[i], "export_list", + EXPORT_INITIAL_SIZE, EXPORT_LIMIT, f); + } } /* @@ -138,29 +203,42 @@ init_export_table(void) * called through such an export entry. * 3) This function is suitable for the implementation of erlang:apply/3. */ +extern Export* /* inline-helper */ +erts_find_export_entry(Eterm m, Eterm f, unsigned int a,ErtsCodeIndex code_ix); Export* -erts_find_export_entry(Eterm m, Eterm f, unsigned int a) +erts_find_export_entry(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix) { HashValue hval = EXPORT_HASH((BeamInstr) m, (BeamInstr) f, (BeamInstr) a); int ix; HashBucket* b; - ix = hval % export_table.htable.size; - b = export_table.htable.bucket[ix]; + ix = hval % export_tables[code_ix].htable.size; + b = export_tables[code_ix].htable.bucket[ix]; /* * Note: We have inlined the code from hash.c for speed. */ while (b != (HashBucket*) 0) { - Export* ep = (Export *) b; + Export* ep = ((struct export_entry*) b)->ep; if (ep->code[0] == m && ep->code[1] == f && ep->code[2] == a) { - break; + return ep; } b = b->next; } - return (Export*)b; + return NULL; +} + +static struct export_entry* init_template(struct export_templ* templ, + Eterm m, Eterm f, unsigned a) +{ + templ->entry.ep = &templ->exp; + templ->entry.slot.index = -1; + templ->exp.code[0] = m; + templ->exp.code[1] = f; + templ->exp.code[2] = a; + return &templ->entry; } @@ -176,47 +254,41 @@ erts_find_export_entry(Eterm m, Eterm f, unsigned int a) */ Export* -erts_find_function(Eterm m, Eterm f, unsigned int a) +erts_find_function(Eterm m, Eterm f, unsigned int a, ErtsCodeIndex code_ix) { - Export e; - Export* ep; - - e.code[0] = m; - e.code[1] = f; - e.code[2] = a; + struct export_templ templ; + struct export_entry* ee; - ep = hash_get(&export_table.htable, (void*) &e); - if (ep != NULL && ep->address == ep->code+3 && - ep->code[3] != (BeamInstr) em_call_traced_function) { - ep = NULL; + ee = hash_get(&export_tables[code_ix].htable, init_template(&templ, m, f, a)); + if (ee == NULL || (ee->ep->addressv[code_ix] == ee->ep->code+3 && + ee->ep->code[3] != (BeamInstr) em_call_traced_function)) { + return NULL; } - return ep; + return ee->ep; } /* * Returns a pointer to an existing export entry for a MFA, * or creates a new one and returns the pointer. * - * This function provides unlocked write access to the main export - * table. It should only be used during start up or when - * all other threads are blocked. + * This function acts on the staging export table. It should only be used + * to load new code. */ Export* erts_export_put(Eterm mod, Eterm func, unsigned int arity) { - Export e; - int ix; + ErtsCodeIndex code_ix = erts_staging_code_ix(); + struct export_templ templ; + struct export_entry* ee; - ERTS_SMP_LC_ASSERT(erts_initialized == 0 - || erts_smp_thr_progress_is_blocking()); ASSERT(is_atom(mod)); ASSERT(is_atom(func)); - e.code[0] = mod; - e.code[1] = func; - e.code[2] = arity; - ix = index_put(&export_table, (void*) &e); - return (Export*) erts_index_lookup(&export_table, ix); + export_staging_lock(); + ee = (struct export_entry*) index_put_entry(&export_tables[code_ix], + init_template(&templ, mod, func, arity)); + export_staging_unlock(); + return ee->ep; } /* @@ -224,77 +296,117 @@ erts_export_put(Eterm mod, Eterm func, unsigned int arity) * export entry (making a call through it will cause the error_handler to * be called). * - * Stub export entries will be placed in the secondary export table. - * erts_export_consolidate() will move all stub export entries into the - * main export table (will be done the next time code is loaded). + * Stub export entries will be placed in the loader export table. */ Export* erts_export_get_or_make_stub(Eterm mod, Eterm func, unsigned int arity) { - Export e; + ErtsCodeIndex code_ix; Export* ep; + IF_DEBUG(int retrying = 0;) ASSERT(is_atom(mod)); ASSERT(is_atom(func)); - - e.code[0] = mod; - e.code[1] = func; - e.code[2] = arity; - ep = erts_find_export_entry(mod, func, arity); - if (ep == 0) { - /* - * The code is not loaded (yet). Put the export in the secondary - * export table, to avoid having to lock the main export table. - */ - export_write_lock(); - ep = (Export *) hash_put(&secondary_export_table, (void*) &e); - export_write_unlock(); - } + + do { + code_ix = erts_active_code_ix(); + ep = erts_find_export_entry(mod, func, arity, code_ix); + if (ep == 0) { + /* + * The code is not loaded (yet). Put the export in the staging + * export table, to avoid having to lock the active export table. + */ + export_staging_lock(); + if (erts_active_code_ix() == code_ix) { + struct export_templ templ; + struct export_entry* entry; + + IndexTable* tab = &export_tables[erts_staging_code_ix()]; + init_template(&templ, mod, func, arity); + entry = (struct export_entry *) index_put_entry(tab, &templ.entry); + ep = entry->ep; + ASSERT(ep); + } + else { /* race */ + ASSERT(!retrying); + IF_DEBUG(retrying = 1); + } + export_staging_unlock(); + } + } while (!ep); return ep; } -/* - * To be called before loading code (with other threads blocked). - * This function will move all export entries from the secondary - * export table into the primary. - */ -void -erts_export_consolidate(void) +Export *export_list(int i, ErtsCodeIndex code_ix) { -#ifdef DEBUG - HashInfo hi; -#endif - - ERTS_SMP_LC_ASSERT(erts_initialized == 0 - || erts_smp_thr_progress_is_blocking()); - - export_write_lock(); - erts_index_merge(&secondary_export_table, &export_table); - erts_hash_merge(&secondary_export_table, &export_table.htable); - export_write_unlock(); -#ifdef DEBUG - hash_get_info(&hi, &export_table.htable); - ASSERT(export_table.entries == hi.objs); -#endif + return ((struct export_entry*) erts_index_lookup(&export_tables[code_ix], i))->ep; } -Export *export_list(int i) +int export_list_size(ErtsCodeIndex code_ix) { - return (Export*) erts_index_lookup(&export_table, i); + return export_tables[code_ix].entries; } -int export_list_size(void) +int export_table_sz(void) { - return export_table.entries; + int i, bytes = 0; + + export_staging_lock(); + for (i=0; i<ERTS_NUM_CODE_IX; i++) { + bytes += index_table_sz(&export_tables[i]); + } + export_staging_unlock(); + return bytes; +} +int export_entries_sz(void) +{ + return erts_smp_atomic_read_nob(&total_entries_bytes); +} +Export *export_get(Export *e) +{ + struct export_entry ee; + struct export_entry* entry; + + ee.ep = e; + entry = (struct export_entry*)hash_get(&export_tables[erts_active_code_ix()].htable, &ee); + return entry ? entry->ep : NULL; } -int export_table_sz(void) +IF_DEBUG(static ErtsCodeIndex debug_start_load_ix = 0;) + + +void export_start_staging(void) { - return index_table_sz(&export_table); + ErtsCodeIndex dst_ix = erts_staging_code_ix(); + ErtsCodeIndex src_ix = erts_active_code_ix(); + IndexTable* dst = &export_tables[dst_ix]; + IndexTable* src = &export_tables[src_ix]; + struct export_entry* src_entry; + struct export_entry* dst_entry; + int i; + + ASSERT(dst_ix != src_ix); + ASSERT(debug_start_load_ix == -1); + + export_staging_lock(); + /* + * Insert all entries in src into dst table + */ + for (i = 0; i < src->entries; i++) { + src_entry = (struct export_entry*) erts_index_lookup(src, i); + src_entry->ep->addressv[dst_ix] = src_entry->ep->addressv[src_ix]; + dst_entry = (struct export_entry*) index_put_entry(dst, src_entry); + ASSERT(entry_to_blob(src_entry) == entry_to_blob(dst_entry)); + } + export_staging_unlock(); + + IF_DEBUG(debug_start_load_ix = dst_ix); } -Export *export_get(Export *e) +void export_end_staging(int commit) { - return hash_get(&export_table.htable, e); + ASSERT(debug_start_load_ix == erts_staging_code_ix()); + IF_DEBUG(debug_start_load_ix = -1); } + diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h index c604fdf7c3..ec9fcb26f2 100644 --- a/erts/emulator/beam/export.h +++ b/erts/emulator/beam/export.h @@ -28,13 +28,15 @@ #include "index.h" #endif +#include "code_ix.h" + /* ** Export entry */ + typedef struct export { - IndexSlot slot; /* MUST BE LOCATED AT TOP OF STRUCT!!! */ - void* address; /* Pointer to code for function. */ + void* addressv[ERTS_NUM_CODE_IX]; /* Pointer to code for function. */ struct binary* match_prog_set; /* Match program for tracing. */ BeamInstr fake_op_func_info_for_hipe[2]; /* MUST be just before code[] */ @@ -59,21 +61,38 @@ typedef struct export void init_export_table(void); void export_info(int, void *); -Export* erts_find_export_entry(Eterm m, Eterm f, unsigned int a); +ERTS_GLB_INLINE Export* erts_active_export_entry(Eterm m, Eterm f, unsigned a); Export* erts_export_put(Eterm mod, Eterm func, unsigned int arity); - Export* erts_export_get_or_make_stub(Eterm, Eterm, unsigned); -void erts_export_consolidate(void); -Export *export_list(int); -int export_list_size(void); +Export *export_list(int,ErtsCodeIndex); +int export_list_size(ErtsCodeIndex); int export_table_sz(void); +int export_entries_sz(void); Export *export_get(Export*); +void export_start_staging(void); +void export_end_staging(int commit); + +extern erts_smp_mtx_t export_staging_lock; +#define export_staging_lock() erts_smp_mtx_lock(&export_staging_lock) +#define export_staging_unlock() erts_smp_mtx_unlock(&export_staging_lock) #include "beam_load.h" /* For em_* extern declarations */ #define ExportIsBuiltIn(EntryPtr) \ -(((EntryPtr)->address == (EntryPtr)->code + 3) && \ +(((EntryPtr)->addressv[erts_active_code_ix()] == (EntryPtr)->code + 3) && \ ((EntryPtr)->code[3] == (BeamInstr) em_apply_bif)) -#endif +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE Export* +erts_active_export_entry(Eterm m, Eterm f, unsigned int a) +{ + extern Export* erts_find_export_entry(Eterm m, Eterm f, unsigned a, ErtsCodeIndex); + return erts_find_export_entry(m, f, a, erts_active_code_ix()); +} + +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ + +#endif /* __EXPORT_H__ */ + diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index 9d52ed4e98..25f593640c 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -2562,7 +2562,7 @@ dec_term_atom_common: goto error; } if (edep && (edep->flags & ERTS_DIST_EXT_BTT_SAFE)) { - if (!erts_find_export_entry(mod, name, arity)) + if (!erts_active_export_entry(mod, name, arity)) goto error; } *objp = make_export(hp); diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index f1335f600d..6eac0db363 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -28,6 +28,7 @@ #include "hash.h" #include "index.h" #include "atom.h" +#include "code_ix.h" #include "export.h" #include "module.h" #include "register.h" @@ -847,6 +848,8 @@ void erts_queue_monitor_message(Process *, Eterm, Eterm, Eterm); +void erts_init_trap_export(Export* ep, Eterm m, Eterm f, Uint a, + Eterm (*bif)(Process*,Eterm*)); void erts_init_bif(void); Eterm erl_send(Process *p, Eterm to, Eterm msg); @@ -869,24 +872,33 @@ typedef struct { Eterm* fname_ptr; /* Pointer to fname table */ } FunctionInfo; -struct LoaderState* erts_alloc_loader_state(void); -Eterm erts_prepare_loading(struct LoaderState*, Process *c_p, +Binary* erts_alloc_loader_state(void); +Eterm erts_module_for_prepared_code(Binary* magic); +Eterm erts_prepare_loading(Binary* loader_state, Process *c_p, Eterm group_leader, Eterm* modp, byte* code, Uint size); -Eterm erts_finish_loading(struct LoaderState* stp, Process* c_p, +Eterm erts_finish_loading(Binary* loader_state, Process* c_p, ErtsProcLocks c_p_locks, Eterm* modp); -Eterm erts_load_module(Process *c_p, ErtsProcLocks c_p_locks, - Eterm group_leader, Eterm* mod, byte* code, Uint size); +Eterm erts_preload_module(Process *c_p, ErtsProcLocks c_p_locks, + Eterm group_leader, Eterm* mod, byte* code, Uint size); void init_load(void); BeamInstr* find_function_from_pc(BeamInstr* pc); Eterm* erts_build_mfa_item(FunctionInfo* fi, Eterm* hp, Eterm args, Eterm* mfa_p); -void erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info); void erts_set_current_function(FunctionInfo* fi, BeamInstr* current); Eterm erts_module_info_0(Process* p, Eterm module); Eterm erts_module_info_1(Process* p, Eterm module, Eterm what); Eterm erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info); +/* beam_ranges.c */ +void erts_init_ranges(void); +void erts_start_staging_ranges(void); +void erts_end_staging_ranges(int commit); +void erts_update_ranges(BeamInstr* code, Uint size); +void erts_remove_from_ranges(BeamInstr* code); +UWord erts_ranges_sz(void); +void erts_lookup_function_info(FunctionInfo* fi, BeamInstr* pc, int full_info); + /* break.c */ void init_break_handler(void); void erts_set_ignore_break(void); @@ -1483,7 +1495,7 @@ void erts_cleanup_offheap(ErlOffHeap *offheap); Uint erts_fit_in_bits(Uint); int list_length(Eterm); -Export* erts_find_function(Eterm, Eterm, unsigned int); +Export* erts_find_function(Eterm, Eterm, unsigned int, ErtsCodeIndex); int erts_is_builtin(Eterm, Eterm, int); Uint32 make_broken_hash(Eterm); Uint32 block_hash(byte *, unsigned, Uint32); @@ -1761,6 +1773,7 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on, Binary **meta_match_spec, struct trace_pattern_flags *trace_pattern_flags, Eterm *meta_tracer_pid); +int erts_is_default_trace_enabled(void); void erts_bif_trace_init(void); /* diff --git a/erts/emulator/beam/index.c b/erts/emulator/beam/index.c index a4a3007f93..25d5cce0f3 100644 --- a/erts/emulator/beam/index.c +++ b/erts/emulator/beam/index.c @@ -68,14 +68,14 @@ erts_index_init(ErtsAlcType_t type, IndexTable* t, char* name, return t; } -int -index_put(IndexTable* t, void* tmpl) +IndexSlot* +index_put_entry(IndexTable* t, void* tmpl) { int ix; IndexSlot* p = (IndexSlot*) hash_put(&t->htable, tmpl); if (p->index >= 0) { - return p->index; + return p; } ix = t->entries; @@ -92,7 +92,7 @@ index_put(IndexTable* t, void* tmpl) t->entries++; p->index = ix; t->seg_table[ix>>INDEX_PAGE_SHIFT][ix&INDEX_PAGE_MASK] = p; - return ix; + return p; } int index_get(IndexTable* t, void* tmpl) @@ -135,3 +135,18 @@ void erts_index_merge(Hash* src, IndexTable* dst) } } } + +void index_erase_latest_from(IndexTable* t, Uint from_ix) +{ + if(from_ix < (Uint)t->entries) { + int ix; + for (ix = from_ix; ix < t->entries; ix++) { + IndexSlot* obj = t->seg_table[ix>>INDEX_PAGE_SHIFT][ix&INDEX_PAGE_MASK]; + hash_erase(&t->htable, obj); + } + t->entries = from_ix; + } + else { + ASSERT(from_ix == t->entries); + } +} diff --git a/erts/emulator/beam/index.h b/erts/emulator/beam/index.h index 4eb9b1f992..3afe48d007 100644 --- a/erts/emulator/beam/index.h +++ b/erts/emulator/beam/index.h @@ -55,12 +55,24 @@ void index_info(int, void *, IndexTable*); int index_table_sz(IndexTable *); int index_get(IndexTable*, void*); -int index_put(IndexTable*, void*); + +IndexSlot* index_put_entry(IndexTable*, void*); void erts_index_merge(Hash*, IndexTable*); +/* Erase all entries with index 'ix' and higher +*/ +void index_erase_latest_from(IndexTable*, Uint ix); + +ERTS_GLB_INLINE int index_put(IndexTable*, void*); ERTS_GLB_INLINE IndexSlot* erts_index_lookup(IndexTable*, Uint); #if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE int index_put(IndexTable* t, void* tmpl) +{ + return index_put_entry(t, tmpl)->index; +} + ERTS_GLB_INLINE IndexSlot* erts_index_lookup(IndexTable* t, Uint ix) { diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c index b93b1ad09a..1ef71cda79 100644 --- a/erts/emulator/beam/module.c +++ b/erts/emulator/beam/module.c @@ -26,21 +26,32 @@ #include "global.h" #include "module.h" +#ifdef DEBUG +# define IF_DEBUG(x) x +#else +# define IF_DEBUG(x) +#endif + #define MODULE_SIZE 50 #define MODULE_LIMIT (64*1024) -static IndexTable module_table; +static IndexTable module_tables[ERTS_NUM_CODE_IX]; -/* - * SMP note: We don't need to look accesses to the module table because - * there is one only scheduler thread when we update it. +erts_smp_rwmtx_t the_old_code_rwlocks[ERTS_NUM_CODE_IX]; + +static erts_smp_atomic_t tot_module_bytes; + +/* SMP note: Active module table lookup and current module instance can be + * read without any locks. Old module instances are protected by + * "the_old_code_rwlocks" as purging is done on active module table. + * Staging table is protected by the "code_ix lock". */ #include "erl_smp.h" void module_info(int to, void *to_arg) { - index_info(to, to_arg, &module_table); + index_info(to, to_arg, &module_tables[erts_active_code_ix()]); } @@ -59,45 +70,67 @@ static int module_cmp(Module* tmpl, Module* obj) static Module* module_alloc(Module* tmpl) { Module* obj = (Module*) erts_alloc(ERTS_ALC_T_MODULE, sizeof(Module)); + erts_smp_atomic_add_nob(&tot_module_bytes, sizeof(Module)); obj->module = tmpl->module; - obj->code = 0; - obj->old_code = 0; - obj->code_length = 0; - obj->old_code_length = 0; + obj->curr.code = 0; + obj->old.code = 0; + obj->curr.code_length = 0; + obj->old.code_length = 0; obj->slot.index = -1; - obj->nif = NULL; - obj->old_nif = NULL; + obj->curr.nif = NULL; + obj->old.nif = NULL; + obj->curr.num_breakpoints = 0; + obj->old.num_breakpoints = 0; + obj->curr.num_traced_exports = 0; + obj->old.num_traced_exports = 0; return obj; } +static void module_free(Module* mod) +{ + erts_free(ERTS_ALC_T_MODULE, mod); + erts_smp_atomic_add_nob(&tot_module_bytes, -sizeof(Module)); +} void init_module_table(void) { HashFunctions f; + int i; f.hash = (H_FUN) module_hash; f.cmp = (HCMP_FUN) module_cmp; f.alloc = (HALLOC_FUN) module_alloc; - f.free = 0; + f.free = (HFREE_FUN) module_free; + + for (i = 0; i < ERTS_NUM_CODE_IX; i++) { + erts_index_init(ERTS_ALC_T_MODULE_TABLE, &module_tables[i], "module_code", + MODULE_SIZE, MODULE_LIMIT, f); + } - erts_index_init(ERTS_ALC_T_MODULE_TABLE, &module_table, "module_code", - MODULE_SIZE, MODULE_LIMIT, f); + for (i=0; i<ERTS_NUM_CODE_IX; i++) { + erts_smp_rwmtx_init_x(&the_old_code_rwlocks[i], "old_code", make_small(i)); + } + erts_smp_atomic_init_nob(&tot_module_bytes, 0); } Module* -erts_get_module(Eterm mod) +erts_get_module(Eterm mod, ErtsCodeIndex code_ix) { Module e; int index; + IndexTable* mod_tab; ASSERT(is_atom(mod)); + + mod_tab = &module_tables[code_ix]; + e.module = atom_val(mod); - index = index_get(&module_table, (void*) &e); + index = index_get(mod_tab, (void*) &e); if (index == -1) { return NULL; } else { - return (Module*) erts_index_lookup(&module_table, index); + return (Module*) erts_index_lookup(mod_tab, index); } } @@ -105,27 +138,101 @@ Module* erts_put_module(Eterm mod) { Module e; - int index; + IndexTable* mod_tab; + int oldsz, newsz; + Module* res; ASSERT(is_atom(mod)); ERTS_SMP_LC_ASSERT(erts_initialized == 0 - || erts_smp_thr_progress_is_blocking()); + || erts_is_code_ix_locked()); + + mod_tab = &module_tables[erts_staging_code_ix()]; e.module = atom_val(mod); - index = index_put(&module_table, (void*) &e); - return (Module*) erts_index_lookup(&module_table, index); + oldsz = index_table_sz(mod_tab); + res = (Module*) index_put_entry(mod_tab, (void*) &e); + newsz = index_table_sz(mod_tab); + erts_smp_atomic_add_nob(&tot_module_bytes, (newsz - oldsz)); + return res; } -Module *module_code(int i) +Module *module_code(int i, ErtsCodeIndex code_ix) { - return (Module*) erts_index_lookup(&module_table, i); + return (Module*) erts_index_lookup(&module_tables[code_ix], i); } -int module_code_size(void) +int module_code_size(ErtsCodeIndex code_ix) { - return module_table.entries; + return module_tables[code_ix].entries; } int module_table_sz(void) { - return index_table_sz(&module_table); + return erts_smp_atomic_read_nob(&tot_module_bytes); +} + +#ifdef DEBUG +static ErtsCodeIndex dbg_load_code_ix = 0; +#endif + +static int entries_at_start_staging = 0; + +void module_start_staging(void) +{ + IndexTable* src = &module_tables[erts_active_code_ix()]; + IndexTable* dst = &module_tables[erts_staging_code_ix()]; + Module* src_mod; + Module* dst_mod; + int i, oldsz, newsz; + + ASSERT(dbg_load_code_ix == -1); + ASSERT(dst->entries <= src->entries); + + /* + * Make sure our existing modules are up-to-date + */ + for (i = 0; i < dst->entries; i++) { + src_mod = (Module*) erts_index_lookup(src, i); + dst_mod = (Module*) erts_index_lookup(dst, i); + ASSERT(src_mod->module == dst_mod->module); + + dst_mod->curr = src_mod->curr; + dst_mod->old = src_mod->old; + } + + /* + * Copy all new modules from active table + */ + oldsz = index_table_sz(dst); + for (i = dst->entries; i < src->entries; i++) { + src_mod = (Module*) erts_index_lookup(src, i); + dst_mod = (Module*) index_put_entry(dst, src_mod); + ASSERT(dst_mod != src_mod); + + dst_mod->curr = src_mod->curr; + dst_mod->old = src_mod->old; + } + newsz = index_table_sz(dst); + erts_smp_atomic_add_nob(&tot_module_bytes, (newsz - oldsz)); + + entries_at_start_staging = dst->entries; + IF_DEBUG(dbg_load_code_ix = erts_staging_code_ix()); +} + +void module_end_staging(int commit) +{ + ASSERT(dbg_load_code_ix == erts_staging_code_ix()); + + if (!commit) { /* abort */ + IndexTable* tab = &module_tables[erts_staging_code_ix()]; + int oldsz, newsz; + + ASSERT(entries_at_start_staging <= tab->entries); + oldsz = index_table_sz(tab); + index_erase_latest_from(tab, entries_at_start_staging); + newsz = index_table_sz(tab); + erts_smp_atomic_add_nob(&tot_module_bytes, (newsz - oldsz)); + } + + IF_DEBUG(dbg_load_code_ix = -1); } + diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h index 694e4ab72f..6e123a0ffe 100644 --- a/erts/emulator/beam/module.h +++ b/erts/emulator/beam/module.h @@ -24,28 +24,72 @@ #include "index.h" #endif +struct erl_module_instance { + BeamInstr* code; + int code_length; /* Length of loaded code in bytes. */ + unsigned catches; + struct erl_module_nif* nif; + int num_breakpoints; + int num_traced_exports; +}; typedef struct erl_module { IndexSlot slot; /* Must be located at top of struct! */ int module; /* Atom index for module (not tagged). */ - BeamInstr* code; - BeamInstr* old_code; - int code_length; /* Length of loaded code in bytes. */ - int old_code_length; /* Length of old loaded code in bytes */ - unsigned catches, old_catches; - struct erl_module_nif* nif; - struct erl_module_nif* old_nif; + struct erl_module_instance curr; + struct erl_module_instance old; /* protected by "old_code" rwlock */ } Module; -Module* erts_get_module(Eterm mod); +Module* erts_get_module(Eterm mod, ErtsCodeIndex code_ix); Module* erts_put_module(Eterm mod); void init_module_table(void); +void module_start_staging(void); +void module_end_staging(int commit); void module_info(int, void *); -Module *module_code(int); -int module_code_size(void); +Module *module_code(int, ErtsCodeIndex); +int module_code_size(ErtsCodeIndex); int module_table_sz(void); +ERTS_GLB_INLINE void erts_rwlock_old_code(ErtsCodeIndex); +ERTS_GLB_INLINE void erts_rwunlock_old_code(ErtsCodeIndex); +ERTS_GLB_INLINE void erts_rlock_old_code(ErtsCodeIndex); +ERTS_GLB_INLINE void erts_runlock_old_code(ErtsCodeIndex); +#ifdef ERTS_ENABLE_LOCK_CHECK +int erts_is_old_code_rlocked(ErtsCodeIndex); +#endif + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +extern erts_smp_rwmtx_t the_old_code_rwlocks[ERTS_NUM_CODE_IX]; + +ERTS_GLB_INLINE void erts_rwlock_old_code(ErtsCodeIndex code_ix) +{ + erts_smp_rwmtx_rwlock(&the_old_code_rwlocks[code_ix]); +} +ERTS_GLB_INLINE void erts_rwunlock_old_code(ErtsCodeIndex code_ix) +{ + erts_smp_rwmtx_rwunlock(&the_old_code_rwlocks[code_ix]); +} +ERTS_GLB_INLINE void erts_rlock_old_code(ErtsCodeIndex code_ix) +{ + erts_smp_rwmtx_rlock(&the_old_code_rwlocks[code_ix]); +} +ERTS_GLB_INLINE void erts_runlock_old_code(ErtsCodeIndex code_ix) +{ + erts_smp_rwmtx_runlock(&the_old_code_rwlocks[code_ix]); +} + +#ifdef ERTS_ENABLE_LOCK_CHECK +ERTS_GLB_INLINE int erts_is_old_code_rlocked(ErtsCodeIndex code_ix) +{ + return erts_smp_lc_rwmtx_is_rlocked(&the_old_code_rwlocks[code_ix]); +} #endif + +#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ + + +#endif /* !__MODULE_H__ */ diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index fc53a88a3a..f051f6aa5b 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -829,16 +829,20 @@ call_ext_only Ar=u==2 Bif=u$bif:erlang:load_nif/2 => allocate u Ar | i_call_ext # -# The apply/2 and apply/3 BIFs are instructions. +# apply/2 is an instruction, not a BIF. # call_ext u==2 u$func:erlang:apply/2 => i_apply_fun call_ext_last u==2 u$func:erlang:apply/2 D => i_apply_fun_last D call_ext_only u==2 u$func:erlang:apply/2 => i_apply_fun_only -call_ext u==3 u$func:erlang:apply/3 => i_apply -call_ext_last u==3 u$func:erlang:apply/3 D => i_apply_last D -call_ext_only u==3 u$func:erlang:apply/3 => i_apply_only +# +# The apply/3 BIF is an instruction. +# + +call_ext u==3 u$bif:erlang:apply/3 => i_apply +call_ext_last u==3 u$bif:erlang:apply/3 D => i_apply_last D +call_ext_only u==3 u$bif:erlang:apply/3 => i_apply_only # # The exit/1 and throw/1 BIFs never execute the instruction following them; diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 47a99fdbe6..608bb5ecaa 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -535,6 +535,12 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #endif /* __WIN32__ */ +#ifdef HAVE_SOCKLEN_T +# define SOCKLEN_T socklen_t +#else +# define SOCKLEN_T int +#endif + #include "packet_parser.h" #define get_int24(s) ((((unsigned char*) (s))[0] << 16) | \ @@ -5340,13 +5346,8 @@ static int setopt_prio_tos_trick int res; int res_prio; int res_tos; -#ifdef HAVE_SOCKLEN_T - socklen_t -#else - int -#endif - tmp_arg_sz_prio = sizeof(tmp_ival_prio), - tmp_arg_sz_tos = sizeof(tmp_ival_tos); + SOCKLEN_T tmp_arg_sz_prio = sizeof(tmp_ival_prio); + SOCKLEN_T tmp_arg_sz_tos = sizeof(tmp_ival_tos); res_prio = sock_getopt(fd, SOL_SOCKET, SO_PRIORITY, (char *) &tmp_ival_prio, &tmp_arg_sz_prio); @@ -7754,8 +7755,8 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, desc->state = INET_STATE_BOUND; if ((port = inet_address_port(&local)) == 0) { - len = sizeof(local); - sock_name(desc->s, (struct sockaddr*) &local, (unsigned int*)&len); + SOCKLEN_T adrlen = sizeof(local); + sock_name(desc->s, &local.sa, &adrlen); port = inet_address_port(&local); } port = sock_ntohs(port); diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index 28e4382835..6340c39e69 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -609,8 +609,8 @@ static Uint *hipe_find_emu_address(Eterm mod, Eterm name, unsigned int arity) Uint *code_base; int i, n; - modp = erts_get_module(mod); - if (modp == NULL || (code_base = modp->code) == NULL) + modp = erts_get_module(mod, erts_active_code_ix()); + if (modp == NULL || (code_base = modp->curr.code) == NULL) return NULL; n = code_base[MI_NUM_FUNCTIONS]; for (i = 0; i < n; ++i) { @@ -648,7 +648,7 @@ static void *hipe_get_emu_address(Eterm m, Eterm f, unsigned int arity, int is_r /* if not found, stub it via the export entry */ /* no lock needed around erts_export_get_or_make_stub() */ Export *export_entry = erts_export_get_or_make_stub(m, f, arity); - address = export_entry->address; + address = export_entry->addressv[erts_active_code_ix()]; } return address; } @@ -1591,7 +1591,7 @@ BIF_RETTYPE hipe_nonclosure_address(BIF_ALIST_2) f = tp[2]; if (is_not_atom(m) || is_not_atom(f)) goto badfun; - if (!erts_find_export_entry(m, f, BIF_ARG_2)) + if (!erts_active_export_entry(m, f, BIF_ARG_2)) goto badfun; } else goto badfun; diff --git a/erts/emulator/hipe/hipe_bif2.c b/erts/emulator/hipe/hipe_bif2.c index ee97541e15..4d42efc1cc 100644 --- a/erts/emulator/hipe/hipe_bif2.c +++ b/erts/emulator/hipe/hipe_bif2.c @@ -189,3 +189,10 @@ BIF_RETTYPE hipe_debug_bif_wrapper(BIF_ALIST_1) #endif /* ERTS_ENABLE_LOCK_CHECK && ERTS_SMP */ + +BIF_RETTYPE hipe_bifs_debug_native_called_2(BIF_ALIST_2) +{ + erts_printf("hipe_debug_native_called: %T(%T)\r\n", BIF_ARG_1, BIF_ARG_2); + BIF_RET(am_ok); +} + diff --git a/erts/emulator/hipe/hipe_bif2.tab b/erts/emulator/hipe/hipe_bif2.tab index 51323ce7af..d43ee40c5d 100644 --- a/erts/emulator/hipe/hipe_bif2.tab +++ b/erts/emulator/hipe/hipe_bif2.tab @@ -30,3 +30,4 @@ bif hipe_bifs:in_native/0 bif hipe_bifs:modeswitch_debug_on/0 bif hipe_bifs:modeswitch_debug_off/0 bif hipe_bifs:show_message_area/0 +bif hipe_bifs:debug_native_called/2 diff --git a/erts/emulator/hipe/hipe_bif_list.m4 b/erts/emulator/hipe/hipe_bif_list.m4 index 942fa0c5cb..d9aa09b79e 100644 --- a/erts/emulator/hipe/hipe_bif_list.m4 +++ b/erts/emulator/hipe/hipe_bif_list.m4 @@ -165,6 +165,7 @@ gc_bif_interface_2(nbif_put_2, put_2) gc_bif_interface_1(nbif_hipe_bifs_show_nstack_1, hipe_show_nstack_1) gc_bif_interface_1(nbif_hipe_bifs_show_pcb_1, hipe_bifs_show_pcb_1) gc_bif_interface_0(nbif_hipe_bifs_nstack_used_size_0, hipe_bifs_nstack_used_size_0) +gc_bif_interface_2(nbif_hipe_bifs_debug_native_called, hipe_bifs_debug_native_called_2) /* * Arithmetic operators called indirectly by the HiPE compiler. diff --git a/erts/emulator/hipe/hipe_native_bif.h b/erts/emulator/hipe/hipe_native_bif.h index 9e3a156fbc..3f460a5a5c 100644 --- a/erts/emulator/hipe/hipe_native_bif.h +++ b/erts/emulator/hipe/hipe_native_bif.h @@ -110,6 +110,9 @@ int hipe_bs_put_big_integer(Eterm, Uint, byte*, unsigned, unsigned); AEXTERN(Eterm,nbif_check_get_msg,(Process*)); Eterm hipe_check_get_msg(Process*); +AEXTERN(BIF_RETTYPE,nbif_hipe_bifs_debug_native_called,(Process*,Eterm,Eterm)); +BIF_RETTYPE hipe_bifs_debug_native_called_2(BIF_ALIST_2); + /* * SMP-specific stuff */ diff --git a/erts/emulator/hipe/hipe_primops.h b/erts/emulator/hipe/hipe_primops.h index 38509c105b..52b4681cfe 100644 --- a/erts/emulator/hipe/hipe_primops.h +++ b/erts/emulator/hipe/hipe_primops.h @@ -80,6 +80,7 @@ PRIMOP_LIST(am_fclearerror_error, &nbif_fclearerror_error) #ifdef NO_FPE_SIGNALS PRIMOP_LIST(am_emulate_fpe, &nbif_emulate_fpe) #endif +PRIMOP_LIST(am_debug_native_called, &nbif_hipe_bifs_debug_native_called) #if defined(__sparc__) #include "hipe_sparc_primops.h" diff --git a/erts/emulator/hipe/hipe_stack.c b/erts/emulator/hipe/hipe_stack.c index da462a64e1..53c316ba52 100644 --- a/erts/emulator/hipe/hipe_stack.c +++ b/erts/emulator/hipe/hipe_stack.c @@ -130,7 +130,7 @@ struct sdesc *hipe_decode_sdesc(Eterm arg) struct sdesc *sdesc; if (is_not_tuple(arg) || - (tuple_val(arg))[0] != make_arityval(5) || + (tuple_val(arg))[0] != make_arityval(6) || term_to_Uint((tuple_val(arg))[1], &ra) == 0 || term_to_Uint((tuple_val(arg))[2], &exnra) == 0 || is_not_small((tuple_val(arg))[3]) || @@ -183,5 +183,13 @@ struct sdesc *hipe_decode_sdesc(Eterm arg) off = unsigned_val(live[i]); sdesc->livebits[off / 32] |= (1 << (off & 31)); } +#ifdef DEBUG + { + Eterm mfa_tpl = tuple_val(arg)[6]; + sdesc->dbg_M = tuple_val(mfa_tpl)[1]; + sdesc->dbg_F = tuple_val(mfa_tpl)[2]; + sdesc->dbg_A = tuple_val(mfa_tpl)[3]; + } +#endif return sdesc; } diff --git a/erts/emulator/hipe/hipe_stack.h b/erts/emulator/hipe/hipe_stack.h index 4c14b4a519..f2dab4fbcf 100644 --- a/erts/emulator/hipe/hipe_stack.h +++ b/erts/emulator/hipe/hipe_stack.h @@ -35,6 +35,10 @@ struct sdesc { struct sdesc *next; /* hash collision chain */ } bucket; unsigned int summary; /* frame size, exn handler presence flag, arity */ +#ifdef DEBUG + Eterm dbg_M, dbg_F; + unsigned dbg_A; +#endif unsigned int livebits[1]; /* size depends on arch & data in summary field */ }; diff --git a/erts/emulator/hipe/hipe_x86_gc.h b/erts/emulator/hipe/hipe_x86_gc.h index e4607ad27d..aa4abb6f59 100644 --- a/erts/emulator/hipe/hipe_x86_gc.h +++ b/erts/emulator/hipe/hipe_x86_gc.h @@ -69,6 +69,11 @@ nstack_walk_init_sdesc(const Process *p, struct nstack_walk_state *state) nstkarity = 0; state->sdesc0[0].summary = (0 << 9) | (0 << 8) | nstkarity; state->sdesc0[0].livebits[0] = 0; +# ifdef DEBUG + state->sdesc0[0].dbg_M = 0; + state->sdesc0[0].dbg_F = am_init; + state->sdesc0[0].dbg_A = 0; +# endif /* XXX: this appears to prevent a gcc-4.1.1 bug on x86 */ __asm__ __volatile__("" : : "m"(*state) : "memory"); return &state->sdesc0[0]; diff --git a/erts/emulator/hipe/hipe_x86_glue.h b/erts/emulator/hipe/hipe_x86_glue.h index b0db93267c..63ad250d60 100644 --- a/erts/emulator/hipe/hipe_x86_glue.h +++ b/erts/emulator/hipe/hipe_x86_glue.h @@ -62,6 +62,9 @@ static __inline__ void hipe_arch_glue_init(void) .sdesc = { .bucket = { .hvalue = (unsigned long)nbif_return }, .summary = (1<<8), + #ifdef DEBUG + .dbg_F = am_return, + #endif }, }; hipe_init_sdesc_table(&nbif_return_sdesc.sdesc); diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile index a3dcbc4cf3..efa3cd475f 100644 --- a/erts/emulator/test/Makefile +++ b/erts/emulator/test/Makefile @@ -47,6 +47,7 @@ MODULES= \ busy_port_SUITE \ call_trace_SUITE \ code_SUITE \ + code_parallel_load_SUITE \ crypto_SUITE \ ddll_SUITE \ decode_packet_SUITE \ diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl index c7617d3b90..90c89cc12b 100644 --- a/erts/emulator/test/bif_SUITE.erl +++ b/erts/emulator/test/bif_SUITE.erl @@ -25,7 +25,9 @@ init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, display/1, display_huge/0, - types/1, + erl_bif_types/1,guard_bifs_in_erl_bif_types/1, + shadow_comments/1, + specs/1,improper_bif_stubs/1,auto_imports/1, t_list_to_existing_atom/1,os_env/1,otp_7526/1, binary_to_atom/1,binary_to_existing_atom/1, atom_to_binary/1,min_max/1]). @@ -33,7 +35,9 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [types, t_list_to_existing_atom, os_env, otp_7526, + [erl_bif_types, guard_bifs_in_erl_bif_types, shadow_comments, + specs, improper_bif_stubs, auto_imports, + t_list_to_existing_atom, os_env, otp_7526, display, atom_to_binary, binary_to_atom, binary_to_existing_atom, min_max]. @@ -86,33 +90,20 @@ deeep(N,Acc) -> deeep(N) -> deeep(N,[hello]). +erl_bif_types(Config) when is_list(Config) -> + ensure_erl_bif_types_compiled(), -types(Config) when is_list(Config) -> - c:l(erl_bif_types), - case erlang:function_exported(erl_bif_types, module_info, 0) of - false -> - %% Fail cleanly. - ?line ?t:fail("erl_bif_types not compiled"); - true -> - types_1() - end. - -types_1() -> - ?line List0 = erlang:system_info(snifs), + List0 = erlang:system_info(snifs), %% Ignore missing type information for hipe BIFs. - ?line List = [MFA || {M,_,_}=MFA <- List0, M =/= hipe_bifs], + List = [MFA || {M,_,_}=MFA <- List0, M =/= hipe_bifs], - case [MFA || MFA <- List, not known_types(MFA)] of - [] -> - types_2(List); - BadTypes -> - io:put_chars("No type information:\n"), - io:format("~p\n", [lists:sort(BadTypes)]), - ?line ?t:fail({length(BadTypes),bifs_without_types}) - end. + KnownTypes = [MFA || MFA <- List, known_types(MFA)], + io:format("There are ~p BIFs with type information in erl_bif_types.", + [length(KnownTypes)]), + erl_bif_types_2(KnownTypes). -types_2(List) -> +erl_bif_types_2(List) -> BadArity = [MFA || {M,F,A}=MFA <- List, begin Types = erl_bif_types:arg_types(M, F, A), @@ -120,14 +111,14 @@ types_2(List) -> end], case BadArity of [] -> - types_3(List); + erl_bif_types_3(List); [_|_] -> io:put_chars("Bifs with bad arity\n"), io:format("~p\n", [BadArity]), ?line ?t:fail({length(BadArity),bad_arity}) end. -types_3(List) -> +erl_bif_types_3(List) -> BadSmokeTest = [MFA || {M,F,A}=MFA <- List, begin try erl_bif_types:type(M, F, A) of @@ -151,9 +142,220 @@ types_3(List) -> ?line ?t:fail({length(BadSmokeTest),bad_smoke_test}) end. +guard_bifs_in_erl_bif_types(_Config) -> + ensure_erl_bif_types_compiled(), + + List0 = erlang:system_info(snifs), + List = [{F,A} || {erlang,F,A} <- List0, + erl_internal:guard_bif(F, A)], + Not = [FA || {F,A}=FA <- List, + not erl_bif_types:is_known(erlang, F, A)], + case Not of + [] -> + ok; + [_|_] -> + io:put_chars( + ["Dialyzer requires that all guard BIFs " + "have type information in erl_bif_types.\n\n" + "The following guard BIFs have no type information " + "in erl_bif_types:\n\n", + [io_lib:format(" ~p/~p\n", [F,A]) || {F,A} <- Not]]), + ?t:fail() + end. + +shadow_comments(_Config) -> + ensure_erl_bif_types_compiled(), + + List0 = erlang:system_info(snifs), + List1 = [MFA || {M,_,_}=MFA <- List0, M =/= hipe_bifs], + List = [MFA || MFA <- List1, not is_operator(MFA)], + HasTypes = [MFA || {M,F,A}=MFA <- List, + erl_bif_types:is_known(M, F, A)], + Path = get_code_path(), + BifRel = sofs:relation(HasTypes, [{m,f,a}]), + BifModules = sofs:to_external(sofs:projection(1, BifRel)), + AbstrByModule = [extract_abstract(Mod, Path) || Mod <- BifModules], + Specs0 = [extract_specs(Mod, Abstr) || + {Mod,Abstr} <- AbstrByModule], + Specs = lists:append(Specs0), + SpecFuns0 = [F || {F,_} <- Specs], + SpecFuns = sofs:relation(SpecFuns0, [{m,f,a}]), + HasTypesAndSpecs = sofs:intersection(BifRel, SpecFuns), + Commented0 = lists:append([extract_comments(Mod, Path) || + Mod <- BifModules]), + Commented = sofs:relation(Commented0, [{m,f,a}]), + {NoComments0,_,NoBifSpecs0} = + sofs:symmetric_partition(HasTypesAndSpecs, Commented), + NoComments = sofs:to_external(NoComments0), + NoBifSpecs = sofs:to_external(NoBifSpecs0), + + case NoComments of + [] -> + ok; + [_|_] -> + io:put_chars( + ["If a BIF stub has both a spec and has type information in " + "erl_bif_types, there *must*\n" + "be a comment in the source file to make that immediately " + "obvious.\n\nThe following comments are missing:\n\n", + [io_lib:format("%% Shadowed by erl_bif_types: ~p:~p/~p\n", + [M,F,A]) || {M,F,A} <- NoComments]]), + ?t:fail() + end, + + case NoBifSpecs of + [] -> + ok; + [_|_] -> + io:put_chars( + ["The following functions have \"shadowed\" comments " + "claiming that there is type information in erl_bif_types,\n" + "but actually there is no such type information.\n\n" + "Therefore, the following comments should be removed:\n\n", + [io_lib:format("%% Shadowed by erl_bif_types: ~p:~p/~p\n", + [M,F,A]) || {M,F,A} <- NoBifSpecs]]), + ?t:fail() + end. + +extract_comments(Mod, Path) -> + Beam = which(Mod, Path), + SrcDir = filename:join(filename:dirname(filename:dirname(Beam)), "src"), + Src = filename:join(SrcDir, atom_to_list(Mod) ++ ".erl"), + {ok,Bin} = file:read_file(Src), + Lines0 = binary:split(Bin, <<"\n">>, [global]), + Lines1 = [T || <<"%% Shadowed by erl_bif_types: ",T/binary>> <- Lines0], + {ok,ReMFA} = re:compile("([^:]*):([^/]*)/(\\d*)"), + Lines = [L || L <- Lines1, re:run(L, ReMFA, [{capture,[]}]) =:= match], + [begin + {match,[M,F,A]} = re:run(L, ReMFA, [{capture,all_but_first,list}]), + {list_to_atom(M),list_to_atom(F),list_to_integer(A)} + end || L <- Lines]. + +ensure_erl_bif_types_compiled() -> + c:l(erl_bif_types), + case erlang:function_exported(erl_bif_types, module_info, 0) of + false -> + %% Fail cleanly. + ?t:fail("erl_bif_types not compiled"); + true -> + ok + end. + known_types({M,F,A}) -> erl_bif_types:is_known(M, F, A). +specs(_) -> + List0 = erlang:system_info(snifs), + + %% Ignore missing type information for hipe BIFs. + List1 = [MFA || {M,_,_}=MFA <- List0, M =/= hipe_bifs], + + %% Ignore all operators. + List = [MFA || MFA <- List1, not is_operator(MFA)], + + %% Extract specs from the abstract code for all BIFs. + Path = get_code_path(), + BifRel = sofs:relation(List, [{m,f,a}]), + BifModules = sofs:to_external(sofs:projection(1, BifRel)), + AbstrByModule = [extract_abstract(Mod, Path) || Mod <- BifModules], + Specs0 = [extract_specs(Mod, Abstr) || + {Mod,Abstr} <- AbstrByModule], + Specs = lists:append(Specs0), + BifSet = sofs:set(List, [function]), + SpecRel0 = sofs:relation(Specs, [{function,spec}]), + SpecRel = sofs:restriction(SpecRel0, BifSet), + + %% Find BIFs without specs. + NoSpecs0 = sofs:difference(BifSet, sofs:domain(SpecRel)), + NoSpecs = sofs:to_external(NoSpecs0), + case NoSpecs of + [] -> + ok; + [_|_] -> + io:put_chars("The following BIFs don't have specs:\n"), + [print_mfa(MFA) || MFA <- NoSpecs], + ?t:fail() + end. + +is_operator({erlang,F,A}) -> + erl_internal:arith_op(F, A) orelse + erl_internal:bool_op(F, A) orelse + erl_internal:comp_op(F, A) orelse + erl_internal:list_op(F, A) orelse + erl_internal:send_op(F, A); +is_operator(_) -> false. + +extract_specs(M, Abstr) -> + [{make_mfa(M, Name),Spec} || {attribute,_,spec,{Name,Spec}} <- Abstr]. + +make_mfa(M, {F,A}) -> {M,F,A}; +make_mfa(M, {M,_,_}=MFA) -> MFA. + +improper_bif_stubs(_) -> + Bifs0 = erlang:system_info(snifs), + Bifs = [MFA || {M,_,_}=MFA <- Bifs0, M =/= hipe_bifs], + Path = get_code_path(), + BifRel = sofs:relation(Bifs, [{m,f,a}]), + BifModules = sofs:to_external(sofs:projection(1, BifRel)), + AbstrByModule = [extract_abstract(Mod, Path) || Mod <- BifModules], + Funcs0 = [extract_functions(Mod, Abstr) || + {Mod,Abstr} <- AbstrByModule], + Funcs = lists:append(Funcs0), + BifSet = sofs:set(Bifs, [function]), + FuncRel0 = sofs:relation(Funcs, [{function,code}]), + FuncRel = sofs:restriction(FuncRel0, BifSet), + [check_stub(MFA, Body) || {MFA,Body} <- sofs:to_external(FuncRel)], + ok. + +auto_imports(_Config) -> + Path = get_code_path(), + {erlang,Abstr} = extract_abstract(erlang, Path), + SpecFuns = [Name || {attribute,_,spec,{Name,_}} <- Abstr], + auto_imports(SpecFuns, 0). + +auto_imports([{F,A}|T], Errors) -> + case erl_internal:bif(F, A) of + false -> + io:format("~p/~p: not auto-imported, but spec claims it " + "is auto-imported", [F,A]), + auto_imports(T, Errors+1); + true -> + auto_imports(T, Errors) + end; +auto_imports([{erlang,F,A}|T], Errors) -> + case erl_internal:bif(F, A) of + false -> + auto_imports(T, Errors); + true -> + io:format("~p/~p: auto-imported, but " + "spec claims it is *not* auto-imported", [F,A]), + auto_imports(T, Errors+1) + end; +auto_imports([], 0) -> + ok; +auto_imports([], Errors) -> + ?t:fail({Errors,inconsistencies}). + +extract_functions(M, Abstr) -> + [{{M,F,A},Body} || {function,_,F,A,Body} <- Abstr]. + +check_stub({erlang,apply,3}, _) -> + ok; +check_stub({_,F,A}, B) -> + try + [{clause,_,Args,[],Body}] = B, + A = length(Args), + [{call,_,{remote,_,{atom,_,erlang},{atom,_,nif_error}},[_]}] = Body + catch + _:_ -> + io:put_chars("Invalid body for the following BIF stub:\n"), + Func = {function,0,F,A,B}, + io:put_chars(erl_pp:function(Func)), + io:nl(), + io:put_chars("The body should be: erlang:nif_error(undef)"), + ?t:fail() + end. + t_list_to_existing_atom(Config) when is_list(Config) -> ?line all = list_to_existing_atom("all"), ?line ?MODULE = list_to_existing_atom(?MODULE_STRING), @@ -442,3 +644,30 @@ min_max(Config) when is_list(Config) -> id(I) -> I. +%% Get code path, including the path for the erts application. +get_code_path() -> + case code:lib_dir(erts) of + {error,bad_name} -> + Erts = filename:join([code:root_dir(),"erts","preloaded","ebin"]), + [Erts|code:get_path()]; + _ -> + code:get_path() + end. + +which(Mod, Path) -> + which_1(atom_to_list(Mod) ++ ".beam", Path). + +which_1(Base, [D|Ds]) -> + Path = filename:join(D, Base), + case filelib:is_regular(Path) of + true -> Path; + false -> which_1(Base, Ds) + end. +print_mfa({M,F,A}) -> + io:format("~p:~p/~p", [M,F,A]). + +extract_abstract(Mod, Path) -> + Beam = which(Mod, Path), + {ok,{Mod,[{abstract_code,{raw_abstract_v1,Abstr}}]}} = + beam_lib:chunks(Beam, [abstract_code]), + {Mod,Abstr}. diff --git a/erts/emulator/test/call_trace_SUITE.erl b/erts/emulator/test/call_trace_SUITE.erl index 7030ebed3f..67212cd469 100644 --- a/erts/emulator/test/call_trace_SUITE.erl +++ b/erts/emulator/test/call_trace_SUITE.erl @@ -25,6 +25,7 @@ init_per_testcase/2,end_per_testcase/2, hipe/1,process_specs/1,basic/1,flags/1,errors/1,pam/1,change_pam/1, return_trace/1,exception_trace/1,on_load/1,deep_exception/1, + upgrade/1, exception_nocatch/1,bit_syntax/1]). %% Helper functions. @@ -46,6 +47,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> Common = [errors, on_load], NotHipe = [process_specs, basic, flags, pam, change_pam, + upgrade, return_trace, exception_trace, deep_exception, exception_nocatch, bit_syntax], Hipe = [hipe], @@ -267,6 +269,118 @@ foo() -> foo0. foo(X) -> X+1. foo(X, Y) -> X+Y. + +%% Note that the semantics that this test case verifies +%% are not explicitly specified in the docs (what I could find in R15B). +%% This test case was written to verify that we do not change +%% any behaviour with the introduction of "block-free" upgrade in R16. +%% In short: Do not refer to this test case as an authority of how it must work. +upgrade(doc) -> + "Test tracing on module being upgraded"; +upgrade(Config) when is_list(Config) -> + V1 = compile_version(my_upgrade_test, 1, Config), + V2 = compile_version(my_upgrade_test, 2, Config), + start_tracer(), + upgrade_do(V1, V2, false), + upgrade_do(V1, V2, true). + +upgrade_do(V1, V2, TraceLocalVersion) -> + {module,my_upgrade_test} = erlang:load_module(my_upgrade_test, V1), + + + %% Test that trace is cleared after load_module + + trace_func({my_upgrade_test,'_','_'}, [], [global]), + case TraceLocalVersion of + true -> trace_func({my_upgrade_test,local_version,0}, [], [local]); + _ -> ok + end, + 1 = my_upgrade_test:version(), + 1 = my_upgrade_test:do_local(), + 1 = my_upgrade_test:do_real_local(), + put('F1_exp', my_upgrade_test:make_fun_exp()), + put('F1_loc', my_upgrade_test:make_fun_local()), + 1 = (get('F1_exp'))(), + 1 = (get('F1_loc'))(), + + Self = self(), + expect({trace,Self,call,{my_upgrade_test,version,[]}}), + expect({trace,Self,call,{my_upgrade_test,do_local,[]}}), + expect({trace,Self,call,{my_upgrade_test,do_real_local,[]}}), + case TraceLocalVersion of + true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); + _ -> ok + end, + expect({trace,Self,call,{my_upgrade_test,make_fun_exp,[]}}), + expect({trace,Self,call,{my_upgrade_test,make_fun_local,[]}}), + expect({trace,Self,call,{my_upgrade_test,version,[]}}), % F1_exp + case TraceLocalVersion of + true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); % F1_loc + _ -> ok + end, + + {module,my_upgrade_test} = erlang:load_module(my_upgrade_test, V2), + 2 = my_upgrade_test:version(), + put('F2_exp', my_upgrade_test:make_fun_exp()), + put('F2_loc', my_upgrade_test:make_fun_local()), + 2 = (get('F1_exp'))(), + 1 = (get('F1_loc'))(), + 2 = (get('F2_exp'))(), + 2 = (get('F2_loc'))(), + expect(), + + put('F1_exp', undefined), + put('F1_loc', undefined), + erlang:garbage_collect(), + erlang:purge_module(my_upgrade_test), + + % Test that trace is cleared after delete_module + + trace_func({my_upgrade_test,'_','_'}, [], [global]), + case TraceLocalVersion of + true -> trace_func({my_upgrade_test,local_version,0}, [], [local]); + _ -> ok + end, + 2 = my_upgrade_test:version(), + 2 = my_upgrade_test:do_local(), + 2 = my_upgrade_test:do_real_local(), + 2 = (get('F2_exp'))(), + 2 = (get('F2_loc'))(), + + expect({trace,Self,call,{my_upgrade_test,version,[]}}), + expect({trace,Self,call,{my_upgrade_test,do_local,[]}}), + expect({trace,Self,call,{my_upgrade_test,do_real_local,[]}}), + case TraceLocalVersion of + true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); + _ -> ok + end, + expect({trace,Self,call,{my_upgrade_test,version,[]}}), % F2_exp + case TraceLocalVersion of + true -> expect({trace,Self,call,{my_upgrade_test,local_version,[]}}); % F2_loc + _ -> ok + end, + + true = erlang:delete_module(my_upgrade_test), + {'EXIT',{undef,_}} = (catch my_upgrade_test:version()), + {'EXIT',{undef,_}} = (catch ((get('F2_exp'))())), + 2 = (get('F2_loc'))(), + expect(), + + put('F2_exp', undefined), + put('F2_loc', undefined), + erlang:garbage_collect(), + erlang:purge_module(my_upgrade_test), + ok. + +compile_version(Module, Version, Config) -> + Data = ?config(data_dir, Config), + File = filename:join(Data, atom_to_list(Module)), + {ok,Module,Bin} = compile:file(File, [{d,'VERSION',Version}, + binary,report]), + Bin. + + + %% Test flags (arity, timestamp) for call_trace/3. %% Also, test the '{tracer,Pid}' option. flags(_Config) -> @@ -1151,11 +1265,13 @@ trace_info(What, Key) -> Res. trace_func(MFA, MatchSpec) -> - get(tracer) ! {apply,self(),{erlang,trace_pattern,[MFA, MatchSpec]}}, + trace_func(MFA, MatchSpec, []). +trace_func(MFA, MatchSpec, Flags) -> + get(tracer) ! {apply,self(),{erlang,trace_pattern,[MFA, MatchSpec, Flags]}}, Res = receive {apply_result,Result} -> Result end, - ok = io:format("trace_pattern(~p, ~p) -> ~p", [MFA,MatchSpec,Res]), + ok = io:format("trace_pattern(~p, ~p, ~p) -> ~p", [MFA,MatchSpec,Flags,Res]), Res. trace_pid(Pid, On, Flags) -> diff --git a/erts/emulator/test/call_trace_SUITE_data/my_upgrade_test.erl b/erts/emulator/test/call_trace_SUITE_data/my_upgrade_test.erl new file mode 100644 index 0000000000..11b8a95209 --- /dev/null +++ b/erts/emulator/test/call_trace_SUITE_data/my_upgrade_test.erl @@ -0,0 +1,26 @@ +-module(my_upgrade_test). + +-export([version/0]). +-export([do_local/0]). +-export([do_real_local/0]). +-export([make_fun_exp/0]). +-export([make_fun_local/0]). + + +version() -> + ?VERSION. + +do_local() -> + version(). + +do_real_local() -> + local_version(). + +local_version() -> + ?VERSION. + +make_fun_exp() -> + fun() -> ?MODULE:version() end. + +make_fun_local() -> + fun() -> local_version() end. diff --git a/erts/emulator/test/code_parallel_load_SUITE.erl b/erts/emulator/test/code_parallel_load_SUITE.erl new file mode 100644 index 0000000000..aa9e4c96c6 --- /dev/null +++ b/erts/emulator/test/code_parallel_load_SUITE.erl @@ -0,0 +1,198 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% Author: Björn-Egil Dahlberg + +-module(code_parallel_load_SUITE). +-export([ + all/0, + suite/0, + init_per_suite/1, + end_per_suite/1, + init_per_testcase/2, + end_per_testcase/2 + ]). + +-export([ + multiple_load_check_purge_repeat/1, + many_load_distributed_only_once/1 + ]). + +-define(model, code_parallel_load_SUITE_model). +-define(interval, 50). +-define(number_of_processes, 160). +-define(passes, 4). + + +-include_lib("test_server/include/test_server.hrl"). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [ + multiple_load_check_purge_repeat, + many_load_distributed_only_once + ]. + + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> + Dog=?t:timetrap(?t:minutes(3)), + [{watchdog, Dog}|Config]. + +end_per_testcase(_Func, Config) -> + SConf = ?config(save_config, Config), + Pids = proplists:get_value(purge_pids, SConf), + + case check_old_code(?model) of + true -> check_and_purge_processes_code(Pids, ?model); + _ -> ok + end, + case erlang:delete_module(?model) of + true -> check_and_purge_processes_code(Pids, ?model); + _ -> ok + end, + Dog=?config(watchdog, Config), + ?t:timetrap_cancel(Dog). + + +multiple_load_check_purge_repeat(_Conf) -> + Ts = [v1,v2,v3,v4,v5,v6], + + %% generate code that receives a token, code switches to new code + %% then matches this token against a literal code token + %% should be identical + %% (smoke test for parallel code loading + Codes = [{T, generate(?model, [], [ + format("check(T) -> receive {_Pid, change, T1} -> " + " ~w:check(T1)\n" + " after 0 -> T = f(), check(T) end.\n", [?model]), + format("f() -> ~w.~n", [T]) + ])} || T <- Ts], + + Pids = setup_code_changer(Codes), + {save_config, [{purge_pids,Pids}]}. + +setup_code_changer([{Token,Code}|Cs] = Codes) -> + {module, ?model} = erlang:load_module(?model,Code), + Pids = setup_checkers(Token,?number_of_processes), + code_changer(Cs, Codes, ?interval,Pids,?passes), + Pids. + +code_changer(_, _, _, Pids, 0) -> + [unlink(Pid) || Pid <- Pids], + [exit(Pid, die) || Pid <- Pids], + io:format("done~n"), + ok; +code_changer([], Codes, T, Pids, Ps) -> + code_changer(Codes, Codes, T, Pids, Ps - 1); +code_changer([{Token,Code}|Cs], Codes, T, Pids, Ps) -> + receive after T -> + io:format("load code with token ~4w : pass ~4w~n", [Token, Ps]), + {module, ?model} = erlang:load_module(?model, Code), + % this is second time we call load_module for this module + % so it should have old code + [Pid ! {self(), change, Token} || Pid <- Pids], + % should we wait a moment or just blantantly try to check and purge repeatadly? + receive after 1 -> ok end, + ok = check_and_purge_processes_code(Pids, ?model), + code_changer(Cs, Codes, T, Pids, Ps) + end. + + + +many_load_distributed_only_once(_Conf) -> + Ts = [<<"first version">>, <<"second version">>], + + [{Token1,Code1},{Token2, Code2}] = [{T, generate(?model, [], [ + "check({<<\"second version\">> = V, Pid}) -> V = f(), Pid ! {self(), completed, V}, ok;\n" ++ + format("check(T) -> receive {Pid, change, T1, B} -> " + " Res = erlang:load_module(~w, B), Pid ! {self(), change, Res},\n" + " ~w:check({T1, Pid})\n" + " after 0 -> T = f(), check(T) end.\n", [?model, ?model]), + format("f() -> ~w.~n", [T]) + ])} || T <- Ts], + + + {module, ?model} = erlang:load_module(?model, Code1), + Pids = setup_checkers(Token1,?number_of_processes), + + receive after 1000 -> ok end, % give 'em some time to spin up + [Pid ! {self(), change, Token2, Code2} || Pid <- Pids], + Loads = [receive {Pid, change, Res} -> Res end || Pid <- Pids], + [receive {Pid, completed, Token2} -> ok end || Pid <- Pids], + + ok = ensure_only_one_load(Loads, 0), + {save_config, [{purge_pids,Pids}]}. + +ensure_only_one_load([], 1) -> ok; +ensure_only_one_load([], _) -> too_many_loads; +ensure_only_one_load([{module, ?model}|Loads], N) -> + ensure_only_one_load(Loads, N + 1); +ensure_only_one_load([{error, not_purged}|Loads], N) -> + ensure_only_one_load(Loads, N). +% no other return values are allowed from load_module + + +%% aux + +setup_checkers(_,0) -> []; +setup_checkers(T,N) -> [spawn_link(fun() -> ?model:check(T) end) | setup_checkers(T, N-1)]. + +check_and_purge_processes_code(Pids, M) -> + check_and_purge_processes_code(Pids, M, []). +check_and_purge_processes_code([], M, []) -> + erlang:purge_module(M), + ok; +check_and_purge_processes_code([], M, Pending) -> + io:format("Processes ~w are still executing old code - retrying.~n", [Pending]), + check_and_purge_processes_code(Pending, M, []); +check_and_purge_processes_code([Pid|Pids], M, Pending) -> + case erlang:check_process_code(Pid, M) of + false -> + check_and_purge_processes_code(Pids, M, Pending); + true -> + check_and_purge_processes_code(Pids, M, [Pid|Pending]) + end. + + +generate(Module, Attributes, FunStrings) -> + FunForms = function_forms(FunStrings), + Forms = [ + {attribute,1,module,Module}, + {attribute,2,export,[FA || {FA,_} <- FunForms]} + ] ++ [{attribute, 3, A, V}|| {A, V} <- Attributes] ++ + [ Function || {_, Function} <- FunForms], + {ok, Module, Bin} = compile:forms(Forms), + Bin. + + +function_forms([]) -> []; +function_forms([S|Ss]) -> + {ok, Ts,_} = erl_scan:string(S), + {ok, Form} = erl_parse:parse_form(Ts), + Fun = element(3, Form), + Arity = element(4, Form), + [{{Fun,Arity}, Form}|function_forms(Ss)]. + +format(F,Ts) -> lists:flatten(io_lib:format(F, Ts)). diff --git a/erts/emulator/test/mtx_SUITE_data/Makefile.src b/erts/emulator/test/mtx_SUITE_data/Makefile.src index b6c843269c..37eb1daa72 100644 --- a/erts/emulator/test/mtx_SUITE_data/Makefile.src +++ b/erts/emulator/test/mtx_SUITE_data/Makefile.src @@ -27,4 +27,11 @@ LIBS = @ERTS_LIBS@ all: $(NIF_LIBS) +mtx_SUITE.c: force_rebuild + touch mtx_SUITE.c + +force_rebuild: + echo "Force rebuild to compensate for emulator type dependencies" + + @SHLIB_RULES@ diff --git a/erts/etc/unix/etp-commands b/erts/etc/unix/etp-commands index 79e5d6b1d8..ce6f0c9959 100644 --- a/erts/etc/unix/etp-commands +++ b/erts/etc/unix/etp-commands @@ -1022,16 +1022,17 @@ define etp-cp-1 # Non-reentrant # set $etp_cp = (Eterm)($arg0) - set $etp_cp_low = modules - set $etp_cp_high = $etp_cp_low + num_loaded_modules - set $etp_cp_mid = mid_module + set $etp_ranges = &r[(int)the_active_code_index] + set $etp_cp_low = $etp_ranges->modules + set $etp_cp_high = $etp_cp_low + $etp_ranges->n + set $etp_cp_mid = (Range*)$etp_ranges->mid set $etp_cp_p = 0 # while $etp_cp_low < $etp_cp_high if $etp_cp < $etp_cp_mid->start set $etp_cp_high = $etp_cp_mid else - if $etp_cp > $etp_cp_mid->end + if $etp_cp > (BeamInstr*)$etp_cp_mid->end set $etp_cp_low = $etp_cp_mid + 1 else set $etp_cp_p = $etp_cp_low = $etp_cp_high = $etp_cp_mid diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam Binary files differindex df1831f340..62d161850c 100644 --- a/erts/preloaded/ebin/erl_prim_loader.beam +++ b/erts/preloaded/ebin/erl_prim_loader.beam diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex b78747bc84..1dce82f611 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam Binary files differindex cc170b86b2..3bf5777b19 100644 --- a/erts/preloaded/ebin/init.beam +++ b/erts/preloaded/ebin/init.beam diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam Binary files differindex 45a409738c..ab86e0eab4 100644 --- a/erts/preloaded/ebin/otp_ring0.beam +++ b/erts/preloaded/ebin/otp_ring0.beam diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex 87e80aae9b..5cd0722a24 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam Binary files differindex f382236af7..23c1d59cd0 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam Binary files differindex 411fc8d524..bff09897d9 100644 --- a/erts/preloaded/ebin/prim_zip.beam +++ b/erts/preloaded/ebin/prim_zip.beam diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam Binary files differindex bf88a51502..4d86fe4e00 100644 --- a/erts/preloaded/ebin/zlib.beam +++ b/erts/preloaded/ebin/zlib.beam diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 4cbff3f36e..5e451c015b 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -48,9 +48,7 @@ -deprecated([hash/2]). -% Get rid of autoimports of spawn to avoid clashes with ourselves. --compile({no_auto_import,[spawn/1]}). --compile({no_auto_import,[spawn/4]}). +%% Get rid of autoimports of spawn to avoid clashes with ourselves. -compile({no_auto_import,[spawn_link/1]}). -compile({no_auto_import,[spawn_link/4]}). -compile({no_auto_import,[spawn_opt/2]}). @@ -59,10 +57,2069 @@ -export_type([timestamp/0]). +-type ext_binary() :: binary(). -type timestamp() :: {MegaSecs :: non_neg_integer(), Secs :: non_neg_integer(), MicroSecs :: non_neg_integer()}. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Native code BIF stubs and their types +%% (BIF's actually implemented in this module goes last in the file) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Exports for all native code stubs +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-export([adler32/1, adler32/2, adler32_combine/3, append_element/2]). +-export([atom_to_binary/2, atom_to_list/1, binary_part/2, binary_part/3]). +-export([binary_to_atom/2, binary_to_existing_atom/2, binary_to_list/1]). +-export([binary_to_list/3, binary_to_term/1, binary_to_term/2]). +-export([bit_size/1, bitsize/1, bitstr_to_list/1, bitstring_to_list/1]). +-export([bump_reductions/1, byte_size/1, call_on_load_function/1]). +-export([cancel_timer/1, check_old_code/1, check_process_code/2, crc32/1]). +-export([crc32/2, crc32_combine/3, date/0, decode_packet/3]). +-export([delete_module/1, demonitor/1, demonitor/2, display/1]). +-export([display_nl/0, display_string/1, dist_exit/3, erase/0, erase/1]). +-export([error/1, error/2, exit/1, exit/2, external_size/1]). +-export([external_size/2, finish_after_on_load/2, finish_loading/1, float/1]). +-export([float_to_list/1, fun_info/2, fun_to_list/1, function_exported/3]). +-export([garbage_collect/0, garbage_collect/1]). +-export([garbage_collect_message_area/0, get/0, get/1, get_keys/1]). +-export([get_module_info/1, get_stacktrace/0, group_leader/0]). +-export([group_leader/2, halt/0, halt/1, hash/2, hibernate/3]). +-export([integer_to_list/1, iolist_size/1, iolist_to_binary/1]). +-export([is_alive/0, is_builtin/3, is_process_alive/1, length/1, link/1]). +-export([list_to_atom/1, list_to_binary/1, list_to_bitstr/1]). +-export([list_to_bitstring/1, list_to_existing_atom/1, list_to_float/1]). +-export([list_to_integer/1, list_to_pid/1, list_to_tuple/1, loaded/0]). +-export([localtime/0, make_ref/0, match_spec_test/3, md5/1, md5_final/1]). +-export([md5_init/0, md5_update/2, module_loaded/1, monitor/2]). +-export([monitor_node/2, monitor_node/3, nif_error/1, nif_error/2 +]). +-export([node/0, node/1, now/0, phash/2, phash2/1, phash2/2]). +-export([pid_to_list/1, port_close/1, port_command/2, port_command/3]). +-export([port_connect/2, port_control/3, port_get_data/1]). +-export([port_set_data/2, port_to_list/1, ports/0]). +-export([posixtime_to_universaltime/1, pre_loaded/0, prepare_loading/2]). +-export([process_display/2]). +-export([process_flag/3, process_info/1, processes/0, purge_module/1]). +-export([put/2, raise/3, read_timer/1, ref_to_list/1, register/2]). +-export([registered/0, resume_process/1, round/1, self/0, send_after/3]). +-export([seq_trace/2, seq_trace_print/1, seq_trace_print/2, setnode/2]). +-export([setnode/3, size/1, spawn/3, spawn_link/3, split_binary/2]). +-export([start_timer/3, suspend_process/2, system_monitor/0]). +-export([system_monitor/1, system_monitor/2, system_profile/0]). +-export([system_profile/2, throw/1, time/0, trace/3, trace_delivered/1]). +-export([trace_info/2, trunc/1, tuple_size/1, universaltime/0]). +-export([universaltime_to_posixtime/1, unlink/1, unregister/1, whereis/1]). + +-export([abs/1, append/2, element/2, get_module_info/2, hd/1, + is_atom/1, is_binary/1, is_bitstring/1, is_boolean/1, + is_float/1, is_function/1, is_function/2, is_integer/1, + is_list/1, is_number/1, is_pid/1, is_port/1, is_record/2, + is_record/3, is_reference/1, is_tuple/1, load_module/2, + load_nif/2, localtime_to_universaltime/2, make_fun/3, + make_tuple/2, make_tuple/3, nodes/1, open_port/2, + port_call/2, port_call/3, port_info/1, port_info/2, process_flag/2, + process_info/2, send/2, send/3, seq_trace_info/1, + setelement/3, spawn_opt/1, + statistics/1, subtract/2, system_flag/2, + term_to_binary/1, term_to_binary/2, tl/1, trace_pattern/2, + trace_pattern/3, tuple_to_list/1, system_info/1, + universaltime_to_localtime/1]). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% Simple native code BIFs +%%% These are here for the types/specs, the real implementation is in the C code. +%%% The first chunk is originally auto-generated from +%%% $ERL_TOP/lib/hipe/cerl/erl_bif_types.erl as released in R15B. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%% types + +-type fun_info_item() :: + arity | + env | + index | + name | + module | + new_index | + new_uniq | + pid | + type | + uniq. + +-type seq_trace_info() :: + 'send' | + 'receive' | + 'print' | + 'timestamp' | + 'label' | + 'serial'. + +-type seq_trace_info_returns() :: + { seq_trace_info(), non_neg_integer() | + boolean() | + { non_neg_integer(), non_neg_integer() } } | + []. + +-type system_profile_option() :: + 'exclusive' | + 'runnable_ports' | + 'runnable_procs' | + 'scheduler'. + +-type system_monitor_option() :: + 'busy_port' | + 'busy_dist_port' | + {'long_gc', non_neg_integer()} | + {'large_heap', non_neg_integer()}. + + +-type raise_stacktrace() :: + [{module(), atom(), arity() | [term()]} | + {function(), [term()]}] | + [{module(), atom(), arity() | [term()], [{atom(),term()}]} | + {function(), [term()], [{atom(),term()}]}]. + +-type bitstring_list() :: + maybe_improper_list(byte() | bitstring() | bitstring_list(), bitstring() | []). + +-type trace_flag() :: + all | + send | + 'receive' | + procs | + call | + silent | + return_to | + running | + exiting | + garbage_collection | + timestamp | + cpu_timestamp | + arity | + set_on_spawn | + set_on_first_spawn | + set_on_link | + set_on_first_link | + {tracer, pid() | port()}. + +-type trace_info_item_result() :: + {traced, global | local | false | undefined} | + {match_spec, trace_match_spec() | false | undefined} | + {meta, pid() | port() | false | undefined | []} | + {meta_match_spec, trace_match_spec() | false | undefined} | + {call_count, non_neg_integer() | boolean() | undefined} | + {call_time, [{pid(), non_neg_integer(), + non_neg_integer(), non_neg_integer()}] | boolean() | undefined}. + +-type trace_info_flag() :: + send | + 'receive' | + set_on_spawn | + call | + return_to | + procs | + set_on_first_spawn | + set_on_link | + running | + garbage_collection | + timestamp | + arity. + +-type trace_info_return() :: + undefined | + {flags, [trace_info_flag()]} | + {tracer, pid() | port() | []} | + trace_info_item_result() | + {all, [ trace_info_item_result() ] | false | undefined}. + +%% Specs and stubs +%% adler32/1 +-spec erlang:adler32(Data) -> non_neg_integer() when + Data :: iodata(). +adler32(_Data) -> + erlang:nif_error(undefined). + +%% adler32/2 +-spec erlang:adler32(OldAdler, Data) -> non_neg_integer() when + OldAdler :: non_neg_integer(), + Data :: iodata(). +adler32(_OldAdler, _Data) -> + erlang:nif_error(undefined). + +%% adler32_combine/3 +-spec erlang:adler32_combine(FirstAdler, SecondAdler, SecondSize) -> non_neg_integer() when + FirstAdler :: non_neg_integer(), + SecondAdler :: non_neg_integer(), + SecondSize :: non_neg_integer(). +adler32_combine(_FirstAdler, _SecondAdler, _SecondSize) -> + erlang:nif_error(undefined). + +%% append_element/2 +-spec erlang:append_element(Tuple1, Term) -> Tuple2 when + Tuple1 :: tuple(), + Tuple2 :: tuple(), + Term :: term(). +append_element(_Tuple1, _Term) -> + erlang:nif_error(undefined). + +%% atom_to_binary/2 +-spec atom_to_binary(Atom, Encoding) -> binary() when + Atom :: atom(), + Encoding :: latin1 | unicode | utf8. +atom_to_binary(_Atom, _Encoding) -> + erlang:nif_error(undefined). + +%% atom_to_list/1 +-spec atom_to_list(Atom) -> string() when + Atom :: atom(). +atom_to_list(_Atom) -> + erlang:nif_error(undefined). + +%% binary_part/2 +%% Shadowed by erl_bif_types: erlang:binary_part/2 +-spec binary_part(Subject, PosLen) -> binary() when + Subject :: binary(), + PosLen :: {Start :: non_neg_integer(), Length :: integer()}. +binary_part(_Subject, _PosLen) -> + erlang:nif_error(undefined). + +%% binary_part/3 +%% Shadowed by erl_bif_types: erlang:binary_part/3 +-spec binary_part(Subject, Start, Length) -> binary() when + Subject :: binary(), + Start :: non_neg_integer(), + Length :: integer(). +binary_part(_Subject, _Start, _Length) -> + erlang:nif_error(undefined). + +%% binary_to_atom/2 +-spec binary_to_atom(Binary, Encoding) -> atom() when + Binary :: binary(), + Encoding :: latin1 | unicode | utf8. +binary_to_atom(_Binary, _Encoding) -> + erlang:nif_error(undefined). + +%% binary_to_existing_atom/2 +-spec binary_to_existing_atom(Binary, Encoding) -> atom() when + Binary :: binary(), + Encoding :: latin1 | unicode | utf8. +binary_to_existing_atom(_Binary, _Encoding) -> + erlang:nif_error(undefined). + +%% binary_to_list/1 +-spec binary_to_list(Binary) -> [byte()] when + Binary :: binary(). +binary_to_list(_Binary) -> + erlang:nif_error(undefined). + +%% binary_to_list/3 +-spec binary_to_list(Binary, Start, Stop) -> [byte()] when + Binary :: binary(), + Start :: pos_integer(), + Stop :: pos_integer(). +binary_to_list(_Binary, _Start, _Stop) -> + erlang:nif_error(undefined). + +%% binary_to_term/1 +-spec binary_to_term(Binary) -> term() when + Binary :: ext_binary(). +binary_to_term(_Binary) -> + erlang:nif_error(undefined). + +%% binary_to_term/2 +-spec binary_to_term(Binary, Opts) -> term() when + Binary :: ext_binary(), + Opts :: [safe]. +binary_to_term(_Binary, _Opts) -> + erlang:nif_error(undefined). + +%% bit_size/1 +%% Shadowed by erl_bif_types: erlang:bit_size/1 +-spec bit_size(Bitstring) -> non_neg_integer() when + Bitstring :: bitstring(). +bit_size(_Bitstring) -> + erlang:nif_error(undefined). + +%% bitsize/1 +-spec bitsize(P1) -> non_neg_integer() when + P1 :: bitstring(). +bitsize(_P1) -> + erlang:nif_error(undefined). + +%% bitstr_to_list/1 +-spec erlang:bitstr_to_list(P1) -> [byte() | bitstring()] when + P1 :: bitstring(). +bitstr_to_list(_P1) -> + erlang:nif_error(undefined). + +%% bitstring_to_list/1 +-spec bitstring_to_list(Bitstring) -> [byte() | bitstring()] when + Bitstring :: bitstring(). +bitstring_to_list(_Bitstring) -> + erlang:nif_error(undefined). + +%% bump_reductions/1 +-spec erlang:bump_reductions(Reductions) -> true when + Reductions :: pos_integer(). +bump_reductions(_Reductions) -> + erlang:nif_error(undefined). + +%% byte_size/1 +%% Shadowed by erl_bif_types: erlang:byte_size/1 +-spec byte_size(Bitstring) -> non_neg_integer() when + Bitstring :: bitstring(). +byte_size(_Bitstring) -> + erlang:nif_error(undefined). + +%% call_on_load_function/1 +-spec erlang:call_on_load_function(P1) -> term() when + P1 :: atom(). +call_on_load_function(_P1) -> + erlang:nif_error(undefined). + +%% cancel_timer/1 +-spec erlang:cancel_timer(TimerRef) -> Time | false when + TimerRef :: reference(), + Time :: non_neg_integer(). +cancel_timer(_TimerRef) -> + erlang:nif_error(undefined). + +%% check_old_code/1 +-spec check_old_code(Module) -> boolean() when + Module :: module(). +check_old_code(_Module) -> + erlang:nif_error(undefined). + +%% check_process_code/2 +-spec check_process_code(Pid, Module) -> boolean() when + Pid :: pid(), + Module :: module(). +check_process_code(_Pid, _Module) -> + erlang:nif_error(undefined). + +%% crc32/1 +-spec erlang:crc32(Data) -> non_neg_integer() when + Data :: iodata(). +crc32(_Data) -> + erlang:nif_error(undefined). + +%% crc32/2 +-spec erlang:crc32(OldCrc, Data) -> non_neg_integer() when + OldCrc :: non_neg_integer(), + Data :: iodata(). +crc32(_OldCrc, _Data) -> + erlang:nif_error(undefined). + +%% crc32_combine/3 +-spec erlang:crc32_combine(FirstCrc, SecondCrc, SecondSize) -> non_neg_integer() when + FirstCrc :: non_neg_integer(), + SecondCrc :: non_neg_integer(), + SecondSize :: non_neg_integer(). +crc32_combine(_FirstCrc, _SecondCrc, _SecondSize) -> + erlang:nif_error(undefined). + +%% date/0 +-spec date() -> Date when + Date :: calendar:date(). +date() -> + erlang:nif_error(undefined). + +%% decode_packet/3 +-spec erlang:decode_packet(Type, Bin, Options) -> + {ok, Packet, Rest} | + {more, Length} | + {error, Reason} when + Type :: 'raw' | 0 | 1 | 2 | 4 | 'asn1' | 'cdr' | 'sunrm' | 'fcgi' + | 'tpkt' | 'line' | 'http' | 'http_bin' | 'httph' | 'httph_bin', + Bin :: binary(), + Options :: [Opt], + Opt :: {packet_size, non_neg_integer()} + | {line_length, non_neg_integer()}, + Packet :: binary() | HttpPacket, + Rest :: binary(), + Length :: non_neg_integer() | undefined, + Reason :: term(), + HttpPacket :: HttpRequest + | HttpResponse + | HttpHeader + | 'http_eoh' + | HttpError, + HttpRequest :: {'http_request', HttpMethod, HttpUri, HttpVersion}, + HttpResponse :: {'http_response', HttpVersion, integer(), HttpString}, + HttpHeader :: {'http_header', + integer(), + HttpField, + Reserved :: term(), + Value :: HttpString}, + HttpError :: {'http_error', HttpString}, + HttpMethod :: 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' + | 'TRACE' | HttpString, + HttpUri :: '*' + | { 'absoluteURI', + 'http' | 'https', + Host :: HttpString, + Port :: inet:port_number() | 'undefined', + Path :: HttpString} + | {'scheme', Scheme :: HttpString, HttpString} + | {'abs_path', HttpString} + | HttpString, + HttpVersion :: {Major :: non_neg_integer(), Minor :: non_neg_integer()}, + HttpField :: 'Cache-Control' + | 'Connection' + | 'Date' + | 'Pragma' + | 'Transfer-Encoding' + | 'Upgrade' + | 'Via' + | 'Accept' + | 'Accept-Charset' + | 'Accept-Encoding' + | 'Accept-Language' + | 'Authorization' + | 'From' + | 'Host' + | 'If-Modified-Since' + | 'If-Match' + | 'If-None-Match' + | 'If-Range' + | 'If-Unmodified-Since' + | 'Max-Forwards' + | 'Proxy-Authorization' + | 'Range' + | 'Referer' + | 'User-Agent' + | 'Age' + | 'Location' + | 'Proxy-Authenticate' + | 'Public' + | 'Retry-After' + | 'Server' + | 'Vary' + | 'Warning' + |'Www-Authenticate' + | 'Allow' + | 'Content-Base' + | 'Content-Encoding' + | 'Content-Language' + | 'Content-Length' + | 'Content-Location' + | 'Content-Md5' + | 'Content-Range' + | 'Content-Type' + | 'Etag' + | 'Expires' + | 'Last-Modified' + | 'Accept-Ranges' + | 'Set-Cookie' + | 'Set-Cookie2' + | 'X-Forwarded-For' + | 'Cookie' + | 'Keep-Alive' + | 'Proxy-Connection' + | HttpString, + HttpString :: string() | binary(). +decode_packet(_Type, _Bin, _Options) -> + erlang:nif_error(undefined). + +%% delete_module/1 +-spec delete_module(Module) -> true | undefined when + Module :: module(). +delete_module(_Module) -> + erlang:nif_error(undefined). + +%% demonitor/1 +-spec demonitor(MonitorRef) -> true when + MonitorRef :: reference(). +demonitor(_MonitorRef) -> + erlang:nif_error(undefined). + +%% demonitor/2 +-spec demonitor(MonitorRef, OptionList) -> boolean() when + MonitorRef :: reference(), + OptionList :: [Option], + Option :: flush | info. +demonitor(_MonitorRef, _OptionList) -> + erlang:nif_error(undefined). + +%% display/1 +-spec erlang:display(Term) -> true when + Term :: term(). +display(_Term) -> + erlang:nif_error(undefined). + +%% display_nl/0 +-spec erlang:display_nl() -> true. +display_nl() -> + erlang:nif_error(undefined). + +%% display_string/1 +-spec erlang:display_string(P1) -> true when + P1 :: string(). +display_string(_P1) -> + erlang:nif_error(undefined). + +%% dist_exit/3 +-spec erlang:dist_exit(P1, P2, P3) -> true when + P1 :: pid(), + P2 :: kill | noconnection | normal, + P3 :: pid() | port(). +dist_exit(_P1, _P2, _P3) -> + erlang:nif_error(undefined). + +%% erase/0 +-spec erase() -> [{Key, Val}] when + Key :: term(), + Val :: term(). +erase() -> + erlang:nif_error(undefined). + +%% erase/1 +-spec erase(Key) -> Val | undefined when + Key :: term(), + Val :: term(). +erase(_Key) -> + erlang:nif_error(undefined). + +%% error/1 +%% Shadowed by erl_bif_types: erlang:error/1 +-spec error(Reason) -> no_return() when + Reason :: term(). +error(_Reason) -> + erlang:nif_error(undefined). + +%% error/2 +%% Shadowed by erl_bif_types: erlang:error/2 +-spec error(Reason, Args) -> no_return() when + Reason :: term(), + Args :: [term()]. +error(_Reason, _Args) -> + erlang:nif_error(undefined). + +%% exit/1 +%% Shadowed by erl_bif_types: erlang:exit/1 +-spec exit(Reason) -> no_return() when + Reason :: term(). +exit(_Reason) -> + erlang:nif_error(undefined). + +%% exit/2 +-spec exit(Pid, Reason) -> true when + Pid :: pid() | port(), + Reason :: term(). +exit(_Pid, _Reason) -> + erlang:nif_error(undefined). + +%% external_size/1 +-spec erlang:external_size(Term) -> non_neg_integer() when + Term :: term(). +external_size(_Term) -> + erlang:nif_error(undefined). + +%% external_size/2 +-spec erlang:external_size(Term, Options) -> non_neg_integer() when + Term :: term(), + Options :: [{minor_version, Version :: non_neg_integer()}]. +external_size(_Term, _Options) -> + erlang:nif_error(undefined). + +%% finish_loading/2 +-spec erlang:finish_loading(PreparedCodeBinaries) -> ok | Error when + PreparedCodeBinaries :: [PreparedCodeBinary], + PreparedCodeBinary :: binary(), + ModuleList :: [module()], + Error :: {not_purged,ModuleList} | {on_load,ModuleList}. +finish_loading(_List) -> + erlang:nif_error(undefined). + +%% finish_after_on_load/2 +-spec erlang:finish_after_on_load(P1, P2) -> true when + P1 :: atom(), + P2 :: boolean(). +finish_after_on_load(_P1, _P2) -> + erlang:nif_error(undefined). + +%% float/1 +%% Shadowed by erl_bif_types: erlang:float/1 +-spec float(Number) -> float() when + Number :: number(). +float(_Number) -> + erlang:nif_error(undefined). + +%% float_to_list/1 +-spec float_to_list(Float) -> string() when + Float :: float(). +float_to_list(_Float) -> + erlang:nif_error(undefined). + +%% fun_info/2 +-spec erlang:fun_info(Fun, Item) -> {Item, Info} when + Fun :: function(), + Item :: fun_info_item(), + Info :: term(). +fun_info(_Fun, _Item) -> + erlang:nif_error(undefined). + +%% fun_to_list/1 +-spec erlang:fun_to_list(Fun) -> string() when + Fun :: function(). +fun_to_list(_Fun) -> + erlang:nif_error(undefined). + +%% function_exported/3 +-spec erlang:function_exported(Module, Function, Arity) -> boolean() when + Module :: module(), + Function :: atom(), + Arity :: arity(). +function_exported(_Module, _Function, _Arity) -> + erlang:nif_error(undefined). + +%% garbage_collect/0 +-spec garbage_collect() -> true. +garbage_collect() -> + erlang:nif_error(undefined). + +%% garbage_collect/1 +-spec garbage_collect(Pid) -> boolean() when + Pid :: pid(). +garbage_collect(_Pid) -> + erlang:nif_error(undefined). + +%% garbage_collect_message_area/0 +-spec erlang:garbage_collect_message_area() -> boolean(). +garbage_collect_message_area() -> + erlang:nif_error(undefined). + +%% get/0 +-spec get() -> [{Key, Val}] when + Key :: term(), + Val :: term(). +get() -> + erlang:nif_error(undefined). + +%% get/1 +-spec get(Key) -> Val | undefined when + Key :: term(), + Val :: term(). +get(_Key) -> + erlang:nif_error(undefined). + +%% get_keys/1 +-spec get_keys(Val) -> [Key] when + Val :: term(), + Key :: term(). +get_keys(_Val) -> + erlang:nif_error(undefined). + +%% get_module_info/1 +-spec erlang:get_module_info(P1) -> [{atom(), [{atom(), term()}]}] when + P1 :: atom(). +get_module_info(_P1) -> + erlang:nif_error(undefined). + +%% get_stacktrace/0 +-spec erlang:get_stacktrace() -> [stack_item()]. +get_stacktrace() -> + erlang:nif_error(undefined). + +%% group_leader/0 +-spec group_leader() -> pid(). +group_leader() -> + erlang:nif_error(undefined). + +%% group_leader/2 +-spec group_leader(GroupLeader, Pid) -> true when + GroupLeader :: pid(), + Pid :: pid(). +group_leader(_GroupLeader, _Pid) -> + erlang:nif_error(undefined). + +%% halt/0 +%% Shadowed by erl_bif_types: erlang:halt/0 +-spec halt() -> no_return(). +halt() -> + erlang:nif_error(undefined). + +%% halt/1 +%% Shadowed by erl_bif_types: erlang:halt/1 +-spec halt(Status) -> no_return() when + Status :: non_neg_integer() | string(). +halt(_Status) -> + erlang:nif_error(undefined). + +%% hash/2 +-spec erlang:hash(Term, Range) -> pos_integer() when + Term :: term(), + Range :: pos_integer(). +hash(_Term, _Range) -> + erlang:nif_error(undefined). + +%% hibernate/3 +-spec erlang:hibernate(Module, Function, Args) -> no_return() when + Module :: module(), + Function :: atom(), + Args :: [term()]. +hibernate(_Module, _Function, _Args) -> + erlang:nif_error(undefined). + +%% integer_to_list/1 +-spec integer_to_list(Integer) -> string() when + Integer :: integer(). +integer_to_list(_Integer) -> + erlang:nif_error(undefined). + +%% iolist_size/1 +-spec iolist_size(Item) -> non_neg_integer() when + Item :: iolist() | binary(). +iolist_size(_Item) -> + erlang:nif_error(undefined). + +%% iolist_to_binary/1 +-spec iolist_to_binary(IoListOrBinary) -> binary() when + IoListOrBinary :: iolist() | binary(). +iolist_to_binary(_IoListOrBinary) -> + erlang:nif_error(undefined). + +%% is_alive/0 +-spec is_alive() -> boolean(). +is_alive() -> + erlang:nif_error(undefined). + +%% is_builtin/3 +-spec erlang:is_builtin(Module, Function, Arity) -> boolean() when + Module :: module(), + Function :: atom(), + Arity :: arity(). +is_builtin(_Module, _Function, _Arity) -> + erlang:nif_error(undefined). + +%% is_process_alive/1 +-spec is_process_alive(Pid) -> boolean() when + Pid :: pid(). +is_process_alive(_Pid) -> + erlang:nif_error(undefined). + +%% length/1 +%% Shadowed by erl_bif_types: erlang:length/1 +-spec length(List) -> non_neg_integer() when + List :: [term()]. +length(_List) -> + erlang:nif_error(undefined). + +%% link/1 +-spec link(PidOrPort) -> true when + PidOrPort :: pid() | port(). +link(_PidOrPort) -> + erlang:nif_error(undefined). + +%% list_to_atom/1 +-spec list_to_atom(String) -> atom() when + String :: string(). +list_to_atom(_String) -> + erlang:nif_error(undefined). + +%% list_to_binary/1 +-spec list_to_binary(IoList) -> binary() when + IoList :: iolist(). +list_to_binary(_IoList) -> + erlang:nif_error(undefined). + +%% list_to_bitstr/1 +-spec erlang:list_to_bitstr(P1) -> bitstring() when + P1 :: bitstring_list(). +list_to_bitstr(_P1) -> + erlang:nif_error(undefined). + +%% list_to_bitstring/1 +-spec list_to_bitstring(BitstringList) -> bitstring() when + BitstringList :: bitstring_list(). +list_to_bitstring(_BitstringList) -> + erlang:nif_error(undefined). + +%% list_to_existing_atom/1 +-spec list_to_existing_atom(String) -> atom() when + String :: string(). +list_to_existing_atom(_String) -> + erlang:nif_error(undefined). + +%% list_to_float/1 +-spec list_to_float(String) -> float() when + String :: string(). +list_to_float(_String) -> + erlang:nif_error(undefined). + +%% list_to_integer/1 +-spec list_to_integer(String) -> integer() when + String :: string(). +list_to_integer(_String) -> + erlang:nif_error(undefined). + +%% list_to_pid/1 +-spec list_to_pid(String) -> pid() when + String :: string(). +list_to_pid(_String) -> + erlang:nif_error(undefined). + +%% list_to_tuple/1 +-spec list_to_tuple(List) -> tuple() when + List :: [term()]. +list_to_tuple(_List) -> + erlang:nif_error(undefined). + +%% loaded/0 +-spec erlang:loaded() -> [Module] when + Module :: module(). +loaded() -> + erlang:nif_error(undefined). + +%% localtime/0 +-spec erlang:localtime() -> DateTime when + DateTime :: calendar:datetime(). +localtime() -> + erlang:nif_error(undefined). + +%% make_ref/0 +-spec make_ref() -> reference(). +make_ref() -> + erlang:nif_error(undefined). + +%% match_spec_test/3 +-spec erlang:match_spec_test(P1, P2, P3) -> TestResult when + P1 :: [term()] | tuple(), + P2 :: term(), + P3 :: table | trace, + TestResult :: {ok, term(), [return_trace], [ {error | warning, string()} ]} | {error, [ {error | warning, string()} ]}. +match_spec_test(_P1, _P2, _P3) -> + erlang:nif_error(undefined). + +%% md5/1 +-spec erlang:md5(Data) -> Digest when + Data :: iodata(), + Digest :: binary(). +md5(_Data) -> + erlang:nif_error(undefined). + +%% md5_final/1 +-spec erlang:md5_final(Context) -> Digest when + Context :: binary(), + Digest :: binary(). +md5_final(_Context) -> + erlang:nif_error(undefined). + +%% md5_init/0 +-spec erlang:md5_init() -> Context when + Context :: binary(). +md5_init() -> + erlang:nif_error(undefined). + +%% md5_update/2 +-spec erlang:md5_update(Context, Data) -> NewContext when + Context :: binary(), + Data :: iodata(), + NewContext :: binary(). +md5_update(_Context, _Data) -> + erlang:nif_error(undefined). + +%% module_loaded/1 +-spec module_loaded(Module) -> boolean() when + Module :: module(). +module_loaded(_Module) -> + erlang:nif_error(undefined). + +%% monitor/2 +-spec monitor(Type, Item) -> MonitorRef when + Type :: process, + Item :: pid() | Module | {Module, Node}, + Module :: module(), + Node :: node(), + MonitorRef :: reference(). +monitor(_Type, _Item) -> + erlang:nif_error(undefined). + +%% monitor_node/2 +-spec monitor_node(Node, Flag) -> true when + Node :: node(), + Flag :: boolean(). +monitor_node(_Node, _Flag) -> + erlang:nif_error(undefined). + +%% monitor_node/3 +-spec erlang:monitor_node(Node, Flag, Options) -> true when + Node :: node(), + Flag :: boolean(), + Options :: [Option], + Option :: allow_passive_connect. +monitor_node(_Node, _Flag, _Options) -> + erlang:nif_error(undefined). + +%% nif_error/1 +%% Shadowed by erl_bif_types: erlang:nif_error/1 +-spec erlang:nif_error(Reason) -> no_return() when + Reason :: term(). +nif_error(_Reason) -> + erlang:nif_error(undefined). + +%% nif_error/2 +%% Shadowed by erl_bif_types: erlang:nif_error/2 +-spec erlang:nif_error(Reason, Args) -> no_return() when + Reason :: term(), + Args :: [term()]. +nif_error(_Reason, _Args) -> + erlang:nif_error(undefined). + +%% node/0 +%% Shadowed by erl_bif_types: erlang:node/0 +-spec node() -> Node when + Node :: node(). +node() -> + erlang:nif_error(undefined). + +%% node/1 +%% Shadowed by erl_bif_types: erlang:node/1 +-spec node(Arg) -> Node when + Arg :: pid() | port() | reference(), + Node :: node(). +node(_Arg) -> + erlang:nif_error(undefined). + +%% now/0 +-spec now() -> Timestamp when + Timestamp :: timestamp(). +now() -> + erlang:nif_error(undefined). + +%% phash/2 +-spec erlang:phash(Term, Range) -> Hash when + Term :: term(), + Range :: pos_integer(), + Hash :: pos_integer(). +phash(_Term, _Range) -> + erlang:nif_error(undefined). + +%% phash2/1 +-spec erlang:phash2(Term) -> Hash when + Term :: term(), + Hash :: non_neg_integer(). +phash2(_Term) -> + erlang:nif_error(undefined). + +%% phash2/2 +-spec erlang:phash2(Term, Range) -> Hash when + Term :: term(), + Range :: pos_integer(), + Hash :: non_neg_integer(). +phash2(_Term, _Range) -> + erlang:nif_error(undefined). + +%% pid_to_list/1 +-spec pid_to_list(Pid) -> string() when + Pid :: pid(). +pid_to_list(_Pid) -> + erlang:nif_error(undefined). + +%% port_close/1 +-spec port_close(Port) -> true when + Port :: port() | atom(). +port_close(_Port) -> + erlang:nif_error(undefined). + +%% port_command/2 +-spec port_command(Port, Data) -> true when + Port :: port() | atom(), + Data :: iodata(). +port_command(_Port, _Data) -> + erlang:nif_error(undefined). + +%% port_command/3 +-spec port_command(Port, Data, OptionList) -> boolean() when + Port :: port() | atom(), + Data :: iodata(), + OptionList :: [Option], + Option :: force | nosuspend. +port_command(_Port, _Data, _OptionList) -> + erlang:nif_error(undefined). + +%% port_connect/2 +-spec port_connect(Port, Pid) -> true when + Port :: port() | atom(), + Pid :: pid(). +port_connect(_Port, _Pid) -> + erlang:nif_error(undefined). + +%% port_control/3 +-spec port_control(Port, Operation, Data) -> Res when + Port :: port() | atom(), + Operation :: integer(), + Data :: iodata(), + Res :: string() | binary(). +port_control(_Port, _Operation, _Data) -> + erlang:nif_error(undefined). + +%% port_get_data/1 +-spec erlang:port_get_data(P1) -> term() when + P1 :: port() | atom(). +port_get_data(_P1) -> + erlang:nif_error(undefined). + +%% port_set_data/2 +-spec erlang:port_set_data(P1, P2) -> true when + P1 :: port() | atom(), + P2 :: term(). +port_set_data(_P1, _P2) -> + erlang:nif_error(undefined). + +%% port_to_list/1 +-spec erlang:port_to_list(Port) -> string() when + Port :: port(). +port_to_list(_Port) -> + erlang:nif_error(undefined). + +%% ports/0 +-spec erlang:ports() -> [port()]. +ports() -> + erlang:nif_error(undefined). + +%% posixtime_to_universaltime/1 +-spec erlang:posixtime_to_universaltime(P1) -> {calendar:date(), calendar:time()} when + P1 :: integer(). +posixtime_to_universaltime(_P1) -> + erlang:nif_error(undefined). + +%% prepare_loading/2 +-spec erlang:prepare_loading(Module, Code) -> PreparedCode | {error, Reason} when + Module :: module(), + Code :: binary(), + PreparedCode :: binary(), + Reason :: bad_file. +prepare_loading(_Module, _Code) -> + erlang:nif_error(undefined). + +%% pre_loaded/0 +-spec pre_loaded() -> [module()]. +pre_loaded() -> + erlang:nif_error(undefined). + +%% process_display/2 +-spec erlang:process_display(Pid, Type) -> true when + Pid :: pid(), + Type :: backtrace. +process_display(_Pid, _Type) -> + erlang:nif_error(undefined). + +%% process_flag/3 +-spec process_flag(Pid, Flag, Value) -> OldValue when + Pid :: pid(), + Flag :: save_calls, + Value :: non_neg_integer(), + OldValue :: non_neg_integer(). +process_flag(_Pid, _Flag, _Value) -> + erlang:nif_error(undefined). + +%% process_info/1 +-spec process_info(Pid) -> Info when + Pid :: pid(), + Info :: [InfoTuple] | undefined, + InfoTuple :: process_info_result_item(). +process_info(_Pid) -> + erlang:nif_error(undefined). + +%% processes/0 +-spec processes() -> [pid()]. +processes() -> + erlang:nif_error(undefined). + +%% purge_module/1 +-spec purge_module(Module) -> true when + Module :: atom(). +purge_module(_Module) -> + erlang:nif_error(undefined). + +%% put/2 +-spec put(Key, Val) -> term() when + Key :: term(), + Val :: term(). +put(_Key, _Val) -> + erlang:nif_error(undefined). + +%% raise/3 +-spec erlang:raise(Class, Reason, Stacktrace) -> no_return() when + Class :: error | exit | throw, + Reason :: term(), + Stacktrace :: raise_stacktrace(). +raise(_Class, _Reason, _Stacktrace) -> + erlang:nif_error(undefined). + +%% read_timer/1 +-spec erlang:read_timer(TimerRef) -> non_neg_integer() | false when + TimerRef :: reference(). +read_timer(_TimerRef) -> + erlang:nif_error(undefined). + +%% ref_to_list/1 +-spec erlang:ref_to_list(Ref) -> string() when + Ref :: reference(). +ref_to_list(_Ref) -> + erlang:nif_error(undefined). + +%% register/2 +-spec register(RegName, PidOrPort) -> true when + RegName :: atom(), + PidOrPort :: port() | pid(). +register(_RegName, _PidOrPort) -> + erlang:nif_error(undefined). + +%% registered/0 +-spec registered() -> [RegName] when + RegName :: atom(). +registered() -> + erlang:nif_error(undefined). + +%% resume_process/1 +-spec erlang:resume_process(Suspendee) -> true when + Suspendee :: pid(). +resume_process(_Suspendee) -> + erlang:nif_error(undefined). + +%% round/1 +%% Shadowed by erl_bif_types: erlang:round/1 +-spec round(Number) -> integer() when + Number :: number(). +round(_Number) -> + erlang:nif_error(undefined). + +%% self/0 +%% Shadowed by erl_bif_types: erlang:self/0 +-spec self() -> pid(). +self() -> + erlang:nif_error(undefined). + +%% send_after/3 +-spec erlang:send_after(Time, Dest, Msg) -> TimerRef when + Time :: non_neg_integer(), + Dest :: pid() | atom(), + Msg :: term(), + TimerRef :: reference(). +send_after(_Time, _Dest, _Msg) -> + erlang:nif_error(undefined). + +%% seq_trace/2 +-spec erlang:seq_trace(P1, P2) -> seq_trace_info_returns() | {term(), term(), term(), term(), term()} when + P1 :: atom(), + P2 :: boolean() | {integer(), integer()} | integer() | []. +seq_trace(_P1, _P2) -> + erlang:nif_error(undefined). + +%% seq_trace_print/1 +-spec erlang:seq_trace_print(P1) -> boolean() when + P1 :: term(). +seq_trace_print(_P1) -> + erlang:nif_error(undefined). + +%% seq_trace_print/2 +-spec erlang:seq_trace_print(P1, P2) -> boolean() when + P1 :: atom() | integer(), + P2 :: term(). +seq_trace_print(_P1, _P2) -> + erlang:nif_error(undefined). + +%% setnode/2 +-spec erlang:setnode(P1, P2) -> true when + P1 :: atom(), + P2 :: integer(). +setnode(_P1, _P2) -> + erlang:nif_error(undefined). + +%% setnode/3 +-spec erlang:setnode(P1, P2, P3) -> true when + P1 :: atom(), + P2 :: port(), + P3 :: {term(), term(), term(), term()}. +setnode(_P1, _P2, _P3) -> + erlang:nif_error(undefined). + +%% size/1 +%% Shadowed by erl_bif_types: erlang:size/1 +-spec size(Item) -> non_neg_integer() when + Item :: tuple() | binary(). +size(_Item) -> + erlang:nif_error(undefined). + +%% spawn/3 +-spec spawn(Module, Function, Args) -> pid() when + Module :: module(), + Function :: atom(), + Args :: [term()]. +spawn(_Module, _Function, _Args) -> + erlang:nif_error(undefined). + +%% spawn_link/3 +-spec spawn_link(Module, Function, Args) -> pid() when + Module :: module(), + Function :: atom(), + Args :: [term()]. +spawn_link(_Module, _Function, _Args) -> + erlang:nif_error(undefined). + +%% split_binary/2 +-spec split_binary(Bin, Pos) -> {binary(), binary()} when + Bin :: binary(), + Pos :: non_neg_integer(). +split_binary(_Bin, _Pos) -> + erlang:nif_error(undefined). + +%% start_timer/3 +-spec erlang:start_timer(Time, Dest, Msg) -> TimerRef when + Time :: non_neg_integer(), + Dest :: pid() | atom(), + Msg :: term(), + TimerRef :: reference(). +start_timer(_Time, _Dest, _Msg) -> + erlang:nif_error(undefined). + +%% suspend_process/2 +-spec erlang:suspend_process(Suspendee, OptList) -> boolean() when + Suspendee :: pid(), + OptList :: [Opt], + Opt :: unless_suspending | asynchronous. +suspend_process(_Suspendee, _OptList) -> + erlang:nif_error(undefined). + +%% system_monitor/0 +-spec erlang:system_monitor() -> MonSettings when + MonSettings :: undefined | { MonitorPid, Options }, + MonitorPid :: pid(), + Options :: [ system_monitor_option() ]. +system_monitor() -> + erlang:nif_error(undefined). + +%% system_monitor/1 +-spec erlang:system_monitor(Arg) -> MonSettings when + Arg :: undefined | { MonitorPid, Options }, + MonSettings :: undefined | { MonitorPid, Options }, + MonitorPid :: pid(), + Options :: [ system_monitor_option() ]. +system_monitor(_Arg) -> + erlang:nif_error(undefined). + +%% system_monitor/2 +-spec erlang:system_monitor(MonitorPid, Options) -> MonSettings when + MonitorPid :: pid(), + Options :: [ system_monitor_option() ], + MonSettings :: undefined | { OldMonitorPid, OldOptions }, + OldMonitorPid :: pid(), + OldOptions :: [ system_monitor_option() ]. +system_monitor(_MonitorPid, _Options) -> + erlang:nif_error(undefined). + +%% system_profile/0 +-spec erlang:system_profile() -> ProfilerSettings when + ProfilerSettings :: undefined | { ProfilerPid, Options}, + ProfilerPid :: pid() | port(), + Options :: [ system_profile_option() ]. +system_profile() -> + erlang:nif_error(undefined). + +%% system_profile/2 +-spec erlang:system_profile(ProfilerPid, Options) -> ProfilerSettings when + ProfilerPid :: pid() | port() | undefined, + Options :: [ system_profile_option() ], + ProfilerSettings :: undefined | { pid() | port(), [ system_profile_option() ]}. +system_profile(_ProfilerPid, _Options) -> + erlang:nif_error(undefined). + +%% throw/1 +%% Shadowed by erl_bif_types: erlang:throw/1 +-spec throw(Any) -> no_return() when + Any :: term(). +throw(_Any) -> + erlang:nif_error(undefined). + +%% time/0 +-spec time() -> Time when + Time :: calendar:time(). +time() -> + erlang:nif_error(undefined). + +%% trace/3 +-spec erlang:trace(PidSpec, How, FlagList) -> integer() when + PidSpec :: pid() | existing | new | all, + How :: boolean(), + FlagList :: [trace_flag()]. +trace(_PidSpec, _How, _FlagList) -> + erlang:nif_error(undefined). + +%% trace_delivered/1 +-spec erlang:trace_delivered(Tracee) -> Ref when + Tracee :: pid() | all, + Ref :: reference(). +trace_delivered(_Tracee) -> + erlang:nif_error(undefined). + +%% trace_info/2 +-spec erlang:trace_info(PidOrFunc, Item) -> Res when + PidOrFunc :: pid() | new | {Module, Function, Arity} | on_load, + Module :: module(), + Function :: atom(), + Arity :: arity(), + Item :: flags | tracer | traced | match_spec | meta | meta_match_spec | call_count | call_time | all, + Res :: trace_info_return(). +trace_info(_PidOrFunc, _Item) -> + erlang:nif_error(undefined). + +%% trunc/1 +%% Shadowed by erl_bif_types: erlang:trunc/1 +-spec trunc(Number) -> integer() when + Number :: number(). +trunc(_Number) -> + erlang:nif_error(undefined). + +%% tuple_size/1 +%% Shadowed by erl_bif_types: erlang:tuple_size/1 +-spec tuple_size(Tuple) -> non_neg_integer() when + Tuple :: tuple(). +tuple_size(_Tuple) -> + erlang:nif_error(undefined). + +%% universaltime/0 +-spec erlang:universaltime() -> DateTime when + DateTime :: calendar:datetime(). +universaltime() -> + erlang:nif_error(undefined). + +%% universaltime_to_posixtime/1 +-spec erlang:universaltime_to_posixtime(P1) -> integer() when + P1 :: {calendar:date(), calendar:time()}. +universaltime_to_posixtime(_P1) -> + erlang:nif_error(undefined). + +%% unlink/1 +-spec unlink(Id) -> true when + Id :: pid() | port(). +unlink(_Id) -> + erlang:nif_error(undefined). + +%% unregister/1 +-spec unregister(RegName) -> true when + RegName :: atom(). +unregister(_RegName) -> + erlang:nif_error(undefined). + +%% whereis/1 +-spec whereis(RegName) -> pid() | port() | undefined when + RegName :: atom(). +whereis(_RegName) -> + erlang:nif_error(undefined). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% More complicated native code BIFs +%%% These are here for the types/specs, the real implementation is in the C code. +%%% This chunk is handwritten, i.e. contains more complicated specs. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% types and specs + +%% Shadowed by erl_bif_types: erlang:abs/1 +-spec abs(Float) -> float() when + Float :: float(); + (Int) -> non_neg_integer() when + Int :: integer(). +abs(_Number) -> + erlang:nif_error(undefined). + +%% Not documented +%% Shadowed by erl_bif_types: erlang:append/2 +-spec erlang:append(List,Tail) -> maybe_improper_list() when + List :: [term()], + Tail :: term(). +append(_List,_Tail) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:element/2 +-spec element(N, Tuple) -> term() when + N :: pos_integer(), + Tuple :: tuple(). +element(_N, _Tuple) -> + erlang:nif_error(undefined). + +%% Not documented +-spec erlang:get_module_info(Module, Item) -> ModuleInfo when + Module :: atom(), + Item :: module | imports | exports | functions | attributes | compile | native_addresses, + ModuleInfo :: atom() | [] | [{atom(), arity()}] | [{atom(), term()}] | [{atom(), arity(), integer()}]. +get_module_info(_Module, _Item) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:hd/1 +-spec hd(List) -> term() when + List :: [term(), ...]. +hd(_List) -> + erlang:nif_error(undefined). + +%% erlang:info/1 no longer exists! + +%% Shadowed by erl_bif_types: erlang:is_atom/1 +-spec is_atom(Term) -> boolean() when + Term :: term(). +is_atom(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_binary/1 +-spec is_binary(Term) -> boolean() when + Term :: term(). +is_binary(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_bitstring/1 +-spec is_bitstring(Term) -> boolean() when + Term :: term(). +is_bitstring(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_boolean/1 +-spec is_boolean(Term) -> boolean() when + Term :: term(). +is_boolean(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_float/1 +-spec is_float(Term) -> boolean() when + Term :: term(). +is_float(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_function/1 +-spec is_function(Term) -> boolean() when + Term :: term(). +is_function(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_function/2 +-spec is_function(Term, Arity) -> boolean() when + Term :: term(), + Arity :: arity(). +is_function(_Term, _Arity) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_integer/1 +-spec is_integer(Term) -> boolean() when + Term :: term(). +is_integer(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_list/1 +-spec is_list(Term) -> boolean() when + Term :: term(). +is_list(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_number/1 +-spec is_number(Term) -> boolean() when + Term :: term(). +is_number(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_pid/1 +-spec is_pid(Term) -> boolean() when + Term :: term(). +is_pid(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_port/1 +-spec is_port(Term) -> boolean() when + Term :: term(). +is_port(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_record/2 +-spec is_record(Term,RecordTag) -> boolean() when + Term :: term(), + RecordTag :: atom(). +is_record(_Term,_RecordTag) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_record/3 +-spec is_record(Term,RecordTag,Size) -> boolean() when + Term :: term(), + RecordTag :: atom(), + Size :: non_neg_integer(). +is_record(_Term,_RecordTag,_Size) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_reference/1 +-spec is_reference(Term) -> boolean() when + Term :: term(). +is_reference(_Term) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:is_tuple/1 +-spec is_tuple(Term) -> boolean() when + Term :: term(). +is_tuple(_Term) -> + erlang:nif_error(undefined). + +-spec load_module(Module, Binary) -> {module, Module} | {error, Reason} when + Module :: module(), + Binary :: binary(), + Reason :: badfile | not_purged | on_load. +load_module(Mod, Code) -> + case erlang:prepare_loading(Mod, Code) of + {error,_}=Error -> + Error; + Bin when erlang:is_binary(Bin) -> + case erlang:finish_loading([Bin]) of + ok -> + {module,Mod}; + {Error,[Mod]} -> + {error,Error} + end + end. + +-spec erlang:load_nif(Path, LoadInfo) -> ok | Error when + Path :: string(), + LoadInfo :: term(), + Error :: {error, {Reason, Text :: string()}}, + Reason :: load_failed | bad_lib | load | reload | upgrade | old_code. +load_nif(_Path, _LoadInfo) -> + erlang:nif_error(undefined). + +-spec erlang:localtime_to_universaltime(Localtime, IsDst) -> Universaltime when + Localtime :: calendar:datetime(), + Universaltime :: calendar:datetime(), + IsDst :: true | false | undefined. +localtime_to_universaltime(_Localtime, _IsDst) -> + erlang:nif_error(undefined). + +%% CHECK! Why the strange very thorough specification of the error +%% condition with disallowed arity in erl_bif_types? +%% Not documented +-spec erlang:make_fun(Module, Function, Arity) -> function() when + Module :: atom(), + Function :: atom(), + Arity :: arity(). +make_fun(_Module,_Function, _Arity) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:make_tuple/2 +-spec erlang:make_tuple(Arity, InitialValue) -> tuple() when + Arity :: arity(), + InitialValue :: term(). +make_tuple(_Arity,_InitialValue) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:make_tuple/3 +-spec erlang:make_tuple(Arity, DefaultValue, InitList) -> tuple() when + Arity :: arity(), + DefaultValue :: term(), + InitList :: [{Position :: pos_integer(), term()}]. +make_tuple(_Arity,_DefaultValue,_InitList) -> + erlang:nif_error(undefined). + +-spec nodes(Arg) -> Nodes when + Arg :: NodeType | [NodeType], + NodeType :: visible | hidden | connected | this | known, + Nodes :: [node()]. +nodes(_Arg) -> + erlang:nif_error(undefined). + +-spec open_port(PortName, PortSettings) -> port() when + PortName :: {spawn, Command :: string()} | + {spawn_driver, Command :: [byte()]} | + {spawn_executable, FileName :: file:name() } | + {fd, In :: non_neg_integer(), Out :: non_neg_integer()}, + PortSettings :: [Opt], + Opt :: {packet, N :: 1 | 2 | 4} + | stream + | {line, L :: non_neg_integer()} + | {cd, Dir :: string()} + | {env, Env :: [{Name :: string(), Val :: string() | false}]} + | {args, [string() | binary()]} + | {arg0, string() | binary()} + | exit_status + | use_stdio + | nouse_stdio + | stderr_to_stdout + | in + | out + | binary + | eof. +open_port(_PortName,_PortSettings) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:port_call/2 +-spec erlang:port_call(Port, Data) -> term() when + Port :: port() | atom(), + Data :: term(). +port_call(_Port, _Data) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:port_call/3 +-spec erlang:port_call(Port, Operation, Data) -> term() when + Port :: port() | atom(), + Operation :: integer(), + Data :: term(). +port_call(_Port, _Operation, _Data) -> + erlang:nif_error(undefined). + +-type port_info_item() :: + registered_name | + id | + connected | + links | + name | + input | + output. + +-type port_info_result_item() :: + {registered_name, RegName :: atom()} | + {id, Index :: non_neg_integer()} | + {connected, Pid :: pid()} | + {links, Pids :: [pid()]} | + {name, String :: string()} | + {input, Bytes :: non_neg_integer()} | + {output, Bytes :: non_neg_integer()}. + +%% Shadowed by erl_bif_types: erlang:port_info/1 +-spec erlang:port_info(Port) -> Result when + Port :: port() | atom(), + Result :: [port_info_result_item()] | undefined. +port_info(_Result) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:port_info/2 +-spec erlang:port_info(Port, Item) -> Result when + Port :: port() | atom(), + Item :: port_info_item(), + Result :: port_info_result_item() | undefined. +port_info(_Result, _Item) -> + erlang:nif_error(undefined). + +-type priority_level() :: + low | normal | high | max. + +-spec process_flag(trap_exit, Boolean) -> OldBoolean when + Boolean :: boolean(), + OldBoolean :: boolean(); + (error_handler, Module) -> OldModule when + Module :: atom(), + OldModule :: atom(); + (min_heap_size, MinHeapSize) -> OldMinHeapSize when + MinHeapSize :: non_neg_integer(), + OldMinHeapSize :: non_neg_integer(); + (min_bin_vheap_size, MinBinVHeapSize) -> OldMinBinVHeapSize when + MinBinVHeapSize :: non_neg_integer(), + OldMinBinVHeapSize :: non_neg_integer(); + (priority, Level) -> OldLevel when + Level :: priority_level(), + OldLevel :: priority_level(); + (save_calls, N) -> OldN when + N :: 0..10000, + OldN :: 0..10000; + (sensitive, Boolean) -> OldBoolean when + Boolean :: boolean(), + OldBoolean :: boolean(); + %% Deliberately not documented. + ({monitor_nodes, term()}, term()) -> term(); + (monitor_nodes, term()) -> term(). + +process_flag(_Flag, _Value) -> + erlang:nif_error(undefined). + +-type process_info_item() :: + backtrace | + binary | + catchlevel | + current_function | + current_location | + current_stacktrace | + dictionary | + error_handler | + garbage_collection | + group_leader | + heap_size | + initial_call | + links | + last_calls | + memory | + message_binary | + message_que_len | + messages | + min_heap_size | + min_bin_vheap_size | + monitored_by | + monitors | + priority | + reductions | + registered_name | + sequential_trace_token | + stack_size | + status | + suspending | + total_heap_size | + trace | + trap_exit. + +-type process_info_result_item() :: + {backtrace, Bin :: binary()} | + {binary, BinInfo :: [{non_neg_integer(), + non_neg_integer(), + non_neg_integer()}]} | + {catchlevel, CatchLevel :: non_neg_integer()} | + {current_function, + {Module :: module(), Function :: atom(), Arity :: arity()}} | + {current_location, + {Module :: module(), Function :: atom(), Arity :: arity(), + Location :: [{file, Filename :: string()} | % not a stack_item()! + {line, Line :: pos_integer()}]}} | + {current_stacktrace, Stack :: [stack_item()]} | + {dictionary, Dictionary :: [{Key :: term(), Value :: term()}]} | + {error_handler, Module :: module()} | + {garbage_collection, GCInfo :: [{atom(),non_neg_integer()}]} | + {group_leader, GroupLeader :: pid()} | + {heap_size, Size :: non_neg_integer()} | + {initial_call, mfa()} | + {links, Pids :: [pid()]} | + {last_calls, false | (Calls :: [mfa()])} | + {memory, Size :: non_neg_integer()} | + {message_binary, BinInfo :: term()} | + {message_que_len, MessageQueueLen :: non_neg_integer()} | + {messages, MessageQueue :: [term()]} | + {min_heap_size, MinHeapSize :: non_neg_integer()} | + {min_bin_vheap_size, MinBinVHeapSize :: non_neg_integer()} | + {monitored_by, Pids :: [pid()]} | + {monitors, + Monitors :: [{process, Pid :: pid() | + {RegName :: atom(), Node :: node()}}]} | + {priority, Level :: priority_level()} | + {reductions, Number :: non_neg_integer()} | + {registered_name, Atom :: atom()} | + {sequential_trace_token, [] | (SequentialTraceToken :: term())} | + {stack_size, Size :: non_neg_integer()} | + {status, Status :: exiting | garbage_collecting | waiting | running | runnable | suspended} | + {suspending, + SuspendeeList :: [{Suspendee :: pid(), + ActiveSuspendCount :: non_neg_integer(), + OutstandingSuspendCount ::non_neg_integer()}]} | + {total_heap_size, Size :: non_neg_integer()} | + {trace, InternalTraceFlags :: non_neg_integer()} | + {trap_exit, Boolean :: boolean()}. + +-type stack_item() :: + {Module :: module(), + Function :: atom(), + Arity :: arity() | (Args :: [term()]), + Location :: [{file, Filename :: string()} | + {line, Line :: pos_integer()}]}. + +-spec process_info(Pid, Item) -> + InfoTuple | [] | undefined when + Pid :: pid(), + Item :: process_info_item(), + InfoTuple :: process_info_result_item(); + (Pid, ItemList) -> InfoTupleList | [] | undefined when + Pid :: pid(), + ItemList :: [Item], + Item :: process_info_item(), + InfoTupleList :: [InfoTuple], + InfoTuple :: process_info_result_item(). +process_info(_Pid,_ItemSpec) -> + erlang:nif_error(undefined). + +-spec erlang:send(Dest, Msg) -> Msg when + Dest :: dst(), + Msg :: term(). +send(_Dest,_Msg) -> + erlang:nif_error(undefined). + +-spec erlang:send(Dest, Msg, Options) -> Res when + Dest :: dst(), + Msg :: term(), + Options :: [nosuspend | noconnect], + Res :: ok | nosuspend | noconnect. +send(_Dest,_Msg,_Options) -> + erlang:nif_error(undefined). + +%% Not documented +-spec erlang:seq_trace_info(send) -> {send, boolean()}; + ('receive') -> {'receive', boolean()}; + (print) -> {print, boolean()}; + (timestamp) -> {timestamp, boolean()}; + (label) -> [] | {label, non_neg_integer()}; + (serial) -> [] | {serial, {non_neg_integer(), non_neg_integer()}}. +seq_trace_info(_What) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:setelement/3 +-spec setelement(Index, Tuple1, Value) -> Tuple2 when + Index :: pos_integer(), + Tuple1 :: tuple(), + Tuple2 :: tuple(), + Value :: term(). +setelement(_Index, _Tuple1, _Value) -> + erlang:nif_error(undefined). + +-spec erlang:spawn_opt({Module, Function, Args, Options}) -> pid() | {pid(), reference()} when + Module :: module(), + Function :: atom(), + Args :: [term()], + Options :: [Option], + Option :: link | monitor | {priority, Level} + | {fullsweep_after, Number :: non_neg_integer()} + | {min_heap_size, Size :: non_neg_integer()} + | {min_bin_vheap_size, VSize :: non_neg_integer()}, + Level :: low | normal | high. +spawn_opt(_Tuple) -> + erlang:nif_error(undefined). + +-spec statistics(context_switches) -> {ContextSwitches,0} when + ContextSwitches :: non_neg_integer(); + (exact_reductions) -> {Total_Exact_Reductions, + Exact_Reductions_Since_Last_Call} when + Total_Exact_Reductions :: non_neg_integer(), + Exact_Reductions_Since_Last_Call :: non_neg_integer(); + (garbage_collection) -> {Number_of_GCs, Words_Reclaimed, 0} when + Number_of_GCs :: non_neg_integer(), + Words_Reclaimed :: non_neg_integer(); + (io) -> {{input, Input}, {output, Output}} when + Input :: non_neg_integer(), + Output :: non_neg_integer(); + (reductions) -> {Total_Reductions, + Reductions_Since_Last_Call} when + Total_Reductions :: non_neg_integer(), + Reductions_Since_Last_Call :: non_neg_integer(); + (run_queue) -> non_neg_integer(); + (runtime) -> {Total_Run_Time, Time_Since_Last_Call} when + Total_Run_Time :: non_neg_integer(), + Time_Since_Last_Call :: non_neg_integer(); + (scheduler_wall_time) -> [{SchedulerId, ActiveTime, TotalTime}] | undefined when + SchedulerId :: pos_integer(), + ActiveTime :: non_neg_integer(), + TotalTime :: non_neg_integer(); + (wall_clock) -> {Total_Wallclock_Time, + Wallclock_Time_Since_Last_Call} when + Total_Wallclock_Time :: non_neg_integer(), + Wallclock_Time_Since_Last_Call :: non_neg_integer(). +statistics(_Item) -> + erlang:nif_error(undefined). + +%% Not documented +%% Shadowed by erl_bif_types: erlang:subtract/2 +-spec erlang:subtract([term()], [term()]) -> [term()]. +subtract(_,_) -> + erlang:nif_error(undefined). + +-type scheduler_bind_type() :: + 'no_node_processor_spread' | + 'no_node_thread_spread' | + 'no_spread' | + 'processor_spread' | + 'spread' | + 'thread_spread' | + 'thread_no_node_processor_spread' | + 'unbound'. + +-spec erlang:system_flag(backtrace_depth, Depth) -> OldDepth when + Depth :: non_neg_integer(), + OldDepth :: non_neg_integer(); + (cpu_topology, CpuTopology) -> OldCpuTopology when + CpuTopology :: cpu_topology(), + OldCpuTopology :: cpu_topology(); + (fullsweep_after, Number) -> OldNumber when + Number :: non_neg_integer(), + OldNumber :: non_neg_integer(); + (min_heap_size, MinHeapSize) -> OldMinHeapSize when + MinHeapSize :: non_neg_integer(), + OldMinHeapSize :: non_neg_integer(); + (min_bin_vheap_size, MinBinVHeapSize) -> + OldMinBinVHeapSize when + MinBinVHeapSize :: non_neg_integer(), + OldMinBinVHeapSize :: non_neg_integer(); + (multi_scheduling, BlockState) -> OldBlockState when + BlockState :: block | unblock, + OldBlockState :: block | unblock | enabled; + (scheduler_bind_type, How) -> OldBindType when + How :: scheduler_bind_type() | default_bind, + OldBindType :: scheduler_bind_type(); + (scheduler_wall_time, Boolean) -> OldBoolean when + Boolean :: boolean(), + OldBoolean :: boolean(); + (schedulers_online, SchedulersOnline) -> + OldSchedulersOnline when + SchedulersOnline :: pos_integer(), + OldSchedulersOnline :: pos_integer(); + (trace_control_word, TCW) -> OldTCW when + TCW :: non_neg_integer(), + OldTCW :: non_neg_integer(); + %% These are deliberately not documented + (internal_cpu_topology, term()) -> term(); + (sequential_tracer, pid() | port() | false) -> pid() | port() | false; + (1,0) -> true. + +system_flag(_Flag, _Value) -> + erlang:nif_error(undefined). + +-spec term_to_binary(Term) -> ext_binary() when + Term :: term(). +term_to_binary(_Term) -> + erlang:nif_error(undefined). + +-spec term_to_binary(Term, Options) -> ext_binary() when + Term :: term(), + Options :: [compressed | + {compressed, Level :: 0..9} | + {minor_version, Version :: 0..1} ]. +term_to_binary(_Term, _Options) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:tl/1 +-spec tl(List) -> term() when + List :: [term(), ...]. +tl(_List) -> + erlang:nif_error(undefined). + +-type trace_pattern_mfa() :: + {atom(),atom(),arity() | '_'} | on_load. +-type trace_match_spec() :: + [{[term()] | '_' ,[term()],[term()]}]. + +-spec erlang:trace_pattern(MFA, MatchSpec) -> non_neg_integer() when + MFA :: trace_pattern_mfa(), + MatchSpec :: (MatchSpecList :: trace_match_spec()) + | boolean() + | restart + | pause. +trace_pattern(_MFA, _MatchSpec) -> + erlang:nif_error(undefined). + +-type trace_pattern_flag() :: + global | local | + meta | {meta, Pid :: pid()} | + call_count | + call_time. + +-spec erlang:trace_pattern(MFA, MatchSpec, FlagList) -> non_neg_integer() when + MFA :: trace_pattern_mfa(), + MatchSpec :: (MatchSpecList :: trace_match_spec()) + | boolean() + | restart + | pause, + FlagList :: [ trace_pattern_flag() ]. +trace_pattern(_MFA, _MatchSpec, _FlagList) -> + erlang:nif_error(undefined). + +%% Shadowed by erl_bif_types: erlang:tuple_to_list/1 +-spec tuple_to_list(Tuple) -> [term()] when + Tuple :: tuple(). +tuple_to_list(_Tuple) -> + erlang:nif_error(undefined). + +-type cpu_topology() :: + [LevelEntry :: level_entry()] | undefined. +-type level_entry() :: + {LevelTag :: level_tag(), SubLevel :: sub_level()} + | {LevelTag :: level_tag(), + InfoList :: info_list(), + SubLevel :: sub_level()}. +-type level_tag() :: core | node | processor | thread. +-type sub_level() :: [LevelEntry :: level_entry()] + | (LogicalCpuId :: {logical, non_neg_integer()}). +-type info_list() :: []. + +%% Note: changing the ordering number of a clause will change the docs! +%% Shadowed by erl_bif_types: erlang:system_info/1 +-spec erlang:system_info + (allocated_areas) -> [ tuple() ]; + (allocator) -> + {Allocator, Version, Features, Settings} when + Allocator :: undefined | glibc, + Version :: [non_neg_integer()], + Features :: [atom()], + Settings :: [{Subsystem :: atom(), + [{Parameter :: atom(), + Value :: term()}]}]; + (alloc_util_allocators) -> [Alloc] when + Alloc :: atom(); + ({allocator, Alloc}) -> [_] when %% More or less anything + Alloc :: atom(); + ({allocator_sizes, Alloc}) -> [_] when %% More or less anything + Alloc :: atom(); + (build_type) -> opt | debug | purify | quantify | purecov | + gcov | valgrind | gprof | lcnt; + (c_compiler_used) -> {atom(), term()}; + (check_io) -> [_]; + (compat_rel) -> integer(); + (cpu_topology) -> CpuTopology when + CpuTopology :: cpu_topology(); + ({cpu_topology, defined | detected | used}) -> CpuTopology when + CpuTopology :: cpu_topology(); + (creation) -> integer(); + (debug_compiled) -> boolean(); + (dist) -> binary(); + (dist_ctrl) -> {Node :: node(), + ControllingEntity :: port() | pid()}; + (driver_version) -> string(); + (elib_malloc) -> false; + (dist_buf_busy_limit) -> non_neg_integer(); + (fullsweep_after) -> {fullsweep_after, non_neg_integer()}; + (garbage_collection) -> [{atom(), integer()}]; + (global_heaps_size) -> non_neg_integer(); + (heap_sizes) -> [non_neg_integer()]; + (heap_type) -> private | shared | hybrid; + (info) -> binary(); + (kernel_poll) -> boolean(); + (loaded) -> binary(); + (logical_processors | + logical_processors_available | + logical_processors_online) -> unknown | pos_integer(); + (machine) -> string(); + (min_heap_size) -> {min_heap_size, MinHeapSize :: pos_integer()}; + (min_bin_vheap_size) -> {min_bin_vheap_size, + MinBinVHeapSize :: pos_integer()}; + (modified_timing_level) -> integer() | undefined; + (multi_scheduling) -> disabled | blocked | enabled; + (multi_scheduling_blockers) -> [PID :: pid()]; + (otp_release) -> string(); + (process_count) -> pos_integer(); + (process_limit) -> pos_integer(); + (procs) -> binary(); + (scheduler_bind_type) -> spread | + processor_spread | + thread_spread | + thread_no_node_processor_spread | + no_node_processor_spread | + no_node_thread_spread | + no_spread | + unbound; + (scheduler_bindings) -> tuple(); + (scheduler_id) -> SchedulerId :: pos_integer(); + (schedulers | schedulers_online) -> pos_integer(); + (smp_support) -> boolean(); + (system_version) -> string(); + (system_architecture) -> string(); + (threads) -> boolean(); + (thread_pool_size) -> non_neg_integer(); + (trace_control_word) -> non_neg_integer(); + (update_cpu_info) -> changed | unchanged; + (version) -> string(); + (wordsize | {wordsize, internal} | {wordsize, external}) -> 4 | 8. +system_info(_Item) -> + erlang:nif_error(undefined). + +-spec erlang:universaltime_to_localtime(Universaltime) -> Localtime when + Localtime :: calendar:datetime(), + Universaltime :: calendar:datetime(). +universaltime_to_localtime(_Universaltime) -> + erlang:nif_error(undefined). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% End of native code BIFs +%%% Actual Erlang implementation of some BIF's follow +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%-------------------------------------------------------------------------- -spec apply(Fun, Args) -> term() when @@ -71,6 +2128,7 @@ apply(Fun, Args) -> erlang:apply(Fun, Args). +%% Shadowed by erl_bif_types: erlang:apply/3 -spec apply(Module, Function, Args) -> term() when Module :: module(), Function :: atom(), @@ -82,42 +2140,42 @@ apply(Mod, Name, Args) -> -spec spawn(Fun) -> pid() when Fun :: function(). -spawn(F) when is_function(F) -> - spawn(erlang, apply, [F, []]); -spawn({M,F}=MF) when is_atom(M), is_atom(F) -> - spawn(erlang, apply, [MF, []]); +spawn(F) when erlang:is_function(F) -> + erlang:spawn(erlang, apply, [F, []]); +spawn({M,F}=MF) when erlang:is_atom(M), erlang:is_atom(F) -> + erlang:spawn(erlang, apply, [MF, []]); spawn(F) -> erlang:error(badarg, [F]). -spec spawn(Node, Fun) -> pid() when Node :: node(), Fun :: function(). -spawn(N, F) when N =:= node() -> - spawn(F); -spawn(N, F) when is_function(F) -> - spawn(N, erlang, apply, [F, []]); -spawn(N, {M,F}=MF) when is_atom(M), is_atom(F) -> - spawn(N, erlang, apply, [MF, []]); +spawn(N, F) when N =:= erlang:node() -> + erlang:spawn(F); +spawn(N, F) when erlang:is_function(F) -> + erlang:spawn(N, erlang, apply, [F, []]); +spawn(N, {M,F}=MF) when erlang:is_atom(M), erlang:is_atom(F) -> + erlang:spawn(N, erlang, apply, [MF, []]); spawn(N, F) -> erlang:error(badarg, [N, F]). -spec spawn_link(Fun) -> pid() when Fun :: function(). -spawn_link(F) when is_function(F) -> - spawn_link(erlang, apply, [F, []]); -spawn_link({M,F}=MF) when is_atom(M), is_atom(F) -> - spawn_link(erlang, apply, [MF, []]); +spawn_link(F) when erlang:is_function(F) -> + erlang:spawn_link(erlang, apply, [F, []]); +spawn_link({M,F}=MF) when erlang:is_atom(M), erlang:is_atom(F) -> + erlang:spawn_link(erlang, apply, [MF, []]); spawn_link(F) -> erlang:error(badarg, [F]). -spec spawn_link(Node, Fun) -> pid() when Node :: node(), Fun :: function(). -spawn_link(N, F) when N =:= node() -> +spawn_link(N, F) when N =:= erlang:node() -> spawn_link(F); -spawn_link(N, F) when is_function(F) -> +spawn_link(N, F) when erlang:is_function(F) -> spawn_link(N, erlang, apply, [F, []]); -spawn_link(N, {M,F}=MF) when is_atom(M), is_atom(F) -> +spawn_link(N, {M,F}=MF) when erlang:is_atom(M), erlang:is_atom(F) -> spawn_link(N, erlang, apply, [MF, []]); spawn_link(N, F) -> erlang:error(badarg, [N, F]). @@ -126,7 +2184,7 @@ spawn_link(N, F) -> -spec spawn_monitor(Fun) -> {pid(), reference()} when Fun :: function(). -spawn_monitor(F) when is_function(F, 0) -> +spawn_monitor(F) when erlang:is_function(F, 0) -> erlang:spawn_opt({erlang,apply,[F,[]],[monitor]}); spawn_monitor(F) -> erlang:error(badarg, [F]). @@ -135,7 +2193,9 @@ spawn_monitor(F) -> Module :: module(), Function :: atom(), Args :: [term()]. -spawn_monitor(M, F, A) when is_atom(M), is_atom(F), is_list(A) -> +spawn_monitor(M, F, A) when erlang:is_atom(M), + erlang:is_atom(F), + erlang:is_list(A) -> erlang:spawn_opt({M,F,A,[monitor]}); spawn_monitor(M, F, A) -> erlang:error(badarg, [M,F,A]). @@ -148,9 +2208,9 @@ spawn_monitor(M, F, A) -> | {min_heap_size, Size :: non_neg_integer()} | {min_bin_vheap_size, VSize :: non_neg_integer()}, Level :: low | normal | high. -spawn_opt(F, O) when is_function(F) -> +spawn_opt(F, O) when erlang:is_function(F) -> spawn_opt(erlang, apply, [F, []], O); -spawn_opt({M,F}=MF, O) when is_atom(M), is_atom(F) -> +spawn_opt({M,F}=MF, O) when erlang:is_atom(M), erlang:is_atom(F) -> spawn_opt(erlang, apply, [MF, []], O); spawn_opt({M,F,A}, O) -> % For (undocumented) backward compatibility spawn_opt(M, F, A, O); @@ -166,11 +2226,11 @@ spawn_opt(F, O) -> | {min_heap_size, Size :: non_neg_integer()} | {min_bin_vheap_size, VSize :: non_neg_integer()}, Level :: low | normal | high. -spawn_opt(N, F, O) when N =:= node() -> +spawn_opt(N, F, O) when N =:= erlang:node() -> spawn_opt(F, O); -spawn_opt(N, F, O) when is_function(F) -> +spawn_opt(N, F, O) when erlang:is_function(F) -> spawn_opt(N, erlang, apply, [F, []], O); -spawn_opt(N, {M,F}=MF, O) when is_atom(M), is_atom(F) -> +spawn_opt(N, {M,F}=MF, O) when erlang:is_atom(M), erlang:is_atom(F) -> spawn_opt(N, erlang, apply, [MF, []], O); spawn_opt(N, F, O) -> erlang:error(badarg, [N, F, O]). @@ -182,9 +2242,14 @@ spawn_opt(N, F, O) -> Module :: module(), Function :: atom(), Args :: [term()]. -spawn(N,M,F,A) when N =:= node(), is_atom(M), is_atom(F), is_list(A) -> - spawn(M,F,A); -spawn(N,M,F,A) when is_atom(N), is_atom(M), is_atom(F) -> +spawn(N,M,F,A) when N =:= erlang:node(), + erlang:is_atom(M), + erlang:is_atom(F), + erlang:is_list(A) -> + erlang:spawn(M,F,A); +spawn(N,M,F,A) when erlang:is_atom(N), + erlang:is_atom(M), + erlang:is_atom(F) -> case is_well_formed_list(A) of true -> ok; @@ -192,9 +2257,9 @@ spawn(N,M,F,A) when is_atom(N), is_atom(M), is_atom(F) -> erlang:error(badarg, [N, M, F, A]) end, case catch gen_server:call({net_kernel,N}, - {spawn,M,F,A,group_leader()}, + {spawn,M,F,A,erlang:group_leader()}, infinity) of - Pid when is_pid(Pid) -> + Pid when erlang:is_pid(Pid) -> Pid; Error -> case remote_spawn_error(Error, {no_link, N, M, F, A, []}) of @@ -212,9 +2277,14 @@ spawn(N,M,F,A) -> Module :: module(), Function :: atom(), Args :: [term()]. -spawn_link(N,M,F,A) when N =:= node(), is_atom(M), is_atom(F), is_list(A) -> - spawn_link(M,F,A); -spawn_link(N,M,F,A) when is_atom(N), is_atom(M), is_atom(F) -> +spawn_link(N,M,F,A) when N =:= erlang:node(), + erlang:is_atom(M), + erlang:is_atom(F), + erlang:is_list(A) -> + erlang:spawn_link(M,F,A); +spawn_link(N,M,F,A) when erlang:is_atom(N), + erlang:is_atom(M), + erlang:is_atom(F) -> case is_well_formed_list(A) of true -> ok; @@ -222,9 +2292,9 @@ spawn_link(N,M,F,A) when is_atom(N), is_atom(M), is_atom(F) -> erlang:error(badarg, [N, M, F, A]) end, case catch gen_server:call({net_kernel,N}, - {spawn_link,M,F,A,group_leader()}, + {spawn_link,M,F,A,erlang:group_leader()}, infinity) of - Pid when is_pid(Pid) -> + Pid when erlang:is_pid(Pid) -> Pid; Error -> case remote_spawn_error(Error, {link, N, M, F, A, []}) of @@ -268,11 +2338,13 @@ spawn_opt(M, F, A, Opts) -> | {min_heap_size, Size :: non_neg_integer()} | {min_bin_vheap_size, VSize :: non_neg_integer()}, Level :: low | normal | high. -spawn_opt(N, M, F, A, O) when N =:= node(), - is_atom(M), is_atom(F), is_list(A), - is_list(O) -> +spawn_opt(N, M, F, A, O) when N =:= erlang:node(), + erlang:is_atom(M), erlang:is_atom(F), + erlang:is_list(A), erlang:is_list(O) -> spawn_opt(M, F, A, O); -spawn_opt(N, M, F, A, O) when is_atom(N), is_atom(M), is_atom(F) -> +spawn_opt(N, M, F, A, O) when erlang:is_atom(N), + erlang:is_atom(M), + erlang:is_atom(F) -> case {is_well_formed_list(A), is_well_formed_list(O)} of {true, true} -> ok; @@ -291,9 +2363,9 @@ spawn_opt(N, M, F, A, O) when is_atom(N), is_atom(M), is_atom(F) -> {no_link,[]}, O), case catch gen_server:call({net_kernel,N}, - {spawn_opt,M,F,A,NO,L,group_leader()}, + {spawn_opt,M,F,A,NO,L,erlang:group_leader()}, infinity) of - Pid when is_pid(Pid) -> + Pid when erlang:is_pid(Pid) -> Pid; Error -> case remote_spawn_error(Error, {L, N, M, F, A, NO}) of @@ -331,11 +2403,11 @@ is_well_formed_list(_) -> crasher(Node,Mod,Fun,Args,[],Reason) -> error_logger:warning_msg("** Can not start ~w:~w,~w on ~w **~n", [Mod,Fun,Args,Node]), - exit(Reason); + erlang:exit(Reason); crasher(Node,Mod,Fun,Args,Opts,Reason) -> error_logger:warning_msg("** Can not start ~w:~w,~w (~w) on ~w **~n", [Mod,Fun,Args,Opts,Node]), - exit(Reason). + erlang:exit(Reason). -spec erlang:yield() -> 'true'. yield() -> @@ -356,7 +2428,7 @@ disconnect_node(Node) -> Item :: arity | env | index | name | module | new_index | new_uniq | pid | type | uniq, Info :: term(). -fun_info(Fun) when is_function(Fun) -> +fun_info(Fun) when erlang:is_function(Fun) -> Keys = [type,env,arity,name,uniq,index,new_uniq,new_index,module,pid], fun_info_1(Keys, Fun, []). @@ -388,11 +2460,9 @@ send_nosuspend(Pid, Msg, Opts) -> _ -> false end. --spec erlang:localtime_to_universaltime({Date1, Time1}) -> {Date2, Time2} when - Date1 :: calendar:date(), - Date2 :: calendar:date(), - Time1 :: calendar:time(), - Time2 :: calendar:time(). +-spec erlang:localtime_to_universaltime(Localtime) -> Universaltime when + Localtime :: calendar:datetime(), + Universaltime :: calendar:datetime(). localtime_to_universaltime(Localtime) -> erlang:localtime_to_universaltime(Localtime, undefined). @@ -412,25 +2482,25 @@ suspend_process(P) -> %% reactivate the command. %% --spec dlink(pid() | port()) -> 'true'. +-spec erlang:dlink(pid() | port()) -> 'true'. dlink(Pid) -> - case net_kernel:connect(node(Pid)) of - true -> link(Pid); - false -> erlang:dist_exit(self(), noconnection, Pid), true + case net_kernel:connect(erlang:node(Pid)) of + true -> erlang:link(Pid); + false -> erlang:dist_exit(erlang:self(), noconnection, Pid), true end. %% Can this ever happen? --spec dunlink(identifier()) -> 'true'. +-spec erlang:dunlink(identifier()) -> 'true'. dunlink(Pid) -> - case net_kernel:connect(node(Pid)) of - true -> unlink(Pid); + case net_kernel:connect(erlang:node(Pid)) of + true -> erlang:unlink(Pid); false -> true end. dmonitor_node(Node, Flag, []) -> case net_kernel:connect(Node) of true -> erlang:monitor_node(Node, Flag, []); - false -> self() ! {nodedown, Node}, true + false -> erlang:self() ! {nodedown, Node}, true end; dmonitor_node(Node, Flag, Opts) -> @@ -438,31 +2508,31 @@ dmonitor_node(Node, Flag, Opts) -> true -> case net_kernel:passive_cnct(Node) of true -> erlang:monitor_node(Node, Flag, Opts); - false -> self() ! {nodedown, Node}, true + false -> erlang:self() ! {nodedown, Node}, true end; _ -> dmonitor_node(Node,Flag,[]) end. dgroup_leader(Leader, Pid) -> - case net_kernel:connect(node(Pid)) of - true -> group_leader(Leader, Pid); + case net_kernel:connect(erlang:node(Pid)) of + true -> erlang:group_leader(Leader, Pid); false -> true %% bad arg ? end. dexit(Pid, Reason) -> - case net_kernel:connect(node(Pid)) of - true -> exit(Pid, Reason); + case net_kernel:connect(erlang:node(Pid)) of + true -> erlang:exit(Pid, Reason); false -> true end. -dsend(Pid, Msg) when is_pid(Pid) -> - case net_kernel:connect(node(Pid)) of +dsend(Pid, Msg) when erlang:is_pid(Pid) -> + case net_kernel:connect(erlang:node(Pid)) of true -> erlang:send(Pid, Msg); false -> Msg end; -dsend(Port, Msg) when is_port(Port) -> - case net_kernel:connect(node(Port)) of +dsend(Port, Msg) when erlang:is_port(Port) -> + case net_kernel:connect(erlang:node(Port)) of true -> erlang:send(Port, Msg); false -> Msg end; @@ -473,13 +2543,13 @@ dsend({Name, Node}, Msg) -> ignored -> Msg % Not distributed. end. -dsend(Pid, Msg, Opts) when is_pid(Pid) -> - case net_kernel:connect(node(Pid)) of +dsend(Pid, Msg, Opts) when erlang:is_pid(Pid) -> + case net_kernel:connect(erlang:node(Pid)) of true -> erlang:send(Pid, Msg, Opts); false -> ok end; -dsend(Port, Msg, Opts) when is_port(Port) -> - case net_kernel:connect(node(Port)) of +dsend(Port, Msg, Opts) when erlang:is_port(Port) -> + case net_kernel:connect(erlang:node(Port)) of true -> erlang:send(Port, Msg, Opts); false -> ok end; @@ -490,21 +2560,23 @@ dsend({Name, Node}, Msg, Opts) -> ignored -> ok % Not distributed. end. --spec dmonitor_p('process', pid() | {atom(),atom()}) -> reference(). +-spec erlang:dmonitor_p('process', pid() | {atom(),atom()}) -> reference(). dmonitor_p(process, ProcSpec) -> %% ProcSpec = pid() | {atom(),atom()} %% ProcSpec CANNOT be an atom because a locally registered process %% is never handled here. Node = case ProcSpec of - {S,N} when is_atom(S), is_atom(N), N =/= node() -> N; - _ when is_pid(ProcSpec) -> node(ProcSpec) + {S,N} when erlang:is_atom(S), + erlang:is_atom(N), + N =/= erlang:node() -> N; + _ when erlang:is_pid(ProcSpec) -> erlang:node(ProcSpec) end, case net_kernel:connect(Node) of true -> erlang:monitor(process, ProcSpec); false -> - Ref = make_ref(), - self() ! {'DOWN', Ref, process, ProcSpec, noconnection}, + Ref = erlang:make_ref(), + erlang:self() ! {'DOWN', Ref, process, ProcSpec, noconnection}, Ref end. @@ -512,7 +2584,7 @@ dmonitor_p(process, ProcSpec) -> %% Trap function used when modified timing has been enabled. %% --spec delay_trap(Result, timeout()) -> Result. +-spec erlang:delay_trap(Result, timeout()) -> Result. delay_trap(Result, 0) -> erlang:yield(), Result; delay_trap(Result, Timeout) -> receive after Timeout -> Result end. @@ -526,12 +2598,12 @@ delay_trap(Result, Timeout) -> receive after Timeout -> Result end. -spec erlang:set_cookie(Node, Cookie) -> true when Node :: node(), Cookie :: atom(). -set_cookie(Node, C) when Node =/= nonode@nohost, is_atom(Node) -> - case is_atom(C) of +set_cookie(Node, C) when Node =/= nonode@nohost, erlang:is_atom(Node) -> + case erlang:is_atom(C) of true -> auth:set_cookie(Node, C); false -> - error(badarg) + erlang:error(badarg) end. -spec erlang:get_cookie() -> Cookie | nocookie when @@ -545,7 +2617,8 @@ get_cookie() -> integer_to_list(I, 10) -> erlang:integer_to_list(I); integer_to_list(I, Base) - when is_integer(I), is_integer(Base), Base >= 2, Base =< 1+$Z-$A+10 -> + when erlang:is_integer(I), erlang:is_integer(Base), + Base >= 2, Base =< 1+$Z-$A+10 -> if I < 0 -> [$-|integer_to_list(-I, Base, [])]; true -> @@ -575,9 +2648,10 @@ integer_to_list(I0, Base, R0) -> list_to_integer(L, 10) -> erlang:list_to_integer(L); list_to_integer(L, Base) - when is_list(L), is_integer(Base), Base >= 2, Base =< 1+$Z-$A+10 -> + when erlang:is_list(L), erlang:is_integer(Base), + Base >= 2, Base =< 1+$Z-$A+10 -> case list_to_integer_sign(L, Base) of - I when is_integer(I) -> + I when erlang:is_integer(I) -> I; Fault -> erlang:error(Fault, [L,Base]) @@ -587,7 +2661,7 @@ list_to_integer(L, Base) -> list_to_integer_sign([$-|[_|_]=L], Base) -> case list_to_integer(L, Base, 0) of - I when is_integer(I) -> + I when erlang:is_integer(I) -> -I; I -> I @@ -600,13 +2674,13 @@ list_to_integer_sign(_, _) -> badarg. list_to_integer([D|L], Base, I) - when is_integer(D), D >= $0, D =< $9, D < Base+$0 -> + when erlang:is_integer(D), D >= $0, D =< $9, D < Base+$0 -> list_to_integer(L, Base, I*Base + D-$0); list_to_integer([D|L], Base, I) - when is_integer(D), D >= $A, D < Base+$A-10 -> + when erlang:is_integer(D), D >= $A, D < Base+$A-10 -> list_to_integer(L, Base, I*Base + D-$A+10); list_to_integer([D|L], Base, I) - when is_integer(D), D >= $a, D < Base+$a-10 -> + when erlang:is_integer(D), D >= $a, D < Base+$a-10 -> list_to_integer(L, Base, I*Base + D-$a+10); list_to_integer([], _, I) -> I; @@ -618,7 +2692,8 @@ list_to_integer(_, _, _) -> %% erlang:demonitor(Ref, [flush]) traps to %% erlang:flush_monitor_message(Ref, Res) when %% it needs to flush a monitor message. -flush_monitor_message(Ref, Res) when is_reference(Ref), is_atom(Res) -> +flush_monitor_message(Ref, Res) when erlang:is_reference(Ref), + erlang:is_atom(Res) -> receive {_, Ref, _, _, _} -> ok after 0 -> ok end, Res. @@ -644,7 +2719,7 @@ set_cpu_topology(CpuTopology) -> cput_e2i_clvl({logical, _}, _PLvl) -> #cpu.logical; cput_e2i_clvl([E | _], PLvl) -> - case element(1, E) of + case erlang:element(1, E) of node -> case PLvl of 0 -> #cpu.node; #cpu.processor -> #cpu.processor_node @@ -713,7 +2788,7 @@ cput_e2i({thread, TL}, Nid, PId, #cpu{thread = T0} = CPU, PLvl, #cpu.thread, cput_e2i(TL, Nid, PId, CPU#cpu{thread = T0+1}, #cpu.thread, Lvl, Res); cput_e2i({logical, ID}, _Nid, PId, #cpu{processor=P, core=C, thread=T} = CPU, PLvl, #cpu.logical, Res) - when PLvl < #cpu.logical, is_integer(ID), 0 =< ID, ID < 65536 -> + when PLvl < #cpu.logical, erlang:is_integer(ID), 0 =< ID, ID < 65536 -> [CPU#cpu{processor = case P of -1 -> PId+1; _ -> P end, core = case C of -1 -> 0; _ -> C end, thread = case T of -1 -> 0; _ -> T end, @@ -738,9 +2813,9 @@ cput_i2e([], _Frst, _Lvl, _TM) -> cput_i2e([#cpu{logical = LID}| _], _Frst, Lvl, _TM) when Lvl == #cpu.logical -> {logical, LID}; cput_i2e([#cpu{} = I | Is], Frst, Lvl, TM) -> - cput_i2e(element(Lvl, I), Frst, Is, [I], Lvl, TM). + cput_i2e(erlang:element(Lvl, I), Frst, Is, [I], Lvl, TM). -cput_i2e(V, Frst, [I | Is], SameV, Lvl, TM) when V =:= element(Lvl, I) -> +cput_i2e(V, Frst, [I | Is], SameV, Lvl, TM) when V =:= erlang:element(Lvl, I) -> cput_i2e(V, Frst, Is, [I | SameV], Lvl, TM); cput_i2e(-1, true, [], SameV, Lvl, TM) -> cput_i2e(rvrs(SameV), true, Lvl+1, TM); @@ -754,10 +2829,10 @@ cput_i2e(_V, _Frst, Is, SameV, Lvl, TM) -> [{cput_i2e_tag(Lvl, TM), cput_i2e(rvrs(SameV), true, Lvl+1, TM)} | cput_i2e(Is, false, Lvl, TM)]. -cput_i2e_tag_map() -> list_to_tuple([cpu | record_info(fields, cpu)]). +cput_i2e_tag_map() -> erlang:list_to_tuple([cpu | record_info(fields, cpu)]). cput_i2e_tag(Lvl, TM) -> - case element(Lvl, TM) of processor_node -> node; Other -> Other end. + case erlang:element(Lvl, TM) of processor_node -> node; Other -> Other end. rvrs([_] = L) -> L; rvrs(Xs) -> rvrs(Xs, []). @@ -776,7 +2851,7 @@ rvrs([X|Xs],Ys) -> rvrs(Xs, [X|Ys]). %% functions in bif.c. Do not make %% any changes to it without reading %% the comment about them in bif.c! --spec await_proc_exit(dst(), 'apply' | 'data' | 'reason', term()) -> term(). +-spec erlang:await_proc_exit(dst(), 'apply' | 'data' | 'reason', term()) -> term(). await_proc_exit(Proc, Op, Data) -> Mon = erlang:monitor(process, Proc), receive @@ -814,7 +2889,9 @@ max(A, _) -> A. %% erts_memory() in $ERL_TOP/erts/emulator/beam/erl_alloc.c %% --type memory_type() :: 'total' | 'processes' | 'processes_used' | 'system' | 'atom' | 'atom_used' | 'binary' | 'code' | 'ets' | 'low' | 'maximum'. +-type memory_type() :: 'total' | 'processes' | 'processes_used' | 'system' + | 'atom' | 'atom_used' | 'binary' | 'code' | 'ets' + | 'low' | 'maximum'. -define(CARRIER_ALLOCS, [mseg_alloc, sbmbc_alloc, sbmbc_low_alloc]). -define(LOW_ALLOCS, [sbmbc_low_alloc, ll_low_alloc, std_low_alloc]). @@ -833,7 +2910,9 @@ max(A, _) -> A. low = 0, maximum = 0}). --spec memory() -> [{memory_type(), non_neg_integer()}]. +-spec erlang:memory() -> [{Type, Size}] when + Type :: memory_type(), + Size :: non_neg_integer(). memory() -> case aa_mem_data(au_mem_data(?ALL_NEEDED_ALLOCS)) of notsup -> @@ -858,8 +2937,9 @@ memory() -> {ets, Mem#memory.ets} | Tail] end. --spec memory(memory_type()|[memory_type()]) -> non_neg_integer() | [{memory_type(), non_neg_integer()}]. -memory(Type) when is_atom(Type) -> +-spec erlang:memory(Type :: memory_type()) -> non_neg_integer(); + (TypeList :: [memory_type()]) -> [{memory_type(), non_neg_integer()}]. +memory(Type) when erlang:is_atom(Type) -> {AA, ALCU, ChkSup, BadArgZero} = need_mem_info(Type), case get_mem_data(ChkSup, ALCU, AA) of notsup -> @@ -871,7 +2951,7 @@ memory(Type) when is_atom(Type) -> _ -> Value end end; -memory(Types) when is_list(Types) -> +memory(Types) when erlang:is_list(Types) -> {AA, ALCU, ChkSup, BadArgZeroList} = need_mem_info_list(Types), case get_mem_data(ChkSup, ALCU, AA) of notsup -> @@ -1079,7 +3159,7 @@ au_mem_data(EMD, []) -> EMD. au_mem_data(Allocs) -> - Ref = make_ref(), + Ref = erlang:make_ref(), erlang:system_info({allocator_sizes, Ref, Allocs}), receive_emd(Ref). @@ -1165,11 +3245,11 @@ alloc_info(Allocs) -> alloc_sizes(Allocs) -> get_alloc_info(allocator_sizes, Allocs). -get_alloc_info(Type, AAtom) when is_atom(AAtom) -> +get_alloc_info(Type, AAtom) when erlang:is_atom(AAtom) -> [{AAtom, Result}] = get_alloc_info(Type, [AAtom]), Result; -get_alloc_info(Type, AList) when is_list(AList) -> - Ref = make_ref(), +get_alloc_info(Type, AList) when erlang:is_list(AList) -> + Ref = erlang:make_ref(), erlang:system_info({Type, Ref, AList}), receive_allocator(Ref, erlang:system_info(schedulers), @@ -1206,7 +3286,7 @@ receive_allocator(Ref, N, Acc) -> receive_allocator(Ref, N-1, insert_info(InfoList, Acc)) end. --spec await_sched_wall_time_modifications(Ref, Result) -> boolean() when +-spec erlang:await_sched_wall_time_modifications(Ref, Result) -> boolean() when Ref :: reference(), Result :: boolean(). @@ -1214,12 +3294,12 @@ await_sched_wall_time_modifications(Ref, Result) -> sched_wall_time(Ref, erlang:system_info(schedulers)), Result. --spec gather_sched_wall_time_result(Ref) -> [{pos_integer(), - non_neg_integer(), - non_neg_integer()}] when +-spec erlang:gather_sched_wall_time_result(Ref) -> [{pos_integer(), + non_neg_integer(), + non_neg_integer()}] when Ref :: reference(). -gather_sched_wall_time_result(Ref) when is_reference(Ref) -> +gather_sched_wall_time_result(Ref) when erlang:is_reference(Ref) -> sched_wall_time(Ref, erlang:system_info(schedulers), []). sched_wall_time(_Ref, 0) -> diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 36cbe329e8..fcf94c5fa2 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2011. All Rights Reserved. +%% Copyright Ericsson AB 2000-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -147,6 +147,32 @@ -define(POSIX_FADV_NOREUSE, 5). +%%% BIFs + +-export([internal_name2native/1, + internal_native2name/1, + internal_normalize_utf8/1]). + +-type unicode_string() :: [unicode:unicode_char()]. +-type prim_file_name() :: unicode_string() | unicode:unicode_binary(). + +-spec internal_name2native(prim_file_name()) -> binary(). + +internal_name2native(_) -> + erlang:nif_error(undefined). + +-spec internal_native2name(binary()) -> prim_file_name(). + +internal_native2name(_) -> + erlang:nif_error(undefined). + +-spec internal_normalize_utf8(unicode:unicode_binary()) -> unicode_string(). + +internal_normalize_utf8(_) -> + erlang:nif_error(undefined). + +%%% End of BIFs + %%%----------------------------------------------------------------- %%% Functions operating on a file through a handle. ?FD_DRV. %%% diff --git a/erts/test/Makefile b/erts/test/Makefile index 68be3f2178..f79bb6e5f0 100644 --- a/erts/test/Makefile +++ b/erts/test/Makefile @@ -28,7 +28,6 @@ EBIN = . # ---------------------------------------------------- MODULES= \ - autoimport_SUITE \ erlc_SUITE \ install_SUITE \ nt_SUITE \ @@ -39,14 +38,11 @@ MODULES= \ erlexec_SUITE \ z_SUITE -ERL_XML = $(ERL_TOP)/erts/doc/src/erlang.xml -ERL_XML_TARGET = autoimport_SUITE_data/erlang.xml - ERL_FILES= $(MODULES:%=%.erl) TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) -EXTRA_FILES = install_SUITE_data/install_bin $(ERL_XML_TARGET) +EXTRA_FILES = install_SUITE_data/install_bin # ---------------------------------------------------- # Release directory specification @@ -68,10 +64,6 @@ install_SUITE_data/install_bin: ../../make/install_bin rm -f $@ cp -p $< $@ -$(ERL_XML_TARGET): $(ERL_XML) - rm -f $@ - cp -p $< $@ - clean: rm -f $(TARGET_FILES) $(EXTRA_FILES) rm -f core *~ diff --git a/erts/test/autoimport_SUITE.erl b/erts/test/autoimport_SUITE.erl deleted file mode 100644 index 71ed5204b1..0000000000 --- a/erts/test/autoimport_SUITE.erl +++ /dev/null @@ -1,196 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1998-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%%% Purpose: Test erlang.xml re autoimports --module(autoimport_SUITE). - --include_lib("test_server/include/test_server.hrl"). --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, - init_per_testcase/2,end_per_testcase/2, - autoimports/1]). --define(TEST_TIMEOUT, ?t:seconds(180)). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [autoimports]. - -groups() -> - []. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -init_per_testcase(_Func, Config) -> - Dog = test_server:timetrap(?TEST_TIMEOUT), - [{watchdog, Dog} | Config]. - -end_per_testcase(_Func, Config) -> - Dog = ?config(watchdog, Config), - catch test_server:timetrap_cancel(Dog), - ok. - - -autoimports(suite) -> - []; -autoimports(doc) -> - ["Check that erlang.xml documents autoimports correctly"]; -autoimports(Config) when is_list(Config) -> - ?line XML = filename:join([?config(data_dir,Config),"erlang.xml"]), - ?line case xml(XML) of - [] -> - ok; - List -> - lists:foreach(fun({[],F,A}) -> - io:format("erlang:~s/~p is wrongly " - "documented as ~s/~p~n", - [F,A,F,A]); - ({"erlang",F,A}) -> - io:format("~s/~p is wrongly " - "documented as " - "erlang:~s/~p~n", - [F,A,F,A]) - end,List), - ?t:fail({wrong_autoimports,List}) - end. - -%% -%% Ugly chunk of code to heuristically analyze the erlang.xml -%% documentation file. Don't view this as an example... -%% - -xml(XMLFile) -> - {ok,File} = file:open(XMLFile,[read]), - xskip_to_funcs(file:read_line(File),File), - DocData = xloop(file:read_line(File),File), - true = DocData =/= [], - file:close(File), - analyze(DocData). - -%% Skip lines up to and including the <funcs> tag. -xskip_to_funcs({ok,Line},File) -> - case re:run(Line,"\\<funcs\\>",[{capture,none}]) of - nomatch -> - xskip_to_funcs(file:read_line(File),File); - match -> - ok - end. - -xloop({ok,Line},File) -> - case re:run(Line,"\\<name\\>",[{capture,none}]) of - nomatch -> - xloop(file:read_line(File),File); - match -> - X = re:replace(Line,"\\).*",")",[{return,list}]), - Y = re:replace(X,".*\\>","",[{return,list}]), - Mod = get_module(Y), - Rest1 = fstrip(Mod++":",Y), - Func = get_function(Rest1), - Rest2 = fstrip(Func++"(", Rest1), - Argc = count_args(Rest2,1,0,false), - [{Mod,Func,Argc} | - xloop(file:read_line(File),File)] - end; -xloop(_,_) -> - []. - -analyze([{[],Func,Arity}|T]) -> - case erl_internal:bif(list_to_atom(Func),Arity) of - true -> - analyze(T); - false -> - [{[],Func,Arity} | - analyze(T)] - end; -analyze([{"erlang",Func,Arity}|T]) -> - case erl_internal:bif(list_to_atom(Func),Arity) of - true -> - [{"erlang",Func,Arity}|analyze(T)]; - false -> - analyze(T) - end; -analyze([_|T]) -> - analyze(T); -analyze([]) -> - []. - - -count_args([],_,N,false) -> - N; -count_args([],_,N,true) -> - N+1; -count_args(_,0,N,true) -> - N+1; -count_args(_,0,N,false) -> - N; -count_args([Par|T],Level,N,Got) when (Par =:= 40) or - (Par =:= 123) or (Par =:= 91) -> - count_args(T,Level+1,N,(Level =:= 1) or Got); -count_args([41|T],1,N,true) -> - count_args(T,0,N+1,false); -count_args([Par|T],Level,N, Got) when (Par =:= 41) or - (Par =:= 125) or (Par =:= 93) -> - count_args(T,Level-1,N,Got); -count_args([$,|T],1,N,true) -> - count_args(T,1,N+1,false); -count_args([$ |T],A,B,C) -> - count_args(T,A,B,C); -count_args([_|T],1,N,_) -> - count_args(T,1,N,true); -count_args([_|T],A,B,C) -> - count_args(T,A,B,C). - -fstrip([],X) -> - X; -fstrip(_,[]) -> - []; -fstrip([H|T1],[H|T2]) -> - fstrip(T1,T2); -fstrip(_,L) -> - L. - -get_module(X) -> - get_module(X,[]). -get_module([],_) -> - []; -get_module([$:|_],Acc) -> - lists:reverse(Acc); -get_module([40|_],_) -> %( - []; -get_module([H|T],Acc) -> - get_module(T,[H|Acc]). - -get_function(X) -> - get_function(X,[]). -get_function([],_) -> - []; -get_function([40|_],Acc) -> %( - lists:reverse(Acc); -get_function([H|T],Acc) -> - get_function(T,[H|Acc]). diff --git a/erts/test/autoimport_SUITE_data/dummy.txt b/erts/test/autoimport_SUITE_data/dummy.txt deleted file mode 100644 index 972643e527..0000000000 --- a/erts/test/autoimport_SUITE_data/dummy.txt +++ /dev/null @@ -1,19 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1998-2010. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% Purpouse: Dummy diff --git a/erts/vsn.mk b/erts/vsn.mk index bbf77b1a68..a420781e9f 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -17,8 +17,8 @@ # %CopyrightEnd% # -VSN = 5.9.1 -SYSTEM_VSN = R15B01 +VSN = 5.10 +SYSTEM_VSN = R16B # Port number 4365 in 4.2 # Port number 4366 in 4.3 diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/inets b/lib/dialyzer/test/r9c_SUITE_data/results/inets index 773525eb7f..d789d8d246 100644 --- a/lib/dialyzer/test/r9c_SUITE_data/results/inets +++ b/lib/dialyzer/test/r9c_SUITE_data/results/inets @@ -31,11 +31,11 @@ httpd_sup.erl:92: The variable Else can never match since previous clauses compl mod_auth.erl:559: The pattern {'error', Reason} can never match the type {_,integer(),maybe_improper_list(),_} mod_auth_dets.erl:120: The call lists:foreach(fun((_) -> 'true' | {'error','no_such_group' | 'no_such_group_member'}),{'ok',[any()]}) will never return since it differs in the 2nd argument from the success typing arguments: (fun((_) -> any()),[any()]) mod_auth_plain.erl:100: The variable _ can never match since previous clauses completely covered the type {'ok',[any()]} -mod_auth_plain.erl:159: The variable _ can never match since previous clauses completely covered the type [any()] -mod_auth_plain.erl:83: The variable O can never match since previous clauses completely covered the type [any()] +mod_auth_plain.erl:159: The variable _ can never match since previous clauses completely covered the type [[any()]] +mod_auth_plain.erl:83: The variable O can never match since previous clauses completely covered the type [[any()]] mod_cgi.erl:372: The pattern {'http_response', NewAccResponse} can never match the type 'ok' mod_dir.erl:101: The call lists:flatten(nonempty_improper_list(atom() | [any()] | char(),atom())) will never return since it differs in the 1st argument from the success typing arguments: ([any()]) -mod_dir.erl:72: The pattern {'error', Reason} can never match the type {'ok',[[[any()] | char()],...]} +mod_dir.erl:72: The pattern {'error', Reason} can never match the type {'ok',[[[any()] | non_neg_integer()],...]} mod_get.erl:135: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]> mod_head.erl:80: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]> mod_htaccess.erl:460: The pattern {'error', BadData} can never match the type {'ok',_} @@ -47,9 +47,9 @@ mod_include.erl:692: The pattern <{'read', Reason}, Info, Path> can never match mod_include.erl:706: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]> mod_include.erl:716: Function read_error/3 will never be called mod_include.erl:719: Function read_error/4 will never be called -mod_security_server.erl:386: The variable O can never match since previous clauses completely covered the type [any()] -mod_security_server.erl:433: The variable Other can never match since previous clauses completely covered the type [any()] -mod_security_server.erl:585: The variable _ can never match since previous clauses completely covered the type [any()] -mod_security_server.erl:608: The variable _ can never match since previous clauses completely covered the type [any()] -mod_security_server.erl:641: The variable _ can never match since previous clauses completely covered the type [any()] +mod_security_server.erl:386: The variable O can never match since previous clauses completely covered the type [tuple()] +mod_security_server.erl:433: The variable Other can never match since previous clauses completely covered the type [tuple()] +mod_security_server.erl:585: The variable _ can never match since previous clauses completely covered the type [tuple()] +mod_security_server.erl:608: The variable _ can never match since previous clauses completely covered the type [tuple()] +mod_security_server.erl:641: The variable _ can never match since previous clauses completely covered the type [tuple()] uri.erl:146: The pattern {'error', Error} can never match since previous clauses completely covered the type {_,{[],[]}} diff --git a/lib/dialyzer/test/user_SUITE_data/results/wsp_pdu b/lib/dialyzer/test/user_SUITE_data/results/wsp_pdu index a47b1f1f2c..d1f8f4caf2 100644 --- a/lib/dialyzer/test/user_SUITE_data/results/wsp_pdu +++ b/lib/dialyzer/test/user_SUITE_data/results/wsp_pdu @@ -6,7 +6,7 @@ wsp_pdu.erl:2403: The call wsp_pdu:d_date(Data1::binary()) will never return sin wsp_pdu.erl:2406: Guard test is_integer(Sec::{[byte()] | byte() | {'long',binary()} | {'short',binary()},binary()}) can never succeed wsp_pdu.erl:2408: The pattern {'short', Data2} can never match the type {[byte()] | byte() | {'long',binary()} | {'short',binary()},binary()} wsp_pdu.erl:2755: Function parse_push_flag/1 has no local return -wsp_pdu.erl:2756: The call erlang:integer_to_list(Value::[any()]) will never return since it differs in the 1st argument from the success typing arguments: (integer()) +wsp_pdu.erl:2756: The call erlang:integer_to_list(Value::[any()]) breaks the contract (Integer) -> string() when is_subtype(Integer,integer()) wsp_pdu.erl:2875: The call wsp_pdu:d_text_string(Data::byte()) will never return since it differs in the 1st argument from the success typing arguments: (binary()) wsp_pdu.erl:2976: The call wsp_pdu:d_q_value(QData::byte()) will never return since it differs in the 1st argument from the success typing arguments: (<<_:8,_:_*8>>) wsp_pdu.erl:3336: The call wsp_pdu:encode_typed_field(Ver::any(),'Q-value',ParamValue::any()) will never return since it differs in the 2nd argument from the success typing arguments: (any(),'Constrained-encoding' | 'Date-value' | 'No-value' | 'Short-integer' | 'Text-string' | 'Text-value' | 'Well-known-charset',any()) diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 845df0ca61..3d1e3e8137 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2011. All Rights Reserved. +%% Copyright Ericsson AB 2003-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -45,11 +45,9 @@ t_atom_vals/1, t_binary/0, t_bitstr/0, - t_bitstrlist/0, t_boolean/0, t_byte/0, t_char/0, - t_charlist/0, t_cons/0, t_cons/2, t_cons_hd/1, @@ -72,8 +70,6 @@ t_non_neg_integer/0, t_pos_integer/0, t_integers/1, - t_iodata/0, - t_iolist/0, t_is_any/1, t_is_atom/1, t_is_binary/1, @@ -85,7 +81,6 @@ t_is_fun/1, t_is_integer/1, t_is_integer/1, - t_is_list/1, t_is_nil/1, t_is_none/1, t_is_none_or_unit/1, @@ -118,14 +113,11 @@ t_subtract/2, t_sup/1, t_sup/2, - t_tid/0, - t_timeout/0, t_tuple/0, t_tuple/1, t_tuple_args/1, t_tuple_size/1, - t_tuple_subtypes/1, - t_unicode_string/0 + t_tuple_subtypes/1 ]). -ifdef(DO_ERL_BIF_TYPES_TEST). @@ -144,110 +136,13 @@ type(M, F, A) -> -spec type(atom(), atom(), arity(), [erl_types:erl_type()]) -> erl_types:erl_type(). -%%-- binary ------------------------------------------------------------------- -type(binary, at, 2, Xs) -> - strict(arg_types(binary, at, 2), Xs, fun(_) -> t_integer() end); -type(binary, bin_to_list, Arity, Xs) when 1 =< Arity, Arity =< 3 -> - strict(arg_types(binary, bin_to_list, Arity), Xs, - fun(_) -> t_list(t_integer()) end); -type(binary, compile_pattern, 1, Xs) -> - strict(arg_types(binary, compile_pattern, 1), Xs, - fun(_) -> t_binary_compiled_pattern() end); -type(binary, copy, Arity, Xs) when Arity =:= 1; Arity =:= 2 -> - strict(arg_types(binary, copy, Arity), Xs, - fun(_) -> t_binary() end); -type(binary, decode_unsigned, Arity, Xs) when Arity =:= 1; Arity =:= 2 -> - strict(arg_types(binary, decode_unsigned, Arity), Xs, - fun(_) -> t_non_neg_integer() end); -type(binary, encode_unsigned, Arity, Xs) when Arity =:= 1; Arity =:= 2 -> - strict(arg_types(binary, encode_unsigned, Arity), Xs, - fun(_) -> t_binary() end); -type(binary, first, 1, Xs) -> - strict(arg_types(binary, first, 1), Xs, fun(_) -> t_non_neg_integer() end); -type(binary, last, 1, Xs) -> - strict(arg_types(binary, last, 1), Xs, fun(_) -> t_non_neg_integer() end); -type(binary, list_to_bin, 1, Xs) -> - type(erlang, list_to_binary, 1, Xs); -type(binary, longest_common_prefix, 1, Xs) -> - strict(arg_types(binary, longest_common_prefix, 1), Xs, - fun(_) -> t_integer() end); -type(binary, longest_common_suffix, 1, Xs) -> - strict(arg_types(binary, longest_common_suffix, 1), Xs, - fun(_) -> t_integer() end); -type(binary, match, Arity, Xs) when Arity =:= 2; Arity =:= 3 -> - strict(arg_types(binary, match, Arity), Xs, - fun(_) -> - t_sup(t_atom('nomatch'), t_binary_canonical_part()) - end); -type(binary, matches, Arity, Xs) when Arity =:= 2; Arity =:= 3 -> - strict(arg_types(binary, matches, Arity), Xs, - fun(_) -> t_list(t_binary_canonical_part()) end); -type(binary, part, 2, Xs) -> - type(erlang, binary_part, 2, Xs); -type(binary, part, 3, Xs) -> - type(erlang, binary_part, 3, Xs); -type(binary, referenced_byte_size, 1, Xs) -> - strict(arg_types(binary, referenced_byte_size, 1), Xs, - fun(_) -> t_non_neg_integer() end); -%%-- code --------------------------------------------------------------------- -type(code, get_chunk, 2, Xs) -> - strict(arg_types(code, get_chunk, 2), Xs, - fun (_) -> t_sup(t_binary(), t_atom('undefined')) end); -type(code, is_module_native, 1, Xs) -> - strict(arg_types(code, is_module_native, 1), Xs, - fun (_) -> t_sup(t_boolean(), t_atom('undefined')) end); -type(code, module_md5, 1, Xs) -> - strict(arg_types(code, module_md5, 1), Xs, - fun (_) -> t_sup(t_binary(), t_atom('undefined')) end); -type(code, make_stub_module, 3, Xs) -> - strict(arg_types(code, make_stub_module, 3), Xs, fun ([Mod,_,_]) -> Mod end); -type(code, rehash, 0, _) -> - t_atom('ok'); -%%-- erl_ddll ----------------------------------------------------------------- -type(erl_ddll, demonitor, 1, Xs) -> - type(erlang, demonitor, 1, Xs); -type(erl_ddll, format_error_int, 1, Xs) -> - strict(arg_types(erl_ddll, format_error_int, 1), Xs, - fun (_) -> t_string() end); -type(erl_ddll, info, 2, Xs) -> - strict(arg_types(erl_ddll, info, 2), Xs, fun (_) -> t_atom() end); -type(erl_ddll, loaded_drivers, 0, _) -> - t_tuple([t_atom('ok'), t_list(t_string())]); -type(erl_ddll, monitor, 2, Xs) -> % return type is the same, though args are not - type(erlang, monitor, 2, Xs); -type(erl_ddll, try_load, 3, Xs) -> - strict(arg_types(erl_ddll, try_load, 3), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('ok'), t_atom('already_loaded')]), - t_tuple([t_atom('ok'), t_atom('loaded')]), - t_tuple([t_atom('ok'), - t_atom('pending_driver'), t_reference()]), - t_tuple([t_atom('error'), t_atom('inconsistent')]), - t_tuple([t_atom('error'), t_atom('permanent')])]) - end); -type(erl_ddll, try_unload, 2, Xs) -> - strict(arg_types(erl_ddll, try_unload, 2), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('ok'), t_atom('pending_process')]), - t_tuple([t_atom('ok'), t_atom('unloaded')]), - t_tuple([t_atom('ok'), t_atom('pending_driver')]), - t_tuple([t_atom('ok'), - t_atom('pending_driver'), t_reference()]), - t_tuple([t_atom('error'), t_atom('permanent')]), - t_tuple([t_atom('error'), t_atom('not_loaded')]), - t_tuple([t_atom('error'), - t_atom('not_loaded_by_this_process')])]) - end); %%-- erlang ------------------------------------------------------------------- type(erlang, halt, 0, _) -> t_none(); type(erlang, halt, 1, _) -> t_none(); type(erlang, exit, 1, _) -> t_none(); -%% Note that exit/2 sends an exit signal to another process. -type(erlang, exit, 2, _) -> t_atom('true'); type(erlang, error, 1, _) -> t_none(); type(erlang, error, 2, _) -> t_none(); type(erlang, throw, 1, _) -> t_none(); -type(erlang, hibernate, 3, _) -> t_none(); type(erlang, '==', 2, Xs = [X1, X2]) -> case t_is_atom(X1) andalso t_is_atom(X2) of true -> type(erlang, '=:=', 2, Xs); @@ -599,20 +494,12 @@ type(erlang, 'bnot', 1, Xs) -> {ok, T} -> T end end); -%% This returns (-X)-1, so it often gives a negative result. -%% strict(arg_types(erlang, 'bnot', 1), Xs, fun (_) -> t_integer() end); +%% Guard bif, needs to be here. type(erlang, abs, 1, Xs) -> strict(arg_types(erlang, abs, 1), Xs, fun ([X]) -> X end); -type(erlang, adler32, 1, Xs) -> - strict(arg_types(erlang, adler32, 1), Xs, fun (_) -> t_adler32() end); -type(erlang, adler32, 2, Xs) -> - strict(arg_types(erlang, adler32, 2), Xs, fun (_) -> t_adler32() end); -type(erlang, adler32_combine, 3, Xs) -> - strict(arg_types(erlang, adler32_combine, 3), Xs, - fun (_) -> t_adler32() end); +%% This returns (-X)-1, so it often gives a negative result. +%% strict(arg_types(erlang, 'bnot', 1), Xs, fun (_) -> t_integer() end); type(erlang, append, 2, Xs) -> type(erlang, '++', 2, Xs); % alias -type(erlang, append_element, 2, Xs) -> - strict(arg_types(erlang, append_element, 2), Xs, fun (_) -> t_tuple() end); type(erlang, apply, 2, Xs) -> Fun = fun ([X, _Y]) -> case t_is_fun(X) of @@ -625,90 +512,24 @@ type(erlang, apply, 2, Xs) -> strict(arg_types(erlang, apply, 2), Xs, Fun); type(erlang, apply, 3, Xs) -> strict(arg_types(erlang, apply, 3), Xs, fun (_) -> t_any() end); -type(erlang, atom_to_binary, 2, Xs) -> - strict(arg_types(erlang, atom_to_binary, 2), Xs, fun (_) -> t_binary() end); -type(erlang, atom_to_list, 1, Xs) -> - strict(arg_types(erlang, atom_to_list, 1), Xs, fun (_) -> t_string() end); +%% Guard bif, needs to be here. type(erlang, binary_part, 2, Xs) -> strict(arg_types(erlang, binary_part, 2), Xs, fun (_) -> t_binary() end); +%% Guard bif, needs to be here. type(erlang, binary_part, 3, Xs) -> strict(arg_types(erlang, binary_part, 3), Xs, fun (_) -> t_binary() end); -type(erlang, binary_to_atom, 2, Xs) -> - strict(arg_types(erlang, binary_to_atom, 2), Xs, fun (_) -> t_atom() end); -type(erlang, binary_to_existing_atom, 2, Xs) -> - type(erlang, binary_to_atom, 2, Xs); -type(erlang, binary_to_list, 1, Xs) -> - strict(arg_types(erlang, binary_to_list, 1), Xs, - fun (_) -> t_list(t_byte()) end); -type(erlang, binary_to_list, 3, Xs) -> - strict(arg_types(erlang, binary_to_list, 3), Xs, - fun (_) -> t_list(t_byte()) end); -type(erlang, binary_to_term, 1, Xs) -> - strict(arg_types(erlang, binary_to_term, 1), Xs, fun (_) -> t_any() end); -type(erlang, binary_to_term, 2, Xs) -> - strict(arg_types(erlang, binary_to_term, 2), Xs, fun (_) -> t_any() end); -type(erlang, bitsize, 1, Xs) -> % XXX: TAKE OUT - type(erlang, bit_size, 1, Xs); +%% Guard bif, needs to be here. type(erlang, bit_size, 1, Xs) -> strict(arg_types(erlang, bit_size, 1), Xs, fun (_) -> t_non_neg_integer() end); -type(erlang, bitstr_to_list, 1, Xs) -> % XXX: TAKE OUT - type(erlang, bitstring_to_list, 1, Xs); -type(erlang, bitstring_to_list, 1, Xs) -> - strict(arg_types(erlang, bitstring_to_list, 1), Xs, - fun (_) -> t_list(t_sup(t_byte(), t_bitstr())) end); -type(erlang, bump_reductions, 1, Xs) -> - strict(arg_types(erlang, bump_reductions, 1), Xs, - fun (_) -> t_atom('true') end); +%% Guard bif, needs to be here. type(erlang, byte_size, 1, Xs) -> strict(arg_types(erlang, byte_size, 1), Xs, fun (_) -> t_non_neg_integer() end); -type(erlang, call_on_load_function, 1, Xs) -> - %% Internal BIF used by on_load. - strict(arg_types(erlang, call_on_load_function, 1), Xs, - fun (_) -> t_any() end); -type(erlang, cancel_timer, 1, Xs) -> - strict(arg_types(erlang, cancel_timer, 1), Xs, - fun (_) -> t_sup(t_integer(), t_atom('false')) end); -type(erlang, check_old_code, 1, Xs) -> - strict(arg_types(erlang, check_old_code, 1), Xs, - fun (_) -> t_boolean() end); -type(erlang, check_process_code, 2, Xs) -> - strict(arg_types(erlang, check_process_code, 2), Xs, - fun (_) -> t_boolean() end); -type(erlang, crc32, 1, Xs) -> - strict(arg_types(erlang, crc32, 1), Xs, fun (_) -> t_crc32() end); -type(erlang, crc32, 2, Xs) -> - strict(arg_types(erlang, crc32, 2), Xs, fun (_) -> t_crc32() end); -type(erlang, crc32_combine, 3, Xs) -> - strict(arg_types(erlang, crc32_combine, 3), Xs, fun (_) -> t_crc32() end); -type(erlang, date, 0, _) -> - t_date(); -type(erlang, decode_packet, 3, Xs) -> - strict(arg_types(erlang, decode_packet, 3), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('ok'), t_packet(), t_binary()]), - t_tuple([t_atom('more'), t_sup([t_non_neg_integer(), - t_atom('undefined')])]), - t_tuple([t_atom('error'), t_any()])]) - end); -type(erlang, delete_module, 1, Xs) -> - strict(arg_types(erlang, delete_module, 1), Xs, - fun (_) -> t_sup(t_atom('true'), t_atom('undefined')) end); -type(erlang, demonitor, 1, Xs) -> - strict(arg_types(erlang, demonitor, 1), Xs, fun (_) -> t_atom('true') end); -%% TODO: overapproximation -- boolean only if 'info' is part of arg2 otherwise 'true' -type(erlang, demonitor, 2, Xs) -> - strict(arg_types(erlang, demonitor, 2), Xs, fun (_) -> t_boolean() end); type(erlang, disconnect_node, 1, Xs) -> strict(arg_types(erlang, disconnect_node, 1), Xs, fun (_) -> t_sup([t_boolean(), t_atom('ignored')]) end); -type(erlang, display, 1, _) -> t_atom('true'); -type(erlang, display_string, 1, Xs) -> - strict(arg_types(erlang, display_string, 1), Xs, fun(_) -> t_atom('true') end); -type(erlang, display_nl, 0, _) -> - t_atom('true'); -type(erlang, dist_exit, 3, Xs) -> - strict(arg_types(erlang, dist_exit, 3), Xs, fun (_) -> t_atom('true') end); +%% Guard bif, needs to be here. +%% Also much more expressive than anything you could write in a spec... type(erlang, element, 2, Xs) -> strict(arg_types(erlang, element, 2), Xs, fun ([X1, X2]) -> @@ -732,95 +553,22 @@ type(erlang, element, 2, Xs) -> t_sup([type(erlang, element, 2, [X1, Y]) || Y <- Ts]) end end); -type(erlang, erase, 0, _) -> t_any(); -type(erlang, erase, 1, _) -> t_any(); -type(erlang, external_size, 1, _) -> t_integer(); -type(erlang, external_size, 2, _) -> t_integer(); -type(erlang, finish_after_on_load, 2, Xs) -> - %% Internal BIF used by on_load. - strict(arg_types(erlang, finish_after_on_load, 2), Xs, - fun (_) -> t_atom('true') end); +%% Guard bif, needs to be here. type(erlang, float, 1, Xs) -> strict(arg_types(erlang, float, 1), Xs, fun (_) -> t_float() end); -type(erlang, float_to_list, 1, Xs) -> - strict(arg_types(erlang, float_to_list, 1), Xs, fun (_) -> t_string() end); -type(erlang, function_exported, 3, Xs) -> - strict(arg_types(erlang, function_exported, 3), Xs, - fun (_) -> t_boolean() end); type(erlang, fun_info, 1, Xs) -> strict(arg_types(erlang, fun_info, 1), Xs, fun (_) -> t_list(t_tuple([t_atom(), t_any()])) end); -type(erlang, fun_info, 2, Xs) -> - strict(arg_types(erlang, fun_info, 2), Xs, - fun (_) -> t_tuple([t_atom(), t_any()]) end); -type(erlang, fun_to_list, 1, Xs) -> - strict(arg_types(erlang, fun_to_list, 1), Xs, fun (_) -> t_string() end); -type(erlang, garbage_collect, 0, _) -> t_atom('true'); -type(erlang, garbage_collect, 1, Xs) -> - strict(arg_types(erlang, garbage_collect, 1), Xs, fun (_) -> t_boolean() end); -type(erlang, garbage_collect_message_area, 0, _) -> - t_boolean(); -type(erlang, get, 0, _) -> t_list(t_tuple(2)); -type(erlang, get, 1, _) -> t_any(); % | t_atom('undefined') type(erlang, get_cookie, 0, _) -> t_atom(); % | t_atom('nocookie') -type(erlang, get_keys, 1, _) -> t_list(); -type(erlang, get_module_info, 1, Xs) -> - strict(arg_types(erlang, get_module_info, 1), Xs, - fun (_) -> - t_list(t_tuple([t_atom(), t_list(t_tuple([t_atom(), t_any()]))])) - end); -type(erlang, get_module_info, 2, Xs) -> - T_module_info_2_returns = - t_sup([t_atom(), - t_list(t_tuple([t_atom(), t_any()])), - t_list(t_tuple([t_atom(), t_arity(), t_integer()]))]), - strict(arg_types(erlang, get_module_info, 2), Xs, - fun ([Module, Item]) -> - case t_is_atom(Item) of - true -> - case t_atom_vals(Item) of - ['module'] -> t_inf(t_atom(), Module); - ['imports'] -> t_nil(); - ['exports'] -> t_list(t_tuple([t_atom(), t_arity()])); - ['functions'] -> t_list(t_tuple([t_atom(), t_arity()])); - ['attributes'] -> t_list(t_tuple([t_atom(), t_any()])); - ['compile'] -> t_list(t_tuple([t_atom(), t_any()])); - ['native_addresses'] -> % [{FunName, Arity, Address}] - t_list(t_tuple([t_atom(), t_arity(), t_integer()])); - List when is_list(List) -> - T_module_info_2_returns; - unknown -> - T_module_info_2_returns - end; - false -> - T_module_info_2_returns - end - end); -type(erlang, get_stacktrace, 0, _) -> - t_list(t_tuple([t_atom(), t_atom(), t_sup([t_arity(), t_list()]), - t_list()])); -type(erlang, group_leader, 0, _) -> t_pid(); -type(erlang, group_leader, 2, Xs) -> - strict(arg_types(erlang, group_leader, 2), Xs, - fun (_) -> t_atom('true') end); -type(erlang, hash, 2, Xs) -> - strict(arg_types(erlang, hash, 2), Xs, fun (_) -> t_integer() end); +%% Guard bif, needs to be here. type(erlang, hd, 1, Xs) -> strict(arg_types(erlang, hd, 1), Xs, fun ([X]) -> t_cons_hd(X) end); -type(erlang, integer_to_list, 1, Xs) -> - strict(arg_types(erlang, integer_to_list, 1), Xs, - fun (_) -> t_string() end); type(erlang, integer_to_list, 2, Xs) -> strict(arg_types(erlang, integer_to_list, 2), Xs, fun (_) -> t_string() end); type(erlang, info, 1, Xs) -> type(erlang, system_info, 1, Xs); % alias -type(erlang, iolist_size, 1, Xs) -> - strict(arg_types(erlang, iolist_size, 1), Xs, - fun (_) -> t_non_neg_integer() end); -type(erlang, iolist_to_binary, 1, Xs) -> - strict(arg_types(erlang, iolist_to_binary, 1), Xs, - fun (_) -> t_binary() end); -type(erlang, is_alive, 0, _) -> t_boolean(); +%% All type tests are guard BIF's and may be implemented in ways that +%% cannot be expressed in a type spec, why they are kept in erl_bif_types. type(erlang, is_atom, 1, Xs) -> Fun = fun (X) -> check_guard(X, fun (Y) -> t_is_atom(Y) end, t_atom()) end, strict(arg_types(erlang, is_atom, 1), Xs, Fun); @@ -829,8 +577,6 @@ type(erlang, is_binary, 1, Xs) -> check_guard(X, fun (Y) -> t_is_binary(Y) end, t_binary()) end, strict(arg_types(erlang, is_binary, 1), Xs, Fun); -type(erlang, is_bitstr, 1, Xs) -> % XXX: TAKE OUT - type(erlang, is_bitstring, 1, Xs); type(erlang, is_bitstring, 1, Xs) -> Fun = fun (X) -> check_guard(X, fun (Y) -> t_is_bitstr(Y) end, t_bitstr()) @@ -841,8 +587,6 @@ type(erlang, is_boolean, 1, Xs) -> check_guard(X, fun (Y) -> t_is_boolean(Y) end, t_boolean()) end, strict(arg_types(erlang, is_boolean, 1), Xs, Fun); -type(erlang, is_builtin, 3, Xs) -> - strict(arg_types(erlang, is_builtin, 3), Xs, fun (_) -> t_boolean() end); type(erlang, is_float, 1, Xs) -> Fun = fun (X) -> check_guard(X, fun (Y) -> t_is_float(Y) end, t_float()) @@ -887,9 +631,6 @@ type(erlang, is_pid, 1, Xs) -> type(erlang, is_port, 1, Xs) -> Fun = fun (X) -> check_guard(X, fun (Y) -> t_is_port(Y) end, t_port()) end, strict(arg_types(erlang, is_port, 1), Xs, Fun); -type(erlang, is_process_alive, 1, Xs) -> - strict(arg_types(erlang, is_process_alive, 1), Xs, - fun (_) -> t_boolean() end); type(erlang, is_record, 2, Xs) -> Fun = fun ([X, Y]) -> case t_is_tuple(X) of @@ -991,68 +732,12 @@ type(erlang, is_tuple, 1, Xs) -> check_guard(X, fun (Y) -> t_is_tuple(Y) end, t_tuple()) end, strict(arg_types(erlang, is_tuple, 1), Xs, Fun); +%% Guard bif, needs to be here. type(erlang, length, 1, Xs) -> strict(arg_types(erlang, length, 1), Xs, fun (_) -> t_non_neg_fixnum() end); -type(erlang, link, 1, Xs) -> - strict(arg_types(erlang, link, 1), Xs, fun (_) -> t_atom('true') end); -type(erlang, list_to_atom, 1, Xs) -> - strict(arg_types(erlang, list_to_atom, 1), Xs, fun (_) -> t_atom() end); -type(erlang, list_to_binary, 1, Xs) -> - strict(arg_types(erlang, list_to_binary, 1), Xs, - fun (_) -> t_binary() end); -type(erlang, list_to_bitstr, 1, Xs) -> - type(erlang, list_to_bitstring, 1, Xs); -type(erlang, list_to_bitstring, 1, Xs) -> - strict(arg_types(erlang, list_to_bitstring, 1), Xs, - fun (_) -> t_bitstr() end); -type(erlang, list_to_existing_atom, 1, Xs) -> - strict(arg_types(erlang, list_to_existing_atom, 1), Xs, - fun (_) -> t_atom() end); -type(erlang, list_to_float, 1, Xs) -> - strict(arg_types(erlang, list_to_float, 1), Xs, fun (_) -> t_float() end); -type(erlang, list_to_integer, 1, Xs) -> - strict(arg_types(erlang, list_to_integer, 1), Xs, - fun (_) -> t_integer() end); type(erlang, list_to_integer, 2, Xs) -> strict(arg_types(erlang, list_to_integer, 2), Xs, fun (_) -> t_integer() end); -type(erlang, list_to_pid, 1, Xs) -> - strict(arg_types(erlang, list_to_pid, 1), Xs, fun (_) -> t_pid() end); -type(erlang, list_to_tuple, 1, Xs) -> - strict(arg_types(erlang, list_to_tuple, 1), Xs, fun (_) -> t_tuple() end); -type(erlang, load_module, 2, Xs) -> - strict(arg_types(erlang, load_module, 2), Xs, - fun ([Mod,_Bin]) -> t_code_load_return(Mod) end); -type(erlang, load_nif, 2, Xs) -> - strict(arg_types(erlang, load_nif, 2), Xs, - fun (_) -> - Reason = t_atoms(['load_failed', 'bad_lib', 'load', - 'reload', 'upgrade', 'old_code']), - RsnPair = t_tuple([Reason, t_string()]), - t_sup(t_atom('ok'), t_tuple([t_atom('error'), RsnPair])) - end); -type(erlang, loaded, 0, _) -> - t_list(t_atom()); -type(erlang, localtime, 0, Xs) -> - type(erlang, universaltime, 0, Xs); % same -type(erlang, localtime_to_universaltime, 1, Xs) -> - type(erlang, universaltime_to_localtime, 1, Xs); % same -type(erlang, localtime_to_universaltime, 2, Xs) -> - strict(arg_types(erlang, localtime_to_universaltime, 2), Xs, % typecheck - fun ([X,_]) -> type(erlang, localtime_to_universaltime, 1, [X]) end); -type(erlang, make_fun, 3, Xs) -> - strict(arg_types(erlang, make_fun, 3), Xs, - fun ([_, _, Arity]) -> - case t_number_vals(Arity) of - [N] -> - case is_integer(N) andalso 0 =< N andalso N =< 255 of - true -> t_fun(N, t_any()); - false -> t_none() - end; - _Other -> t_fun() - end - end); -type(erlang, make_ref, 0, _) -> t_reference(); type(erlang, make_tuple, 2, Xs) -> strict(arg_types(erlang, make_tuple, 2), Xs, fun ([Int, _]) -> @@ -1069,87 +754,19 @@ type(erlang, make_tuple, 3, Xs) -> _Other -> t_tuple() end end); -type(erlang, match_spec_test, 3, Xs) -> - strict(arg_types(erlang, match_spec_test, 3), Xs, - fun (_) -> t_sup(t_tuple([t_atom('ok'), - t_any(), % it can be any term - t_list(t_atom('return_trace')), - t_match_spec_test_errors()]), - t_tuple([t_atom('error'), - t_match_spec_test_errors()])) end); -type(erlang, md5, 1, Xs) -> - strict(arg_types(erlang, md5, 1), Xs, fun (_) -> t_binary() end); -type(erlang, md5_final, 1, Xs) -> - strict(arg_types(erlang, md5_final, 1), Xs, fun (_) -> t_binary() end); -type(erlang, md5_init, 0, _) -> t_binary(); -type(erlang, md5_update, 2, Xs) -> - strict(arg_types(erlang, md5_update, 2), Xs, fun (_) -> t_binary() end); type(erlang, memory, 0, _) -> t_list(t_tuple([t_atom(), t_non_neg_fixnum()])); -type(erlang, memory, 1, Xs) -> - strict(arg_types(erlang, memory, 1), Xs, - fun ([Type]) -> - case t_is_atom(Type) of - true -> t_non_neg_fixnum(); - false -> - case t_is_list(Type) of - true -> t_list(t_tuple([t_atom(), t_non_neg_fixnum()])); - false -> - t_sup(t_non_neg_fixnum(), - t_list(t_tuple([t_atom(), t_non_neg_fixnum()]))) - end - end - end); -type(erlang, module_loaded, 1, Xs) -> - strict(arg_types(erlang, module_loaded, 1), Xs, fun (_) -> t_boolean() end); -type(erlang, monitor, 2, Xs) -> - strict(arg_types(erlang, monitor, 2), Xs, fun (_) -> t_reference() end); -type(erlang, monitor_node, 2, Xs) -> - strict(arg_types(erlang, monitor_node, 2), Xs, - fun (_) -> t_atom('true') end); -type(erlang, monitor_node, 3, Xs) -> - strict(arg_types(erlang, monitor_node, 3), Xs, - fun (_) -> t_atom('true') end); type(erlang, nif_error, 1, _) -> t_any(); % this BIF and the next one are stubs for NIFs and never return type(erlang, nif_error, 2, Xs) -> strict(arg_types(erlang, nif_error, 2), Xs, fun (_) -> t_any() end); +%% Guard bif, needs to be here. type(erlang, node, 0, _) -> t_node(); +%% Guard bif, needs to be here. type(erlang, node, 1, Xs) -> strict(arg_types(erlang, node, 1), Xs, fun (_) -> t_node() end); type(erlang, nodes, 0, _) -> t_list(t_node()); -type(erlang, nodes, 1, Xs) -> - strict(arg_types(erlang, nodes, 1), Xs, fun (_) -> t_list(t_node()) end); -type(erlang, now, 0, _) -> - t_timestamp(); -type(erlang, open_port, 2, Xs) -> - strict(arg_types(erlang, open_port, 2), Xs, fun (_) -> t_port() end); -type(erlang, phash, 2, Xs) -> - strict(arg_types(erlang, phash, 2), Xs, fun (_) -> t_pos_integer() end); -type(erlang, phash2, 1, Xs) -> - strict(arg_types(erlang, phash2, 1), Xs, fun (_) -> t_non_neg_integer() end); -type(erlang, phash2, 2, Xs) -> - strict(arg_types(erlang, phash2, 2), Xs, fun (_) -> t_non_neg_integer() end); -type(erlang, pid_to_list, 1, Xs) -> - strict(arg_types(erlang, pid_to_list, 1), Xs, fun (_) -> t_string() end); type(erlang, port_call, Arity, Xs) when Arity =:= 2; Arity =:= 3 -> strict(arg_types(erlang, port_call, Arity), Xs, fun (_) -> t_any() end); -type(erlang, port_close, 1, Xs) -> - strict(arg_types(erlang, port_close, 1), Xs, - fun (_) -> t_atom('true') end); -type(erlang, port_command, 2, Xs) -> - strict(arg_types(erlang, port_command, 2), Xs, - fun (_) -> t_atom('true') end); -type(erlang, port_command, 3, Xs) -> - strict(arg_types(erlang, port_command, 3), Xs, - fun (_) -> t_boolean() end); -type(erlang, port_connect, 2, Xs) -> - strict(arg_types(erlang, port_connect, 2), Xs, - fun (_) -> t_atom('true') end); -type(erlang, port_control, 3, Xs) -> - strict(arg_types(erlang, port_control, 3), Xs, - fun (_) -> t_sup(t_string(), t_binary()) end); -type(erlang, port_get_data, 1, Xs) -> - strict(arg_types(erlang, port_get_data, 1), Xs, fun (_) -> t_any() end); type(erlang, port_info, 1, Xs) -> strict(arg_types(erlang, port_info, 1), Xs, fun (_) -> t_sup(t_atom('undefined'), t_list()) end); @@ -1178,181 +795,11 @@ type(erlang, port_info, 2, Xs) -> t_string()])]) end) end); -type(erlang, port_to_list, 1, Xs) -> - strict(arg_types(erlang, port_to_list, 1), Xs, fun (_) -> t_string() end); -type(erlang, ports, 0, _) -> t_list(t_port()); -type(erlang, port_set_data, 2, Xs) -> - strict(arg_types(erlang, port_set_data, 2), Xs, - fun (_) -> t_atom('true') end); -type(erlang, pre_loaded, 0, _) -> t_list(t_atom()); -type(erlang, process_display, 2, _) -> t_atom('true'); -type(erlang, process_flag, 2, Xs) -> - T_process_flag_returns = t_sup([t_boolean(), t_atom(), t_non_neg_integer()]), - strict(arg_types(erlang, process_flag, 2), Xs, - fun ([Flag, _Option]) -> - case t_is_atom(Flag) of - true -> - case t_atom_vals(Flag) of - ['error_handler'] -> t_atom(); - ['min_heap_size'] -> t_non_neg_integer(); - ['min_bin_vheap_size'] -> t_non_neg_integer(); - ['scheduler'] -> t_non_neg_integer(); - ['monitor_nodes'] -> t_boolean(); - ['priority'] -> t_process_priority_level(); - ['save_calls'] -> t_non_neg_integer(); - ['trap_exit'] -> t_boolean(); - ['sensitive'] -> t_boolean(); - List when is_list(List) -> - T_process_flag_returns; - unknown -> - T_process_flag_returns - end; - false -> % XXX: over-approximation if Flag is tuple - T_process_flag_returns - end - end); -type(erlang, process_flag, 3, Xs) -> - strict(arg_types(erlang, process_flag, 3), Xs, - fun (_) -> t_non_neg_integer() end); -type(erlang, process_info, 1, Xs) -> - strict(arg_types(erlang, process_info, 1), Xs, - fun (_) -> - t_sup(t_list(t_tuple([t_pinfo(), t_any()])), - t_atom('undefined')) - end); -type(erlang, process_info, 2, Xs) -> - %% we define all normal return values: the return when the process exists - %% t_nil() is the return for 'registered_name'; perhaps for more - T_process_info_2_normal_returns = - t_sup([t_tuple([t_pinfo_item(), t_any()]), t_nil()]), - strict(arg_types(erlang, process_info, 2), Xs, - fun ([_Pid, InfoItem]) -> - Ret = case t_is_atom(InfoItem) of - true -> - case t_atom_vals(InfoItem) of - ['backtrace'] -> t_tuple([InfoItem, t_binary()]); - ['current_function'] -> t_tuple([InfoItem, t_mfa()]); - ['dictionary'] -> t_tuple([InfoItem, t_list()]); - ['error_handler'] -> t_tuple([InfoItem, t_atom()]); - ['garbage_collection'] -> - t_tuple([InfoItem, t_list()]); - ['group_leader'] -> t_tuple([InfoItem, t_pid()]); - ['heap_size'] -> - t_tuple([InfoItem, t_non_neg_integer()]); - ['initial_call'] -> t_tuple([InfoItem, t_mfa()]); - ['last_calls'] -> - t_tuple([InfoItem, - t_sup(t_atom('false'), t_list())]); - ['links'] -> t_tuple([InfoItem, t_list(t_pid())]); - ['memory'] -> - t_tuple([InfoItem, t_non_neg_integer()]); - ['message_binary'] -> t_tuple([InfoItem, t_list()]); - ['message_queue_len'] -> - t_tuple([InfoItem, t_non_neg_integer()]); - ['messages'] -> t_tuple([InfoItem, t_list()]); - ['monitored_by'] -> - t_tuple([InfoItem, t_list(t_pid())]); - ['monitors'] -> - t_tuple([InfoItem, - t_list(t_sup(t_tuple([t_atom('process'), - t_pid()]), - t_tuple([t_atom('process'), - t_tuple([t_atom(), - t_atom()])])))]); - ['priority'] -> - t_tuple([InfoItem, t_process_priority_level()]); - ['reductions'] -> - t_tuple([InfoItem, t_non_neg_integer()]); - ['registered_name'] -> - t_sup(t_tuple([InfoItem, t_atom()]), t_nil()); - ['sequential_trace_token'] -> - t_tuple([InfoItem, t_any()]); %% Underspecified - ['stack_size'] -> - t_tuple([InfoItem, t_non_neg_integer()]); - ['status'] -> - t_tuple([InfoItem, t_process_status()]); - ['suspending'] -> - t_tuple([InfoItem, - t_list(t_tuple([t_pid(), - t_non_neg_integer(), - t_non_neg_integer()]))]); - ['total_heap_size'] -> - t_tuple([InfoItem, t_non_neg_integer()]); - ['trap_exit'] -> - t_tuple([InfoItem, t_boolean()]); - List when is_list(List) -> - T_process_info_2_normal_returns; - unknown -> - T_process_info_2_normal_returns - end; - false -> - case t_is_list(InfoItem) of - true -> - t_list(t_tuple([t_pinfo_item(), t_any()])); - false -> - t_sup(T_process_info_2_normal_returns, - t_list(t_tuple([t_pinfo_item(), t_any()]))) - end - end, - t_sup([Ret, t_atom('undefined')]) - end); -type(erlang, processes, 0, _) -> t_list(t_pid()); -type(erlang, purge_module, 1, Xs) -> - strict(arg_types(erlang, purge_module, 1), Xs, - fun (_) -> t_atom('true') end); -type(erlang, put, 2, Xs) -> - strict(arg_types(erlang, put, 2), Xs, fun (_) -> t_any() end); -type(erlang, raise, 3, _) -> t_none(); -type(erlang, read_timer, 1, Xs) -> - strict(arg_types(erlang, read_timer, 1), Xs, - fun (_) -> t_sup(t_non_neg_integer(), t_atom('false')) end); -type(erlang, ref_to_list, 1, Xs) -> - strict(arg_types(erlang, ref_to_list, 1), Xs, fun (_) -> t_string() end); -type(erlang, register, 2, Xs) -> - strict(arg_types(erlang, register, 2), Xs, fun (_) -> t_atom('true') end); -type(erlang, registered, 0, _) -> t_list(t_atom()); -type(erlang, resume_process, 1, Xs) -> - strict(arg_types(erlang, resume_process, 1), Xs, - fun (_) -> t_any() end); %% TODO: overapproximation -- fix this +%% Guard bif, needs to be here. type(erlang, round, 1, Xs) -> strict(arg_types(erlang, round, 1), Xs, fun (_) -> t_integer() end); -type(erlang, posixtime_to_universaltime, 1, Xs) -> - strict(arg_types(erlang, posixtime_to_universaltime, 1), Xs, - fun(_) -> t_tuple([t_date(), t_time()]) end); +%% Guard bif, needs to be here. type(erlang, self, 0, _) -> t_pid(); -type(erlang, send, 2, Xs) -> type(erlang, '!', 2, Xs); % alias -type(erlang, send, 3, Xs) -> - strict(arg_types(erlang, send, 3), Xs, - fun (_) -> t_sup(t_atom('ok'), t_sendoptions()) end); -type(erlang, send_after, 3, Xs) -> - strict(arg_types(erlang, send_after, 3), Xs, fun (_) -> t_reference() end); -type(erlang, seq_trace, 2, Xs) -> - strict(arg_types(erlang, seq_trace, 2), Xs, - fun (_) -> t_sup(t_seq_trace_info_returns(), t_tuple(5)) end); -type(erlang, seq_trace_info, 1, Xs) -> - strict(arg_types(erlang, seq_trace_info, 1), Xs, - fun ([Item]) -> - case t_atom_vals(Item) of - ['label'] -> - t_sup(t_tuple([Item, t_non_neg_integer()]), t_nil()); - ['serial'] -> - t_sup(t_tuple([Item, t_tuple([t_non_neg_integer(), - t_non_neg_integer()])]), - t_nil()); - ['send'] -> t_tuple([Item, t_boolean()]); - ['receive'] -> t_tuple([Item, t_boolean()]); - ['print'] -> t_tuple([Item, t_boolean()]); - ['timestamp'] -> t_tuple([Item, t_boolean()]); - List when is_list(List) -> - t_seq_trace_info_returns(); - unknown -> - t_seq_trace_info_returns() - end - end); -type(erlang, seq_trace_print, 1, Xs) -> - strict(arg_types(erlang, seq_trace_print, 1), Xs, fun (_) -> t_boolean() end); -type(erlang, seq_trace_print, 2, Xs) -> - strict(arg_types(erlang, seq_trace_print, 2), Xs, fun (_) -> t_boolean() end); type(erlang, set_cookie, 2, Xs) -> strict(arg_types(erlang, set_cookie, 2), Xs, fun (_) -> t_atom('true') end); type(erlang, setelement, 3, Xs) -> @@ -1386,144 +833,22 @@ type(erlang, setelement, 3, Xs) -> t_sup([type(erlang, setelement, 3, [X1, Y, X3]) || Y <- Ts]) end end); -type(erlang, setnode, 2, Xs) -> - strict(arg_types(erlang, setnode, 2), Xs, fun (_) -> t_atom('true') end); -type(erlang, setnode, 3, Xs) -> - strict(arg_types(erlang, setnode, 3), Xs, fun (_) -> t_atom('true') end); +%% Guard bif, needs to be here. type(erlang, size, 1, Xs) -> strict(arg_types(erlang, size, 1), Xs, fun (_) -> t_non_neg_integer() end); type(erlang, spawn, 1, Xs) -> strict(arg_types(erlang, spawn, 1), Xs, fun (_) -> t_pid() end); type(erlang, spawn, 2, Xs) -> strict(arg_types(erlang, spawn, 2), Xs, fun (_) -> t_pid() end); -type(erlang, spawn, 3, Xs) -> - strict(arg_types(erlang, spawn, 3), Xs, fun (_) -> t_pid() end); type(erlang, spawn, 4, Xs) -> strict(arg_types(erlang, spawn, 4), Xs, fun (_) -> t_pid() end); type(erlang, spawn_link, 1, Xs) -> type(erlang, spawn, 1, Xs); % same type(erlang, spawn_link, 2, Xs) -> type(erlang, spawn, 2, Xs); % same -type(erlang, spawn_link, 3, Xs) -> type(erlang, spawn, 3, Xs); % same type(erlang, spawn_link, 4, Xs) -> type(erlang, spawn, 4, Xs); % same -type(erlang, spawn_opt, 1, Xs) -> - strict(arg_types(erlang, spawn_opt, 1), Xs, - fun ([Tuple]) -> - Fun = fun (TS) -> - [_, _, _, List] = t_tuple_args(TS), - t_spawn_opt_return(List) - end, - t_sup([Fun(TS) || TS <- t_tuple_subtypes(Tuple)]) - end); -type(erlang, spawn_opt, 2, Xs) -> - strict(arg_types(erlang, spawn_opt, 2), Xs, - fun ([_, List]) -> t_spawn_opt_return(List) end); -type(erlang, spawn_opt, 3, Xs) -> - strict(arg_types(erlang, spawn_opt, 3), Xs, - fun ([_, _, List]) -> t_spawn_opt_return(List) end); -type(erlang, spawn_opt, 4, Xs) -> - strict(arg_types(erlang, spawn_opt, 4), Xs, - fun ([_, _, _, List]) -> t_spawn_opt_return(List) end); -type(erlang, split_binary, 2, Xs) -> - strict(arg_types(erlang, split_binary, 2), Xs, - fun (_) -> t_tuple([t_binary(), t_binary()]) end); -type(erlang, start_timer, 3, Xs) -> - strict(arg_types(erlang, start_timer, 3), Xs, fun (_) -> t_reference() end); -type(erlang, statistics, 1, Xs) -> - strict(arg_types(erlang, statistics, 1), Xs, - fun ([Type]) -> - T_statistics_1 = t_sup([t_non_neg_integer(), - t_tuple([t_non_neg_integer(), - t_non_neg_integer()]), - %% When called with the argument 'io'. - t_tuple([t_tuple([t_atom('input'), - t_non_neg_integer()]), - t_tuple([t_atom('output'), - t_non_neg_integer()])]), - t_tuple([t_non_neg_integer(), - t_non_neg_integer(), - t_non_neg_integer()])]), - case t_atom_vals(Type) of - ['context_switches'] -> - t_tuple([t_non_neg_integer(), t_integer(0)]); - ['exact_reductions'] -> - t_tuple([t_non_neg_integer(), t_non_neg_integer()]); - ['garbage_collection'] -> - t_tuple([t_non_neg_integer(), - t_non_neg_integer(), - t_integer(0)]); - ['io'] -> - t_tuple([t_tuple([t_atom('input'), t_non_neg_integer()]), - t_tuple([t_atom('output'), t_non_neg_integer()])]); - ['reductions'] -> - t_tuple([t_non_neg_integer(), t_non_neg_integer()]); - ['run_queue'] -> - t_non_neg_integer(); - ['runtime'] -> - t_tuple([t_non_neg_integer(), t_integer(0)]); - ['wall_clock'] -> - t_tuple([t_non_neg_integer(), t_integer(0)]); - List when is_list(List) -> - T_statistics_1; - unknown -> - T_statistics_1 - end - end); type(erlang, subtract, 2, Xs) -> type(erlang, '--', 2, Xs); % alias type(erlang, suspend_process, 1, Xs) -> strict(arg_types(erlang, suspend_process, 1), Xs, fun (_) -> t_atom('true') end); -type(erlang, suspend_process, 2, Xs) -> - strict(arg_types(erlang, suspend_process, 2), Xs, - fun (_) -> t_boolean() end); -type(erlang, system_flag, 2, Xs) -> - strict(arg_types(erlang, system_flag, 2), Xs, - fun ([Flag,_Value]) -> - %% this provides an overapproximation of all return values - T_system_flag_2 = t_sup([t_boolean(), - t_integer(), - t_sequential_tracer(), - t_system_cpu_topology(), - t_system_multi_scheduling()]), - case t_is_atom(Flag) of - true -> - case t_atom_vals(Flag) of - ['backtrace_depth'] -> - t_non_neg_fixnum(); - ['cpu_topology'] -> - t_system_cpu_topology(); - ['debug_flags'] -> - t_atom('true'); - ['display_items'] -> - t_non_neg_fixnum(); - ['fullsweep_after'] -> - t_non_neg_fixnum(); - ['min_heap_size'] -> - t_non_neg_fixnum(); - ['min_bin_vheap_size'] -> - t_non_neg_fixnum(); - ['multi_scheduling'] -> - t_system_multi_scheduling(); - ['schedulers_online'] -> - t_pos_fixnum(); - ['scheduler_bind_type'] -> - t_scheduler_bind_type_results(); - ['sequential_tracer'] -> - t_sequential_tracer(); - ['trace_control_word'] -> - t_integer(); - List when is_list(List) -> - T_system_flag_2; - unknown -> - T_system_flag_2 - end; - false -> - case t_is_integer(Flag) of % SHOULD BE: t_is_fixnum - true -> - t_atom('true'); - false -> - T_system_flag_2 - end - end - end); type(erlang, system_info, 1, Xs) -> strict(arg_types(erlang, system_info, 1), Xs, fun ([Type]) -> @@ -1543,12 +868,8 @@ type(erlang, system_info, 1, Xs) -> t_list(t_tuple([t_atom(), t_list(t_tuple([t_atom(), t_any()]))]))]); - ['build_type'] -> - t_system_build_type_return(); ['break_ignored'] -> t_boolean(); - ['c_compiler_used'] -> - t_tuple([t_atom(), t_any()]); ['cpu_topology'] -> t_system_cpu_topology(); ['compat_rel'] -> @@ -1561,8 +882,6 @@ type(erlang, system_info, 1, Xs) -> t_binary(); ['dist_ctrl'] -> t_list(t_tuple([t_atom(), t_sup([t_pid(), t_port])])); - ['driver_version'] -> - t_string(); %% elib_malloc is intentionally not included, %% because it scheduled for removal in R15. ['endian'] -> @@ -1576,9 +895,7 @@ type(erlang, system_info, 1, Xs) -> ['heap_sizes'] -> t_list(t_integer()); ['heap_type'] -> - t_sup([t_atom('private'), - t_atom('shared'), - t_atom('hybrid')]); + t_sup([t_atom('private'), t_atom('hybrid')]); ['hipe_architecture'] -> t_atoms(['amd64', 'arm', 'powerpc', 'ppc64', 'undefined', 'ultrasparc', 'x86']); @@ -1586,20 +903,12 @@ type(erlang, system_info, 1, Xs) -> t_binary(); ['internal_cpu_topology'] -> %% Undocumented internal feature t_internal_cpu_topology(); - ['kernel_poll'] -> - t_boolean(); ['loaded'] -> t_binary(); ['logical_processors'] -> t_non_neg_fixnum(); ['machine'] -> t_string(); - ['min_heap_size'] -> - t_tuple([t_atom('min_heap_size'), - t_non_neg_integer()]); - ['min_bin_vheap_size'] -> - t_tuple([t_atom('min_bin_vheap_size'), - t_non_neg_integer()]); ['multi_scheduling'] -> t_system_multi_scheduling(); ['multi_scheduling_blockers'] -> @@ -1614,8 +923,6 @@ type(erlang, system_info, 1, Xs) -> t_non_neg_fixnum(), t_non_neg_fixnum()]), t_string()); - ['otp_release'] -> - t_string(); ['process_count'] -> t_non_neg_fixnum(); ['process_limit'] -> @@ -1645,8 +952,6 @@ type(erlang, system_info, 1, Xs) -> t_non_neg_fixnum(); ['trace_control_word'] -> t_integer(); - ['update_cpu_info'] -> - t_sup([t_atom('changed'), t_atom('unchanged')]); ['version'] -> t_string(); ['wordsize'] -> @@ -1660,56 +965,13 @@ type(erlang, system_info, 1, Xs) -> t_any() %% overapproximation as the return value might change end end); -type(erlang, system_monitor, 0, Xs) -> - strict(arg_types(erlang, system_monitor, 0), Xs, - fun (_) -> t_system_monitor_settings() end); -type(erlang, system_monitor, 1, Xs) -> - strict(arg_types(erlang, system_monitor, 1), Xs, - fun (_) -> t_system_monitor_settings() end); -type(erlang, system_monitor, 2, Xs) -> - strict(arg_types(erlang, system_monitor, 2), Xs, - fun (_) -> t_system_monitor_settings() end); -type(erlang, system_profile, 0, _) -> - t_system_profile_return(); -type(erlang, system_profile, 2, Xs) -> - strict(arg_types(erlang, system_profile, 2), Xs, - fun (_) -> t_system_profile_return() end); -type(erlang, term_to_binary, 1, Xs) -> - strict(arg_types(erlang, term_to_binary, 1), Xs, fun (_) -> t_binary() end); -type(erlang, term_to_binary, 2, Xs) -> - strict(arg_types(erlang, term_to_binary, 2), Xs, fun (_) -> t_binary() end); -type(erlang, time, 0, _) -> - t_tuple([t_non_neg_integer(), t_non_neg_integer(), t_non_neg_integer()]); +%% Guard bif, needs to be here. type(erlang, tl, 1, Xs) -> strict(arg_types(erlang, tl, 1), Xs, fun ([X]) -> t_cons_tl(X) end); -type(erlang, trace, 3, Xs) -> - strict(arg_types(erlang, trace, 3), Xs, fun (_) -> t_integer() end); -type(erlang, trace_delivered, 1, Xs) -> - strict(arg_types(erlang, trace_delivered, 1), Xs, - fun (_) -> t_reference() end); -type(erlang, trace_info, 2, Xs) -> - strict(arg_types(erlang, trace_info, 2), Xs, - fun (_) -> - t_tuple([t_atom(), - t_sup([%% the following is info about a PID - t_list(t_atom()), t_pid(), t_port(), - %% the following is info about a func - t_atom('global'), t_atom('local'), - t_atom('false'), t_atom('true'), - t_list(), t_pid(), t_port(), - t_integer(), - t_list(t_tuple([t_atom(), t_any()])), - %% and this is the 'not found' value - t_atom('undefined')])]) - end); -type(erlang, trace_pattern, 2, Xs) -> - strict(arg_types(erlang, trace_pattern, 2), Xs, - fun (_) -> t_non_neg_fixnum() end); %% num of MFAs that match pattern -type(erlang, trace_pattern, 3, Xs) -> - strict(arg_types(erlang, trace_pattern, 3), Xs, - fun (_) -> t_non_neg_fixnum() end); %% num of MFAs that match pattern +%% Guard bif, needs to be here. type(erlang, trunc, 1, Xs) -> strict(arg_types(erlang, trunc, 1), Xs, fun (_) -> t_integer() end); +%% Guard bif, needs to be here. type(erlang, tuple_size, 1, Xs) -> strict(arg_types(erlang, tuple_size, 1), Xs, fun (_) -> t_non_neg_integer() end); type(erlang, tuple_to_list, 1, Xs) -> @@ -1732,266 +994,10 @@ type(erlang, tuple_to_list, 1, Xs) -> end end end); -type(erlang, universaltime, 0, _) -> - t_tuple([t_date(), t_time()]); -type(erlang, universaltime_to_localtime, 1, Xs) -> - strict(arg_types(erlang, universaltime_to_localtime, 1), Xs, - fun ([T]) -> T end); -type(erlang, universaltime_to_posixtime, 1, Xs) -> - strict(arg_types(erlang, universaltime_to_posixtime,1), Xs, - fun(_) -> t_integer() end); -type(erlang, unlink, 1, Xs) -> - strict(arg_types(erlang, unlink, 1), Xs, fun (_) -> t_atom('true') end); -type(erlang, unregister, 1, Xs) -> - strict(arg_types(erlang, unregister, 1), Xs, fun (_) -> t_atom('true') end); -type(erlang, whereis, 1, Xs) -> - strict(arg_types(erlang, whereis, 1), Xs, - fun (_) -> t_sup([t_pid(), t_port(), t_atom('undefined')]) end); type(erlang, yield, 0, _) -> t_atom('true'); -%%-- erl_prim_loader ---------------------------------------------------------- -type(erl_prim_loader, get_file, 1, Xs) -> - strict(arg_types(erl_prim_loader, get_file, 1), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_binary(), t_string()]), - t_atom('error')) - end); -type(erl_prim_loader, get_path, 0, _) -> - t_tuple([t_atom('ok'), t_list(t_string())]); -type(erl_prim_loader, set_path, 1, Xs) -> - strict(arg_types(erl_prim_loader, set_path, 1), Xs, - fun (_) -> t_atom('ok') end); -%%-- error_logger ------------------------------------------------------------- -type(error_logger, warning_map, 0, _) -> - t_sup([t_atom('info'), t_atom('warning'), t_atom('error')]); -%%-- erts_debug --------------------------------------------------------------- -type(erts_debug, breakpoint, 2, Xs) -> - strict(arg_types(erts_debug, breakpoint, 2), Xs, fun (_) -> t_fixnum() end); -type(erts_debug, disassemble, 1, Xs) -> - strict(arg_types(erts_debug, disassemble, 1), Xs, - fun (_) -> t_sup([t_atom('false'), - t_atom('undef'), - t_tuple([t_integer(), t_binary(), t_mfa()])]) end); -type(erts_debug, display, 1, _) -> - t_string(); -type(erts_debug, dist_ext_to_term, 2, Xs) -> - strict(arg_types(erts_debug, dist_ext_to_term, 2), Xs, - fun (_) -> t_any() end); -type(erts_debug, dump_monitors, 1, Xs) -> - strict(arg_types(erts_debug, dump_monitors, 1), Xs, - fun(_) -> t_atom('true') end); -type(erts_debug, dump_links, 1, Xs) -> - strict(arg_types(erts_debug, dump_links, 1), Xs, - fun(_) -> t_atom('true') end); -type(erts_debug, flat_size, 1, Xs) -> - strict(arg_types(erts_debug, flat_size, 1), Xs, fun (_) -> t_integer() end); -type(erts_debug, get_internal_state, 1, _) -> - t_any(); -type(erts_debug, instructions, 0, _) -> - t_list(t_list(t_byte())); -type(erts_debug, lock_counters, 1, Xs) -> - strict(arg_types(erts_debug, lock_counters, 1), Xs, - fun ([Arg]) -> - case t_is_atom(Arg) of - true -> - case t_atom_vals(Arg) of - ['enabled'] -> t_boolean(); - ['info'] -> t_any(); - ['clear'] -> t_atom(ok); - _ -> t_sup([t_boolean(), t_any(), t_atom('ok')]) - end; - false -> - case t_is_tuple(Arg) of - true -> t_boolean(); - false -> t_sup([t_boolean(), t_any(), t_atom('ok')]) - end - end - end); -type(erts_debug, same, 2, Xs) -> - strict(arg_types(erts_debug, same, 2), Xs, fun (_) -> t_boolean() end); -type(erts_debug, set_internal_state, 2, _) -> - t_any(); %%-- ets ---------------------------------------------------------------------- -type(ets, all, 0, _) -> - t_list(t_tab()); -type(ets, delete, 1, Xs) -> - strict(arg_types(ets, delete, 1), Xs, fun (_) -> t_atom('true') end); -type(ets, delete, 2, Xs) -> - strict(arg_types(ets, delete, 2), Xs, fun (_) -> t_atom('true') end); -type(ets, delete_all_objects, 1, Xs) -> - strict(arg_types(ets, delete_all_objects, 1), Xs, - fun (_) -> t_atom('true') end); -type(ets, delete_object, 2, Xs) -> - strict(arg_types(ets, delete_object, 2), Xs, fun (_) -> t_atom('true') end); -type(ets, first, 1, Xs) -> - strict(arg_types(ets, first, 1), Xs, fun (_) -> t_any() end); -type(ets, give_away, 3, Xs) -> - strict(arg_types(ets, give_away, 3), Xs, fun (_) -> t_atom('true') end); -type(ets, info, 1, Xs) -> - strict(arg_types(ets, info, 1), Xs, - fun (_) -> - t_sup(t_list(t_tuple([t_ets_info_items(), t_any()])), - t_atom('undefined')) - end); -type(ets, info, 2, Xs) -> - strict(arg_types(ets, info, 2), Xs, fun (_) -> t_any() end); -type(ets, insert, 2, Xs) -> - strict(arg_types(ets, insert, 2), Xs, fun (_) -> t_atom('true') end); -type(ets, insert_new, 2, Xs) -> - strict(arg_types(ets, insert_new, 2), Xs, fun (_) -> t_boolean() end); -type(ets, is_compiled_ms, 1, Xs) -> - strict(arg_types(ets, is_compiled_ms, 1), Xs, fun (_) -> t_boolean() end); -type(ets, last, 1, Xs) -> - type(ets, first, 1, Xs); -type(ets, lookup, 2, Xs) -> - strict(arg_types(ets, lookup, 2), Xs, fun (_) -> t_list(t_tuple()) end); -type(ets, lookup_element, 3, Xs) -> - strict(arg_types(ets, lookup_element, 3), Xs, fun (_) -> t_any() end); -type(ets, match, 1, Xs) -> - strict(arg_types(ets, match, 1), Xs, fun (_) -> t_matchres() end); -type(ets, match, 2, Xs) -> - strict(arg_types(ets, match, 2), Xs, fun (_) -> t_list() end); -type(ets, match, 3, Xs) -> - strict(arg_types(ets, match, 3), Xs, fun (_) -> t_matchres() end); -type(ets, match_object, 1, Xs) -> type(ets, match, 1, Xs); -type(ets, match_object, 2, Xs) -> type(ets, match, 2, Xs); -type(ets, match_object, 3, Xs) -> type(ets, match, 3, Xs); -type(ets, match_spec_compile, 1, Xs) -> - strict(arg_types(ets, match_spec_compile, 1), Xs, fun (_) -> t_any() end); -type(ets, match_spec_run_r, 3, Xs) -> - strict(arg_types(ets, match_spec_run_r, 3), Xs, fun (_) -> t_list() end); -type(ets, member, 2, Xs) -> - strict(arg_types(ets, member, 2), Xs, fun (_) -> t_boolean() end); -type(ets, new, 2, Xs) -> - strict(arg_types(ets, new, 2), Xs, fun (_) -> t_tab() end); -type(ets, next, 2, Xs) -> - strict(arg_types(ets, next, 2), Xs, - %% t_any below stands for: term() | '$end_of_table' - fun (_) -> t_any() end); -type(ets, prev, 2, Xs) -> type(ets, next, 2, Xs); type(ets, rename, 2, Xs) -> strict(arg_types(ets, rename, 2), Xs, fun ([_, Name]) -> Name end); -type(ets, safe_fixtable, 2, Xs) -> - strict(arg_types(ets, safe_fixtable, 2), Xs, fun (_) -> t_atom('true') end); -type(ets, select, 1, Xs) -> - strict(arg_types(ets, select, 1), Xs, fun (_) -> t_matchres() end); -type(ets, select, 2, Xs) -> - strict(arg_types(ets, select, 2), Xs, fun (_) -> t_list() end); -type(ets, select, 3, Xs) -> - strict(arg_types(ets, select, 3), Xs, fun (_) -> t_matchres() end); -type(ets, select_count, 2, Xs) -> - strict(arg_types(ets, select_count, 2), Xs, - fun (_) -> t_non_neg_fixnum() end); -type(ets, select_delete, 2, Xs) -> - strict(arg_types(ets, select_delete, 2), Xs, - fun (_) -> t_non_neg_fixnum() end); -type(ets, select_reverse, 1, Xs) -> type(ets, select, 1, Xs); -type(ets, select_reverse, 2, Xs) -> type(ets, select, 2, Xs); -type(ets, select_reverse, 3, Xs) -> type(ets, select, 3, Xs); -type(ets, setopts, 2, Xs) -> - strict(arg_types(ets, setopts, 2), Xs, fun (_) -> t_atom('true') end); -type(ets, slot, 2, Xs) -> - strict(arg_types(ets, slot, 2), Xs, - fun (_) -> t_sup(t_list(t_tuple()), t_atom('$end_of_table')) end); -type(ets, update_counter, 3, Xs) -> - strict(arg_types(ets, update_counter, 3), Xs, - fun ([_, _, Op]) -> - case t_is_integer(Op) of - true -> t_integer(); - false -> - case t_is_tuple(Op) of - true -> t_integer(); - false -> - case t_is_list(Op) of - true -> t_list(t_integer()); - false -> - case t_is_nil(Op) of - true -> t_nil(); - false -> t_sup([t_integer(), t_list(t_integer())]) - end - end - end - end - end); -type(ets, update_element, 3, Xs) -> - strict(arg_types(ets, update_element, 3), Xs, fun (_) -> t_boolean() end); -%%-- file --------------------------------------------------------------------- -type(file, native_name_encoding, 0, _) -> - t_file_encoding(); -%%-- prim_file ---------------------------------------------------------------- -type(prim_file, internal_name2native, 1, Xs) -> - strict(arg_types(prim_file, internal_name2native, 1), Xs, - fun (_) -> t_binary() end); -type(prim_file, internal_native2name, 1, Xs) -> - strict(arg_types(prim_file, internal_native2name, 1), Xs, - fun (_) -> t_prim_file_name() end); -type(prim_file, internal_normalize_utf8, 1, Xs) -> - strict(arg_types(prim_file, internal_normalize_utf8, 1), Xs, - fun (_) -> t_unicode_string() end); -%%-- gen_tcp ------------------------------------------------------------------ -%% NOTE: All type information for this module added to avoid loss of precision -type(gen_tcp, accept, 1, Xs) -> - strict(arg_types(gen_tcp, accept, 1), Xs, fun (_) -> t_gen_tcp_accept() end); -type(gen_tcp, accept, 2, Xs) -> - strict(arg_types(gen_tcp, accept, 2), Xs, fun (_) -> t_gen_tcp_accept() end); -type(gen_tcp, connect, 3, Xs) -> - strict(arg_types(gen_tcp, connect, 3), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_socket()]), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -type(gen_tcp, connect, 4, Xs) -> - strict(arg_types(gen_tcp, connect, 4), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_socket()]), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -type(gen_tcp, listen, 2, Xs) -> - strict(arg_types(gen_tcp, listen, 2), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_socket()]), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -type(gen_tcp, recv, 2, Xs) -> - strict(arg_types(gen_tcp, recv, 2), Xs, fun (_) -> t_gen_tcp_recv() end); -type(gen_tcp, recv, 3, Xs) -> - strict(arg_types(gen_tcp, recv, 3), Xs, fun (_) -> t_gen_tcp_recv() end); -type(gen_tcp, send, 2, Xs) -> - strict(arg_types(gen_tcp, send, 2), Xs, - fun (_) -> - t_sup(t_atom('ok'), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -type(gen_tcp, shutdown, 2, Xs) -> - strict(arg_types(gen_tcp, shutdown, 2), Xs, - fun (_) -> - t_sup(t_atom('ok'), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -%%-- gen_udp ------------------------------------------------------------------ -%% NOTE: All type information for this module added to avoid loss of precision -type(gen_udp, open, 1, Xs) -> - strict(arg_types(gen_udp, open, 1), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_socket()]), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -type(gen_udp, open, 2, Xs) -> - strict(arg_types(gen_udp, open, 2), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_socket()]), - t_tuple([t_atom('error'), t_inet_posix_error()])) - end); -type(gen_udp, recv, 2, Xs) -> - strict(arg_types(gen_udp, recv, 2), Xs, fun (_) -> t_gen_udp_recv() end); -type(gen_udp, recv, 3, Xs) -> - strict(arg_types(gen_udp, recv, 3), Xs, fun (_) -> t_gen_udp_recv() end); -type(gen_udp, send, 4, Xs) -> - strict(arg_types(gen_udp, send, 4), Xs, - fun (_) -> - t_sup(t_atom('ok'), - t_tuple([t_atom('error'), t_sup(t_atom('not_owner'), - t_inet_posix_error())])) - end); %%-- hipe_bifs ---------------------------------------------------------------- type(hipe_bifs, add_ref, 2, Xs) -> strict(arg_types(hipe_bifs, add_ref, 2), Xs, fun (_) -> t_nil() end); @@ -2114,26 +1120,6 @@ type(hipe_bifs, write_u32, 2, Xs) -> strict(arg_types(hipe_bifs, write_u32, 2), Xs, fun (_) -> t_nil() end); type(hipe_bifs, write_u64, 2, Xs) -> strict(arg_types(hipe_bifs, write_u64, 2), Xs, fun (_) -> t_nil() end); -%%-- io ----------------------------------------------------------------------- -type(io, format, 1, Xs) -> - strict(arg_types(io, format, 1), Xs, fun (_) -> t_atom('ok') end); -type(io, format, 2, Xs) -> - strict(arg_types(io, format, 2), Xs, fun (_) -> t_atom('ok') end); -type(io, format, 3, Xs) -> - strict(arg_types(io, format, 3), Xs, fun (_) -> t_atom('ok') end); -type(io, fwrite, 1, Xs) -> type(io, format, 1, Xs); % same -type(io, fwrite, 2, Xs) -> type(io, format, 2, Xs); % same -type(io, fwrite, 3, Xs) -> type(io, format, 3, Xs); % same -type(io, put_chars, 1, Xs) -> - strict(arg_types(io, put_chars, 1), Xs, fun (_) -> t_atom('ok') end); -type(io, put_chars, 2, Xs) -> - strict(arg_types(io, put_chars, 2), Xs, fun (_) -> t_atom('ok') end); -%%-- io_lib ------------------------------------------------------------------- -type(io_lib, format, 2, Xs) -> - strict(arg_types(io_lib, format, 2), Xs, - %% t_list() because the character list might be arbitrarily nested - fun (_) -> t_list(t_sup(t_char(), t_list())) end); -type(io_lib, fwrite, 2, Xs) -> type(io_lib, format, 2, Xs); % same %%-- lists -------------------------------------------------------------------- type(lists, all, 2, Xs) -> strict(arg_types(lists, all, 2), Xs, @@ -2503,8 +1489,6 @@ type(lists, merge, 2, Xs) -> end end end); -%% type(lists, merge, 3, Xs) -> -%% type(lists, merge3, 3, Xs) -> type(lists, min, 1, Xs) -> strict(arg_types(lists, min, 1), Xs, fun ([L]) -> t_list_elements(L) end); type(lists, nth, 2, Xs) -> @@ -2541,10 +1525,6 @@ type(lists, reverse, 1, Xs) -> strict(arg_types(lists, reverse, 1), Xs, fun ([X]) -> X end); type(lists, reverse, 2, Xs) -> type(erlang, '++', 2, Xs); % reverse-onto is just like append -type(lists, seq, 2, Xs) -> - strict(arg_types(lists, seq, 2), Xs, fun (_) -> t_list(t_integer()) end); -type(lists, seq, 3, Xs) -> - strict(arg_types(lists, seq, 3), Xs, fun (_) -> t_list(t_integer()) end); type(lists, sort, 1, Xs) -> strict(arg_types(lists, sort, 1), Xs, fun ([X]) -> X end); type(lists, sort, 2, Xs) -> @@ -2651,95 +1631,7 @@ type(lists, zipwith, 3, Xs) -> type(lists, zipwith3, 4, Xs) -> strict(arg_types(lists, zipwith3, 4), Xs, fun ([F,_As,_Bs,_Cs]) -> t_sup(t_list(t_fun_range(F)), t_nil()) end); -%%-- math --------------------------------------------------------------------- -type(math, acos, 1, Xs) -> - strict(arg_types(math, acos, 1), Xs, fun (_) -> t_float() end); -type(math, acosh, 1, Xs) -> - strict(arg_types(math, acosh, 1), Xs, fun (_) -> t_float() end); -type(math, asin, 1, Xs) -> - strict(arg_types(math, asin, 1), Xs, fun (_) -> t_float() end); -type(math, asinh, 1, Xs) -> - strict(arg_types(math, asinh, 1), Xs, fun (_) -> t_float() end); -type(math, atan, 1, Xs) -> - strict(arg_types(math, atan, 1), Xs, fun (_) -> t_float() end); -type(math, atan2, 2, Xs) -> - strict(arg_types(math, atan2, 2), Xs, fun (_) -> t_float() end); -type(math, atanh, 1, Xs) -> - strict(arg_types(math, atanh, 1), Xs, fun (_) -> t_float() end); -type(math, cos, 1, Xs) -> - strict(arg_types(math, cos, 1), Xs, fun (_) -> t_float() end); -type(math, cosh, 1, Xs) -> - strict(arg_types(math, cosh, 1), Xs, fun (_) -> t_float() end); -type(math, erf, 1, Xs) -> - strict(arg_types(math, erf, 1), Xs, fun (_) -> t_float() end); -type(math, erfc, 1, Xs) -> - strict(arg_types(math, erfc, 1), Xs, fun (_) -> t_float() end); -type(math, exp, 1, Xs) -> - strict(arg_types(math, exp, 1), Xs, fun (_) -> t_float() end); -type(math, log, 1, Xs) -> - strict(arg_types(math, log, 1), Xs, fun (_) -> t_float() end); -type(math, log10, 1, Xs) -> - strict(arg_types(math, log10, 1), Xs, fun (_) -> t_float() end); -type(math, pi, 0, _) -> t_float(); -type(math, pow, 2, Xs) -> - strict(arg_types(math, pow, 2), Xs, fun (_) -> t_float() end); -type(math, sin, 1, Xs) -> - strict(arg_types(math, sin, 1), Xs, fun (_) -> t_float() end); -type(math, sinh, 1, Xs) -> - strict(arg_types(math, sinh, 1), Xs, fun (_) -> t_float() end); -type(math, sqrt, 1, Xs) -> - strict(arg_types(math, sqrt, 1), Xs, fun (_) -> t_float() end); -type(math, tan, 1, Xs) -> - strict(arg_types(math, tan, 1), Xs, fun (_) -> t_float() end); -type(math, tanh, 1, Xs) -> - strict(arg_types(math, tanh, 1), Xs, fun (_) -> t_float() end); -%%-- net_kernel --------------------------------------------------------------- -type(net_kernel, dflag_unicode_io, 1, Xs) -> - strict(arg_types(net_kernel, dflag_unicode_io, 1), Xs, - fun (_) -> t_boolean() end); -%%-- ordsets ------------------------------------------------------------------ -type(ordsets, filter, 2, Xs) -> - type(lists, filter, 2, Xs); -type(ordsets, fold, 3, Xs) -> - type(lists, foldl, 3, Xs); -%%-- os ----------------------------------------------------------------------- -type(os, getenv, 0, _) -> t_list(t_string()); -type(os, getenv, 1, Xs) -> - strict(arg_types(os, getenv, 1), Xs, - fun (_) -> t_sup(t_string(), t_atom('false')) end); -type(os, getpid, 0, _) -> t_string(); -type(os, putenv, 2, Xs) -> - strict(arg_types(os, putenv, 2), Xs, fun (_) -> t_atom('true') end); -type(os, timestamp, 0, _) -> - t_timestamp(); -%%-- re ----------------------------------------------------------------------- -type(re, compile, 1, Xs) -> - strict(arg_types(re, compile, 1), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_re_MP()]), - t_tuple([t_atom('error'), t_re_ErrorSpec()])) - end); -type(re, compile, 2, Xs) -> - strict(arg_types(re, compile, 2), Xs, - fun (_) -> - t_sup(t_tuple([t_atom('ok'), t_re_MP()]), - t_tuple([t_atom('error'), t_re_ErrorSpec()])) - end); -type(re, run, 2, Xs) -> - strict(arg_types(re, run, 2), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('match'), t_re_Captured()]), - t_atom('nomatch'), - t_tuple([t_atom('error'), t_re_ErrorSpec()])]) - end); -type(re, run, 3, Xs) -> - strict(arg_types(re, run, 3), Xs, - fun (_) -> - t_sup([t_tuple([t_atom('match'), t_re_Captured()]), - t_atom('match'), - t_atom('nomatch'), - t_tuple([t_atom('error'), t_re_ErrorSpec()])]) - end); + %%-- string ------------------------------------------------------------------- type(string, chars, 2, Xs) -> % NOTE: added to avoid loss of information strict(arg_types(string, chars, 2), Xs, fun (_) -> t_string() end); @@ -2758,41 +1650,6 @@ type(string, chars, 3, Xs) -> % NOTE: added to avoid loss of information end end end); -type(string, concat, 2, Xs) -> % NOTE: added to avoid loss of information - strict(arg_types(string, concat, 2), Xs, fun (_) -> t_string() end); -type(string, equal, 2, Xs) -> % NOTE: added to avoid loss of information - strict(arg_types(string, equal, 2), Xs, fun (_) -> t_boolean() end); -type(string, to_float, 1, Xs) -> - strict(arg_types(string, to_float, 1), Xs, - fun (_) -> t_sup(t_tuple([t_float(), t_string()]), - t_tuple([t_atom('error'), - t_sup(t_atom('no_float'), - t_atom('not_a_list'))])) - end); -type(string, to_integer, 1, Xs) -> - strict(arg_types(string, to_integer, 1), Xs, - fun (_) -> t_sup(t_tuple([t_integer(), t_string()]), - t_tuple([t_atom('error'), - t_sup(t_atom('no_integer'), - t_atom('not_a_list'))])) - end); -%%-- unicode ------------------------------------------------------------------ -type(unicode, characters_to_binary, 2, Xs) -> - strict(arg_types(unicode, characters_to_binary, 2), Xs, - fun (_) -> - t_sup([t_binary(), - t_tuple([t_atom('error'), t_binary(), t_ML()]), - t_tuple([t_atom('incomplete'), t_binary(), t_ML()])]) - end); -type(unicode, characters_to_list, 2, Xs) -> - strict(arg_types(unicode, characters_to_list, 2), Xs, - fun (_) -> - t_sup([t_string(), - t_tuple([t_atom('error'), t_string(), t_ML()]), - t_tuple([t_atom('incomplete'), t_string(), t_ML()])]) - end); -type(unicode, bin_is_7bit, 1, Xs) -> - strict(arg_types(unicode, bin_is_7bit, 1), Xs, fun (_) -> t_boolean() end); %%----------------------------------------------------------------------------- type(M, F, A, Xs) when is_atom(M), is_atom(F), @@ -3247,107 +2104,6 @@ key_comparisons_fail(X0, KeyPos, TupleList) -> -spec arg_types(atom(), atom(), arity()) -> [erl_types:erl_type()] | 'unknown'. -%%------- binary -------------------------------------------------------------- -arg_types(binary, at, 2) -> - [t_binary(), t_non_neg_integer()]; -arg_types(binary, bin_to_list, 1) -> - [t_binary()]; -arg_types(binary, bin_to_list, 2) -> - [t_binary(), t_binary_part()]; -arg_types(binary, bin_to_list, 3) -> - [t_binary(), t_integer(), t_non_neg_integer()]; -arg_types(binary, compile_pattern, 1) -> - [t_sup(t_binary(), t_list(t_binary()))]; -arg_types(binary, copy, 1) -> - [t_binary()]; -arg_types(binary, copy, 2) -> - [t_binary(), t_non_neg_integer()]; -arg_types(binary, decode_unsigned, 1) -> - [t_binary()]; -arg_types(binary, decode_unsigned, 2) -> - [t_binary(), t_endian()]; -arg_types(binary, encode_unsigned, 1) -> - [t_non_neg_integer()]; -arg_types(binary, encode_unsigned, 2) -> - [t_non_neg_integer(), t_endian()]; -arg_types(binary, first, 1) -> - [t_binary()]; -arg_types(binary, last, 1) -> - [t_binary()]; -arg_types(binary, list_to_bin, 1) -> - arg_types(erlang, list_to_binary, 1); -arg_types(binary, longest_common_prefix, 1) -> - [t_list(t_binary())]; -arg_types(binary, longest_common_suffix, 1) -> - [t_list(t_binary())]; -arg_types(binary, match, 2) -> - [t_binary(), t_binary_pattern()]; -arg_types(binary, match, 3) -> - [t_binary(), t_binary_pattern(), t_binary_options()]; -arg_types(binary, matches, 2) -> - [t_binary(), t_binary_pattern()]; -arg_types(binary, matches, 3) -> - [t_binary(), t_binary_pattern(), t_binary_options()]; -arg_types(binary, part, 2) -> - arg_types(erlang, binary_part, 2); -arg_types(binary, part, 3) -> - arg_types(erlang, binary_part, 3); -arg_types(binary, referenced_byte_size, 1) -> - [t_binary()]; -%%------- code ---------------------------------------------------------------- -arg_types(code, get_chunk, 2) -> - [t_binary(), t_string()]; -arg_types(code, is_module_native, 1) -> - [t_atom()]; -arg_types(code, module_md5, 1) -> - [t_binary()]; -arg_types(code, make_stub_module, 3) -> - [t_atom(), t_binary(), t_tuple([t_list(), t_list()])]; -arg_types(code, rehash, 0) -> - []; -%%------- erl_ddll ------------------------------------------------------------ -arg_types(erl_ddll, demonitor, 1) -> - arg_types(erlang, demonitor, 1); -arg_types(erl_ddll, format_error_int, 1) -> - [t_sup([t_atom('inconsistent'), - t_atom('linked_in_driver'), - t_atom('permanent'), - t_atom('not_loaded'), - t_atom('not_loaded_by_this_process'), - t_atom('not_pending'), - t_atom('already_loaded'), - t_atom('unloading')])]; -arg_types(erl_ddll, info, 2) -> - [t_sup([t_atom(), t_string()]), - t_sup([t_atom('awaiting_load'), - t_atom('awaiting_unload'), - t_atom('driver_options'), - t_atom('linked_in_driver'), - t_atom('permanent'), - t_atom('port_count'), - t_atom('processes')])]; -arg_types(erl_ddll, loaded_drivers, 0) -> - []; -arg_types(erl_ddll, monitor, 2) -> - [t_atom('driver'), - t_tuple([t_atom(), t_sup([t_atom('loaded'), t_atom('unloaded')])])]; -arg_types(erl_ddll, try_load, 3) -> - [t_sup([t_atom(), t_string(), t_nonempty_list(t_sup([t_atom(), t_string()]))]), - t_sup([t_atom(), t_string()]), - t_list(t_sup([t_tuple([t_atom('driver_options'), - t_list(t_atom('kill_ports'))]), - t_tuple([t_atom('monitor'), - t_sup([t_atom('pending_driver'), - t_atom('pending')])]), - t_tuple([t_atom('reload'), - t_sup([t_atom('pending_driver'), - t_atom('pending')])])]))]; -arg_types(erl_ddll, try_unload, 2) -> - [t_sup([t_atom(), t_string(), t_nonempty_list(t_sup([t_atom(), t_string()]))]), - t_list(t_sup([t_atom('kill_ports'), - t_tuple([t_atom('monitor'), - t_sup([t_atom('pending_driver'), - t_atom('pending')])])]))]; %%------- erlang -------------------------------------------------------------- arg_types(erlang, '!', 2) -> Pid = t_sup([t_pid(), t_port(), t_atom(), @@ -3409,18 +2165,11 @@ arg_types(erlang, 'bsl', 2) -> [t_integer(), t_integer()]; arg_types(erlang, 'bnot', 1) -> [t_integer()]; +%% Guard bif, needs to be here. arg_types(erlang, abs, 1) -> [t_number()]; -arg_types(erlang, adler32, 1) -> - [t_iodata()]; -arg_types(erlang, adler32, 2) -> - [t_adler32(), t_iodata()]; -arg_types(erlang, adler32_combine, 3) -> - [t_adler32(), t_adler32(), t_non_neg_integer()]; arg_types(erlang, append, 2) -> arg_types(erlang, '++', 2); -arg_types(erlang, append_element, 2) -> - [t_tuple(), t_any()]; arg_types(erlang, apply, 2) -> [t_sup(t_tuple([t_module(), t_atom()]), @@ -3428,162 +2177,55 @@ arg_types(erlang, apply, 2) -> t_list()]; arg_types(erlang, apply, 3) -> [t_sup(t_atom(), t_tuple()), t_atom(), t_list()]; -arg_types(erlang, atom_to_binary, 2) -> - [t_atom(), t_encoding_a2b()]; -arg_types(erlang, atom_to_list, 1) -> - [t_atom()]; +%% Guard bif, needs to be here. arg_types(erlang, binary_part, 2) -> [t_binary(), t_tuple([t_non_neg_integer(), t_integer()])]; +%% Guard bif, needs to be here. arg_types(erlang, binary_part, 3) -> [t_binary(), t_non_neg_integer(), t_integer()]; -arg_types(erlang, binary_to_atom, 2) -> - [t_binary(), t_encoding_a2b()]; -arg_types(erlang, binary_to_existing_atom, 2) -> - arg_types(erlang, binary_to_atom, 2); -arg_types(erlang, binary_to_list, 1) -> - [t_binary()]; -arg_types(erlang, binary_to_list, 3) -> - [t_binary(), t_pos_integer(), t_pos_integer()]; % I want fixnum, but cannot -arg_types(erlang, binary_to_term, 1) -> - [t_binary()]; -arg_types(erlang, binary_to_term, 2) -> - [t_binary(), t_list(t_atom('safe'))]; -arg_types(erlang, bitsize, 1) -> % XXX: TAKE OUT - arg_types(erlang, bit_size, 1); +%% Guard bif, needs to be here. arg_types(erlang, bit_size, 1) -> [t_bitstr()]; -arg_types(erlang, bitstr_to_list, 1) -> % XXX: TAKE OUT - arg_types(erlang, bitstring_to_list, 1); -arg_types(erlang, bitstring_to_list, 1) -> - [t_bitstr()]; -arg_types(erlang, bump_reductions, 1) -> - [t_pos_fixnum()]; +%% Guard bif, needs to be here. arg_types(erlang, byte_size, 1) -> [t_binary()]; -arg_types(erlang, call_on_load_function, 1) -> - [t_atom()]; -arg_types(erlang, cancel_timer, 1) -> - [t_reference()]; -arg_types(erlang, check_old_code, 1) -> - [t_atom()]; -arg_types(erlang, check_process_code, 2) -> - [t_pid(), t_atom()]; -arg_types(erlang, crc32, 1) -> - [t_iodata()]; -arg_types(erlang, crc32, 2) -> - [t_crc32(), t_iodata()]; -arg_types(erlang, crc32_combine, 3) -> - [t_crc32(), t_crc32(), t_non_neg_integer()]; -arg_types(erlang, date, 0) -> - []; -arg_types(erlang, decode_packet, 3) -> - [t_decode_packet_type(), t_binary(), t_list(t_decode_packet_option())]; -arg_types(erlang, delete_module, 1) -> - [t_atom()]; -arg_types(erlang, demonitor, 1) -> - [t_reference()]; -arg_types(erlang, demonitor, 2) -> - [t_reference(), t_list(t_atoms(['flush', 'info']))]; arg_types(erlang, disconnect_node, 1) -> [t_node()]; -arg_types(erlang, display, 1) -> - [t_any()]; -arg_types(erlang, display_nl, 0) -> - []; -arg_types(erlang, display_string, 1) -> - [t_string()]; -arg_types(erlang, dist_exit, 3) -> - [t_pid(), t_dist_exit(), t_sup(t_pid(), t_port())]; -arg_types(erlang, element, 2) -> - [t_pos_fixnum(), t_tuple()]; -arg_types(erlang, erase, 0) -> +arg_types(erlang, halt, 0) -> []; -arg_types(erlang, erase, 1) -> - [t_any()]; +arg_types(erlang, halt, 1) -> + [t_sup(t_non_neg_fixnum(), t_string())]; arg_types(erlang, error, 1) -> [t_any()]; arg_types(erlang, error, 2) -> [t_any(), t_list()]; arg_types(erlang, exit, 1) -> [t_any()]; -arg_types(erlang, exit, 2) -> - [t_sup(t_pid(), t_port()), t_any()]; -arg_types(erlang, external_size, 1) -> - [t_any()]; % takes any term as input -arg_types(erlang, external_size, 2) -> - [t_any(), t_list()]; % takes any term as input and a list of options -arg_types(erlang, finish_after_on_load, 2) -> - [t_atom(), t_boolean()]; +%% Guard bif, needs to be here. +arg_types(erlang, element, 2) -> + [t_pos_fixnum(), t_tuple()]; +%% Guard bif, needs to be here. arg_types(erlang, float, 1) -> [t_number()]; -arg_types(erlang, float_to_list, 1) -> - [t_float()]; -arg_types(erlang, function_exported, 3) -> - [t_atom(), t_atom(), t_arity()]; arg_types(erlang, fun_info, 1) -> [t_fun()]; -arg_types(erlang, fun_info, 2) -> - [t_fun(), t_atom()]; -arg_types(erlang, fun_to_list, 1) -> - [t_fun()]; -arg_types(erlang, garbage_collect, 0) -> - []; -arg_types(erlang, garbage_collect, 1) -> - [t_pid()]; -arg_types(erlang, garbage_collect_message_area, 0) -> - []; -arg_types(erlang, get, 0) -> - []; -arg_types(erlang, get, 1) -> - [t_any()]; arg_types(erlang, get_cookie, 0) -> []; -arg_types(erlang, get_keys, 1) -> - [t_any()]; -arg_types(erlang, get_stacktrace, 0) -> - []; -arg_types(erlang, get_module_info, 1) -> - [t_atom()]; -arg_types(erlang, get_module_info, 2) -> - [t_atom(), t_module_info_2()]; -arg_types(erlang, group_leader, 0) -> - []; -arg_types(erlang, group_leader, 2) -> - [t_pid(), t_pid()]; -arg_types(erlang, halt, 0) -> - []; -arg_types(erlang, halt, 1) -> - [t_sup(t_non_neg_fixnum(), t_string())]; -arg_types(erlang, hash, 2) -> - [t_any(), t_integer()]; +%% Guard bif, needs to be here. arg_types(erlang, hd, 1) -> [t_cons()]; -arg_types(erlang, hibernate, 3) -> - [t_atom(), t_atom(), t_list()]; arg_types(erlang, info, 1) -> arg_types(erlang, system_info, 1); % alias -arg_types(erlang, iolist_to_binary, 1) -> - [t_sup(t_iolist(), t_binary())]; -arg_types(erlang, iolist_size, 1) -> - [t_sup(t_iolist(), t_binary())]; -arg_types(erlang, integer_to_list, 1) -> - [t_integer()]; arg_types(erlang, integer_to_list, 2) -> [t_integer(), t_from_range(2, 36)]; -arg_types(erlang, is_alive, 0) -> - []; arg_types(erlang, is_atom, 1) -> [t_any()]; arg_types(erlang, is_binary, 1) -> [t_any()]; -arg_types(erlang, is_bitstr, 1) -> % XXX: TAKE OUT - arg_types(erlang, is_bitstring, 1); arg_types(erlang, is_bitstring, 1) -> [t_any()]; arg_types(erlang, is_boolean, 1) -> [t_any()]; -arg_types(erlang, is_builtin, 3) -> - [t_atom(), t_atom(), t_arity()]; arg_types(erlang, is_float, 1) -> [t_any()]; arg_types(erlang, is_function, 1) -> @@ -3600,8 +2242,6 @@ arg_types(erlang, is_pid, 1) -> [t_any()]; arg_types(erlang, is_port, 1) -> [t_any()]; -arg_types(erlang, is_process_alive, 1) -> - [t_pid()]; arg_types(erlang, is_record, 2) -> [t_any(), t_atom()]; arg_types(erlang, is_record, 3) -> @@ -3610,548 +2250,91 @@ arg_types(erlang, is_reference, 1) -> [t_any()]; arg_types(erlang, is_tuple, 1) -> [t_any()]; +%% Guard bif, needs to be here. arg_types(erlang, length, 1) -> [t_list()]; -arg_types(erlang, link, 1) -> - [t_sup(t_pid(), t_port())]; -arg_types(erlang, list_to_atom, 1) -> - [t_string()]; -arg_types(erlang, list_to_binary, 1) -> - [t_iolist()]; -arg_types(erlang, list_to_bitstr, 1) -> % XXX: TAKE OUT - arg_types(erlang, list_to_bitstring, 1); -arg_types(erlang, list_to_bitstring, 1) -> - [t_bitstrlist()]; -arg_types(erlang, list_to_existing_atom, 1) -> - [t_string()]; -arg_types(erlang, list_to_float, 1) -> - [t_list(t_byte())]; -arg_types(erlang, list_to_integer, 1) -> - [t_list(t_byte())]; arg_types(erlang, list_to_integer, 2) -> [t_list(t_byte()), t_from_range(2, 36)]; -arg_types(erlang, list_to_pid, 1) -> - [t_string()]; -arg_types(erlang, list_to_tuple, 1) -> - [t_list()]; -arg_types(erlang, load_module, 2) -> - [t_atom(), t_binary()]; -arg_types(erlang, load_nif, 2) -> - [t_string(), t_any()]; -arg_types(erlang, loaded, 0) -> - []; -arg_types(erlang, localtime, 0) -> - []; -arg_types(erlang, localtime_to_universaltime, 1) -> - [t_tuple([t_date(), t_time()])]; -arg_types(erlang, localtime_to_universaltime, 2) -> - arg_types(erlang, localtime_to_universaltime, 1) ++ - [t_sup(t_boolean(), t_atom('undefined'))]; -arg_types(erlang, make_fun, 3) -> - [t_atom(), t_atom(), t_arity()]; -arg_types(erlang, make_ref, 0) -> - []; arg_types(erlang, make_tuple, 2) -> [t_non_neg_fixnum(), t_any()]; % the value 0 is OK as first argument arg_types(erlang, make_tuple, 3) -> [t_non_neg_fixnum(), t_any(), t_list(t_tuple([t_pos_integer(), t_any()]))]; -arg_types(erlang, match_spec_test, 3) -> - [t_sup(t_list(), t_tuple()), - t_any(), - t_sup(t_atom('table'), t_atom('trace'))]; -arg_types(erlang, md5, 1) -> - [t_sup(t_iolist(), t_binary())]; -arg_types(erlang, md5_final, 1) -> - [t_binary()]; -arg_types(erlang, md5_init, 0) -> - []; -arg_types(erlang, md5_update, 2) -> - [t_binary(), t_sup(t_iolist(), t_binary())]; arg_types(erlang, memory, 0) -> []; -arg_types(erlang, memory, 1) -> - Arg = t_atoms(['total', 'processes', 'processes_used', 'system', - 'atom', 'atom_used', 'binary', 'code', 'ets', - 'maximum']), - [t_sup(Arg, t_list(Arg))]; -arg_types(erlang, module_loaded, 1) -> - [t_atom()]; -arg_types(erlang, monitor, 2) -> - [t_atom(), t_sup([t_pid(), t_atom(), t_tuple([t_atom(), t_node()])])]; -arg_types(erlang, monitor_node, 2) -> - [t_node(), t_boolean()]; -arg_types(erlang, monitor_node, 3) -> - [t_node(), t_boolean(), t_list(t_atom('allow_passive_connect'))]; arg_types(erlang, nif_error, 1) -> [t_any()]; arg_types(erlang, nif_error, 2) -> [t_any(), t_list()]; +%% Guard bif, needs to be here. arg_types(erlang, node, 0) -> []; +%% Guard bif, needs to be here. arg_types(erlang, node, 1) -> [t_identifier()]; arg_types(erlang, nodes, 0) -> []; -arg_types(erlang, nodes, 1) -> - NodesArg = t_atoms(['visible', 'hidden', 'connected', 'this', 'known']), - [t_sup(NodesArg, t_list(NodesArg))]; -arg_types(erlang, now, 0) -> - []; -arg_types(erlang, open_port, 2) -> - ArgT = t_sup(t_unicode_string(), t_binary()), - [t_sup(t_atom(), t_sup([t_tuple([t_atom('spawn'), t_string()]), - t_tuple([t_atom('spawn_driver'), t_string()]), - t_tuple([t_atom('spawn_executable'), ArgT]), - t_tuple([t_atom('fd'), t_integer(), t_integer()])])), - t_list(t_sup(t_sup([t_atom('stream'), - t_atom('exit_status'), - t_atom('use_stdio'), - t_atom('nouse_stdio'), - t_atom('stderr_to_stdout'), - t_atom('in'), - t_atom('out'), - t_atom('binary'), - t_atom('eof'), - t_atom('hide')]), - t_sup([t_tuple([t_atom('packet'), t_integer()]), - t_tuple([t_atom('line'), t_integer()]), - t_tuple([t_atom('cd'), t_string()]), - t_tuple([t_atom('env'), t_list(t_tuple(2))]), % XXX: More - t_tuple([t_atom('args'), t_list(ArgT)]), - t_tuple([t_atom('arg0'), ArgT])])))]; -arg_types(erlang, phash, 2) -> - [t_any(), t_pos_integer()]; -arg_types(erlang, phash2, 1) -> - [t_any()]; -arg_types(erlang, phash2, 2) -> - [t_any(), t_pos_integer()]; -arg_types(erlang, pid_to_list, 1) -> - [t_pid()]; arg_types(erlang, port_call, 2) -> [t_sup(t_port(), t_atom()), t_any()]; arg_types(erlang, port_call, 3) -> [t_sup(t_port(), t_atom()), t_integer(), t_any()]; -arg_types(erlang, port_close, 1) -> - [t_sup(t_port(), t_atom())]; -arg_types(erlang, port_command, 2) -> - [t_sup(t_port(), t_atom()), t_sup(t_iolist(), t_binary())]; -arg_types(erlang, port_command, 3) -> - [t_sup(t_port(), t_atom()), - t_sup(t_iolist(), t_binary()), - t_list(t_atoms(['force', 'nosuspend']))]; -arg_types(erlang, port_connect, 2) -> - [t_sup(t_port(), t_atom()), t_pid()]; -arg_types(erlang, port_control, 3) -> - [t_sup(t_port(), t_atom()), t_integer(), t_sup(t_iolist(), t_binary())]; -arg_types(erlang, port_get_data, 1) -> - [t_sup(t_port(), t_atom())]; arg_types(erlang, port_info, 1) -> [t_sup(t_port(), t_atom())]; arg_types(erlang, port_info, 2) -> [t_sup(t_port(), t_atom()), t_atoms(['registered_name', 'id', 'connected', 'links', 'name', 'input', 'output'])]; -arg_types(erlang, port_to_list, 1) -> - [t_port()]; -arg_types(erlang, ports, 0) -> - []; -arg_types(erlang, port_set_data, 2) -> - [t_sup(t_port(), t_atom()), t_any()]; -arg_types(erlang, pre_loaded, 0) -> - []; -arg_types(erlang, process_display, 2) -> - [t_pid(), t_atom('backtrace')]; -arg_types(erlang, process_flag, 2) -> - [t_sup([t_atom('trap_exit'), - t_atom('error_handler'), - t_atom('min_heap_size'), - t_atom('min_bin_vheap_size'), - t_atom('priority'), - t_atom('save_calls'), - t_atom('sensitive'), - t_atom('scheduler'), % undocumented - t_atom('monitor_nodes'), % undocumented - t_tuple([t_atom('monitor_nodes'), t_list()])]), % undocumented - t_sup([t_boolean(), t_atom(), t_non_neg_integer()])]; -arg_types(erlang, process_flag, 3) -> - [t_pid(), t_atom('save_calls'), t_non_neg_integer()]; -arg_types(erlang, process_info, 1) -> - [t_pid()]; -arg_types(erlang, process_info, 2) -> - [t_pid(), t_pinfo()]; -arg_types(erlang, processes, 0) -> - []; -arg_types(erlang, purge_module, 1) -> - [t_atom()]; -arg_types(erlang, put, 2) -> - [t_any(), t_any()]; -arg_types(erlang, raise, 3) -> - OldStyleType = t_list(t_tuple([t_atom(), t_atom(), - t_sup([t_arity(), t_list()])])), - NewStyleType = type(erlang, get_stacktrace, 0, []), - [t_raise_errorclass(), t_any(), t_sup(OldStyleType, NewStyleType)]; -arg_types(erlang, read_timer, 1) -> - [t_reference()]; -arg_types(erlang, ref_to_list, 1) -> - [t_reference()]; -arg_types(erlang, register, 2) -> - [t_atom(), t_sup(t_port(), t_pid())]; -arg_types(erlang, registered, 0) -> - []; -arg_types(erlang, resume_process, 1) -> - [t_pid()]; % intended for debugging only +%% Guard bif, needs to be here. arg_types(erlang, round, 1) -> [t_number()]; -arg_types(erlang, posixtime_to_universaltime, 1) -> - [t_integer()]; +%% Guard bif, needs to be here. arg_types(erlang, self, 0) -> []; -arg_types(erlang, send, 2) -> - arg_types(erlang, '!', 2); % alias -arg_types(erlang, send, 3) -> - arg_types(erlang, send, 2) ++ [t_list(t_sendoptions())]; -arg_types(erlang, send_after, 3) -> - [t_non_neg_integer(), t_sup(t_pid(), t_atom()), t_any()]; -arg_types(erlang, seq_trace, 2) -> - [t_atom(), t_sup([t_boolean(), t_tuple([t_fixnum(), t_fixnum()]), t_fixnum(), t_nil()])]; -arg_types(erlang, seq_trace_info, 1) -> - [t_seq_trace_info()]; -arg_types(erlang, seq_trace_print, 1) -> - [t_any()]; -arg_types(erlang, seq_trace_print, 2) -> - [t_sup(t_atom(), t_fixnum()), t_any()]; arg_types(erlang, set_cookie, 2) -> [t_node(), t_atom()]; arg_types(erlang, setelement, 3) -> [t_pos_integer(), t_tuple(), t_any()]; -arg_types(erlang, setnode, 2) -> - [t_atom(), t_integer()]; -arg_types(erlang, setnode, 3) -> - [t_atom(), t_port(), t_tuple(4)]; +%% Guard bif, needs to be here. arg_types(erlang, size, 1) -> [t_sup(t_tuple(), t_binary())]; arg_types(erlang, spawn, 1) -> %% TODO: Tuple? [t_fun()]; arg_types(erlang, spawn, 2) -> %% TODO: Tuple? [t_node(), t_fun()]; -arg_types(erlang, spawn, 3) -> %% TODO: Tuple? - [t_atom(), t_atom(), t_list()]; arg_types(erlang, spawn, 4) -> %% TODO: Tuple? [t_node(), t_atom(), t_atom(), t_list()]; arg_types(erlang, spawn_link, 1) -> arg_types(erlang, spawn, 1); % same arg_types(erlang, spawn_link, 2) -> arg_types(erlang, spawn, 2); % same -arg_types(erlang, spawn_link, 3) -> - arg_types(erlang, spawn, 3); % same arg_types(erlang, spawn_link, 4) -> arg_types(erlang, spawn, 4); % same -arg_types(erlang, spawn_opt, 1) -> - [t_tuple([t_atom(), t_atom(), t_list(), t_list(t_spawn_options())])]; -arg_types(erlang, spawn_opt, 2) -> - [t_fun(), t_list(t_spawn_options())]; -arg_types(erlang, spawn_opt, 3) -> - [t_atom(), t_fun(), t_list(t_spawn_options())]; -arg_types(erlang, spawn_opt, 4) -> - [t_node(), t_atom(), t_list(), t_list(t_spawn_options())]; -arg_types(erlang, split_binary, 2) -> - [t_binary(), t_non_neg_integer()]; -arg_types(erlang, start_timer, 3) -> - [t_non_neg_integer(), t_sup(t_pid(), t_atom()), t_any()]; -arg_types(erlang, statistics, 1) -> - [t_sup([t_atom('context_switches'), - t_atom('exact_reductions'), - t_atom('garbage_collection'), - t_atom('io'), - t_atom('reductions'), - t_atom('run_queue'), - t_atom('runtime'), - t_atom('wall_clock')])]; arg_types(erlang, subtract, 2) -> arg_types(erlang, '--', 2); arg_types(erlang, suspend_process, 1) -> [t_pid()]; -arg_types(erlang, suspend_process, 2) -> - [t_pid(), t_list(t_sup([t_atom('unless_suspending'), - t_atom('asynchronous')]))]; -arg_types(erlang, system_flag, 2) -> - [t_sup([t_atom('backtrace_depth'), - t_atom('cpu_topology'), - t_atom('debug_flags'), % undocumented - t_atom('display_items'), % undocumented - t_atom('fullsweep_after'), - t_atom('min_heap_size'), - t_atom('min_bin_vheap_size'), - t_atom('multi_scheduling'), - t_atom('schedulers_online'), - t_atom('scheduler_bind_type'), - %% Undocumented; used to implement (the documented) seq_trace module. - t_atom('sequential_tracer'), - t_atom('trace_control_word'), - %% 'internal_cpu_topology' is an undocumented internal feature. - t_atom('internal_cpu_topology'), - t_integer()]), - t_sup([t_integer(), - %% 'cpu_topology' - t_system_cpu_topology(), - %% 'scheduler_bind_type' - t_scheduler_bind_type_args(), - %% Undocumented: the following is for 'debug_flags' that - %% takes any erlang term as flags and currently ignores it. - %% t_any(), % commented out since it destroys the type signature - %% - %% Again undocumented; the following are for 'sequential_tracer' - t_sequential_tracer(), - %% The following two are for 'multi_scheduling' - t_atom('block'), - t_atom('unblock'), - %% The following is for 'internal_cpu_topology' - t_internal_cpu_topology()])]; arg_types(erlang, system_info, 1) -> [t_sup([t_atom(), % documented t_tuple([t_atom(), t_any()]), % documented t_tuple([t_atom(), t_atom(), t_any()]), t_tuple([t_atom(allocator_sizes), t_reference(), t_any()])])]; -arg_types(erlang, system_monitor, 0) -> - []; -arg_types(erlang, system_monitor, 1) -> - [t_system_monitor_settings()]; -arg_types(erlang, system_monitor, 2) -> - [t_pid(), t_system_monitor_options()]; -arg_types(erlang, system_profile, 0) -> - []; -arg_types(erlang, system_profile, 2) -> - [t_sup([t_pid(), t_port(), t_atom('undefined')]), - t_system_profile_options()]; -arg_types(erlang, term_to_binary, 1) -> - [t_any()]; -arg_types(erlang, term_to_binary, 2) -> - [t_any(), t_list(t_sup([t_atom('compressed'), - t_tuple([t_atom('compressed'), t_from_range(0, 9)]), - t_tuple([t_atom('minor_version'), t_integers([0, 1])])]))]; arg_types(erlang, throw, 1) -> [t_any()]; -arg_types(erlang, time, 0) -> - []; +%% Guard bif, needs to be here. arg_types(erlang, tl, 1) -> [t_cons()]; -arg_types(erlang, trace, 3) -> - [t_sup(t_pid(), t_sup([t_atom('existing'), t_atom('new'), t_atom('all')])), - t_boolean(), - t_list(t_sup(t_atom(), t_tuple(2)))]; -arg_types(erlang, trace_delivered, 1) -> - [t_sup(t_pid(), t_atom('all'))]; -arg_types(erlang, trace_info, 2) -> - [t_sup([%% the following two get info about a PID - t_pid(), t_atom('new'), - %% while the following two get info about a func - t_mfa(), t_atom('on_load')]), - t_sup([%% the following are items about a PID - t_atom('flags'), t_atom('tracer'), - %% while the following are items about a func - t_atom('traced'), t_atom('match_spec'), t_atom('meta'), - t_atom('meta_match_spec'), t_atom('call_count'), - t_atom('call_time'), t_atom('all')])]; -arg_types(erlang, trace_pattern, 2) -> - [t_sup(t_tuple([t_atom(), t_atom(), t_sup(t_arity(), t_atom('_'))]), - t_atom('on_load')), - t_sup([t_boolean(), t_list(), t_atom('restart'), t_atom('pause')])]; -arg_types(erlang, trace_pattern, 3) -> - arg_types(erlang, trace_pattern, 2) ++ - [t_list(t_sup([t_atom('global'), t_atom('local'), - t_atom('meta'), t_tuple([t_atom('meta'), t_pid()]), - t_atom('call_count'), t_atom('call_time')]))]; +%% Guard bif, needs to be here. arg_types(erlang, trunc, 1) -> [t_number()]; +%% Guard bif, needs to be here. arg_types(erlang, tuple_size, 1) -> [t_tuple()]; arg_types(erlang, tuple_to_list, 1) -> [t_tuple()]; -arg_types(erlang, universaltime, 0) -> - []; -arg_types(erlang, universaltime_to_localtime, 1) -> - [t_tuple([t_date(), t_time()])]; -arg_types(erlang, universaltime_to_posixtime, 1) -> - [t_tuple([t_date(), t_time()])]; -arg_types(erlang, unlink, 1) -> - [t_sup(t_pid(), t_port())]; -arg_types(erlang, unregister, 1) -> - [t_atom()]; -arg_types(erlang, whereis, 1) -> - [t_atom()]; arg_types(erlang, yield, 0) -> []; -%%------- erl_prim_loader ----------------------------------------------------- -arg_types(erl_prim_loader, get_file, 1) -> - [t_sup(t_atom(), t_string())]; -arg_types(erl_prim_loader, get_path, 0) -> - []; -arg_types(erl_prim_loader, set_path, 1) -> - [t_list(t_string())]; -%%------- error_logger -------------------------------------------------------- -arg_types(error_logger, warning_map, 0) -> - []; -%%------- erts_debug ---------------------------------------------------------- -arg_types(erts_debug, breakpoint, 2) -> - [t_tuple([t_atom(), t_atom(), t_sup(t_integer(), t_atom('_'))]), t_boolean()]; -arg_types(erts_debug, disassemble, 1) -> - [t_sup(t_mfa(), t_integer())]; -arg_types(erts_debug, display, 1) -> - [t_any()]; -arg_types(erts_debug, dist_ext_to_term, 2) -> - [t_tuple(), t_binary()]; -arg_types(erts_debug, dump_monitors, 1) -> - [t_sup([t_pid(),t_atom()])]; -arg_types(erts_debug, dump_links, 1) -> - [t_sup([t_pid(),t_atom(),t_port()])]; -arg_types(erts_debug, flat_size, 1) -> - [t_any()]; -arg_types(erts_debug, get_internal_state, 1) -> - [t_any()]; -arg_types(erts_debug, instructions, 0) -> - []; -arg_types(erts_debug, lock_counters, 1) -> - [t_sup([t_atom(enabled), - t_atom(info), - t_atom(clear), - t_tuple([t_atom(copy_save), t_boolean()]), - t_tuple([t_atom(process_locks), t_boolean()])])]; -arg_types(erts_debug, same, 2) -> - [t_any(), t_any()]; -arg_types(erts_debug, set_internal_state, 2) -> - [t_any(), t_any()]; %%------- ets ----------------------------------------------------------------- -arg_types(ets, all, 0) -> - []; -arg_types(ets, delete, 1) -> - [t_tab()]; -arg_types(ets, delete, 2) -> - [t_tab(), t_any()]; -arg_types(ets, delete_all_objects, 1) -> - [t_tab()]; -arg_types(ets, delete_object, 2) -> - [t_tab(), t_tuple()]; -arg_types(ets, first, 1) -> - [t_tab()]; -arg_types(ets, give_away, 3) -> - [t_tab(), t_pid(), t_any()]; -arg_types(ets, info, 1) -> - [t_tab()]; -arg_types(ets, info, 2) -> - [t_tab(), t_ets_info_items()]; -arg_types(ets, insert, 2) -> - [t_tab(), t_sup(t_tuple(), t_list(t_tuple()))]; -arg_types(ets, insert_new, 2) -> - [t_tab(), t_sup(t_tuple(), t_list(t_tuple()))]; -arg_types(ets, is_compiled_ms, 1) -> - [t_any()]; -arg_types(ets, last, 1) -> - arg_types(ets, first, 1); -arg_types(ets, lookup, 2) -> - [t_tab(), t_any()]; -arg_types(ets, lookup_element, 3) -> - [t_tab(), t_any(), t_pos_fixnum()]; -arg_types(ets, match, 1) -> - [t_any()]; -arg_types(ets, match, 2) -> - [t_tab(), t_match_pattern()]; -arg_types(ets, match, 3) -> - [t_tab(), t_match_pattern(), t_pos_fixnum()]; -arg_types(ets, match_object, 1) -> - arg_types(ets, match, 1); -arg_types(ets, match_object, 2) -> - arg_types(ets, match, 2); -arg_types(ets, match_object, 3) -> - arg_types(ets, match, 3); -arg_types(ets, match_spec_compile, 1) -> - [t_matchspecs()]; -arg_types(ets, match_spec_run_r, 3) -> - [t_list(t_tuple()),t_matchspecs(), t_list()]; -arg_types(ets, member, 2) -> - [t_tab(), t_any()]; -arg_types(ets, new, 2) -> - [t_atom(), t_ets_new_options()]; -arg_types(ets, next, 2) -> - [t_tab(), t_any()]; -arg_types(ets, prev, 2) -> - [t_tab(), t_any()]; arg_types(ets, rename, 2) -> [t_atom(), t_atom()]; -arg_types(ets, safe_fixtable, 2) -> - [t_tab(), t_boolean()]; -arg_types(ets, select, 1) -> - [t_any()]; -arg_types(ets, select, 2) -> - [t_tab(), t_matchspecs()]; -arg_types(ets, select, 3) -> - [t_tab(), t_matchspecs(), t_pos_fixnum()]; -arg_types(ets, select_count, 2) -> - [t_tab(), t_matchspecs()]; -arg_types(ets, select_delete, 2) -> - [t_tab(), t_matchspecs()]; -arg_types(ets, select_reverse, 1) -> - arg_types(ets, select, 1); -arg_types(ets, select_reverse, 2) -> - arg_types(ets, select, 2); -arg_types(ets, select_reverse, 3) -> - arg_types(ets, select, 3); -arg_types(ets, slot, 2) -> - [t_tab(), t_non_neg_fixnum()]; % 2nd arg can be 0 -arg_types(ets, setopts, 2) -> - Opt = t_sup([t_tuple([t_atom('heir'), t_pid(), t_any()]), - t_tuple([t_atom('heir'), t_atom('none')]), - t_tuple([t_atom('protection'), - t_sup([t_atom('protected'), - t_atom('private'), - t_atom('public')])])]), - [t_tab(), t_sup(Opt, t_list(Opt))]; -arg_types(ets, update_counter, 3) -> - Int = t_integer(), - UpdateOp = t_sup(t_tuple([Int, Int]), t_tuple([Int, Int, Int, Int])), - [t_tab(), t_any(), t_sup([UpdateOp, t_list(UpdateOp), Int])]; -arg_types(ets, update_element, 3) -> - PosValue = t_tuple([t_integer(), t_any()]), - [t_tab(), t_any(), t_sup(PosValue, t_list(PosValue))]; -%%------- file ---------------------------------------------------------------- -arg_types(file, native_name_encoding, 0) -> - []; -%%-- prim_file ---------------------------------------------------------------- -arg_types(prim_file, internal_name2native, 1) -> - [t_prim_file_name()]; -arg_types(prim_file, internal_native2name, 1) -> - [t_binary()]; -arg_types(prim_file, internal_normalize_utf8, 1) -> - [t_binary()]; -%%------- gen_tcp ------------------------------------------------------------- -arg_types(gen_tcp, accept, 1) -> - [t_socket()]; -arg_types(gen_tcp, accept, 2) -> - [t_socket(), t_timeout()]; -arg_types(gen_tcp, connect, 3) -> - [t_gen_tcp_address(), t_gen_tcp_port(), t_list(t_gen_tcp_connect_option())]; -arg_types(gen_tcp, connect, 4) -> - arg_types(gen_tcp, connect, 3) ++ [t_timeout()]; -arg_types(gen_tcp, listen, 2) -> - [t_gen_tcp_port(), t_list(t_gen_tcp_listen_option())]; -arg_types(gen_tcp, recv, 2) -> - [t_socket(), t_non_neg_integer()]; -arg_types(gen_tcp, recv, 3) -> - arg_types(gen_tcp, recv, 2) ++ [t_timeout()]; -arg_types(gen_tcp, send, 2) -> - [t_socket(), t_packet()]; -arg_types(gen_tcp, shutdown, 2) -> - [t_socket(), t_sup([t_atom('read'), t_atom('write'), t_atom('read_write')])]; -%%------- gen_udp ------------------------------------------------------------- -arg_types(gen_udp, open, 1) -> - [t_gen_tcp_port()]; -arg_types(gen_udp, open, 2) -> - [t_gen_tcp_port(), t_list(t_gen_udp_connect_option())]; -arg_types(gen_udp, recv, 2) -> - arg_types(gen_tcp, recv, 2); -arg_types(gen_udp, recv, 3) -> - arg_types(gen_tcp, recv, 3); -arg_types(gen_udp, send, 4) -> - [t_socket(), t_gen_tcp_address(), t_gen_tcp_port(), t_packet()]; %%------- hipe_bifs ----------------------------------------------------------- arg_types(hipe_bifs, add_ref, 2) -> [t_mfa(), t_tuple([t_mfa(), @@ -4198,7 +2381,7 @@ arg_types(hipe_bifs, check_crc, 1) -> arg_types(hipe_bifs, enter_code, 2) -> [t_binary(), t_sup(t_nil(), t_tuple())]; arg_types(hipe_bifs, enter_sdesc, 1) -> - [t_tuple([t_integer(), t_integer(), t_integer(), t_integer(), t_integer()])]; + [t_tuple([t_integer(), t_integer(), t_integer(), t_integer(), t_integer(), t_mfa()])]; arg_types(hipe_bifs, find_na_or_make_stub, 2) -> [t_mfa(), t_boolean()]; arg_types(hipe_bifs, fun_to_address, 1) -> @@ -4249,28 +2432,6 @@ arg_types(hipe_bifs, write_u32, 2) -> [t_integer(), t_integer()]; arg_types(hipe_bifs, write_u64, 2) -> [t_integer(), t_integer()]; -%%------- io ------------------------------------------------------------------ -arg_types(io, format, 1) -> - [t_io_format_string()]; -arg_types(io, format, 2) -> - [t_io_format_string(), t_list()]; -arg_types(io, format, 3) -> - [t_io_device(), t_io_format_string(), t_list()]; -arg_types(io, fwrite, 1) -> - arg_types(io, format, 1); -arg_types(io, fwrite, 2) -> - arg_types(io, format, 2); -arg_types(io, fwrite, 3) -> - arg_types(io, format, 3); -arg_types(io, put_chars, 1) -> - [t_iodata()]; -arg_types(io, put_chars, 2) -> - [t_io_device(), t_iodata()]; -%%------- io_lib -------------------------------------------------------------- -arg_types(io_lib, format, 2) -> - arg_types(io, format, 2); -arg_types(io_lib, fwrite, 2) -> - arg_types(io_lib, format, 2); %%------- lists --------------------------------------------------------------- arg_types(lists, all, 2) -> [t_fun([t_any()], t_boolean()), t_list()]; @@ -4342,10 +2503,6 @@ arg_types(lists, reverse, 1) -> [t_list()]; arg_types(lists, reverse, 2) -> [t_list(), t_any()]; -arg_types(lists, seq, 2) -> - [t_integer(), t_integer()]; -arg_types(lists, seq, 3) -> - [t_integer(), t_integer(), t_integer()]; arg_types(lists, sort, 1) -> [t_list()]; arg_types(lists, sort, 2) -> @@ -4374,97 +2531,12 @@ arg_types(lists, zipwith, 3) -> [t_fun([t_any(), t_any()], t_any()), t_list(), t_list()]; arg_types(lists, zipwith3, 4) -> [t_fun([t_any(), t_any(), t_any()], t_any()), t_list(), t_list(), t_list()]; -%%------- math ---------------------------------------------------------------- -arg_types(math, acos, 1) -> - [t_number()]; -arg_types(math, acosh, 1) -> - [t_number()]; -arg_types(math, asin, 1) -> - [t_number()]; -arg_types(math, asinh, 1) -> - [t_number()]; -arg_types(math, atan, 1) -> - [t_number()]; -arg_types(math, atan2, 2) -> - [t_number(), t_number()]; -arg_types(math, atanh, 1) -> - [t_number()]; -arg_types(math, cos, 1) -> - [t_number()]; -arg_types(math, cosh, 1) -> - [t_number()]; -arg_types(math, erf, 1) -> - [t_number()]; -arg_types(math, erfc, 1) -> - [t_number()]; -arg_types(math, exp, 1) -> - [t_number()]; -arg_types(math, log, 1) -> - [t_number()]; -arg_types(math, log10, 1) -> - [t_number()]; -arg_types(math, pi, 0) -> - []; -arg_types(math, pow, 2) -> - [t_number(), t_number()]; -arg_types(math, sin, 1) -> - [t_number()]; -arg_types(math, sinh, 1) -> - [t_number()]; -arg_types(math, sqrt, 1) -> - [t_number()]; -arg_types(math, tan, 1) -> - [t_number()]; -arg_types(math, tanh, 1) -> - [t_number()]; -%%-- net_kernel --------------------------------------------------------------- -arg_types(net_kernel, dflag_unicode_io, 1) -> - [t_pid()]; -%%------- ordsets ------------------------------------------------------------- -arg_types(ordsets, filter, 2) -> - arg_types(lists, filter, 2); -arg_types(ordsets, fold, 3) -> - arg_types(lists, foldl, 3); -%%------- os ------------------------------------------------------------------ -arg_types(os, getenv, 0) -> - []; -arg_types(os, getenv, 1) -> - [t_string()]; -arg_types(os, getpid, 0) -> - []; -arg_types(os, putenv, 2) -> - [t_string(), t_string()]; -arg_types(os, timestamp, 0) -> - []; -%%-- re ----------------------------------------------------------------------- -arg_types(re, compile, 1) -> - [t_iodata()]; -arg_types(re, compile, 2) -> - [t_sup(t_iodata(), t_charlist()), t_list(t_re_compile_option())]; -arg_types(re, run, 2) -> - [t_sup(t_iodata(), t_charlist()), t_re_RE()]; -arg_types(re, run, 3) -> - [t_sup(t_iodata(), t_charlist()), t_re_RE(), t_list(t_re_run_option())]; + %%------- string -------------------------------------------------------------- arg_types(string, chars, 2) -> [t_char(), t_non_neg_integer()]; arg_types(string, chars, 3) -> [t_char(), t_non_neg_integer(), t_any()]; -arg_types(string, concat, 2) -> - [t_string(), t_string()]; -arg_types(string, equal, 2) -> - [t_string(), t_string()]; -arg_types(string, to_float, 1) -> - [t_string()]; -arg_types(string, to_integer, 1) -> - [t_string()]; -%%------- unicode ------------------------------------------------------------- -arg_types(unicode, characters_to_binary, 2) -> - [t_ML(), t_encoding()]; -arg_types(unicode, characters_to_list, 2) -> - [t_ML(), t_encoding()]; -arg_types(unicode, bin_is_7bit, 1) -> - [t_binary()]; %%----------------------------------------------------------------------------- arg_types(M, F, A) when is_atom(M), is_atom(F), is_integer(A), 0 =< A, A =< 255 -> @@ -4524,245 +2596,22 @@ check_fun_application(Fun, Args) -> %% ===================================================================== -%% These are basic types that should probably be moved to erl_types -%% ===================================================================== - -t_socket() -> t_port(). % alias - -t_ip_address() -> - T_int16 = t_from_range(0, 16#FFFF), - t_sup(t_tuple([t_byte(), t_byte(), t_byte(), t_byte()]), - t_tuple([T_int16, T_int16, T_int16, T_int16, - T_int16, T_int16, T_int16, T_int16])). - -%% ===================================================================== %% Some basic types used in various parts of the system %% ===================================================================== -t_date() -> - t_tuple([t_pos_fixnum(), t_pos_fixnum(), t_pos_fixnum()]). - -t_time() -> - t_tuple([t_non_neg_fixnum(), t_non_neg_fixnum(), t_non_neg_fixnum()]). - -t_timestamp() -> - t_tuple([t_non_neg_fixnum(), t_non_neg_fixnum(), t_non_neg_fixnum()]). - -t_packet() -> - t_sup([t_binary(), t_iolist(), t_httppacket()]). - -t_httppacket() -> - t_sup([t_HttpRequest(), t_HttpResponse(), - t_HttpHeader(), t_atom('http_eoh'), t_HttpError()]). - t_endian() -> t_sup(t_atom('big'), t_atom('little')). %% ===================================================================== -%% HTTP types documented in R12B-4 -%% ===================================================================== - -t_HttpRequest() -> - t_tuple([t_atom('http_request'), t_HttpMethod(), t_HttpUri(), t_HttpVersion()]). - -t_HttpResponse() -> - t_tuple([t_atom('http_response'), t_HttpVersion(), t_integer(), t_HttpString()]). - -t_HttpHeader() -> - t_tuple([t_atom('http_header'), t_integer(), t_HttpField(), t_any(), t_HttpString()]). - -t_HttpError() -> - t_tuple([t_atom('http_error'), t_HttpString()]). - -t_HttpMethod() -> - t_sup(t_HttpMethodAtom(), t_HttpString()). - -t_HttpMethodAtom() -> - t_atoms(['OPTIONS', 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE']). - -t_HttpUri() -> - t_sup([t_atom('*'), - t_tuple([t_atom('absoluteURI'), - t_sup(t_atom('http'), t_atom('https')), - t_HttpString(), - t_sup(t_non_neg_integer(), t_atom('undefined')), - t_HttpString()]), - t_tuple([t_atom('scheme'), t_HttpString(), t_HttpString()]), - t_tuple([t_atom('abs_path'), t_HttpString()]), - t_HttpString()]). - -t_HttpVersion() -> - t_tuple([t_non_neg_integer(), t_non_neg_integer()]). - -t_HttpField() -> - t_sup(t_HttpFieldAtom(), t_HttpString()). - -t_HttpFieldAtom() -> - t_atoms(['Cache-Control', 'Connection', 'Date', 'Pragma', 'Transfer-Encoding', - 'Upgrade', 'Via', 'Accept', 'Accept-Charset', 'Accept-Encoding', - 'Accept-Language', 'Authorization', 'From', 'Host', - 'If-Modified-Since', 'If-Match', 'If-None-Match', 'If-Range', - 'If-Unmodified-Since', 'Max-Forwards', 'Proxy-Authorization', - 'Range', 'Referer', 'User-Agent', 'Age', 'Location', - 'Proxy-Authenticate', 'Public', 'Retry-After', 'Server', 'Vary', - 'Warning', 'Www-Authenticate', 'Allow', 'Content-Base', - 'Content-Encoding', 'Content-Language', 'Content-Length', - 'Content-Location', 'Content-Md5', 'Content-Range', 'Content-Type', - 'Etag', 'Expires', 'Last-Modified', 'Accept-Ranges', - 'Set-Cookie', 'Set-Cookie2', 'X-Forwarded-For', 'Cookie', - 'Keep-Alive', 'Proxy-Connection']). - -t_HttpString() -> - t_sup(t_string(), t_binary()). - -%% ===================================================================== -%% These are used for the built-in functions of 'binary' -%% ===================================================================== - -t_binary_part() -> - t_tuple([t_non_neg_integer(), t_integer()]). - -t_binary_canonical_part() -> - t_tuple([t_non_neg_integer(), t_non_neg_integer()]). - -t_binary_pattern() -> - t_sup([t_binary(), - t_list(t_binary()), - t_binary_compiled_pattern()]). - -t_binary_compiled_pattern() -> - t_tuple([t_sup(t_atom('bm'), t_atom('ac')), t_binary()]). - -t_binary_options() -> - t_list(t_tuple([t_atom('scope'), t_binary_part()])). - -%% ===================================================================== -%% These are used for the built-in functions of 'code' -%% ===================================================================== - -t_code_load_return(Mod) -> - t_sup(t_tuple([t_atom('module'), case t_is_atom(Mod) of - true -> Mod; - false -> t_atom() - end]), - t_tuple([t_atom('error'), t_code_load_error_rsn()])). - -t_code_load_error_rsn() -> % also used in erlang:load_module/2 - t_sup([t_atom('badfile'), - t_atom('nofile'), - t_atom('not_purged'), - t_atom('native_code'), - t_atom('on_load'), - t_atom('sticky_directory')]). % only for the 'code' functions - -%% ===================================================================== %% These are used for the built-in functions of 'erlang' %% ===================================================================== -t_adler32() -> - t_non_neg_integer(). - t_crc32() -> t_non_neg_integer(). -t_decode_packet_option() -> - t_sup([t_tuple([t_atom('packet_size'), t_non_neg_integer()]), - t_tuple([t_atom('line_length'), t_non_neg_integer()])]). - -t_decode_packet_type() -> - t_sup([t_inet_setoption_packettype(), t_atom('httph'), t_atom('httph_bin')]). - -t_dist_exit() -> - t_sup([t_atom('kill'), t_atom('noconnection'), t_atom('normal')]). - -t_match_spec_test_errors() -> - t_list(t_sup(t_tuple([t_atom('error'), t_string()]), - t_tuple([t_atom('warning'), t_string()]))). - -t_module_info_2() -> - t_sup([t_atom('module'), - t_atom('imports'), - t_atom('exports'), - t_atom('functions'), - t_atom('attributes'), - t_atom('compile'), - t_atom('native_addresses')]). - -t_pinfo() -> - t_sup([t_pinfo_item(), t_list(t_pinfo_item())]). - -t_pinfo_item() -> - t_sup([t_atom('backtrace'), - t_atom('current_function'), - t_atom('dictionary'), - t_atom('error_handler'), - t_atom('garbage_collection'), - t_atom('group_leader'), - t_atom('heap_size'), - t_atom('initial_call'), - t_atom('last_calls'), - t_atom('links'), - t_atom('memory'), - t_atom('message_binary'), % for hybrid heap only - t_atom('message_queue_len'), - t_atom('messages'), - t_atom('monitored_by'), - t_atom('monitors'), - t_atom('priority'), - t_atom('reductions'), - t_atom('registered_name'), - t_atom('sequential_trace_token'), - t_atom('stack_size'), - t_atom('status'), - t_atom('suspending'), - t_atom('total_heap_size'), - t_atom('trap_exit')]). - -t_process_priority_level() -> - t_sup([t_atom('max'), t_atom('high'), t_atom('normal'), t_atom('low')]). - -t_process_status() -> - t_sup([t_atom('exiting'), t_atom('garbage_collecting'), - t_atom('runnable'), t_atom('running'), - t_atom('suspended'), t_atom('waiting')]). - -t_raise_errorclass() -> - t_sup([t_atom('error'), t_atom('exit'), t_atom('throw')]). - -t_sendoptions() -> - t_sup(t_atom('noconnect'), t_atom('nosuspend')). - -t_seq_trace_info() -> - t_sup([t_atom('send'), - t_atom('receive'), - t_atom('print'), - t_atom('timestamp'), - t_atom('label'), - t_atom('serial')]). - -%% XXX: Better if we also maintain correspondencies between infos and values -t_seq_trace_info_returns() -> - Values = t_sup([t_non_neg_integer(), t_boolean(), - t_tuple([t_non_neg_integer(), t_non_neg_integer()])]), - t_sup(t_tuple([t_seq_trace_info(), Values]), t_nil()). - t_sequential_tracer() -> t_sup([t_atom('false'), t_pid(), t_port()]). -t_spawn_options() -> - t_sup([t_atom('link'), - t_atom('monitor'), - t_tuple([t_atom('priority'), t_process_priority_level()]), - t_tuple([t_atom('min_heap_size'), t_fixnum()]), - t_tuple([t_atom('min_bin_vheap_size'), t_fixnum()]), - t_tuple([t_atom('fullsweep_after'), t_fixnum()])]). - -t_spawn_opt_return(List) -> - case t_is_none(t_inf(t_list(t_atom('monitor')), List)) of - true -> t_pid(); - false -> t_sup(t_pid(), t_tuple([t_pid(), t_reference()])) - end. - t_system_cpu_topology() -> t_sup(t_atom('undefined'), t_system_cpu_topology_level_entry_list()). @@ -4799,17 +2648,6 @@ t_internal_cpu_topology() -> %% Internal undocumented type t_non_neg_fixnum()])), t_atom('undefined')). -t_scheduler_bind_type_args() -> - t_sup([t_atom('default_bind'), - t_atom('no_node_processor_spread'), - t_atom('no_node_thread_spread'), - t_atom('no_spread'), - t_atom('processor_spread'), - t_atom('spread'), - t_atom('thread_spread'), - t_atom('thread_no_node_processor_spread'), - t_atom('unbound')]). - t_scheduler_bind_type_results() -> t_sup([t_atom('no_node_processor_spread'), t_atom('no_node_thread_spread'), @@ -4820,160 +2658,9 @@ t_scheduler_bind_type_results() -> t_atom('thread_no_node_processor_spread'), t_atom('unbound')]). -t_system_monitor_settings() -> - t_sup([t_atom('undefined'), - t_tuple([t_pid(), t_system_monitor_options()])]). - -t_system_monitor_options() -> - t_list(t_sup([t_atom('busy_port'), - t_atom('busy_dist_port'), - t_tuple([t_atom('long_gc'), t_integer()]), - t_tuple([t_atom('large_heap'), t_integer()])])). - t_system_multi_scheduling() -> t_sup([t_atom('blocked'), t_atom('disabled'), t_atom('enabled')]). -t_system_profile_options() -> - t_list(t_sup([t_atom('exclusive'), - t_atom('runnable_ports'), - t_atom('runnable_procs'), - t_atom('scheduler')])). - -t_system_profile_return() -> - t_sup(t_atom('undefined'), - t_tuple([t_sup(t_pid(), t_port()), t_system_profile_options()])). - -t_system_build_type_return() -> - t_sup([t_atom('opt'), - t_atom('debug'), - t_atom('purify'), - t_atom('quantify'), - t_atom('purecov'), - t_atom('gcov'), - t_atom('valgrind'), - t_atom('gprof'), - t_atom('lcnt')]). - -%% ===================================================================== -%% These are used for the built-in functions of 'ets' -%% ===================================================================== - -t_tab() -> - t_sup(t_tid(), t_atom()). - -t_match_pattern() -> - t_sup(t_atom(), t_tuple()). - -t_matchspecs() -> - t_list(t_tuple([t_match_pattern(), t_list(), t_list()])). - -t_matchres() -> - t_sup(t_tuple([t_list(), t_any()]), t_atom('$end_of_table')). - -%% From the 'ets' documentation -%%----------------------------- -%% Option = Type | Access | named_table | {keypos,Pos} -%% | {heir,pid(),HeirData} | {heir,none} | Tweaks -%% Type = set | ordered_set | bag | duplicate_bag -%% Access = public | protected | private -%% Tweaks = {write_concurrency,boolean()} -%% | {read_concurrency,boolean()} | compressed -%% Pos = integer() -%% HeirData = term() -t_ets_new_options() -> - t_list(t_sup([t_atom('set'), - t_atom('ordered_set'), - t_atom('bag'), - t_atom('duplicate_bag'), - t_atom('public'), - t_atom('protected'), - t_atom('private'), - t_atom('named_table'), - t_tuple([t_atom('keypos'), t_integer()]), - t_tuple([t_atom('heir'), t_pid(), t_any()]), - t_tuple([t_atom('heir'), t_atom('none')]), - t_tuple([t_atom('write_concurrency'), t_boolean()]), - t_tuple([t_atom('read_concurrency'), t_boolean()]), - t_atom('compressed')])). - -t_ets_info_items() -> - t_sup([t_atom('fixed'), - t_atom('safe_fixed'), - t_atom('keypos'), - t_atom('memory'), - t_atom('name'), - t_atom('named_table'), - t_atom('node'), - t_atom('owner'), - t_atom('protection'), - t_atom('size'), - t_atom('compressed'), - t_atom('heir'), - t_atom('stats'), - t_atom('type')]). - -%% ===================================================================== -%% These are used for the built-in functions of 'gen_tcp' -%% ===================================================================== - -t_gen_tcp_accept() -> - t_sup(t_tuple([t_atom('ok'), t_socket()]), - t_tuple([t_atom('error'), t_sup([t_atom('closed'), - t_atom('timeout'), - t_inet_posix_error()])])). - -t_gen_tcp_address() -> - t_sup([t_string(), t_atom(), t_ip_address()]). - -t_gen_tcp_port() -> - t_from_range(0, 16#FFFF). - -t_gen_tcp_connect_option() -> - t_sup([t_atom('list'), - t_atom('binary'), - t_tuple([t_atom('ip'), t_ip_address()]), - t_tuple([t_atom('port'), t_gen_tcp_port()]), - t_tuple([t_atom('fd'), t_integer()]), - t_atom('inet6'), - t_atom('inet'), - t_inet_setoption()]). - -t_gen_tcp_listen_option() -> - t_sup([t_atom('list'), - t_atom('binary'), - t_tuple([t_atom('backlog'), t_non_neg_integer()]), - t_tuple([t_atom('ip'), t_ip_address()]), - t_tuple([t_atom('fd'), t_integer()]), - t_atom('inet6'), - t_atom('inet'), - t_inet_setoption()]). - -t_gen_tcp_recv() -> - t_sup(t_tuple([t_atom('ok'), t_packet()]), - t_tuple([t_atom('error'), t_sup([t_atom('closed'), - t_inet_posix_error()])])). - -%% ===================================================================== -%% These are used for the built-in functions of 'gen_udp' -%% ===================================================================== - -t_gen_udp_connect_option() -> - t_sup([t_atom('list'), - t_atom('binary'), - t_tuple([t_atom('ip'), t_ip_address()]), - t_tuple([t_atom('fd'), t_integer()]), - t_atom('inet6'), - t_atom('inet'), - t_inet_setoption()]). - -t_gen_udp_recv() -> - t_sup(t_tuple([t_atom('ok'), - t_tuple([t_ip_address(), - t_gen_tcp_port(), - t_packet()])]), - t_tuple([t_atom('error'), - t_sup(t_atom('not_owner'), t_inet_posix_error())])). - %% ===================================================================== %% These are used for the built-in functions of 'hipe_bifs' %% ===================================================================== @@ -5006,131 +2693,6 @@ t_insn_type() -> t_atom('closure')]). %% ===================================================================== -%% These are used for the built-in functions of 'inet' -%% ===================================================================== - -t_inet_setoption() -> - t_sup([%% first the 2-tuple options - t_tuple([t_atom('active'), t_sup(t_boolean(), t_atom('once'))]), - t_tuple([t_atom('broadcast'), t_boolean()]), - t_tuple([t_atom('delay_send'), t_boolean()]), - t_tuple([t_atom('dontroute'), t_boolean()]), - t_tuple([t_atom('exit_on_close'), t_boolean()]), - t_tuple([t_atom('header'), t_non_neg_integer()]), - t_tuple([t_atom('keepalive'), t_boolean()]), - t_tuple([t_atom('nodelay'), t_boolean()]), - t_tuple([t_atom('packet'), t_inet_setoption_packettype()]), - t_tuple([t_atom('packet_size'), t_non_neg_integer()]), - t_tuple([t_atom('read_packets'), t_non_neg_integer()]), - t_tuple([t_atom('recbuf'), t_non_neg_integer()]), - t_tuple([t_atom('reuseaddr'), t_boolean()]), - t_tuple([t_atom('send_timeout'), t_non_neg_integer()]), - t_tuple([t_atom('sndbuf'), t_non_neg_integer()]), - t_tuple([t_atom('priority'), t_non_neg_integer()]), - t_tuple([t_atom('tos'), t_non_neg_integer()]), - %% and a 4-tuple option - t_tuple([t_atom('raw'), - t_non_neg_integer(), % protocol level - t_non_neg_integer(), % option number - t_binary()])]). % actual option value - -t_inet_setoption_packettype() -> - t_sup([t_atom('raw'), - t_integers([0,1,2,4]), - t_atom('asn1'), t_atom('cdr'), t_atom('sunrm'), - t_atom('fcgi'), t_atom('tpkt'), t_atom('line'), - t_atom('http'), - t_atom('http_bin')]). %% but t_atom('httph') is not needed - -t_inet_posix_error() -> - t_atom(). %% XXX: Very underspecified - -%% ===================================================================== -%% These are used for the built-in functions of 'io' -%% ===================================================================== - -t_io_device() -> - t_sup(t_atom(), t_pid()). - -%% The documentation in R11B-4 reads -%% Format ::= atom() | string() | binary() -%% but the Format can also be a (deep) list, hence the type below -t_io_format_string() -> - t_sup([t_atom(), t_list(), t_binary()]). - -%% ===================================================================== -%% These are used for the built-in functions of 're'; the functions -%% whose last name component starts with a capital letter are types -%% ===================================================================== - -t_re_MP() -> %% it's supposed to be an opaque data type - t_tuple([t_atom('re_pattern'), t_integer(), t_integer(), t_binary()]). - -t_re_RE() -> - t_sup([t_re_MP(), t_iodata(), t_charlist()]). - -t_re_compile_option() -> - t_sup([t_atoms(['unicode', 'anchored', 'caseless', 'dollar_endonly', - 'dotall', 'extended', 'firstline', 'multiline', - 'no_auto_capture', 'dupnames', 'ungreedy']), - t_tuple([t_atom('newline'), t_re_NLSpec()]), - t_atoms(['bsr_anycrlf', 'bsr_unicode'])]). - -t_re_run_option() -> - t_sup([t_atoms(['anchored', 'global', 'notbol', 'noteol', 'notempty']), - t_tuple([t_atom('offset'), t_integer()]), - t_tuple([t_atom('newline'), t_re_NLSpec()]), - t_tuple([t_atom('capture'), t_re_ValueSpec()]), - t_tuple([t_atom('capture'), t_re_ValueSpec(), t_re_Type()]), - t_re_compile_option()]). - -t_re_ErrorSpec() -> - t_tuple([t_string(), t_non_neg_integer()]). - -t_re_Type() -> - t_atoms(['index', 'list', 'binary']). - -t_re_NLSpec() -> - t_atoms(['cr', 'crlf', 'lf', 'anycrlf', 'any']). - -t_re_ValueSpec() -> - t_sup(t_atoms(['all', 'all_but_first', 'first', 'none']), t_re_ValueList()). - -t_re_ValueList() -> - t_list(t_sup([t_integer(), t_string(), t_atom()])). - -t_re_Captured() -> - t_list(t_sup(t_re_CapturedData(), t_list(t_re_CapturedData()))). - -t_re_CapturedData() -> - t_sup([t_tuple([t_integer(), t_integer()]), t_string(), t_binary()]). - -%% ===================================================================== -%% These are used for the built-in functions of 'prim_file' -%% ===================================================================== - -t_prim_file_name() -> - t_sup(t_unicode_string(), t_binary()). - -%% ===================================================================== -%% These are used for the built-in functions of 'unicode' -%% ===================================================================== - -t_ML() -> % a binary or a possibly deep list of integers or binaries - t_sup(t_list(t_sup([t_integer(), t_binary(), t_list()])), t_binary()). - -t_encoding() -> - t_sup([t_atoms(['latin1', 'unicode', 'utf8', 'utf16', 'utf32']), - t_tuple([t_atom('utf16'), t_endian()]), - t_tuple([t_atom('utf32'), t_endian()])]). - -t_file_encoding() -> - t_atoms(['latin1', 'utf8']). - -t_encoding_a2b() -> % for the 2nd arg of atom_to_binary/2 and binary_to_atom/2 - t_atoms(['latin1', 'unicode', 'utf8']). - -%% ===================================================================== %% Some testing code for ranges below %% ===================================================================== diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl index 2d2b414a70..35a8ce9cfe 100644 --- a/lib/hipe/icode/hipe_beam_to_icode.erl +++ b/lib/hipe/icode/hipe_beam_to_icode.erl @@ -41,6 +41,9 @@ %% %%-ifndef(DEBUG). %%-define(DEBUG,6). +%% Choose one of two tracing methods +%%-define(DEBUG_BIF_CALL_TRACE,true). +%%-define(IO_FORMAT_CALL_TRACE,true). %%-endif. -include("../main/hipe.hrl"). @@ -51,8 +54,27 @@ -define(no_debug_msg(Str,Xs),ok). %%-define(no_debug_msg(Str,Xs),msg(Str,Xs)). --define(mk_debugcode(MFA, Env, Code), - case MFA of +-ifdef(DEBUG_BIF_CALL_TRACE). + +%% Use BIF hipe_bifs_debug_native_called_2 to trace function calls +mk_debug_calltrace({_M,_F,A}=MFA, Env, Code) -> + MFAVar = mk_var(new), + Ignore = mk_var(new), + MkMfa = hipe_icode:mk_move(MFAVar,hipe_icode:mk_const(MFA)), + Args = [mk_var({x,I-1}) || I <- lists:seq(1,A)], + ArgTup = mk_var(new), + MkArgTup = hipe_icode:mk_primop([ArgTup], mktuple, Args), + Call = hipe_icode:mk_primop([Ignore], debug_native_called, + [MFAVar,ArgTup]), + {[MkMfa,MkArgTup,Call | Code], Env}. + +-endif. + +-ifdef(IO_FORMAT_CALL_TRACE). + +%% Use io:format to trace function calls +mk_debug_calltrace(MFA, Env, Code) -> + case MFA of {io,_,_} -> %% We do not want to loop infinitely if we are compiling %% the module io. @@ -69,7 +91,9 @@ Call = hipe_icode:mk_call([Ignore],io,format,[StringVar,MFAVar],remote), {[MkMfa,MkString,Call | Code], Env} - end). + end. +-endif. + %%----------------------------------------------------------------------- %% Exported types @@ -127,7 +151,7 @@ trans_mfa_code(M,F,A, FunBeamCode, ClosureInfo) -> MFA = {M,F,A}, %% Debug code ?IF_DEBUG_LEVEL(5, - {Code3,_Env3} = ?mk_debugcode(MFA, Env2, Code2), + {Code3,_Env3} = mk_debug_calltrace(MFA, Env1, Code2), {Code3,_Env3} = {Code2,Env1}), %% For stack optimization Leafness = leafness(Code3), diff --git a/lib/hipe/icode/hipe_icode_primops.erl b/lib/hipe/icode/hipe_icode_primops.erl index a413531c07..b0113fc556 100644 --- a/lib/hipe/icode/hipe_icode_primops.erl +++ b/lib/hipe/icode/hipe_icode_primops.erl @@ -137,7 +137,8 @@ is_safe({hipe_bs_primop, {bs_private_append, _, _}}) -> false; is_safe({hipe_bs_primop, bs_init_writable}) -> true; is_safe(#mkfun{}) -> true; is_safe(#unsafe_element{}) -> true; -is_safe(#unsafe_update_element{}) -> true. +is_safe(#unsafe_update_element{}) -> true; +is_safe(debug_native_called) -> false. -spec fails(icode_funcall()) -> boolean(). @@ -237,6 +238,7 @@ fails({hipe_bs_primop, bs_init_writable}) -> true; fails(#mkfun{}) -> false; fails(#unsafe_element{}) -> false; fails(#unsafe_update_element{}) -> false; +fails(debug_native_called) -> false; %% Apparently, we are calling fails/1 for all MFAs which are compiled. %% This is weird and we should restructure the compiler to avoid %% calling fails/1 for things that are not primops. @@ -721,6 +723,8 @@ type(Primop, Args) -> erl_types:t_any(); redtest -> erl_types:t_any(); + debug_native_called -> + erl_types:t_any(); {M, F, A} -> erl_bif_types:type(M, F, A, Args) end. @@ -893,6 +897,8 @@ type(Primop) -> erl_types:t_any(); redtest -> erl_types:t_any(); + debug_native_called -> + erl_types:t_any(); {M, F, A} -> erl_bif_types:type(M, F, A) end. diff --git a/lib/hipe/rtl/hipe_rtl_primops.erl b/lib/hipe/rtl/hipe_rtl_primops.erl index 5f273d8251..53aaa72aa6 100644 --- a/lib/hipe/rtl/hipe_rtl_primops.erl +++ b/lib/hipe/rtl/hipe_rtl_primops.erl @@ -396,6 +396,8 @@ gen_primop({Op,Dst,Args,Cont,Fail}, IsGuard, ConstTab) -> [Dst1]-> hipe_tagscheme:unsafe_tag_float(Dst1, Arg) end; + debug_native_called -> + [hipe_rtl:mk_call(Dst, Op, Args, Cont, Fail, not_remote)]; %% Only names listed above are accepted! MFA:s are not primops! _ -> diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml index ee687511a3..bb111a2242 100644 --- a/lib/kernel/doc/src/code.xml +++ b/lib/kernel/doc/src/code.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -728,16 +728,13 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name>is_module_native(Module) -> boolean() | undefined</name> + <name name="is_module_native" arity="1"/> <fsummary>Test whether a module has native code</fsummary> - <type> - <v>Module = module()</v> - </type> <desc> - <p>This function returns <c>true</c> if <c>Module</c> is + <p>This function returns <c>true</c> if <c><anno>Module</anno></c> is name of a loaded module that has native code loaded, and - <c>false</c> if <c>Module</c> is loaded but does not have - native. If <c>Module</c> is not loaded, this function returns + <c>false</c> if <c><anno>Module</anno></c> is loaded but does not have + native. If <c><anno>Module</anno></c> is not loaded, this function returns <c>undefined</c>.</p> </desc> </func> diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml index 1911fb628e..26db11cfcd 100644 --- a/lib/kernel/doc/src/erl_ddll.xml +++ b/lib/kernel/doc/src/erl_ddll.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1997</year><year>2011</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -182,11 +182,8 @@ </datatypes> <funcs> <func> - <name>demonitor(MonitorRef) -> ok</name> + <name name="demonitor" arity="1"/> <fsummary>Remove a monitor for a driver</fsummary> - <type> - <v>MonitorRef = reference()</v> - </type> <desc> <p>Removes a driver monitor in much the same way as <seealso marker="erts:erlang#erlang:demonitor/1">erlang:demonitor/1</seealso> does with process @@ -232,24 +229,19 @@ </desc> </func> <func> - <name>info(Name, Tag) -> Value</name> + <name name="info" arity="2"/> <fsummary>Retrieve specific information about one driver</fsummary> - <type> - <v>Name = string() | atom()</v> - <v>Tag = processes | driver_options | port_count | linked_in_driver | permanent | awaiting_load | awaiting_unload</v> - <v>Value = term()</v> - </type> <desc> <p>This function returns specific information about one aspect - of a driver. The <c>Tag</c> parameter specifies which aspect - to get information about. The <c>Value</c> return differs + of a driver. The <c><anno>Tag</anno></c> parameter specifies which aspect + to get information about. The <c><anno>Value</anno></c> return differs between different tags:</p> <taglist> <tag><em>processes</em></tag> <item> <p>Return all processes containing <seealso marker="#users">users</seealso> of the specific drivers - as a list of tuples <c>{pid(),int()}</c>, where the - <c>int()</c> denotes the number of users in the process + as a list of tuples <c>{pid(),integer() >= 0}</c>, where the + <c>integer()</c> denotes the number of users in the process <c>pid()</c>.</p> </item> <tag><em>driver_options</em></tag> @@ -261,16 +253,16 @@ </item> <tag><em>port_count</em></tag> <item> - <p>Return the number of ports (an <c>int()</c>) using the driver.</p> + <p>Return the number of ports (an <c>integer >= 0()</c>) using the driver.</p> </item> <tag><em>linked_in_driver</em></tag> <item> - <p>Return a <c>bool()</c>, being <c>true</c> if the driver is a + <p>Return a <c>boolean()</c>, being <c>true</c> if the driver is a statically linked in one and <c>false</c> otherwise.</p> </item> <tag><em>permanent</em></tag> <item> - <p>Return a <c>bool()</c>, being <c>true</c> if the driver has made + <p>Return a <c>boolean()</c>, being <c>true</c> if the driver has made itself permanent (and is <em>not</em> a statically linked in driver). <c>false</c> otherwise.</p> </item> @@ -278,14 +270,14 @@ <item> <p>Return a list of all processes having monitors for <c>loading</c> active, each process returned as - <c>{pid(),int()}</c>, where the <c>int()</c> is the + <c>{pid(),integer() >= 0}</c>, where the <c>integer()</c> is the number of monitors held by the process <c>pid()</c>.</p> </item> <tag><em>awaiting_unload</em></tag> <item> <p>Return a list of all processes having monitors for <c>unloading</c> active, each process returned as - <c>{pid(),int()}</c>, where the <c>int()</c> is the + <c>{pid(),integer() >= 0}</c>, where the <c>integer()</c> is the number of monitors held by the process <c>pid()</c>.</p> </item> </taglist> @@ -377,41 +369,34 @@ </desc> </func> <func> - <name>monitor(Tag, Item) -> MonitorRef</name> + <name name="monitor" arity="2"/> <fsummary>Create a monitor for a driver</fsummary> - <type> - <v>Tag = driver </v> - <v>Item = {Name, When}</v> - <v>Name = atom() | string()</v> - <v>When = loaded | unloaded | unloaded_only</v> - <v>MonitorRef = reference()</v> - </type> <desc> <p>This function creates a driver monitor and works in many ways as the function <seealso marker="erts:erlang#erlang:monitor/2">erlang:monitor/2</seealso>, does for processes. When a driver changes state, the monitor results in a monitor-message being sent to the calling - process. The <c>MonitorRef</c> returned by this function is + process. The <c><anno>MonitorRef</anno></c> returned by this function is included in the message sent.</p> <p>As with process monitors, each driver monitor set will only generate <em>one single message</em>. The monitor is "destroyed" after the message is sent and there is then no need to call <seealso marker="#demonitor/1">demonitor/1</seealso>.</p> - <p>The <c>MonitorRef</c> can also be used in subsequent calls + <p>The <c><anno>MonitorRef</anno></c> can also be used in subsequent calls to <seealso marker="#demonitor/1">demonitor/1</seealso> to remove a monitor.</p> <p>The function accepts the following parameters:</p> <taglist> - <tag><em>Tag</em></tag> + <tag><em><anno>Tag</anno></em></tag> <item> <p>The monitor tag is always <c>driver</c> as this function can only be used to create driver monitors. In the future, driver monitors will be integrated with process monitors, why this parameter has to be given for consistence.</p> </item> - <tag><em>Item</em></tag> + <tag><em><anno>Item</anno></em></tag> <item> - <p>The <c>Item</c> parameter specifies which driver one + <p>The <c><anno>Item</anno></c> parameter specifies which driver one wants to monitor (the name of the driver) as well as which state change one wants to monitor. The parameter is a tuple of arity two whose first element is the @@ -588,22 +573,8 @@ </desc> </func> <func> - <name>try_load(Path, Name, OptionList) -> {ok,Status} | {ok, PendingStatus, Ref} | {error, ErrorDesc}</name> + <name name="try_load" arity="3"/> <fsummary>Load a driver</fsummary> - <type> - <v>Path = Name = string() | atom()</v> - <v>OptionList = [ Option ]</v> - <v>Option = {driver_options, DriverOptionList} | {monitor, MonitorOption} | {reload, ReloadOption}</v> - <v>DriverOptionList = [ DriverOption ]</v> - <v>DriverOption = kill_ports</v> - <v>MonitorOption = pending_driver | pending</v> - <v>ReloadOption = pending_driver | pending</v> - <v>Status = loaded | already_loaded | PendingStatus </v> - <v>PendingStatus = pending_driver | pending_process</v> - <v>Ref = reference()</v> - <v>ErrorDesc = ErrorAtom | OpaqueError</v> - <v>ErrorAtom = linked_in_driver | inconsistent | permanent | not_loaded_by_this_process | not_loaded | pending_reload | pending_process</v> - </type> <desc> <p>This function provides more control than the <c>load/2</c>/<c>reload/2</c> and @@ -655,65 +626,65 @@ <p>When the function returns <c>{ok, pending_driver}</c> or <c>{ok, pending_process}</c>, one might want to get information about when the driver is <em>actually</em> loaded. This can - be achieved by using the <c>{monitor, PendingOption}</c> option.</p> + be achieved by using the <c>{monitor, <anno>MonitorOption</anno>}</c> option.</p> <p>When monitoring is requested, and a corresponding <c>{ok, pending_driver}</c> or <c>{ok, pending_process}</c> would be - returned, the function will instead return a tuple <c>{ok, PendingStatus, reference()}</c> and the process will, at a later + returned, the function will instead return a tuple <c>{ok, <anno>PendingStatus</anno>, reference()}</c> and the process will, at a later time when the driver actually gets loaded, get a monitor message. The monitor message one can expect is described in the <seealso marker="#monitor/2">monitor/2</seealso> function description. </p> <note> <p>Note that in case of loading, monitoring can - <em>not</em> only get triggered by using the <c>{reload, ReloadOption}</c> option, but also in special cases where + <em>not</em> only get triggered by using the <c>{reload, <anno>ReloadOption</anno>}</c> option, but also in special cases where the load-error is transient, why <c>{monitor, pending_driver}</c> should be used under basically <em>all</em> real world circumstances!</p> </note> <p>The function accepts the following parameters:</p> <taglist> - <tag><em>Path</em></tag> + <tag><em><anno>Path</anno></em></tag> <item> <p>The filesystem path to the directory where the driver object file is situated. The filename of the object file (minus extension) must correspond to the driver name (used in the name parameter) and the driver must identify itself with the very same name. The - <c>Path</c> might be provided as an <em>io_list</em>, - meaning it can be a list of other io_lists, characters + <c><anno>Path</anno></c> might be provided as an <em>iolist()</em>, + meaning it can be a list of other <c>iolist()</c>s, characters (eight bit integers) or binaries, all to be flattened into a sequence of characters.</p> - <p>The (possibly flattened) <c>Path</c> parameter must be + <p>The (possibly flattened) <c><anno>Path</anno></c> parameter must be consistent throughout the system, a driver should, by all <seealso marker="#users">users</seealso>, be loaded - using the same <em>literal</em><c>Path</c>. The + using the same <em>literal</em><c><anno>Path</anno></c>. The exception is when <em>reloading</em> is requested, in - which case the <c>Path</c> may be specified + which case the <c><anno>Path</anno></c> may be specified differently. Note that all <seealso marker="#users">users</seealso> trying to load the - driver at a later time will need to use the <em>new</em><c>Path</c> if the <c>Path</c> is changed using a + driver at a later time will need to use the <em>new</em><c><anno>Path</anno></c> if the <c><anno>Path</anno></c> is changed using a <c>reload</c> option. This is yet another reason to have <em>only one loader</em> of a driver one wants to upgrade in a running system! </p> </item> - <tag><em>Name</em></tag> + <tag><em><anno>Name</anno></em></tag> <item> <p>The name parameter is the name of the driver to be used in subsequent calls to <seealso marker="erts:erlang#open_port/2">open_port</seealso>. The - name can be specified either as an <c>io_list()</c> or + name can be specified either as an <c>iolist()</c> or as an <c>atom()</c>. The name given when loading is used to find the actual object file (with the - help of the <c>Path</c> and the system implied + help of the <c><anno>Path</anno></c> and the system implied extension suffix, i.e. <c>.so</c>). The name by which the driver identifies itself must also be consistent - with this <c>Name</c> parameter, much as a beam-file's + with this <c><anno>Name</anno></c> parameter, much as a beam-file's module name much correspond to its filename.</p> </item> - <tag><em>OptionList</em></tag> + <tag><em><anno>OptionList</anno></em></tag> <item> <p>A number of options can be specified to control the loading operation. The options are given as a list of two-tuples, the tuples having the following values and meanings:</p> <taglist> - <tag><em>{driver_options, DriverOptionsList}</em></tag> + <tag><em>{driver_options, <anno>DriverOptionList</anno>}</em></tag> <item> <p>This option is to provide options that will change its general behavior and will "stick" to the driver @@ -729,14 +700,14 @@ when the last <seealso marker="#users">user</seealso> calls <seealso marker="#try_unload/2">try_unload/2</seealso>, or the last process having loaded the driver exits.</p> </item> - <tag><em>{monitor, MonitorOption}</em></tag> + <tag><em>{monitor, <anno>MonitorOption</anno>}</em></tag> <item> - <p>A <c>MonitorOption</c> tells <c>try_load/3</c> to + <p>A <c><anno>MonitorOption</anno></c> tells <c>try_load/3</c> to trigger a driver monitor under certain conditions. When the monitor is triggered, the - function will return a three-tuple <c>{ok, PendingStatus, reference()}</c>, where the <c>reference()</c> is + function will return a three-tuple <c>{ok, <anno>PendingStatus</anno>, reference()}</c>, where the <c>reference()</c> is the monitor ref for the driver monitor.</p> - <p>Only one <c>MonitorOption</c> can be specified and + <p>Only one <c><anno>MonitorOption</anno></c> can be specified and it is either the atom <c>pending</c>, which means that a monitor should be created whenever a load operation is delayed, and the atom @@ -747,7 +718,7 @@ is present for completeness, it is very well defined which reload-options might give rise to which delays. It might, however, be a good idea to use the - same <c>MonitorOption</c> as the <c>ReloadOption</c> + same <c><anno>MonitorOption</anno></c> as the <c><anno>ReloadOption</anno></c> if present.</p> <p>If reloading is not requested, it might still be useful to specify the <c>monitor</c> option, as @@ -760,12 +731,12 @@ <c>{monitor, pending_driver}</c> in production code (see the monitor discussion above). </p> </item> - <tag><em>{reload,RealoadOption}</em></tag> + <tag><em>{reload,<anno>ReloadOption</anno>}</em></tag> <item> <p>This option is used when one wants to <em>reload</em> a driver from disk, most often in a code upgrade scenario. Having a <c>reload</c> option - also implies that the <c>Path</c> parameter need + also implies that the <c><anno>Path</anno></c> parameter need <em>not</em> be consistent with earlier loads of the driver.</p> <p>To reload a driver, the process needs to have previously @@ -814,9 +785,9 @@ <tag><em>{error,inconsistent}</em></tag> <item> <p>The driver has already been loaded with either other - <c>DriverOptions</c> or a different <em>literal</em><c>Path</c> argument.</p> + <c><anno>DriverOptionList</anno></c> or a different <em>literal</em><c>Path</c> argument.</p> <p>This can happen even if a <c>reload</c> option is given, - if the <c>DriverOptions</c> differ from the current.</p> + if the <c>DriverOptionList</c> differ from the current.</p> </item> <tag><em>{error, permanent}</em></tag> <item> @@ -830,19 +801,19 @@ </item> <tag><em>{error, pending_reload}</em></tag> <item> - <p>Driver reload is already requested by another <seealso marker="#users">user</seealso> when the <c>{reload, ReloadOption}</c> option was given.</p> + <p>Driver reload is already requested by another <seealso marker="#users">user</seealso> when the <c>{reload, <anno>ReloadOption</anno>}</c> option was given.</p> </item> <tag><em>{error, not_loaded_by_this_process}</em></tag> <item> <p>Appears when the <c>reload</c> option is given. The - driver <c>Name</c> is present in the system, but there is no + driver <c><anno>Name</anno></c> is present in the system, but there is no <seealso marker="#users">user</seealso> of it in this process.</p> </item> <tag><em>{error, not_loaded}</em></tag> <item> <p>Appears when the <c>reload</c> option is given. The - driver <c>Name</c> is not in the system. Only drivers + driver <c><anno>Name</anno></c> is not in the system. Only drivers loaded by this process can be reloaded.</p> </item> </taglist> @@ -856,18 +827,8 @@ </desc> </func> <func> - <name>try_unload(Name, OptionList) -> {ok,Status} | {ok, PendingStatus, Ref} | {error, ErrorAtom}</name> + <name name="try_unload" arity="2"/> <fsummary>Unload a driver</fsummary> - <type> - <v>Name = string() | atom()</v> - <v>OptionList = [ Option ]</v> - <v>Option = {monitor, MonitorOption} | kill_ports</v> - <v>MonitorOption = pending_driver | pending</v> - <v>Status = unloaded | PendingStatus </v> - <v>PendingStatus = pending_driver | pending_process</v> - <v>Ref = reference()</v> - <v>ErrorAtom = linked_in_driver | not_loaded | not_loaded_by_this_process | permanent</v> - </type> <desc> <p>This is the low level function to unload (or decrement reference counts of) a driver. It can be used to force port @@ -948,15 +909,15 @@ </taglist> <p>The function accepts the following parameters:</p> <taglist> - <tag><em>Name</em></tag> + <tag><em><anno>Name</anno></em></tag> <item> <p>The name parameter is the name of the driver to be unloaded. The name can be specified either as an - <c>io_list()</c> or as an <c>atom()</c>. </p> + <c>iolist()</c> or as an <c>atom()</c>. </p> </item> - <tag><em>OptionList</em></tag> + <tag><em><anno>OptionList</anno></em></tag> <item> - <p>The <c>OptionList</c> argument can be used to specify + <p>The <c><anno>OptionList</anno></c> argument can be used to specify certain behavior regarding ports as well as triggering monitors under certain conditions:</p> <taglist> @@ -972,10 +933,10 @@ unloads, one should use the driver option <c>kill_ports</c> when loading the driver instead.</p> </item> - <tag><em>{monitor, MonitorOption}</em></tag> + <tag><em>{monitor, <anno>MonitorOption</anno>}</em></tag> <item> <p>This option creates a driver monitor if the condition - given in <c>MonitorOptions</c> is true. The valid + given in <c><anno>MonitorOption</anno></c> is true. The valid options are:</p> <taglist> <tag><em>pending_driver</em></tag> @@ -989,7 +950,7 @@ <c>{ok, pending_driver}</c> or <c>{ok, pending_process}</c>.</p> </item> </taglist> - <p>The <c>pending_driver</c> <c>MonitorOption</c> is by far + <p>The <c>pending_driver</c> <c><anno>MonitorOption</anno></c> is by far the most useful and it has to be used to ensure that the driver has really been unloaded and the ports closed whenever the <c>kill_ports</c> option is used or the @@ -1016,11 +977,11 @@ </item> <tag><em>{error, not_loaded}</em></tag> <item> - <p>The driver <c>Name</c> is not present in the system.</p> + <p>The driver <c><anno>Name</anno></c> is not present in the system.</p> </item> <tag><em>{error, not_loaded_by_this_process}</em></tag> <item> - <p>The driver <c>Name</c> is present in the system, but + <p>The driver <c><anno>Name</anno></c> is present in the system, but there is no <seealso marker="#users">user</seealso> of it in this process. </p> <p>As a special case, drivers can be unloaded from @@ -1088,12 +1049,8 @@ </desc> </func> <func> - <name>loaded_drivers() -> {ok, Drivers}</name> + <name name="loaded_drivers" arity="0"/> <fsummary>List loaded drivers</fsummary> - <type> - <v>Drivers = [Driver]</v> - <v>Driver = string()</v> - </type> <desc> <p>Returns a list of all the available drivers, both (statically) linked-in and dynamically loaded ones.</p> diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml index 2d95f96ac7..5781591cca 100644 --- a/lib/kernel/doc/src/error_logger.xml +++ b/lib/kernel/doc/src/error_logger.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -127,11 +127,8 @@ ok</pre> </desc> </func> <func> - <name>warning_map() -> Tag</name> + <name name="warning_map" arity="0"/> <fsummary>Return the current mapping for warning events</fsummary> - <type> - <v>Tag = error | warning | info</v> - </type> <desc> <p>Returns the current mapping for warning events. Events sent using <c>warning_msg/1,2</c> or <c>warning_report/1,2</c> diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 772eff13cc..b2a259080d 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -412,7 +412,7 @@ </desc> </func> <func> - <name>file_info(Filename) -> {ok, FileInfo} | {error, Reason}</name> + <name name="file_info" arity="1"/> <fsummary>Get information about a file (deprecated)</fsummary> <desc> <p>This function is obsolete. Use <c>read_file_info/1,2</c> @@ -598,7 +598,7 @@ </desc> </func> <func> - <name>native_name_encoding() -> latin1 | utf8</name> + <name name="native_name_encoding" arity="0"/> <fsummary>Return the VM's configured filename encoding.</fsummary> <desc> <p>This function returns the configured default file name encoding to use for raw file names. Generally an application supplying file names raw (as binaries), should obey the character encoding returned by this function.</p> diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml index e94119845a..1bc5b9e464 100644 --- a/lib/kernel/doc/src/os.xml +++ b/lib/kernel/doc/src/os.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1997</year><year>2011</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -73,7 +73,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </desc> </func> <func> - <name>getenv() -> [string()]</name> + <name name="getenv" arity="0"/> <fsummary>List all environment variables</fsummary> <desc> <p>Returns a list of all environment variables. @@ -83,55 +83,41 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </desc> </func> <func> - <name>getenv(VarName) -> Value | false</name> + <name name="getenv" arity="1"/> <fsummary>Get the value of an environment variable</fsummary> - <type> - <v>VarName = string() </v> - <v>Value = string()</v> - </type> <desc> - <p>Returns the <c>Value</c> of the environment variable - <c>VarName</c>, or <c>false</c> if the environment variable + <p>Returns the <c><anno>Value</anno></c> of the environment variable + <c><anno>VarName</anno></c>, or <c>false</c> if the environment variable is undefined.</p> </desc> </func> <func> - <name>getpid() -> Value </name> + <name name="getpid" arity="0"/> <fsummary>Return the process identifier of the emulator process</fsummary> - <type> - <v>Value = string()</v> - </type> <desc> <p>Returns the process identifier of the current Erlang emulator in the format most commonly used by the operating system - environment. <c>Value</c> is returned as a string containing + environment. <c><anno>Value</anno></c> is returned as a string containing the (usually) numerical identifier for a process. On Unix, this is typically the return value of the <c>getpid()</c> - system call. On VxWorks, <c>Value</c> contains the task id + system call. On VxWorks, <c><anno>Value</anno></c> contains the task id (decimal notation) of the Erlang task. On Windows, the process id as returned by the <c>GetCurrentProcessId()</c> system call is used.</p> </desc> </func> <func> - <name>putenv(VarName, Value) -> true</name> + <name name="putenv" arity="2"/> <fsummary>Set a new value for an environment variable</fsummary> - <type> - <v>VarName = string() </v> - <v>Value = string()</v> - </type> <desc> - <p>Sets a new <c>Value</c> for the environment variable - <c>VarName</c>.</p> + <p>Sets a new <c><anno>Value</anno></c> for the environment variable + <c><anno>VarName</anno></c>.</p> </desc> </func> <func> - <name>timestamp() -> Timestamp</name> + <name name="timestamp" arity="0"/> + <type_desc variable="Timestamp">Timestamp = {MegaSecs, Secs, MicroSecs}</type_desc> <fsummary>Returna a timestamp from the OS in the erlang:now/0 format</fsummary> - <type> - <v>Timestamp = {MegaSecs, Secs, MicroSecs} = <seealso marker="erts:erlang#type-timestamp">erlang:timestamp()</seealso></v> - <v>MegaSecs = Secs = MicroSecs = integer() >= 0</v> - </type> <desc> <p>Returns a tuple in the same format as <seealso marker="erts:erlang#now/0">erlang:now/0</seealso>. The difference is that this function returns what the operating system thinks (a.k.a. the wall clock time) without any attempts at time correction. The result of two different calls to this function is <em>not</em> guaranteed to be different.</p> <p>The most obvious use for this function is logging. The tuple can be used together with the function <seealso marker="stdlib:calendar#now_to_universal_time/1">calendar:now_to_universal_time/1</seealso> diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index b7fda69ce0..a9259817ea 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -70,46 +70,6 @@ -include_lib("kernel/include/file.hrl"). -%% User interface. -%% -%% objfile_extension() -> ".beam" -%% get_path() -> [Dir] -%% set_path([Dir]) -> true | {error, bad_directory | bad_path} -%% add_path(Dir) -> true | {error, bad_directory} -%% add_patha(Dir) -> true | {error, bad_directory} -%% add_pathz(Dir) -> true | {error, bad_directory} -%% add_paths([Dir]) -> ok -%% add_pathsa([Dir]) -> ok -%% add_pathsz([Dir]) -> ok -%% del_path(Dir) -> boolean() | {error, bad_name} -%% replace_path(Name, Dir) -> true | {error, bad_directory | bad_name -%% | {badarg,_}} -%% load_file(Module) -> {module, Module} | {error, What :: atom()} -%% load_abs(File) -> {module, Module} | {error, What :: atom()} -%% load_abs(File, Module) -> {module, Module} | {error, What :: atom()} -%% load_binary(Module, File, Bin)-> {module, Module} | {error, What :: atom()} -%% ensure_loaded(Module) -> {module, Module} | {error, What :: atom()} -%% delete(Module) -> boolean() -%% purge(Module) -> boolean() kills all procs running old code -%% soft_purge(Module) -> boolean() -%% is_loaded(Module) -> {file, loaded_filename()} | false -%% all_loaded() -> [{Module, loaded_filename()}] -%% get_object_code(Module) -> {Module, Bin, Filename} | error -%% stop() -> no_return() -%% root_dir() -> Dir -%% compiler_dir() -> Dir -%% lib_dir() -> Dir -%% lib_dir(Application) -> Dir | {error, bad_name} -%% priv_dir(Application) -> Dir | {error, bad_name} -%% stick_dir(Dir) -> ok | error -%% unstick_dir(Dir) -> ok | error -%% stick_mod(Module) -> true -%% unstick_mod(Module) -> true -%% is_sticky(Module) -> boolean() -%% which(Module) -> Filename | loaded_ret_atoms() | non_existing -%% set_primary_archive((FileName, Bin, FileInfo) -> ok | {error, Reason} -%% clash() -> ok prints out number of clashes - %%---------------------------------------------------------------------------- %% Some types for basic exported functions of this module %%---------------------------------------------------------------------------- @@ -125,6 +85,39 @@ -type loaded_ret_atoms() :: 'cover_compiled' | 'preloaded'. -type loaded_filename() :: (Filename :: file:filename()) | loaded_ret_atoms(). +%%% BIFs + +-export([get_chunk/2, is_module_native/1, make_stub_module/3, module_md5/1]). + +-spec get_chunk(Bin, Chunk) -> + binary() | undefined when + Bin :: binary(), + Chunk :: string(). + +get_chunk(_, _) -> + erlang:nif_error(undef). + +-spec is_module_native(Module) -> true | false | undefined when + Module :: module(). + +is_module_native(_) -> + erlang:nif_error(undef). + +-spec make_stub_module(Module, Beam, Info) -> Module when + Module :: module(), + Beam :: binary(), + Info :: {list(), list()}. + +make_stub_module(_, _, _) -> + erlang:nif_error(undef). + +-spec module_md5(binary()) -> binary() | undefined. + +module_md5(_) -> + erlang:nif_error(undef). + +%%% End of BIFs + %%---------------------------------------------------------------------------- %% User interface %%---------------------------------------------------------------------------- diff --git a/lib/kernel/src/disk_log_1.erl b/lib/kernel/src/disk_log_1.erl index 266df84a03..0cb1ed579a 100644 --- a/lib/kernel/src/disk_log_1.erl +++ b/lib/kernel/src/disk_log_1.erl @@ -1495,7 +1495,7 @@ fwrite_close2(Fd, FileName, B) -> pwrite_close2(Fd, FileName, Position, B) -> case file:pwrite(Fd, Position, B) of ok -> ok; - Error -> file_error(FileName, {error, Error}) + {error,Error} -> file_error(FileName, {error, Error}) end. position2(Fd, FileName, Pos) -> diff --git a/lib/kernel/src/erl_ddll.erl b/lib/kernel/src/erl_ddll.erl index 646cac99c5..f967fcc2ef 100644 --- a/lib/kernel/src/erl_ddll.erl +++ b/lib/kernel/src/erl_ddll.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -30,9 +30,99 @@ %%---------------------------------------------------------------------------- -type path() :: string() | atom(). --type driver() :: string() | atom(). +-type driver() :: iolist() | atom(). %%---------------------------------------------------------------------------- +%%% BIFs + +-export([demonitor/1, info/2, format_error_int/1, monitor/2, + try_load/3, try_unload/2, loaded_drivers/0]). + +-spec demonitor(MonitorRef) -> ok when + MonitorRef :: reference(). + +demonitor(_) -> + erlang:nif_error(undef). + +-spec info(Name, Tag) -> Value when + Name :: driver(), + Tag :: processes | driver_options | port_count | linked_in_driver + | permanent | awaiting_load | awaiting_unload, + Value :: term(). + +info(_, _) -> + erlang:nif_error(undef). + +-spec format_error_int(ErrSpec) -> string() when + ErrSpec :: inconsisten | linked_in_driver | permanent + | not_loaded | not_loaded_by_this_process | not_pending + | already_loaded | unloading. + +format_error_int(_) -> + erlang:nif_error(undef). + +-spec monitor(Tag, Item) -> MonitorRef when + Tag :: driver, + Item :: {Name, When}, + Name :: driver(), + When :: loaded | unloaded | unloaded_only, + MonitorRef :: reference(). + +monitor(_, _) -> + erlang:nif_error(undef). + +-spec try_load(Path, Name, OptionList) -> + {ok,Status} | + {ok, PendingStatus, Ref} | + {error, ErrorDesc} when + Path :: path(), + Name :: driver(), + OptionList :: [Option], + Option :: {driver_options, DriverOptionList} + | {monitor, MonitorOption} + | {reload, ReloadOption}, + DriverOptionList :: [DriverOption], + DriverOption :: kill_ports, + MonitorOption :: pending_driver | pending, + ReloadOption :: pending_driver | pending, + Status :: loaded | already_loaded | PendingStatus, + PendingStatus :: pending_driver | pending_process, + Ref :: reference(), + ErrorDesc :: ErrorAtom | OpaqueError, + ErrorAtom :: linked_in_driver | inconsistent | permanent + | not_loaded_by_this_process | not_loaded + | pending_reload | pending_process, + OpaqueError :: term(). + +try_load(_, _, _) -> + erlang:nif_error(undef). + +-spec try_unload(Name, OptionList) -> + {ok, Status} | + {ok, PendingStatus, Ref} | + {error, ErrorAtom} when + Name :: driver(), + OptionList :: [Option], + Option :: {monitor, MonitorOption} | kill_ports, + MonitorOption :: pending_driver | pending, + Status :: unloaded | PendingStatus, + PendingStatus :: pending_driver | pending_process, + Ref :: reference(), + ErrorAtom :: linked_in_driver | not_loaded | + not_loaded_by_this_process | permanent. + +try_unload(_, _) -> + erlang:nif_error(undef). + +-spec loaded_drivers() -> {ok, Drivers} when + Drivers :: [Driver], + Driver :: string(). + +loaded_drivers() -> + erlang:nif_error(undef). + +%%% End of BIFs + -spec start() -> {'error', {'already_started', 'undefined'}}. diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl index a67b11a888..f8bc5f499c 100644 --- a/lib/kernel/src/error_handler.erl +++ b/lib/kernel/src/error_handler.erl @@ -90,7 +90,7 @@ int() -> int. crash(Fun, Args) -> crash({Fun,Args,[]}). --spec crash(atom(), atom(), arity()) -> no_return(). +-spec crash(atom(), atom(), arity() | [term()]) -> no_return(). crash(M, F, A) -> crash({M,F,A,[]}). diff --git a/lib/kernel/src/error_logger.erl b/lib/kernel/src/error_logger.erl index f94cca000f..92c1eb80dc 100644 --- a/lib/kernel/src/error_logger.erl +++ b/lib/kernel/src/error_logger.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -42,6 +42,18 @@ -type state() :: {non_neg_integer(), non_neg_integer(), [term()]}. +%%% BIF + +-export([warning_map/0]). + +-spec warning_map() -> Tag when + Tag :: error | warning | info. + +warning_map() -> + erlang:nif_error(undef). + +%%% End of BIF + %%----------------------------------------------------------------- -spec start() -> {'ok', pid()} | {'error', any()}. diff --git a/lib/kernel/src/erts_debug.erl b/lib/kernel/src/erts_debug.erl index 7d6a5ade94..b3d54ddc1d 100644 --- a/lib/kernel/src/erts_debug.erl +++ b/lib/kernel/src/erts_debug.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% Copyright Ericsson AB 1999-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -28,6 +28,135 @@ %% same/2 %% flat_size/1 +%%% BIFs + +-export([breakpoint/2, disassemble/1, display/1, dist_ext_to_term/2, + dump_monitors/1, dump_links/1, flat_size/1, + get_internal_state/1, instructions/0, lock_counters/1, + same/2, set_internal_state/2]). + +-spec breakpoint(MFA, Flag) -> non_neg_integer() when + MFA :: {Module :: module(), + Function :: atom(), + Arity :: arity() | '_'}, + Flag :: boolean(). + +breakpoint(_, _) -> + erlang:nif_error(undef). + +-spec disassemble(What) -> false | undef | Result when + What :: MFA | Address, + Result :: {Address, Code, MFA}, + MFA :: mfa(), + Address :: non_neg_integer(), + Code :: binary(). + +disassemble(_) -> + erlang:nif_error(undef). + +-spec display(Term) -> string() when + Term :: term(). + +display(_) -> + erlang:nif_error(undef). + +-spec dist_ext_to_term(Tuple, Binary) -> term() when + Tuple :: tuple(), + Binary :: binary(). + +dist_ext_to_term(_, _) -> + erlang:nif_error(undef). + +-spec dump_monitors(Id) -> true when + Id :: pid() | atom(). + +dump_monitors(_) -> + erlang:nif_error(undef). + +-spec dump_links(Id) -> true when + Id :: pid() | port() | atom(). + +dump_links(_) -> + erlang:nif_error(undef). + +-spec flat_size(Term) -> non_neg_integer() when + Term :: term(). + +flat_size(_) -> + erlang:nif_error(undef). + +-spec get_internal_state(W) -> term() when + W :: reds_left | node_and_dist_references | monitoring_nodes + | next_pid | 'DbTable_words' | check_io_debug + | process_info_args | processes | processes_bif_info + | max_atom_out_cache_index | nbalance | available_internal_state + | force_heap_frags | memory + | {process_status, pid()} + | {link_list, pid() | port() | node()} + | {monitor_list, pid() | node()} + | {channel_number, non_neg_integer()} + | {have_pending_exit, pid() | port() | atom()} + | {binary_info, binary()} + | {term_to_binary_no_funs, term()} + | {dist_port, port()} + | {atom_out_cache_index, atom()} + | {fake_scheduler_bindings, + default_bind | spread | processor_spread | thread_spread + | thread_no_node_processor_spread | no_node_processor_spread + | no_node_thread_spread | no_spread | unbound} + | {reader_groups_map, non_neg_integer()}. + +get_internal_state(_) -> + erlang:nif_error(undef). + +-spec instructions() -> [string()]. + +instructions() -> + erlang:nif_error(undef). + +-spec lock_counters(info) -> term(); + (clear) -> ok; + ({copy_save, boolean()}) -> boolean(); + ({process_locks, boolean()}) -> boolean(). + +lock_counters(_) -> + erlang:nif_error(undef). + +-spec same(Term1, Term2) -> boolean() when + Term1 :: term(), + Term2 :: term(). + +same(_, _) -> + erlang:nif_error(undef). + +-spec set_internal_state(available_internal_state, boolean()) -> boolean(); + (reds_left, non_neg_integer()) -> true; + (block, non_neg_integer()) -> true; + (sleep, non_neg_integer()) -> true; + (block_scheduler, non_neg_integer()) -> true; + (next_pid, non_neg_integer()) -> false | integer(); + (force_gc, pid() | atom()) -> boolean(); + (send_fake_exit_signal, {pid() | port(), pid(), term()}) -> dead | message | unaffected | exit; + (colliding_names, {atom(), non_neg_integer()}) -> + [atom()]; + (binary_loop_limit, default) -> -1; + (binary_loop_limit, non_neg_integer()) -> non_neg_integer(); + (re_loop_limit, default) -> -1; + (re_loop_limit, non_neg_integer()) -> non_neg_integer(); + (unicode_loop_limit, default) -> -1; + (unicode_loop_limit, non_neg_integer()) -> non_neg_integer(); + (hipe_test_reschedule_suspend, term()) -> nil(); + (hipe_test_reschedule_resume, pid() | port()) -> boolean(); + (test_long_gc_sleep, non_neg_integer()) -> true; + (kill_dist_connection, port()) -> boolean(); + (not_running_optimization, boolean()) -> boolean(); + (wait, deallocations) -> ok. + +set_internal_state(_, _) -> + erlang:nif_error(undef). + +%%% End of BIFs + %% size(Term) %% Returns the size of Term in actual heap words. Shared subterms are %% counted once. Example: If A = [a,b], B =[A,A] then size(B) returns 8, diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 4028dd4f0b..101a830ad3 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -111,6 +111,24 @@ -type sendfile_option() :: {chunk_size, non_neg_integer()}. -type file_info_option() :: {'time', 'local'} | {'time', 'universal'} | {'time', 'posix'}. +%%% BIFs + +-export([file_info/1, native_name_encoding/0]). + +-spec file_info(Filename) -> {ok, FileInfo} | {error, Reason} when + Filename :: name(), + FileInfo :: file_info(), + Reason :: posix() | badarg. + +file_info(_) -> + erlang:nif_error(undef). + +-spec native_name_encoding() -> latin1 | utf8. + +native_name_encoding() -> + erlang:nif_error(undef). + +%%% End of BIFs %%%----------------------------------------------------------------- diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl index 8b3aa0286d..cedaaf4f7e 100644 --- a/lib/kernel/src/hipe_unified_loader.erl +++ b/lib/kernel/src/hipe_unified_loader.erl @@ -330,11 +330,16 @@ exports(ExportMap, BaseAddress) -> exports(ExportMap, BaseAddress, [], []). exports([Offset,M,F,A,IsClosure,IsExported|Rest], BaseAddress, MFAs, Addresses) -> - MFA = {M,F,A}, - Address = BaseAddress + Offset, - FunDef = #fundef{address=Address, mfa=MFA, is_closure=IsClosure, - is_exported=IsExported}, - exports(Rest, BaseAddress, [MFA|MFAs], [FunDef|Addresses]); + case IsExported andalso erlang:is_builtin(M, F, A) of + true -> + exports(Rest, BaseAddress, MFAs, Addresses); + _false -> + MFA = {M,F,A}, + Address = BaseAddress + Offset, + FunDef = #fundef{address=Address, mfa=MFA, is_closure=IsClosure, + is_exported=IsExported}, + exports(Rest, BaseAddress, [MFA|MFAs], [FunDef|Addresses]) + end; exports([], _, MFAs, Addresses) -> {MFAs, Addresses}. @@ -498,7 +503,7 @@ patch_offset(Type, Data, Address, ConstAndZone, Addresses) -> Atom = Data, patch_atom(Address, Atom); sdesc -> - patch_sdesc(Data, Address, ConstAndZone); + patch_sdesc(Data, Address, ConstAndZone, Addresses); x86_abs_pcrel -> patch_instr(Address, Data, x86_abs_pcrel) %% _ -> @@ -511,14 +516,16 @@ patch_atom(Address, Atom) -> patch_instr(Address, hipe_bifs:atom_to_word(Atom), atom). patch_sdesc(?STACK_DESC(SymExnRA, FSize, Arity, Live), - Address, {_ConstMap2,CodeAddress}) -> + Address, {_ConstMap2,CodeAddress}, _Addresses) -> ExnRA = case SymExnRA of [] -> 0; % No catch LabelOffset -> CodeAddress + LabelOffset end, ?ASSERT(assert_local_patch(Address)), - hipe_bifs:enter_sdesc({Address, ExnRA, FSize, Arity, Live}). + DBG_MFA = ?IF_DEBUG(address_to_mfa_lth(Address, _Addresses), {undefined,undefined,0}), + hipe_bifs:enter_sdesc({Address, ExnRA, FSize, Arity, Live, DBG_MFA}). + %%---------------------------------------------------------------- %% Handle a 'load_address'-type patch. @@ -725,7 +732,7 @@ find_const(ConstNo, []) -> %% add_ref(CalleeMFA, Address, Addresses, RefType, Trampoline, RemoteOrLocal) -> - CallerMFA = address_to_mfa(Address, Addresses), + CallerMFA = address_to_mfa_lth(Address, Addresses), %% just a sanity assertion below true = case RemoteOrLocal of local -> @@ -738,11 +745,31 @@ add_ref(CalleeMFA, Address, Addresses, RefType, Trampoline, RemoteOrLocal) -> %% io:format("Adding ref ~w\n",[{CallerMFA, CalleeMFA, Address, RefType}]), hipe_bifs:add_ref(CalleeMFA, {CallerMFA,Address,RefType,Trampoline,RemoteOrLocal}). -address_to_mfa(Address, [#fundef{address=Adr, mfa=MFA}|_Rest]) when Address >= Adr -> MFA; -address_to_mfa(Address, [_ | Rest]) -> address_to_mfa(Address, Rest); -address_to_mfa(Address, []) -> - ?error_msg("Local adddress not found ~w\n",[Address]), - exit({?MODULE, local_address_not_found}). +% For FunDefs sorted from low to high addresses +address_to_mfa_lth(Address, FunDefs) -> + case address_to_mfa_lth(Address, FunDefs, false) of + false -> + ?error_msg("Local adddress not found ~w\n",[Address]), + exit({?MODULE, local_address_not_found}); + MFA -> + MFA + end. + +address_to_mfa_lth(Address, [#fundef{address=Adr, mfa=MFA}|Rest], Prev) -> + if Address < Adr -> + Prev; + true -> + address_to_mfa_lth(Address, Rest, MFA) + end; +address_to_mfa_lth(_Address, [], Prev) -> + Prev. + +% For FunDefs sorted from high to low addresses +%% address_to_mfa_htl(Address, [#fundef{address=Adr, mfa=MFA}|_Rest]) when Address >= Adr -> MFA; +%% address_to_mfa_htl(Address, [_ | Rest]) -> address_to_mfa_htl(Address, Rest); +%% address_to_mfa_htl(Address, []) -> +%% ?error_msg("Local adddress not found ~w\n",[Address]), +%% exit({?MODULE, local_address_not_found}). %%---------------------------------------------------------------- %% Change callers of the given module to instead trap to BEAM. diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src index bded2408a7..54628800a8 100644 --- a/lib/kernel/src/kernel.appup.src +++ b/lib/kernel/src/kernel.appup.src @@ -17,11 +17,11 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max two major revisions back - [{<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 - {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 - {<<"2\\.13(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13 + [{<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R14 %% Down to - max two major revisions back - [{<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 - {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 - {<<"2\\.13(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13 + [{<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R14 }. diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl index 9e3d730cee..0d59e7af67 100644 --- a/lib/kernel/src/net_kernel.erl +++ b/lib/kernel/src/net_kernel.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -142,6 +142,17 @@ -include("net_address.hrl"). +%%% BIF + +-export([dflag_unicode_io/1]). + +-spec dflag_unicode_io(pid()) -> boolean(). + +dflag_unicode_io(_) -> + erlang:nif_error(undef). + +%%% End of BIF + %% Interface functions kernel_apply(M,F,A) -> request({apply,M,F,A}). diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl index f6769df585..b986f3a61e 100644 --- a/lib/kernel/src/os.erl +++ b/lib/kernel/src/os.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -24,6 +24,42 @@ -include("file.hrl"). +%%% BIFs + +-export([getenv/0, getenv/1, getpid/0, putenv/2, timestamp/0]). + +-spec getenv() -> [string()]. + +getenv() -> erlang:nif_error(undef). + +-spec getenv(VarName) -> Value | false when + VarName :: string(), + Value :: string(). + +getenv(_) -> + erlang:nif_error(undef). + +-spec getpid() -> Value when + Value :: string(). + +getpid() -> + erlang:nif_error(undef). + +-spec putenv(VarName, Value) -> true when + VarName :: string(), + Value :: string(). + +putenv(_, _) -> + erlang:nif_error(undef). + +-spec timestamp() -> Timestamp when + Timestamp :: erlang:timestamp(). + +timestamp() -> + erlang:nif_error(undef). + +%%% End of BIFs + -spec type() -> vxworks | {Osfamily, Osname} when Osfamily :: unix | win32, Osname :: atom(). diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index 76d3003ff4..46a991eb38 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 2.15.1 +KERNEL_VSN = 2.16 diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml index 7ce2defb72..06cfad0b0b 100644 --- a/lib/stdlib/doc/src/binary.xml +++ b/lib/stdlib/doc/src/binary.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2009</year> - <year>2011</year> + <year>2012</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -77,41 +77,30 @@ </datatypes> <funcs> <func> - <name>at(Subject, Pos) -> byte()</name> + <name name="at" arity="2"/> <fsummary>Returns the byte at a specific position in a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pos = integer() >= 0</v> - </type> <desc> - <p>Returns the byte at position <c>Pos</c> (zero-based) in the binary - <c>Subject</c> as an integer. If <c>Pos</c> >= <c>byte_size(Subject)</c>, + <p>Returns the byte at position <c><anno>Pos</anno></c> (zero-based) in the binary + <c><anno>Subject</anno></c> as an integer. If <c><anno>Pos</anno></c> >= <c>byte_size(<anno>Subject</anno>)</c>, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>bin_to_list(Subject) -> [byte()]</name> + <name name="bin_to_list" arity="1"/> <fsummary>Convert a binary to a list of integers</fsummary> - <type> - <v>Subject = binary()</v> - </type> <desc> - <p>The same as <c>bin_to_list(Subject,{0,byte_size(Subject)})</c>.</p> + <p>The same as <c>bin_to_list(<anno>Subject</anno>,{0,byte_size(<anno>Subject</anno>)})</c>.</p> </desc> </func> <func> - <name>bin_to_list(Subject, PosLen) -> [byte()]</name> + <name name="bin_to_list" arity="2"/> <fsummary>Convert a binary to a list of integers</fsummary> - <type> - <v>Subject = binary()</v> - <v>PosLen = part()</v> - </type> <desc> - <p>Converts <c>Subject</c> to a list of <c>byte()</c>s, each representing + <p>Converts <c><anno>Subject</anno></c> to a list of <c>byte()</c>s, each representing the value of one byte. The <c>part()</c> denotes which part of the <c>binary()</c> to convert. Example:</p> @@ -120,27 +109,19 @@ "rla" %% or [114,108,97] in list notation. </code> - <p>If <c>PosLen</c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> + <p>If <c><anno>PosLen</anno></c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>bin_to_list(Subject, Pos, Len) -> [byte()]</name> + <name name="bin_to_list" arity="3"/> <fsummary>Convert a binary to a list of integers</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pos = integer() >= 0</v> - <v>Len = integer() >= 0</v> - </type> <desc> - <p>The same as<c> bin_to_list(Subject,{Pos,Len})</c>.</p> + <p>The same as<c> bin_to_list(<anno>Subject</anno>,{<anno>Pos</anno>,<anno>Len</anno>})</c>.</p> </desc> </func> <func> - <name>compile_pattern(Pattern) -> cp()</name> + <name name="compile_pattern" arity="1"/> <fsummary>Pre-compiles a binary search pattern</fsummary> - <type> - <v>Pattern = binary() | [ binary() ]</v> - </type> <desc> <p>Builds an internal structure representing a compilation of a @@ -155,7 +136,7 @@ <p>When a list of binaries is given, it denotes a set of alternative binaries to search for. I.e if <c>[<<"functional">>,<<"programming">>]</c> - is given as <c>Pattern</c>, this + is given as <c><anno>Pattern</anno></c>, this means "either <c><<"functional">></c> or <c><<"programming">></c>". The pattern is a set of alternatives; when only a single binary is given, the set has @@ -163,32 +144,25 @@ <p>The list of binaries used for search alternatives shall be flat and proper.</p> - <p>If <c>Pattern</c> is not a binary or a flat proper list of binaries with length > 0, + <p>If <c><anno>Pattern</anno></c> is not a binary or a flat proper list of binaries with length > 0, a <c>badarg</c> exception will be raised.</p> </desc> </func> <func> - <name>copy(Subject) -> binary()</name> + <name name="copy" arity="1"/> <fsummary>Creates a duplicate of a binary</fsummary> - <type> - <v>Subject = binary()</v> - </type> <desc> - <p>The same as <c>copy(Subject, 1)</c>.</p> + <p>The same as <c>copy(<anno>Subject</anno>, 1)</c>.</p> </desc> </func> <func> - <name>copy(Subject,N) -> binary()</name> + <name name="copy" arity="2"/> <fsummary>Duplicates a binary N times and creates a new</fsummary> - <type> - <v>Subject = binary()</v> - <v>N = integer() >= 0</v> - </type> <desc> - <p>Creates a binary with the content of <c>Subject</c> duplicated <c>N</c> times.</p> + <p>Creates a binary with the content of <c><anno>Subject</anno></c> duplicated <c><anno>N</anno></c> times.</p> - <p>This function will always create a new binary, even if <c>N = + <p>This function will always create a new binary, even if <c><anno>N</anno> = 1</c>. By using <c>copy/1</c> on a binary referencing a larger binary, one might free up the larger binary for garbage collection.</p> @@ -201,32 +175,23 @@ large binaries are no longer used in any process, deliberate copying might be a good idea.</p> </note> - <p>If <c>N</c> < <c>0</c>, a <c>badarg</c> exception is raised.</p> + <p>If <c><anno>N</anno></c> < <c>0</c>, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>decode_unsigned(Subject) -> Unsigned</name> + <name name="decode_unsigned" arity="1"/> <fsummary>Decode a whole binary into an integer of arbitrary size</fsummary> - <type> - <v>Subject = binary()</v> - <v>Unsigned = integer() >= 0</v> - </type> <desc> - <p>The same as <c>decode_unsigned(Subject,big)</c>.</p> + <p>The same as <c>decode_unsigned(<anno>Subject</anno>, big)</c>.</p> </desc> </func> <func> - <name>decode_unsigned(Subject, Endianess) -> Unsigned</name> + <name name="decode_unsigned" arity="2"/> <fsummary>Decode a whole binary into an integer of arbitrary size</fsummary> - <type> - <v>Subject = binary()</v> - <v>Endianess = big | little</v> - <v>Unsigned = integer() >= 0</v> - </type> <desc> <p>Converts the binary digit representation, in big or little - endian, of a positive integer in <c>Subject</c> to an Erlang <c>integer()</c>.</p> + endian, of a positive integer in <c><anno>Subject</anno></c> to an Erlang <c>integer()</c>.</p> <p>Example:</p> @@ -237,22 +202,15 @@ </desc> </func> <func> - <name>encode_unsigned(Unsigned) -> binary()</name> + <name name="encode_unsigned" arity="1"/> <fsummary>Encodes an unsigned integer into the minimal binary</fsummary> - <type> - <v>Unsigned = integer() >= 0</v> - </type> <desc> - <p>The same as <c>encode_unsigned(Unsigned,big)</c>.</p> + <p>The same as <c>encode_unsigned(<anno>Unsigned</anno>, big)</c>.</p> </desc> </func> <func> - <name>encode_unsigned(Unsigned,Endianess) -> binary()</name> + <name name="encode_unsigned" arity="2"/> <fsummary>Encodes an unsigned integer into the minimal binary</fsummary> - <type> - <v>Unsigned = integer() >= 0</v> - <v>Endianess = big | little</v> - </type> <desc> <p>Converts a positive integer to the smallest possible @@ -268,51 +226,39 @@ </desc> </func> <func> - <name>first(Subject) -> byte()</name> + <name name="first" arity="1"/> <fsummary>Returns the first byte of a binary</fsummary> - <type> - <v>Subject = binary()</v> - </type> <desc> - <p>Returns the first byte of the binary <c>Subject</c> as an integer. If the - size of <c>Subject</c> is zero, a <c>badarg</c> exception is raised.</p> + <p>Returns the first byte of the binary <c><anno>Subject</anno></c> as an integer. If the + size of <c><anno>Subject</anno></c> is zero, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>last(Subject) -> byte()</name> + <name name="last" arity="1"/> <fsummary>Returns the last byte of a binary</fsummary> - <type> - <v>Subject = binary()</v> - </type> <desc> - <p>Returns the last byte of the binary <c>Subject</c> as an integer. If the - size of <c>Subject</c> is zero, a <c>badarg</c> exception is raised.</p> + <p>Returns the last byte of the binary <c><anno>Subject</anno></c> as an integer. If the + size of <c><anno>Subject</anno></c> is zero, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>list_to_bin(ByteList) -> binary()</name> + <name name="list_to_bin" arity="1"/> <fsummary>Convert a list of integers and binaries to a binary</fsummary> - <type> - <v>ByteList = iodata() (see module erlang)</v> - </type> <desc> <p>Works exactly as <c>erlang:list_to_binary/1</c>, added for completeness.</p> </desc> </func> <func> - <name>longest_common_prefix(Binaries) -> integer() >= 0</name> + <name name="longest_common_prefix" arity="1"/> <fsummary>Returns length of longest common prefix for a set of binaries</fsummary> - <type> - <v>Binaries = [ binary() ]</v> - </type> <desc> <p>Returns the length of the longest common prefix of the - binaries in the list <c>Binaries</c>. Example:</p> + binaries in the list <c><anno>Binaries</anno></c>. Example:</p> <code> 1> binary:longest_common_prefix([<<"erlang">>,<<"ergonomy">>]). @@ -321,19 +267,16 @@ 0 </code> - <p>If <c>Binaries</c> is not a flat list of binaries, a <c>badarg</c> exception is raised.</p> + <p>If <c><anno>Binaries</anno></c> is not a flat list of binaries, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>longest_common_suffix(Binaries) -> integer() >= 0</name> + <name name="longest_common_suffix" arity="1"/> <fsummary>Returns length of longest common suffix for a set of binaries</fsummary> - <type> - <v>Binaries = [ binary() ]</v> - </type> <desc> <p>Returns the length of the longest common suffix of the - binaries in the list <c>Binaries</c>. Example:</p> + binaries in the list <c><anno>Binaries</anno></c>. Example:</p> <code> 1> binary:longest_common_suffix([<<"erlang">>,<<"fang">>]). @@ -347,35 +290,24 @@ </desc> </func> <func> - <name>match(Subject, Pattern) -> Found | <c>nomatch</c></name> + <name name="match" arity="2"/> <fsummary>Searches for the first match of a pattern in a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pattern = binary() | [ binary() ] | cp()</v> - <v>Found = part()</v> - </type> <desc> - <p>The same as <c>match(Subject, Pattern, [])</c>.</p> + <p>The same as <c>match(<anno>Subject</anno>, <anno>Pattern</anno>, [])</c>.</p> </desc> </func> <func> - <name>match(Subject,Pattern,Options) -> Found | <c>nomatch</c></name> + <name name="match" arity="3"/> + <type name="part"/> <fsummary>Searches for the first match of a pattern in a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pattern = binary() | [ binary() ] | cp()</v> - <v>Found = part()</v> - <v>Options = [ Option ]</v> - <v>Option = {scope, part()}</v> - </type> <desc> - <p>Searches for the first occurrence of <c>Pattern</c> in <c>Subject</c> and + <p>Searches for the first occurrence of <c><anno>Pattern</anno></c> in <c><anno>Subject</anno></c> and returns the position and length.</p> - <p>The function will return <c>{Pos,Length}</c> for the binary - in <c>Pattern</c> starting at the lowest position in - <c>Subject</c>, Example:</p> + <p>The function will return <c>{Pos, Length}</c> for the binary + in <c><anno>Pattern</anno></c> starting at the lowest position in + <c><anno>Subject</anno></c>, Example:</p> <code> 1> binary:match(<<"abcde">>, [<<"bcde">>,<<"cd">>],[]). @@ -391,16 +323,16 @@ <p>Summary of the options:</p> <taglist> - <tag>{scope, {Start, Length}}</tag> + <tag>{scope, {<anno>Start</anno>, <anno>Length</anno>}}</tag> <item><p>Only the given part is searched. Return values still have - offsets from the beginning of <c>Subject</c>. A negative <c>Length</c> is - allowed as described in the <c>TYPES</c> section of this manual.</p></item> + offsets from the beginning of <c><anno>Subject</anno></c>. A negative <c>Length</c> is + allowed as described in the <c>DATA TYPES</c> section of this manual.</p></item> </taglist> <p>If none of the strings in - <c>Pattern</c> is found, the atom <c>nomatch</c> is returned.</p> + <c><anno>Pattern</anno></c> is found, the atom <c>nomatch</c> is returned.</p> - <p>For a description of <c>Pattern</c>, see + <p>For a description of <c><anno>Pattern</anno></c>, see <seealso marker="#compile_pattern-1">compile_pattern/1</seealso>.</p> <p>If <c>{scope, {Start,Length}}</c> is given in the options @@ -412,32 +344,21 @@ </desc> </func> <func> - <name>matches(Subject, Pattern) -> Found</name> + <name name="matches" arity="2"/> <fsummary>Searches for all matches of a pattern in a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pattern = binary() | [ binary() ] | cp()</v> - <v>Found = [ part() ] | []</v> - </type> <desc> - <p>The same as <c>matches(Subject, Pattern, [])</c>.</p> + <p>The same as <c>matches(<anno>Subject</anno>, <anno>Pattern</anno>, [])</c>.</p> </desc> </func> <func> - <name>matches(Subject,Pattern,Options) -> Found</name> + <name name="matches" arity="3"/> + <type name="part"/> <fsummary>Searches for all matches of a pattern in a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pattern = binary() | [ binary() ] | cp()</v> - <v>Found = [ part() ] | []</v> - <v>Options = [ Option ]</v> - <v>Option = {scope, part()}</v> - </type> <desc> - <p>Works like match, but the <c>Subject</c> is searched until + <p>Works like <c>match/2</c>, but the <c><anno>Subject</anno></c> is searched until exhausted and a list of all non-overlapping parts matching - <c>Pattern</c> is returned (in order). </p> + <c><anno>Pattern</anno></c> is returned (in order). </p> <p>The first and longest match is preferred to a shorter, which is illustrated by the following example:</p> @@ -458,26 +379,22 @@ <p>If none of the strings in pattern is found, an empty list is returned.</p> - <p>For a description of <c>Pattern</c>, see <seealso marker="#compile_pattern-1">compile_pattern/1</seealso> and for a + <p>For a description of <c><anno>Pattern</anno></c>, see <seealso marker="#compile_pattern-1">compile_pattern/1</seealso> and for a description of available options, see <seealso marker="#match-3">match/3</seealso>.</p> - <p>If <c>{scope, {Start,Length}}</c> is given in the options such that - <c>Start</c> is larger than the size of <c>Subject</c>, <c>Start + Length</c> is - less than zero or <c>Start + Length</c> is larger than the size of - <c>Subject</c>, a <c>badarg</c> exception is raised.</p> + <p>If <c>{scope, {<anno>Start</anno>,<anno>Length</anno>}}</c> is given in the options such that + <c><anno>Start</anno></c> is larger than the size of <c><anno>Subject</anno></c>, <c><anno>Start</anno> + <anno>Length</anno></c> is + less than zero or <c><anno>Start</anno> + <anno>Length</anno></c> is larger than the size of + <c><anno>Subject</anno></c>, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>part(Subject, PosLen) -> binary()</name> + <name name="part" arity="2"/> <fsummary>Extracts a part of a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>PosLen = part()</v> - </type> <desc> - <p>Extracts the part of the binary <c>Subject</c> described by <c>PosLen</c>.</p> + <p>Extracts the part of the binary <c><anno>Subject</anno></c> described by <c><anno>PosLen</anno></c>.</p> <p>Negative length can be used to extract bytes at the end of a binary:</p> @@ -494,25 +411,20 @@ <c>binary_part/3</c>. Those BIFs are allowed in guard tests.</p> </note> - <p>If <c>PosLen</c> in any way references outside the binary, a <c>badarg</c> exception + <p>If <c><anno>PosLen</anno></c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> </desc> </func> <func> - <name>part(Subject, Pos, Len) -> binary()</name> + <name name="part" arity="3"/> <fsummary>Extracts a part of a binary</fsummary> - <type> - <v>Subject = binary()</v> - <v>Pos = integer() >= 0</v> - <v>Len = integer()</v> - </type> <desc> - <p>The same as <c>part(Subject, {Pos, Len})</c>.</p> + <p>The same as <c>part(<anno>Subject</anno>, {<anno>Pos</anno>, <anno>Len</anno>})</c>.</p> </desc> </func> <func> - <name>referenced_byte_size(binary()) -> integer() >= 0</name> + <name name="referenced_byte_size" arity="1"/> <fsummary>Determines the size of the actual binary pointed out by a sub-binary</fsummary> <desc> diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml index efd9514db6..27608e9176 100644 --- a/lib/stdlib/doc/src/ets.xml +++ b/lib/stdlib/doc/src/ets.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -128,11 +128,17 @@ <datatypes> <datatype> + <name name="access"/> + </datatype> + <datatype> <name><marker id="type-continuation">continuation()</marker></name> <desc> <p>Opaque continuation used by <seealso marker="#select/1"> - <c>select/1</c></seealso> and <seealso marker="#select/3"> - <c>select/3</c></seealso>.</p> + <c>select/1,3</c></seealso>, <seealso marker="#select_reverse/1"> + <c>select_reverse/1,3</c></seealso>, <seealso + marker="#match/1"> + <c>match/1,3</c></seealso>, and <seealso marker="#match_object/1"> + <c>match_object/1,3</c></seealso>.</p> </desc> </datatype> <datatype> @@ -149,14 +155,14 @@ <name name="tid"/> <desc><p>A table identifier, as returned by new/2.</p></desc> </datatype> + <datatype> + <name name="type"/> + </datatype> </datatypes> <funcs> <func> - <name>all() -> [Tab]</name> + <name name="all" arity="0"/> <fsummary>Return a list of all ETS tables.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - </type> <desc> <p>Returns a list of all tables at the node. Named tables are given by their names, unnamed tables are given by their @@ -164,48 +170,34 @@ </desc> </func> <func> - <name>delete(Tab) -> true</name> + <name name="delete" arity="1"/> <fsummary>Delete an entire ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - </type> <desc> - <p>Deletes the entire table <c>Tab</c>.</p> + <p>Deletes the entire table <c><anno>Tab</anno></c>.</p> </desc> </func> <func> - <name>delete(Tab, Key) -> true</name> + <name name="delete" arity="2"/> <fsummary>Delete all objects with a given key from an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - </type> <desc> - <p>Deletes all objects with the key <c>Key</c> from the table - <c>Tab</c>.</p> + <p>Deletes all objects with the key <c><anno>Key</anno></c> from the table + <c><anno>Tab</anno></c>.</p> </desc> </func> <func> - <name>delete_all_objects(Tab) -> true</name> + <name name="delete_all_objects" arity="1"/> <fsummary>Delete all objects in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - </type> <desc> - <p>Delete all objects in the ETS table <c>Tab</c>. + <p>Delete all objects in the ETS table <c><anno>Tab</anno></c>. The operation is guaranteed to be <seealso marker="#concurrency">atomic and isolated</seealso>.</p> </desc> </func> <func> - <name>delete_object(Tab,Object) -> true</name> + <name name="delete_object" arity="2"/> <fsummary>Deletes a specific from an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Object = tuple()</v> - </type> <desc> - <p>Delete the exact object <c>Object</c> from the ETS table, + <p>Delete the exact object <c><anno>Object</anno></c> from the ETS table, leaving objects with the same key but other differences (useful for type <c>bag</c>). In a <c>duplicate_bag</c>, all instances of the object will be deleted.</p> @@ -257,14 +249,10 @@ </desc> </func> <func> - <name>first(Tab) -> Key | '$end_of_table'</name> + <name name="first" arity="1"/> <fsummary>Return the first key in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - </type> <desc> - <p>Returns the first key <c>Key</c> in the table <c>Tab</c>. + <p>Returns the first key <c><anno>Key</anno></c> in the table <c><anno>Tab</anno></c>. If the table is of the <c>ordered_set</c> type, the first key in Erlang term order will be returned. If the table is of any other type, the first key according to the table's internal @@ -336,7 +324,7 @@ the source file.</p> <p>The fun is very restricted, it can take only a single parameter (the object to match): a sole variable or a - tuple. It needs to use the <c>is_</c>XXX guard tests. + tuple. It needs to use the <c>is_</c> guard tests. Language constructs that have no representation in a match_spec (like <c>if</c>, <c>case</c>, <c>receive</c> etc) are not allowed.</p> @@ -386,19 +374,14 @@ Error: fun containing local Erlang function calls </desc> </func> <func> - <name>give_away(Tab, Pid, GiftData) -> true</name> + <name name="give_away" arity="3"/> <fsummary>Change owner of a table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Pid = pid()</v> - <v>GiftData = term()</v> - </type> <desc> - <p>Make process <c>Pid</c> the new owner of table <c>Tab</c>. + <p>Make process <c><anno>Pid</anno></c> the new owner of table <c><anno>Tab</anno></c>. If successful, the message - <c>{'ETS-TRANSFER',Tab,FromPid,GiftData}</c> will be sent + <c>{'ETS-TRANSFER',<anno>Tab</anno>,FromPid,<anno>GiftData</anno>}</c> will be sent to the new owner.</p> - <p>The process <c>Pid</c> must be alive, local and not already the + <p>The process <c><anno>Pid</anno></c> must be alive, local and not already the owner of the table. The calling process must be the table owner.</p> <p>Note that <c>give_away</c> does not at all affect the <seealso marker="#heir">heir</seealso> option of the table. A table @@ -421,81 +404,72 @@ Error: fun containing local Erlang function calls </desc> </func> <func> - <name>info(Tab) -> [{Item, Value}] | undefined</name> + <name name="info" arity="1"/> <fsummary>Return information about an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Item = atom(), see below</v> - <v>Value = term(), see below</v> - </type> <desc> - <p>Returns information about the table <c>Tab</c> as a list of - <c>{Item, Value}</c> tuples. If <c>Tab</c> has the correct type + <p>Returns information about the table <c><anno>Tab</anno></c> as a list of + tuples. If <c><anno>Tab</anno></c> has the correct type for a table identifier, but does not refer to an existing ETS - table, <c>undefined</c> is returned. If <c>Tab</c> is not of the + table, <c>undefined</c> is returned. If <c><anno>Tab</anno></c> is not of the correct type, this function fails with reason <c>badarg</c>.</p> <list type="bulleted"> - <item><c>Item=memory, Value=integer()</c> <br></br> - - The number of words allocated to the table.</item> - <item><c>Item=owner, Value=pid()</c> <br></br> + <item><c>{compressed, boolean()}</c> <br></br> - The pid of the owner of the table.</item> - <item><c>Item=heir, Value=pid()|none</c> <br></br> + Indicates if the table is compressed or not.</item> + <item><c>{heir, pid() | none}</c> <br></br> The pid of the heir of the table, or <c>none</c> if no heir is set.</item> - <item><c>Item=name, Value=atom()</c> <br></br> + <item><c>{keypos, integer() >= 1}</c> <br></br> - The name of the table.</item> - <item><c>Item=size, Value=integer()</c> <br></br> + The key position.</item> + <item><c>{memory, integer() >= 0</c> <br></br> - The number of objects inserted in the table.</item> - <item><c>Item=node, Value=atom()</c> <br></br> + The number of words allocated to the table.</item> + <item><c>{name, atom()}</c> <br></br> - The node where the table is stored. This field is no longer - meaningful as tables cannot be accessed from other nodes.</item> - <item><c>Item=named_table, Value=true|false</c> <br></br> + The name of the table.</item> + <item><c>{named_table, boolean()}</c> <br></br> Indicates if the table is named or not.</item> - <item><c>Item=type, Value=set|ordered_set|bag|duplicate_bag</c> <br></br> + <item><c>{node, node()}</c> <br></br> - The table type.</item> - <item><c>Item=keypos, Value=integer()</c> <br></br> + The node where the table is stored. This field is no longer + meaningful as tables cannot be accessed from other nodes.</item> + <item><c>{owner, pid()}</c> <br></br> - The key position.</item> - <item><c>Item=protection, Value=public|protected|private</c> <br></br> + The pid of the owner of the table.</item> + <item><c>{protection, <seealso marker="#type-access">access()</seealso>}</c> <br></br> The table access rights.</item> - <item><c>Item=compressed, Value=true|false</c> <br></br> + <item><c>{size, integer() >= 0</c> <br></br> - Indicates if the table is compressed or not.</item> + The number of objects inserted in the table.</item> + <item><c>{type, <seealso marker="#type-type">type()</seealso>}</c> <br></br> + + The table type.</item> </list> </desc> </func> <func> - <name>info(Tab, Item) -> Value | undefined</name> + <name name="info" arity="2"/> <fsummary>Return the information associated with given item for an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Item, Value - see below</v> - </type> <desc> <p>Returns the information associated with <c>Item</c> for - the table <c>Tab</c>, or returns <c>undefined</c> if <c>Tab</c> + the table <c><anno>Tab</anno></c>, or returns <c>undefined</c> if <c>Tab</c> does not refer an existing ETS table. - If <c>Tab</c> is not of the correct type, or if <c>Item</c> is not + If <c><anno>Tab</anno></c> is not of the correct type, or if <c><anno>Item</anno></c> is not one of the allowed values, this function fails with reason <c>badarg</c>.</p> <warning><p>In R11B and earlier, this function would not fail but return <c>undefined</c> for invalid values for <c>Item</c>.</p> </warning> - <p>In addition to the <c>{Item,Value}</c> + <p>In addition to the <c>{<anno>Item</anno>,<anno>Value</anno>}</c> pairs defined for <c>info/1</c>, the following items are allowed:</p> <list type="bulleted"> - <item><c>Item=fixed, Value=true|false</c> <br></br> + <item><c>Item=fixed, Value=boolean()</c> <br></br> Indicates if the table is fixed by any process or not.</item> <item> @@ -547,15 +521,11 @@ Error: fun containing local Erlang function calls </desc> </func> <func> - <name>insert(Tab, ObjectOrObjects) -> true</name> + <name name="insert" arity="2"/> <fsummary>Insert an object into an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>ObjectOrObjects = tuple() | [tuple()]</v> - </type> <desc> <p>Inserts the object or all of the objects in the list - <c>ObjectOrObjects</c> into the table <c>Tab</c>. + <c><anno>ObjectOrObjects</anno></c> into the table <c><anno>Tab</anno></c>. If the table is a <c>set</c> and the key of the inserted objects <em>matches</em> the key of any object in the table, the old object will be replaced. If the table is an @@ -572,19 +542,15 @@ Error: fun containing local Erlang function calls </desc> </func> <func> - <name>insert_new(Tab, ObjectOrObjects) -> boolean()</name> + <name name="insert_new" arity="2"/> <fsummary>Insert an object into an ETS table if the key is not already present.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>ObjectOrObjects = tuple() | [tuple()]</v> - </type> <desc> <p>This function works exactly like <c>insert/2</c>, with the exception that instead of overwriting objects with the same key (in the case of <c>set</c> or <c>ordered_set</c>) or adding more objects with keys already existing in the table (in the case of <c>bag</c> and <c>duplicate_bag</c>), it - simply returns <c>false</c>. If <c>ObjectOrObjects</c> is a + simply returns <c>false</c>. If <c><anno>ObjectOrObjects</anno></c> is a list, the function checks <em>every</em> key prior to inserting anything. Nothing will be inserted if not <em>all</em> keys present in the list are absent from the @@ -593,11 +559,8 @@ Error: fun containing local Erlang function calls </desc> </func> <func> - <name>is_compiled_ms(Term) -> boolean()</name> + <name name="is_compiled_ms" arity="1"/> <fsummary>Checks if an Erlang term is the result of ets:match_spec_compile</fsummary> - <type> - <v>Term = term()</v> - </type> <desc> <p>This function is used to check if a term is a valid compiled <seealso marker="#match_spec">match_spec</seealso>. @@ -626,14 +589,10 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>last(Tab) -> Key | '$end_of_table'</name> + <name name="last" arity="1"/> <fsummary>Return the last key in an ETS table of type<c>ordered_set</c>.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - </type> <desc> - <p>Returns the last key <c>Key</c> according to Erlang term + <p>Returns the last key <c><anno>Key</anno></c> according to Erlang term order in the table <c>Tab</c> of the <c>ordered_set</c> type. If the table is of any other type, the function is synonymous to <c>first/2</c>. If the table is empty, @@ -642,16 +601,11 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>lookup(Tab, Key) -> [Object]</name> + <name name="lookup" arity="2"/> <fsummary>Return all objects with a given key in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - <v>Object = tuple()</v> - </type> <desc> - <p>Returns a list of all objects with the key <c>Key</c> in - the table <c>Tab</c>.</p> + <p>Returns a list of all objects with the key <c><anno>Key</anno></c> in + the table <c><anno>Tab</anno></c>.</p> <p>In the case of <c>set, bag and duplicate_bag</c>, an object is returned only if the given key <em>matches</em> the key of the object in the table. If the table is an @@ -681,22 +635,16 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>lookup_element(Tab, Key, Pos) -> Elem</name> + <name name="lookup_element" arity="3"/> <fsummary>Return the <c>Pos</c>:th element of all objects with a given key in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - <v>Pos = integer()</v> - <v>Elem = term() | [term()]</v> - </type> <desc> - <p>If the table <c>Tab</c> is of type <c>set</c> or - <c>ordered_set</c>, the function returns the <c>Pos</c>:th - element of the object with the key <c>Key</c>.</p> + <p>If the table <c><anno>Tab</anno></c> is of type <c>set</c> or + <c>ordered_set</c>, the function returns the <c><anno>Pos</anno></c>:th + element of the object with the key <c><anno>Key</anno></c>.</p> <p>If the table is of type <c>bag</c> or <c>duplicate_bag</c>, - the functions returns a list with the <c>Pos</c>:th element of - every object with the key <c>Key</c>.</p> - <p>If no object with the key <c>Key</c> exists, the function + the functions returns a list with the <c><anno>Pos</anno></c>:th element of + every object with the key <c><anno>Key</anno></c>.</p> + <p>If no object with the key <c><anno>Key</anno></c> exists, the function will exit with reason <c>badarg</c>.</p> <p>The difference between <c>set</c>, <c>bag</c> and <c>duplicate_bag</c> on one hand, and <c>ordered_set</c> on @@ -708,16 +656,11 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match(Tab, Pattern) -> [Match]</name> + <name name="match" arity="2"/> <fsummary>Match the objects in an ETS table against a pattern.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Pattern = tuple()</v> - <v>Match = [term()]</v> - </type> <desc> - <p>Matches the objects in the table <c>Tab</c> against the - pattern <c>Pattern</c>.</p> + <p>Matches the objects in the table <c><anno>Tab</anno></c> against the + pattern <c><anno>Pattern</anno></c>.</p> <p>A pattern is a term that may contain:</p> <list type="bulleted"> <item>bound parts (Erlang terms),</item> @@ -744,18 +687,12 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match(Tab, Pattern, Limit) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="match" arity="3"/> <fsummary>Match the objects in an ETS table against a pattern and returns part of the answers.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Pattern = tuple()</v> - <v>Match = [term()]</v> - <v>Continuation = term()</v> - </type> <desc> <p>Works like <c>ets:match/2</c> but only returns a limited - (<c>Limit</c>) number of matching objects. The - <c>Continuation</c> term can then be used in subsequent calls + (<c><anno>Limit</anno></c>) number of matching objects. The + <c><anno>Continuation</anno></c> term can then be used in subsequent calls to <c>ets:match/1</c> to get the next chunk of matching objects. This is a space efficient way to work on objects in a table which is still faster than traversing the table object @@ -764,16 +701,12 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match(Continuation) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="match" arity="1"/> <fsummary>Continues matching objects in an ETS table.</fsummary> - <type> - <v>Match = [term()]</v> - <v>Continuation = term()</v> - </type> <desc> <p>Continues a match started with <c>ets:match/3</c>. The next chunk of the size given in the initial <c>ets:match/3</c> - call is returned together with a new <c>Continuation</c> + call is returned together with a new <c><anno>Continuation</anno></c> that can be used in subsequent calls to this function.</p> <p><c>'$end_of_table'</c> is returned when there are no more objects in the table.</p> @@ -789,15 +722,11 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match_object(Tab, Pattern) -> [Object]</name> + <name name="match_object" arity="2"/> <fsummary>Match the objects in an ETS table against a pattern.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Pattern = Object = tuple()</v> - </type> <desc> - <p>Matches the objects in the table <c>Tab</c> against the - pattern <c>Pattern</c>. See <c>match/2</c> for a description + <p>Matches the objects in the table <c><anno>Tab</anno></c> against the + pattern <c><anno>Pattern</anno></c>. See <c>match/2</c> for a description of patterns. The function returns a list of all objects which match the pattern.</p> <p>If the key is specified in the pattern, the match is very @@ -809,18 +738,12 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match_object(Tab, Pattern, Limit) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="match_object" arity="3"/> <fsummary>Match the objects in an ETS table against a pattern and returns part of the answers.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Pattern = tuple()</v> - <v>Match = [term()]</v> - <v>Continuation = term()</v> - </type> <desc> <p>Works like <c>ets:match_object/2</c> but only returns a - limited (<c>Limit</c>) number of matching objects. The - <c>Continuation</c> term can then be used in subsequent calls + limited (<c><anno>Limit</anno></c>) number of matching objects. The + <c><anno>Continuation</anno></c> term can then be used in subsequent calls to <c>ets:match_object/1</c> to get the next chunk of matching objects. This is a space efficient way to work on objects in a table which is still faster than traversing the table object @@ -829,29 +752,23 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match_object(Continuation) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="match_object" arity="1"/> <fsummary>Continues matching objects in an ETS table.</fsummary> - <type> - <v>Match = [term()]</v> - <v>Continuation = term()</v> - </type> <desc> <p>Continues a match started with <c>ets:match_object/3</c>. The next chunk of the size given in the initial <c>ets:match_object/3</c> call is returned together with a - new <c>Continuation</c> that can be used in subsequent calls + new <c><anno>Continuation</anno></c> that can be used in subsequent calls to this function.</p> <p><c>'$end_of_table'</c> is returned when there are no more objects in the table.</p> </desc> </func> <func> - <name>match_spec_compile(MatchSpec) -> CompiledMatchSpec</name> + <name name="match_spec_compile" arity="1"/> + <type name="comp_match_spec"/> + <type_desc name="comp_match_spec">A compiled match specification.</type_desc> <fsummary>Compiles a match specification into its internal representation</fsummary> - <type> - <v>MatchSpec = match_spec()</v> - <v>CompiledMatchSpec = comp_match_spec()</v> - </type> <desc> <p>This function transforms a <seealso marker="#match_spec">match_spec</seealso> into an @@ -863,7 +780,7 @@ ets:is_compiled_ms(Broken).</code> valid compiled match_spec, nor can it be stored on disk). The validity of a compiled match_spec can be checked using <c>ets:is_compiled_ms/1</c>.</p> - <p>If the term <c>MatchSpec</c> can not be compiled (does not + <p>If the term <c><anno>MatchSpec</anno></c> can not be compiled (does not represent a valid match_spec), a <c>badarg</c> fault is thrown.</p> <note> @@ -873,25 +790,23 @@ ets:is_compiled_ms(Broken).</code> </desc> </func> <func> - <name>match_spec_run(List,CompiledMatchSpec) -> list()</name> + <name name="match_spec_run" arity="2"/> + <type name="comp_match_spec"/> + <type_desc name="comp_match_spec">A compiled match specification.</type_desc> <fsummary>Performs matching, using a compiled match_spec, on a list of tuples</fsummary> - <type> - <v>List = [ tuple() ]</v> - <v>CompiledMatchSpec = comp_match_spec()</v> - </type> <desc> <p>This function executes the matching specified in a compiled <seealso marker="#match_spec">match_spec</seealso> on - a list of tuples. The <c>CompiledMatchSpec</c> term should be + a list of tuples. The <c><anno>CompiledMatchSpec</anno></c> term should be the result of a call to <c>ets:match_spec_compile/1</c> and is hence the internal representation of the match_spec one wants to use.</p> - <p>The matching will be executed on each element in <c>List</c> + <p>The matching will be executed on each element in <c><anno>List</anno></c> and the function returns a list containing all results. If an - element in <c>List</c> does not match, nothing is returned + element in <c><anno>List</anno></c> does not match, nothing is returned for that element. The length of the result list is therefore equal or less than the the length of the parameter - <c>List</c>. The two calls in the following example will give + <c><anno>List</anno></c>. The two calls in the following example will give the same result (but certainly not the same execution time...):</p> <code type="none"> @@ -910,37 +825,23 @@ ets:select(Table,MatchSpec),</code> </desc> </func> <func> - <name>member(Tab, Key) -> true | false</name> + <name name="member" arity="2"/> <fsummary>Tests for occurrence of a key in an ETS table</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - </type> <desc> <p>Works like <c>lookup/2</c>, but does not return the objects. The function returns <c>true</c> if one or more elements in - the table has the key <c>Key</c>, <c>false</c> otherwise.</p> + the table has the key <c><anno>Key</anno></c>, <c>false</c> otherwise.</p> </desc> </func> <func> - <name>new(Name, Options) -> tid() | atom()</name> + <name name="new" arity="2"/> <fsummary>Create a new ETS table.</fsummary> - <type> - <v>Name = atom()</v> - <v>Options = [Option]</v> - <v> Option = Type | Access | named_table | {keypos,Pos} | {heir,pid(),HeirData} | {heir,none} | Tweaks</v> - <v> Type = set | ordered_set | bag | duplicate_bag</v> - <v> Access = public | protected | private</v> - <v> Tweaks = {write_concurrency,boolean()} | {read_concurrency,boolean()} | compressed</v> - <v> Pos = integer()</v> - <v> HeirData = term()</v> - </type> <desc> <p>Creates a new table and returns a table identifier which can be used in subsequent operations. The table identifier can be sent to other processes so that a table can be shared between different processes within a node.</p> - <p>The parameter <c>Options</c> is a list of atoms which + <p>The parameter <c><anno>Options</anno></c> is a list of atoms which specifies table type, access rights, key position and if the table is named or not. If one or more options are left out, the default values are used. This means that not specifying @@ -997,27 +898,27 @@ ets:select(Table,MatchSpec),</code> </item> <item> <p><c>named_table</c> - If this option is present, the name <c>Name</c> is + If this option is present, the name <c><anno>Name</anno></c> is associated with the table identifier. The name can then be used instead of the table identifier in subsequent operations.</p> </item> <item> - <p><c>{keypos,Pos}</c> + <p><c>{keypos,<anno>Pos</anno>}</c> Specfies which element in the stored tuples should be used as key. By default, it is the first element, i.e. - <c>Pos=1</c>. However, this is not always appropriate. In + <c><anno>Pos</anno>=1</c>. However, this is not always appropriate. In particular, we do not want the first element to be the key if we want to store Erlang records in a table.</p> <p>Note that any tuple stored in the table must have at - least <c>Pos</c> number of elements.</p> + least <c><anno>Pos</anno></c> number of elements.</p> </item> <item> <marker id="heir"></marker> - <p><c>{heir,Pid,HeirData} | {heir,none}</c><br></br> + <p><c>{heir,<anno>Pid</anno>,<anno>HeirData</anno>} | {heir,none}</c><br></br> Set a process as heir. The heir will inherit the table if the owner terminates. The message - <c>{'ETS-TRANSFER',tid(),FromPid,HeirData}</c> will be sent to + <c>{'ETS-TRANSFER',tid(),FromPid,<anno>HeirData</anno>}</c> will be sent to the heir when that happens. The heir must be a local process. Default heir is <c>none</c>, which will destroy the table when the owner terminates.</p> @@ -1082,15 +983,11 @@ ets:select(Table,MatchSpec),</code> </desc> </func> <func> - <name>next(Tab, Key1) -> Key2 | '$end_of_table'</name> + <name name="next" arity="2"/> <fsummary>Return the next key in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key1 = Key2 = term()</v> - </type> <desc> - <p>Returns the next key <c>Key2</c>, following the key - <c>Key1</c> in the table <c>Tab</c>. If the table is of the + <p>Returns the next key <c><anno>Key2</anno></c>, following the key + <c><anno>Key1</anno></c> in the table <c><anno>Tab</anno></c>. If the table is of the <c>ordered_set</c> type, the next key in Erlang term order is returned. If the table is of any other type, the next key according to the table's internal order is returned. If there @@ -1105,16 +1002,12 @@ ets:select(Table,MatchSpec),</code> </desc> </func> <func> - <name>prev(Tab, Key1) -> Key2 | '$end_of_table'</name> + <name name="prev" arity="2"/> <fsummary>Return the previous key in an ETS table of type<c>ordered_set</c>.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key1 = Key2 = term()</v> - </type> <desc> - <p>Returns the previous key <c>Key2</c>, preceding the key - <c>Key1</c> according the Erlang term order in the table - <c>Tab</c> of the <c>ordered_set</c> type. If the table is of + <p>Returns the previous key <c><anno>Key2</anno></c>, preceding the key + <c><anno>Key1</anno></c> according the Erlang term order in the table + <c><anno>Tab</anno></c> of the <c>ordered_set</c> type. If the table is of any other type, the function is synonymous to <c>next/2</c>. If there is no previous key, <c>'$end_of_table'</c> is returned.</p> @@ -1122,14 +1015,11 @@ ets:select(Table,MatchSpec),</code> </desc> </func> <func> - <name>rename(Tab, Name) -> Name</name> + <name name="rename" arity="2"/> <fsummary>Rename a named ETS table.</fsummary> - <type> - <v>Tab = Name = atom()</v> - </type> <desc> - <p>Renames the named table <c>Tab</c> to the new name - <c>Name</c>. Afterwards, the old name can not be used to + <p>Renames the named table <c><anno>Tab</anno></c> to the new name + <c><anno>Name</anno></c>. Afterwards, the old name can not be used to access the table. Renaming an unnamed table has no effect.</p> </desc> </func> @@ -1186,18 +1076,15 @@ ets:select(ets:repair_continuation(Broken,MS)).</code> </desc> </func> <func> - <name>safe_fixtable(Tab, true|false) -> true</name> + <name name="safe_fixtable" arity="2"/> <fsummary>Fix an ETS table for safe traversal.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - </type> <desc> <p>Fixes a table of the <c>set</c>, <c>bag</c> or <c>duplicate_bag</c> table type for safe traversal.</p> <p>A process fixes a table by calling - <c>safe_fixtable(Tab,true)</c>. The table remains fixed until + <c>safe_fixtable(<anno>Tab</anno>, true)</c>. The table remains fixed until the process releases it by calling - <c>safe_fixtable(Tab,false)</c>, or until the process + <c>safe_fixtable(<anno>Tab</anno>, false)</c>, or until the process terminates.</p> <p>If several processes fix a table, the table will remain fixed until all processes have released it (or terminated). @@ -1242,15 +1129,10 @@ clean_all_with_value(Tab,X,Key) -> </desc> </func> <func> - <name>select(Tab, MatchSpec) -> [Match]</name> + <name name="select" arity="2"/> <fsummary>Match the objects in an ETS table against a match_spec.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Match = term()</v> - <v>MatchSpec = match_spec()</v> - </type> <desc> - <p>Matches the objects in the table <c>Tab</c> using a + <p>Matches the objects in the table <c><anno>Tab</anno></c> using a <seealso marker="#match_spec">match_spec</seealso>. This is a more general call than the <c>ets:match/2</c> and <c>ets:match_object/2</c> calls. In its simplest forms the @@ -1337,18 +1219,12 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>select(Tab, MatchSpec, Limit) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="select" arity="3"/> <fsummary>Match the objects in an ETS table against a match_spec and returns part of the answers.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Match = term()</v> - <v>MatchSpec = match_spec()</v> - <v>Continuation = term()</v> - </type> <desc> <p>Works like <c>ets:select/2</c> but only returns a limited - (<c>Limit</c>) number of matching objects. The - <c>Continuation</c> term can then be used in subsequent calls + (<c><anno>Limit</anno></c>) number of matching objects. The + <c><anno>Continuation</anno></c> term can then be used in subsequent calls to <c>ets:select/1</c> to get the next chunk of matching objects. This is a space efficient way to work on objects in a table which is still faster than traversing the table object @@ -1357,33 +1233,23 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>select(Continuation) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="select" arity="1"/> <fsummary>Continue matching objects in an ETS table.</fsummary> - <type> - <v>Match = term()</v> - <v>Continuation = term()</v> - </type> <desc> <p>Continues a match started with <c>ets:select/3</c>. The next chunk of the size given in the initial <c>ets:select/3</c> - call is returned together with a new <c>Continuation</c> + call is returned together with a new <c><anno>Continuation</anno></c> that can be used in subsequent calls to this function.</p> <p><c>'$end_of_table'</c> is returned when there are no more objects in the table.</p> </desc> </func> <func> - <name>select_count(Tab, MatchSpec) -> NumMatched</name> + <name name="select_count" arity="2"/> <fsummary>Match the objects in an ETS table against a match_spec and returns the number of objects for which the match_spec returned 'true'</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Object = tuple()</v> - <v>MatchSpec = match_spec()</v> - <v>NumMatched = integer()</v> - </type> <desc> - <p>Matches the objects in the table <c>Tab</c> using a + <p>Matches the objects in the table <c><anno>Tab</anno></c> using a <seealso marker="#match_spec">match_spec</seealso>. If the match_spec returns <c>true</c> for an object, that object considered a match and is counted. For any other result from @@ -1396,16 +1262,10 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>select_delete(Tab, MatchSpec) -> NumDeleted</name> + <name name="select_delete" arity="2"/> <fsummary>Match the objects in an ETS table against a match_spec and deletes objects where the match_spec returns 'true'</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Object = tuple()</v> - <v>MatchSpec = match_spec()</v> - <v>NumDeleted = integer()</v> - </type> <desc> - <p>Matches the objects in the table <c>Tab</c> using a + <p>Matches the objects in the table <c><anno>Tab</anno></c> using a <seealso marker="#match_spec">match_spec</seealso>. If the match_spec returns <c>true</c> for an object, that object is removed from the table. For any other result from the @@ -1422,13 +1282,8 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>select_reverse(Tab, MatchSpec) -> [Match]</name> + <name name="select_reverse" arity="2"/> <fsummary>Match the objects in an ETS table against a match_spec.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Match = term()</v> - <v>MatchSpec = match_spec()</v> - </type> <desc> <p>Works like <c>select/2</c>, but returns the list in reverse @@ -1438,14 +1293,8 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>select_reverse(Tab, MatchSpec, Limit) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="select_reverse" arity="3"/> <fsummary>Match the objects in an ETS table against a match_spec and returns part of the answers.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Match = term()</v> - <v>MatchSpec = match_spec()</v> - <v>Continuation = term()</v> - </type> <desc> <p>Works like <c>select/3</c>, but for the <c>ordered_set</c> @@ -1456,18 +1305,14 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> <p>Note that this is <em>not</em> equivalent to reversing the result list of a <c>select/3</c> call, as the result list - is not only reversed, but also contains the last <c>Limit</c> + is not only reversed, but also contains the last <c><anno>Limit</anno></c> matching objects in the table, not the first.</p> </desc> </func> <func> - <name>select_reverse(Continuation) -> {[Match],Continuation} | '$end_of_table'</name> + <name name="select_reverse" arity="1"/> <fsummary>Continue matching objects in an ETS table.</fsummary> - <type> - <v>Match = term()</v> - <v>Continuation = term()</v> - </type> <desc> <p>Continues a match started with @@ -1477,7 +1322,7 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> returned list will also contain objects with keys in reverse order.</p> - <p>For all other table types, the behaviour is exatly that of <c>select/1</c>.</p> + <p>For all other table types, the behaviour is exactly that of <c>select/1</c>.</p> <p>Example:</p> <code> 1> T = ets:new(x,[ordered_set]). @@ -1501,14 +1346,8 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>setopts(Tab, Opts) -> true</name> + <name name="setopts" arity="2"/> <fsummary>Set table options.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Opts = Opt | [Opt]</v> - <v>Opt = {heir,pid(),HeirData} | {heir,none}</v> - <v>HeirData = term()</v> - </type> <desc> <p>Set table options. The only option that currently is allowed to be set after the table has been created is @@ -1517,28 +1356,23 @@ is_integer(X), is_integer(Y), X + Y < 4711]]></code> </desc> </func> <func> - <name>slot(Tab, I) -> [Object] | '$end_of_table'</name> + <name name="slot" arity="2"/> <fsummary>Return all objects in a given slot of an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>I = integer()</v> - <v>Object = tuple()</v> - </type> <desc> <p>This function is mostly for debugging purposes, Normally one should use <c>first/next</c> or <c>last/prev</c> instead.</p> - <p>Returns all objects in the <c>I</c>:th slot of the table - <c>Tab</c>. A table can be traversed by repeatedly calling - the function, starting with the first slot <c>I=0</c> and + <p>Returns all objects in the <c><anno>I</anno></c>:th slot of the table + <c><anno>Tab</anno></c>. A table can be traversed by repeatedly calling + the function, starting with the first slot <c><anno>I</anno>=0</c> and ending when <c>'$end_of_table'</c> is returned. The function will fail with reason <c>badarg</c> if the - <c>I</c> argument is out of range.</p> + <c><anno>I</anno></c> argument is out of range.</p> <p>Unless a table of type <c>set</c>, <c>bag</c> or <c>duplicate_bag</c> is protected using <c>safe_fixtable/2</c>, see above, a traversal may fail if concurrent updates are made to the table. If the table is of type <c>ordered_set</c>, the function returns a list - containing the <c>I</c>:th object in Erlang term order.</p> + containing the <c><anno>I</anno></c>:th object in Erlang term order.</p> </desc> </func> <func> @@ -1754,16 +1588,16 @@ true</pre> </desc> </func> <func> - <name>update_counter(Tab, Key, UpdateOp) -> Result</name> - <name>update_counter(Tab, Key, [UpdateOp]) -> [Result]</name> - <name>update_counter(Tab, Key, Incr) -> Result</name> + <name name="update_counter" arity="3" clause_i="1"/> + <name name="update_counter" arity="3" clause_i="2"/> + <name name="update_counter" arity="3" clause_i="3"/> + <type variable="Tab"/> + <type variable="Key"/> + <type variable="UpdateOp" name_i="1"/> + <type variable="Pos" name_i="1"/> + <type variable="Threshold" name_i="1"/> + <type variable="SetValue" name_i="1"/> <fsummary>Update a counter object in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = term()</v> - <v>UpdateOp = {Pos,Incr} | {Pos,Incr,Threshold,SetValue}</v> - <v>Pos = Incr = Threshold = SetValue = Result = integer()</v> - </type> <desc> <p>This function provides an efficient way to update one or more counters, without the hassle of having to look up an object, update @@ -1771,22 +1605,22 @@ true</pre> into the table again. (The update is done atomically; i.e. no process can access the ets table in the middle of the operation.) </p> - <p>It will destructively update the object with key <c>Key</c> - in the table <c>Tab</c> by adding <c>Incr</c> to the element - at the <c>Pos</c>:th position. The new counter value is + <p>It will destructively update the object with key <c><anno>Key</anno></c> + in the table <c><anno>Tab</anno></c> by adding <c><anno>Incr</anno></c> to the element + at the <c><anno>Pos</anno></c>:th position. The new counter value is returned. If no position is specified, the element directly following the key (<c><![CDATA[<keypos>+1]]></c>) is updated.</p> - <p>If a <c>Threshold</c> is specified, the counter will be - reset to the value <c>SetValue</c> if the following + <p>If a <c><anno>Threshold</anno></c> is specified, the counter will be + reset to the value <c><anno>SetValue</anno></c> if the following conditions occur:</p> <list type="bulleted"> - <item>The <c>Incr</c> is not negative (<c>>= 0</c>) and the - result would be greater than (<c>></c>) <c>Threshold</c></item> - <item>The <c>Incr</c> is negative (<c><![CDATA[< 0]]></c>) and the + <item>The <c><anno>Incr</anno></c> is not negative (<c>>= 0</c>) and the + result would be greater than (<c>></c>) <c><anno>Threshold</anno></c></item> + <item>The <c><anno>Incr</anno></c> is negative (<c><![CDATA[< 0]]></c>) and the result would be less than (<c><![CDATA[<]]></c>) - <c>Threshold</c></item> + <c><anno>Threshold</anno></c></item> </list> - <p>A list of <c>UpdateOp</c> can be supplied to do several update + <p>A list of <c><anno>UpdateOp</anno></c> can be supplied to do several update operations within the object. The operations are carried out in the order specified in the list. If the same counter position occurs more than one time in the list, the corresponding counter will thus @@ -1797,7 +1631,7 @@ true</pre> returned. If the function should fail, no updates will be done at all. </p> - <p>The given Key is used to identify the object by either + <p>The given <c><anno>Key</anno></c> is used to identify the object by either <em>matching</em> the key of an object in a <c>set</c> table, or <em>compare equal</em> to the key of an object in an <c>ordered_set</c> table (see @@ -1812,29 +1646,28 @@ true</pre> <item>the object has the wrong arity,</item> <item>the element to update is not an integer,</item> <item>the element to update is also the key, or,</item> - <item>any of <c>Pos</c>, <c>Incr</c>, <c>Threshold</c> or - <c>SetValue</c> is not an integer</item> + <item>any of <c><anno>Pos</anno></c>, <c><anno>Incr</anno></c>, <c><anno>Threshold</anno></c> or + <c><anno>SetValue</anno></c> is not an integer</item> </list> </desc> </func> <func> - <name>update_element(Tab, Key, {Pos,Value}) -> true | false</name> - <name>update_element(Tab, Key, [{Pos,Value}]) -> true | false</name> + <name name="update_element" arity="3" clause_i="1"/> + <name name="update_element" arity="3" clause_i="2"/> + <type variable="Tab"/> + <type variable="Key"/> + <type variable="Value"/> + <type variable="Pos"/> <fsummary>Updates the <c>Pos</c>:th element of the object with a given key in an ETS table.</fsummary> - <type> - <v>Tab = tid() | atom()</v> - <v>Key = Value = term()</v> - <v>Pos = integer()</v> - </type> <desc> <p>This function provides an efficient way to update one or more elements within an object, without the hassle of having to look up, update and write back the entire object. </p> - <p>It will destructively update the object with key <c>Key</c> - in the table <c>Tab</c>. The element at the <c>Pos</c>:th position - will be given the value <c>Value</c>. </p> - <p>A list of <c>{Pos,Value}</c> can be supplied to update several + <p>It will destructively update the object with key <c><anno>Key</anno></c> + in the table <c><anno>Tab</anno></c>. The element at the <c><anno>Pos</anno></c>:th position + will be given the value <c><anno>Value</anno></c>. </p> + <p>A list of <c>{<anno>Pos</anno>,<anno>Value</anno>}</c> can be supplied to update several elements within the same object. If the same position occurs more than one in the list, the last value in the list will be written. If the list is empty or the function fails, no updates will be done at @@ -1842,9 +1675,9 @@ true</pre> can never see any intermediate results. </p> <p>The function returns <c>true</c> if an object with the key - <c>Key</c> was found, <c>false</c> otherwise. + <c><anno>Key</anno></c> was found, <c>false</c> otherwise. </p> - <p>The given Key is used to identify the object by either + <p>The given <c><anno>Key</anno></c> is used to identify the object by either <em>matching</em> the key of an object in a <c>set</c> table, or <em>compare equal</em> to the key of an object in an <c>ordered_set</c> table (see @@ -1855,7 +1688,7 @@ true</pre> <list type="bulleted"> <item>the table is not of type <c>set</c> or <c>ordered_set</c>,</item> - <item><c>Pos</c> is less than 1 or greater than the object + <item><c><anno>Pos</anno></c> is less than 1 or greater than the object arity, or,</item> <item>the element to update is also the key</item> </list> diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml index 7042c84437..fc58f3e4d2 100644 --- a/lib/stdlib/doc/src/lists.xml +++ b/lib/stdlib/doc/src/lists.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -248,18 +248,13 @@ flatmap(Fun, List1) -> </desc> </func> <func> - <name>keyfind(Key, N, TupleList) -> Tuple | false</name> + <name name="keyfind" arity="3"/> + <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <fsummary>Search for an element in a list of tuples</fsummary> - <type> - <v>Key = term()</v> - <v>N = 1..tuple_size(Tuple)</v> - <v>TupleList = [Tuple]</v> - <v>Tuple = tuple()</v> - </type> - <desc> - <p>Searches the list of tuples <c>TupleList</c> for a - tuple whose <c>N</c>th element compares equal to <c>Key</c>. - Returns <c>Tuple</c> if such a tuple is found, + <desc> + <p>Searches the list of tuples <c><anno>TupleList</anno></c> for a + tuple whose <c><anno>N</anno></c>th element compares equal to <c><anno>Key</anno></c>. + Returns <c><anno>Tuple</anno></c> if such a tuple is found, otherwise <c>false</c>.</p> </desc> </func> @@ -281,17 +276,12 @@ flatmap(Fun, List1) -> </desc> </func> <func> - <name>keymember(Key, N, TupleList) -> boolean()</name> + <name name="keymember" arity="3"/> + <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <fsummary>Test for membership of a list of tuples</fsummary> - <type> - <v>Key = term()</v> - <v>N = 1..tuple_size(Tuple)</v> - <v>TupleList = [Tuple]</v> - <v> Tuple = tuple()</v> - </type> - <desc> - <p>Returns <c>true</c> if there is a tuple in <c>TupleList</c> - whose <c>N</c>th element compares equal to <c>Key</c>, otherwise + <desc> + <p>Returns <c>true</c> if there is a tuple in <c><anno>TupleList</anno></c> + whose <c><anno>N</anno></c>th element compares equal to <c><anno>Key</anno></c>, otherwise <c>false</c>.</p> </desc> </func> @@ -321,18 +311,13 @@ flatmap(Fun, List1) -> </desc> </func> <func> - <name>keysearch(Key, N, TupleList) -> {value, Tuple} | false</name> + <name name="keysearch" arity="3"/> + <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <fsummary>Search for an element in a list of tuples</fsummary> - <type> - <v>Key = term()</v> - <v>N = 1..tuple_size(Tuple)</v> - <v>TupleList = [Tuple]</v> - <v>Tuple = tuple()</v> - </type> - <desc> - <p>Searches the list of tuples <c>TupleList</c> for a - tuple whose <c>N</c>th element compares equal to <c>Key</c>. - Returns <c>{value, Tuple}</c> if such a tuple is found, + <desc> + <p>Searches the list of tuples <c><anno>TupleList</anno></c> for a + tuple whose <c><anno>N</anno></c>th element compares equal to <c><anno>Key</anno></c>. + Returns <c>{value, <anno>Tuple</anno>}</c> if such a tuple is found, otherwise <c>false</c>.</p> <note><p>This function is retained for backward compatibility. The function <c>lists:keyfind/3</c> (introduced in R13A) @@ -425,15 +410,11 @@ flatmap(Fun, List1) -> </desc> </func> <func> - <name>member(Elem, List) -> boolean()</name> + <name name="member" arity="2"/> <fsummary>Test for membership of a list</fsummary> - <type> - <v>Elem = term()</v> - <v>List = [term()]</v> - </type> <desc> - <p>Returns <c>true</c> if <c>Elem</c> matches some element of - <c>List</c>, otherwise <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Elem</anno></c> matches some element of + <c><anno>List</anno></c>, otherwise <c>false</c>.</p> </desc> </func> <func> @@ -562,14 +543,11 @@ c</pre> </desc> </func> <func> - <name>reverse(List1, Tail) -> List2</name> + <name name="reverse" arity="2"/> <fsummary>Reverse a list appending a tail</fsummary> - <type> - <v>List1 = Tail = List2 = [term()]</v> - </type> <desc> - <p>Returns a list with the elements in <c>List1</c> - in reverse order, with the tail <c>Tail</c> appended. For + <p>Returns a list with the elements in <c><anno>List1</anno></c> + in reverse order, with the tail <c><anno>Tail</anno></c> appended. For example:</p> <pre> > <input>lists:reverse([1, 2, 3, 4], [a, b, c]).</input> diff --git a/lib/stdlib/doc/src/math.xml b/lib/stdlib/doc/src/math.xml index 518457d5d8..0219dcce10 100644 --- a/lib/stdlib/doc/src/math.xml +++ b/lib/stdlib/doc/src/math.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>1996</year> - <year>2011</year> + <year>2012</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -52,54 +52,47 @@ </desc> </func> <func> - <name>sin(X)</name> - <name>cos(X)</name> - <name>tan(X)</name> - <name>asin(X)</name> - <name>acos(X)</name> - <name>atan(X)</name> - <name>atan2(Y, X)</name> - <name>sinh(X)</name> - <name>cosh(X)</name> - <name>tanh(X)</name> - <name>asinh(X)</name> - <name>acosh(X)</name> - <name>atanh(X)</name> - <name>exp(X)</name> - <name>log(X)</name> - <name>log10(X)</name> - <name>pow(X, Y)</name> - <name>sqrt(X)</name> + <name name="sin" arity="1"/> + <name name="cos" arity="1"/> + <name name="tan" arity="1"/> + <name name="asin" arity="1"/> + <name name="acos" arity="1"/> + <name name="atan" arity="1"/> + <name name="atan2" arity="2"/> + <name name="sinh" arity="1"/> + <name name="cosh" arity="1"/> + <name name="tanh" arity="1"/> + <name name="asinh" arity="1"/> + <name name="acosh" arity="1"/> + <name name="atanh" arity="1"/> + <name name="exp" arity="1"/> + <name name="log" arity="1"/> + <name name="log10" arity="1"/> + <name name="pow" arity="2"/> + <name name="sqrt" arity="1"/> + <type variable="X" name_i="7"/> + <type variable="Y" name_i="7"/> <fsummary>Diverse math functions</fsummary> - <type> - <v>X = Y = number()</v> - </type> <desc> <p>A collection of math functions which return floats. Arguments are numbers. </p> </desc> </func> <func> - <name>erf(X) -> float()</name> + <name name="erf" arity="1"/> <fsummary>Error function.</fsummary> - <type> - <v>X = number()</v> - </type> <desc> - <p>Returns the error function of <c>X</c>, where</p> + <p>Returns the error function of <c><anno>X</anno></c>, where</p> <pre> erf(X) = 2/sqrt(pi)*integral from 0 to X of exp(-t*t) dt. </pre> </desc> </func> <func> - <name>erfc(X) -> float()</name> + <name name="erfc" arity="1"/> <fsummary>Another error function</fsummary> - <type> - <v>X = number()</v> - </type> <desc> <p><c>erfc(X)</c> returns <c>1.0 - erf(X)</c>, computed by - methods that avoid cancellation for large <c>X</c>. </p> + methods that avoid cancellation for large <c><anno>X</anno></c>. </p> </desc> </func> </funcs> diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml index 6d5336796c..c6f45fb1e1 100644 --- a/lib/stdlib/doc/src/re.xml +++ b/lib/stdlib/doc/src/re.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2007</year> - <year>2011</year> + <year>2012</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -78,28 +78,15 @@ </datatypes> <funcs> <func> - <name>compile(Regexp) -> {ok, MP} | {error, ErrSpec}</name> + <name name="compile" arity="1"/> <fsummary>Compile a regular expression into a match program</fsummary> - <type> - <v>Regexp = iodata()</v> - </type> <desc> - <p>The same as <c>compile(Regexp,[])</c></p> + <p>The same as <c>compile(<anno>Regexp</anno>,[])</c></p> </desc> </func> <func> - <name>compile(Regexp,Options) -> {ok, MP} | {error, ErrSpec}</name> + <name name="compile" arity="2"/> <fsummary>Compile a regular expression into a match program</fsummary> - <type> - <v>Regexp = iodata() | <seealso marker="unicode#type-charlist">io:charlist()</seealso></v> - <v>Options = [ Option ]</v> - <v>Option = <seealso marker="#type-compile_option">compile_option()</seealso></v> - <v>NLSpec = <seealso marker="#type-nl_spec">nl_spec()</seealso></v> - <v>MP = <seealso marker="#type-mp">mp()</seealso></v> - <v>ErrSpec = {ErrString, Position}</v> - <v>ErrString = string()</v> - <v>Position = non_neg_integer()</v> - </type> <desc> <p>This function compiles a regular expression with the syntax described below into an internal format to be used later as a @@ -165,44 +152,23 @@ This option makes it possible to include comments inside complicated patterns. N </func> <func> - <name>run(Subject,RE) -> {match, Captured} | nomatch</name> + <name name="run" arity="2"/> <fsummary>Match a subject against regular expression and capture subpatterns</fsummary> - <type> - <v>Subject = iodata() | <seealso marker="unicode#type-charlist">io:charlist()</seealso></v> - <v>RE = <seealso marker="#type-mp">mp()</seealso> | iodata()</v> - <v>Captured = [ CaptureData ]</v> - <v>CaptureData = {integer(),integer()}</v> - </type> <desc> - <p>The same as <c>run(Subject,RE,[])</c>.</p> + <p>The same as <c>run(<anno>Subject</anno>,<anno>RE</anno>,[])</c>.</p> </desc> </func> <func> - <name>run(Subject,RE,Options) -> {match, Captured} | match | nomatch</name> + <name name="run" arity="3"/> + <type_desc variable="CompileOpt">See <seealso marker="#compile_options">compile/2</seealso> above.</type_desc> <fsummary>Match a subject against regular expression and capture subpatterns</fsummary> - <type> - <v>Subject = iodata() | <seealso marker="unicode#type-charlist">io:charlist()</seealso></v> - <v>RE = <seealso marker="#type-mp">mp()</seealso> | iodata() | <seealso marker="unicode#type-charlist">io:charlist()</seealso></v> - <v>Options = [ Option ]</v> - <v>Option = anchored | global | notbol | noteol | notempty | {offset, integer() >= 0} | {newline, NLSpec} | bsr_anycrlf | bsr_unicode | {capture, ValueSpec} | {capture, ValueSpec, Type} | CompileOpt</v> - <v>Type = index | list | binary</v> - <v>ValueSpec = all | all_but_first | first | none | ValueList</v> - <v>ValueList = [ ValueID ]</v> - <v>ValueID = integer() | string() | atom()</v> - <v>CompileOpt = <seealso marker="#type-compile_option">compile_option()</seealso></v> - <d>See <seealso marker="#compile_options">compile/2</seealso> above.</d> - <v>NLSpec = <seealso marker="#type-nl_spec">nl_spec()</seealso></v> - <v>Captured = [ CaptureData ] | [ [ CaptureData ] ... ]</v> - <v>CaptureData = {integer(),integer()} | ListConversionData | binary()</v> - <v>ListConversionData = string() | {error, string(), binary()} | {incomplete, string(), binary()}</v> - </type> <desc> <p>Executes a regexp matching, returning <c>match/{match, - Captured}</c> or <c>nomatch</c>. The regular expression can be + <anno>Captured</anno>}</c> or <c>nomatch</c>. The regular expression can be given either as <c>iodata()</c> in which case it is automatically compiled (as by <c>re:compile/2</c>) and executed, - or as a pre compiled <c>mp()</c> in which case it is executed + or as a pre-compiled <c>mp()</c> in which case it is executed against the subject directly.</p> <p>When compilation is involved, the exception <c>badarg</c> is @@ -214,23 +180,23 @@ This option makes it possible to include comments inside complicated patterns. N list can only contain the options <c>anchored</c>, <c>global</c>, <c>notbol</c>, <c>noteol</c>, <c>notempty</c>, <c>{offset, integer() >= 0}</c>, <c>{newline, - NLSpec}</c> and <c>{capture, ValueSpec}/{capture, ValueSpec, - Type}</c>. Otherwise all options valid for the + <anno>NLSpec</anno>}</c> and <c>{capture, <anno>ValueSpec</anno>}/{capture, <anno>ValueSpec</anno>, + <anno>Type</anno>}</c>. Otherwise all options valid for the <c>re:compile/2</c> function are allowed as well. Options allowed both for compilation and execution of a match, namely - <c>anchored</c> and <c>{newline, NLSpec}</c>, will affect both + <c>anchored</c> and <c>{newline, <anno>NLSpec</anno>}</c>, will affect both the compilation and execution if present together with a non pre-compiled regular expression.</p> <p>If the regular expression was previously compiled with the - option <c>unicode</c>, the <c>Subject</c> should be provided as + option <c>unicode</c>, the <c><anno>Subject</anno></c> should be provided as a valid Unicode <c>charlist()</c>, otherwise any <c>iodata()</c> will do. If compilation is involved and the option - <c>unicode</c> is given, both the <c>Subject</c> and the regular + <c>unicode</c> is given, both the <c><anno>Subject</anno></c> and the regular expression should be given as valid Unicode <c>charlists()</c>.</p> - <p>The <c>{capture, ValueSpec}/{capture, ValueSpec, Type}</c> + <p>The <c>{capture, <anno>ValueSpec</anno>}/{capture, <anno>ValueSpec</anno>, <anno>Type</anno>}</c> defines what to return from the function upon successful matching. The <c>capture</c> tuple may contain both a value specification telling which of the captured @@ -244,9 +210,9 @@ This option makes it possible to include comments inside complicated patterns. N at all is to be done (<c>{capture, none}</c>), the function will return the single atom <c>match</c> upon successful matching, otherwise the tuple - <c>{match, ValueList}</c> is returned. Disabling capturing can + <c>{match, <anno>ValueList</anno>}</c> is returned. Disabling capturing can be done either by specifying <c>none</c> or an empty list as - <c>ValueSpec</c>.</p> + <c><anno>ValueSpec</anno></c>.</p> <p>The options relevant for execution are:</p> @@ -266,7 +232,7 @@ This option makes it possible to include comments inside complicated patterns. N Perl). Each match is returned as a separate <c>list()</c> containing the specific match as well as any matching subexpressions (or as specified by the <c>capture - option</c>). The <c>Captured</c> part of the return value will + option</c>). The <c><anno>Captured</anno></c> part of the return value will hence be a <c>list()</c> of <c>list()</c>s when this option is given.</p> @@ -362,7 +328,7 @@ This option makes it possible to include comments inside complicated patterns. N subject string. The offset is zero-based, so that the default is <c>{offset,0}</c> (all of the subject string).</item> - <tag><c>{newline, NLSpec}</c></tag> + <tag><c>{newline, <anno>NLSpec</anno>}</c></tag> <item> <p>Override the default definition of a newline in the subject string, which is LF (ASCII 10) in Erlang.</p> <taglist> @@ -383,7 +349,7 @@ This option makes it possible to include comments inside complicated patterns. N <tag><c>bsr_unicode</c></tag> <item>Specifies specifically that \R is to match all the Unicode newline characters (including crlf etc, the default).(overrides compilation option)</item> - <tag><c>{capture, ValueSpec}</c>/<c>{capture, ValueSpec, Type}</c></tag> + <tag><c>{capture, <anno>ValueSpec</anno>}</c>/<c>{capture, <anno>ValueSpec</anno>, <anno>Type</anno>}</c></tag> <item> <p>Specifies which captured substrings are returned and in what @@ -392,7 +358,7 @@ This option makes it possible to include comments inside complicated patterns. N substring as well as all capturing subpatterns (all of the pattern is automatically captured). The default return type is (zero-based) indexes of the captured parts of the string, given as - <c>{Offset,Length}</c> pairs (the <c>index</c> <c>Type</c> of + <c>{Offset,Length}</c> pairs (the <c>index</c> <c><anno>Type</anno></c> of capturing).</p> <p>As an example of the default behavior, the following call:</p> @@ -422,8 +388,8 @@ This option makes it possible to include comments inside complicated patterns. N <p>The capture tuple is built up as follows:</p> <taglist> - <tag><c>ValueSpec</c></tag> - <item><p>Specifies which captured (sub)patterns are to be returned. The ValueSpec can either be an atom describing a predefined set of return values, or a list containing either the indexes or the names of specific subpatterns to return.</p> + <tag><c><anno>ValueSpec</anno></c></tag> + <item><p>Specifies which captured (sub)patterns are to be returned. The <c><anno>ValueSpec</anno></c> can either be an atom describing a predefined set of return values, or a list containing either the indexes or the names of specific subpatterns to return.</p> <p>The predefined sets of subpatterns are:</p> <taglist> <tag><c>all</c></tag> @@ -437,7 +403,7 @@ This option makes it possible to include comments inside complicated patterns. N </taglist> <p>The value list is a list of indexes for the subpatterns to return, where index 0 is for all of the pattern, and 1 is for the first explicit capturing subpattern in the regular expression, and so forth. When using named captured subpatterns (see below) in the regular expression, one can use <c>atom()</c>s or <c>string()</c>s to specify the subpatterns to be returned. For example, consider the regular expression:</p> <code> ".*(abcd).*"</code> - <p>matched against the string ""ABCabcdABC", capturing only the "abcd" part (the first explicit subpattern):</p> + <p>matched against the string "ABCabcdABC", capturing only the "abcd" part (the first explicit subpattern):</p> <code> re:run("ABCabcdABC",".*(abcd).*",[{capture,[1]}]).</code> <p>The call will yield the following result:</p> <code> {match,[{3,4}]}</code> @@ -460,8 +426,8 @@ This option makes it possible to include comments inside complicated patterns. N or list respectively.</p> </item> - <tag><c>Type</c></tag> - <item><p>Optionally specifies how captured substrings are to be returned. If omitted, the default of <c>index</c> is used. The <c>Type</c> can be one of the following:</p> + <tag><c><anno>Type</anno></c></tag> + <item><p>Optionally specifies how captured substrings are to be returned. If omitted, the default of <c>index</c> is used. The <c><anno>Type</anno></c> can be one of the following:</p> <taglist> <tag><c>index</c></tag> <item>Return captured substrings as pairs of byte indexes into the subject string and length of the matching string in the subject (as if the subject string was flattened with <c>iolist_to_binary/1</c> or <c>unicode:characters_to_binary/2</c> prior to matching). Note that the <c>unicode</c> option results in <em>byte-oriented</em> indexes in a (possibly virtual) <em>UTF-8 encoded</em> binary. A byte index tuple <c>{0,2}</c> might therefore represent one or two characters when <c>unicode</c> is in effect. This might seem counter-intuitive, but has been deemed the most effective and useful way to way to do it. To return lists instead might result in simpler code if that is desired. This return type is the default.</item> @@ -478,7 +444,7 @@ This option makes it possible to include comments inside complicated patterns. N <code> "ABCabcdABC"</code> <p>the subpattern at index 2 won't match, as "abdd" is not present in the string, but the complete pattern matches (due to the alternative <c>a(..d)</c>. The subpattern at index 2 is therefore unassigned and the default return value will be:</p> <code> {match,[{0,10},{3,4},{-1,0},{4,3}]}</code> - <p>Setting the capture <c>Type</c> to <c>binary</c> would give the following:</p> + <p>Setting the capture <c><anno>Type</anno></c> to <c>binary</c> would give the following:</p> <code> {match,[<<"ABCabcdABC">>,<<"abcd">>,<<>>,<<"bcd">>]}</code> <p>where the empty binary (<c><<>></c>) represents the unassigned subpattern. In the <c>binary</c> case, some information about the matching is therefore lost, the <c><<>></c> might just as well be an empty string captured.</p> <p>If differentiation between empty matches and non existing subpatterns is necessary, use the <c>type</c> <c>index</c> diff --git a/lib/stdlib/doc/src/string.xml b/lib/stdlib/doc/src/string.xml index 48867ffe72..549c871aed 100644 --- a/lib/stdlib/doc/src/string.xml +++ b/lib/stdlib/doc/src/string.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -255,18 +255,12 @@ sub_string("Hello World", 4, 8). </desc> </func> <func> - <name>to_float(String) -> {Float,Rest} | {error,Reason} </name> + <name name="to_float" arity="1"/> <fsummary>Returns a float whose text representation is the integers (ASCII values) in String.</fsummary> - <type> - <v>String = string()</v> - <v>Float = float()</v> - <v>Rest = string()</v> - <v>Reason = no_float | not_a_list</v> - </type> <desc> - <p>Argument <c>String</c> is expected to start with a valid text + <p>Argument <c><anno>String</anno></c> is expected to start with a valid text represented float (the digits being ASCII values). Remaining characters - in the string after the float are returned in <c>Rest</c>.</p> + in the string after the float are returned in <c><anno>Rest</anno></c>.</p> <p>Example:</p> <code type="none"> > {F1,Fs} = string:to_float("1.0-1.0e-1"), @@ -280,18 +274,12 @@ sub_string("Hello World", 4, 8). </desc> </func> <func> - <name>to_integer(String) -> {Int,Rest} | {error,Reason} </name> + <name name="to_integer" arity="1"/> <fsummary>Returns an integer whose text representation is the integers (ASCII values) in String.</fsummary> - <type> - <v>String = string()</v> - <v>Int = integer()</v> - <v>Rest = string()</v> - <v>Reason = no_integer | not_a_list</v> - </type> <desc> - <p>Argument <c>String</c> is expected to start with a valid text + <p>Argument <c><anno>String</anno></c> is expected to start with a valid text represented integer (the digits being ASCII values). Remaining characters - in the string after the integer are returned in <c>Rest</c>.</p> + in the string after the integer are returned in <c><anno>Rest</anno></c>.</p> <p>Example:</p> <code type="none"> > {I1,Is} = string:to_integer("33+22"), diff --git a/lib/stdlib/doc/src/unicode.xml b/lib/stdlib/doc/src/unicode.xml index 1001ebbae4..1f6cbaccd7 100644 --- a/lib/stdlib/doc/src/unicode.xml +++ b/lib/stdlib/doc/src/unicode.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>1996</year> - <year>2011</year> + <year>2012</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -130,34 +130,24 @@ </desc> </func> <func> - <name>characters_to_list(Data, InEncoding) -> Result</name> + <name name="characters_to_list" arity="2"/> <fsummary>Convert a collection of characters to list of Unicode characters</fsummary> - <type> - <v>Data = <seealso marker="#type-latin1_chardata">latin1_chardata()</seealso> - | <seealso marker="#type-chardata">chardata()</seealso> - | <seealso marker="#type-external_chardata">external_chardata()</seealso></v> - <v>Result = list() | {error, list(), RestData} | {incomplete, list(), binary()}</v> - <v>RestData = <seealso marker="#type-latin1_chardata">latin1_chardata()</seealso> - | <seealso marker="#type-chardata">chardata()</seealso> - | <seealso marker="#type-external_chardata">external_chardata()</seealso></v> - <v>InEncoding = <seealso marker="#type-encoding">encoding()</seealso></v> - </type> <desc> <p>This function converts a possibly deep list of integers and binaries into a list of integers representing unicode characters. The binaries in the input may have characters encoded as latin1 (0 - 255, one character per byte), in which - case the <c>InEncoding</c> parameter should be given as + case the <c><anno>InEncoding</anno></c> parameter should be given as <c>latin1</c>, or have characters encoded as one of the - UTF-encodings, which is given as the <c>InEncoding</c> - parameter. Only when the <c>InEncoding</c> is one of the UTF + UTF-encodings, which is given as the <c><anno>InEncoding</anno></c> + parameter. Only when the <c><anno>InEncoding</anno></c> is one of the UTF encodings, integers in the list are allowed to be grater than 255.</p> - <p>If <c>InEncoding</c> is <c>latin1</c>, the <c>Data</c> parameter + <p>If <c><anno>InEncoding</anno></c> is <c>latin1</c>, the <c><anno>Data</anno></c> parameter corresponds to the <c>iodata()</c> type, but for <c>unicode</c>, - the <c>Data</c> parameter can contain integers greater than 255 + the <c><anno>Data</anno></c> parameter can contain integers greater than 255 (unicode characters beyond the iso-latin-1 range), which would make it invalid as <c>iodata()</c>.</p> @@ -188,16 +178,16 @@ depth as the original data. The error occurs when traversing the list and whatever's left to decode is simply returned as is.</p> - <p>However, if the input <c>Data</c> is a pure binary, the third + <p>However, if the input <c><anno>Data</anno></c> is a pure binary, the third part of the error tuple is guaranteed to be a binary as well.</p> <p>Errors occur for the following reasons:</p> <list type="bulleted"> - <item>Integers out of range - If <c>InEncoding</c> is + <item>Integers out of range - If <c><anno>InEncoding</anno></c> is <c>latin1</c>, an error occurs whenever an integer greater - than 255 is found in the lists. If <c>InEncoding</c> is + than 255 is found in the lists. If <c><anno>InEncoding</anno></c> is of a Unicode type, an error occurs whenever an integer <list type="bulleted"> <item>greater than <c>16#10FFFF</c> @@ -208,7 +198,7 @@ is found. </item> - <item>UTF encoding incorrect - If <c>InEncoding</c> is + <item>UTF encoding incorrect - If <c><anno>InEncoding</anno></c> is one of the UTF types, the bytes in any binaries have to be valid in that encoding. Errors can occur for various reasons, including "pure" decoding errors @@ -220,7 +210,7 @@ number should have been encoded in fewer bytes. The case of a truncated UTF is handled specially, see the paragraph about incomplete binaries below. If - <c>InEncoding</c> is <c>latin1</c>, binaries are always valid + <c><anno>InEncoding</anno></c> is <c>latin1</c>, binaries are always valid as long as they contain whole bytes, as each byte falls into the valid iso-latin-1 range.</item> @@ -238,7 +228,7 @@ the first part of a (so far) valid UTF character.</p> <p>If one UTF characters is split over two consecutive - binaries in the <c>Data</c>, the conversion succeeds. This means + binaries in the <c><anno>Data</anno></c>, the conversion succeeds. This means that a character can be decoded from a range of binaries as long as the whole range is given as input without errors occurring. Example:</p> @@ -274,21 +264,11 @@ </desc> </func> <func> - <name>characters_to_binary(Data,InEncoding) -> Result</name> + <name name="characters_to_binary" arity="2"/> <fsummary>Convert a collection of characters to an UTF-8 binary</fsummary> - <type> - <v>Data = <seealso marker="#type-latin1_chardata">latin1_chardata()</seealso> - | <seealso marker="#type-chardata">chardata()</seealso> - | <seealso marker="#type-external_chardata">external_chardata()</seealso></v> - <v>Result = binary() | {error, binary(), RestData} | {incomplete, binary(), binary()}</v> - <v>RestData = <seealso marker="#type-latin1_chardata">latin1_chardata()</seealso> - | <seealso marker="#type-chardata">chardata()</seealso> - | <seealso marker="#type-external_chardata">external_chardata()</seealso></v> - <v>InEncoding = <seealso marker="#type-encoding">encoding()</seealso></v> - </type> <desc> - <p>Same as characters_to_binary(Data, InEncoding, unicode).</p> + <p>Same as characters_to_binary(<anno>Data</anno>, <anno>InEncoding</anno>, unicode).</p> </desc> </func> <func> diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl index cb1e12ae46..0e95372a76 100644 --- a/lib/stdlib/src/binary.erl +++ b/lib/stdlib/src/binary.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -18,29 +18,185 @@ %% -module(binary). %% -%% The following functions implemented as BIF's -%% binary:compile_pattern/1 -%% binary:match/{2,3} -%% binary:matches/{2,3} -%% binary:longest_common_prefix/1 -%% binary:longest_common_suffix/1 -%% binary:first/1 -%% binary:last/1 -%% binary:at/2 -%% binary:part/{2,3} -%% binary:bin_to_list/{1,2,3} -%% binary:list_to_bin/1 -%% binary:copy/{1,2} -%% binary:referenced_byte_size/1 -%% binary:decode_unsigned/{1,2} -%% - Not yet: -%% %% Implemented in this module: -export([split/2,split/3,replace/3,replace/4]). -opaque cp() :: tuple(). -type part() :: {Start :: non_neg_integer(), Length :: integer()}. +%%% BIFs. + +-export([at/2, bin_to_list/1, bin_to_list/2, bin_to_list/3, + compile_pattern/1, copy/1, copy/2, decode_unsigned/1, + decode_unsigned/2, encode_unsigned/1, encode_unsigned/2, + first/1, last/1, list_to_bin/1, longest_common_prefix/1, + longest_common_suffix/1, match/2, match/3, matches/2, + matches/3, part/2, part/3, referenced_byte_size/1]). + +-spec at(Subject, Pos) -> byte() when + Subject :: binary(), + Pos :: non_neg_integer(). + +at(_, _) -> + erlang:nif_error(undef). + +-spec bin_to_list(Subject) -> [byte()] when + Subject :: binary(). + +bin_to_list(_) -> + erlang:nif_error(undef). + +-spec bin_to_list(Subject, PosLen) -> [byte()] when + Subject :: binary(), + PosLen :: part(). + +bin_to_list(_, _) -> + erlang:nif_error(undef). + +-spec bin_to_list(Subject, Pos, Len) -> [byte()] when + Subject :: binary(), + Pos :: non_neg_integer(), + Len :: non_neg_integer(). + +bin_to_list(_, _, _) -> + erlang:nif_error(undef). + +-spec compile_pattern(Pattern) -> cp() when + Pattern :: binary() | [binary()]. + +compile_pattern(_) -> + erlang:nif_error(undef). + +-spec copy(Subject) -> binary() when + Subject :: binary(). + +copy(_) -> + erlang:nif_error(undef). + +-spec copy(Subject, N) -> binary() when + Subject :: binary(), + N :: non_neg_integer(). + +copy(_, _) -> + erlang:nif_error(undef). + +-spec decode_unsigned(Subject) -> Unsigned when + Subject :: binary(), + Unsigned :: non_neg_integer(). + +decode_unsigned(_) -> + erlang:nif_error(undef). + +-spec decode_unsigned(Subject, Endianess) -> Unsigned when + Subject :: binary(), + Endianess :: big | little, + Unsigned :: non_neg_integer(). + +decode_unsigned(_, _) -> + erlang:nif_error(undef). + +-spec encode_unsigned(Unsigned) -> binary() when + Unsigned :: non_neg_integer(). + +encode_unsigned(_) -> + erlang:nif_error(undef). + +-spec encode_unsigned(Unsigned, Endianess) -> binary() when + Unsigned :: non_neg_integer(), + Endianess :: big | little. + +encode_unsigned(_, _) -> + erlang:nif_error(undef). + +-spec first(Subject) -> byte() when + Subject :: binary(). + +first(_) -> + erlang:nif_error(undef). + +-spec last(Subject) -> byte() when + Subject :: binary(). + +last(_) -> + erlang:nif_error(undef). + +-spec list_to_bin(ByteList) -> binary() when + ByteList :: iodata(). + +list_to_bin(_) -> + erlang:nif_error(undef). + +-spec longest_common_prefix(Binaries) -> non_neg_integer() when + Binaries :: [binary()]. + +longest_common_prefix(_) -> + erlang:nif_error(undef). + +-spec longest_common_suffix(Binaries) -> non_neg_integer() when + Binaries :: [binary()]. + +longest_common_suffix(_) -> + erlang:nif_error(undef). + +-spec match(Subject, Pattern) -> Found | nomatch when + Subject :: binary(), + Pattern :: binary() | [binary()] | cp(), + Found :: part(). + +match(_, _) -> + erlang:nif_error(undef). + +-spec match(Subject, Pattern, Options) -> Found | nomatch when + Subject :: binary(), + Pattern :: binary() | [binary()] | cp(), + Found :: part(), + Options :: [Option], + Option :: {scope, part()}. + +match(_, _, _) -> + erlang:nif_error(undef). + +-spec matches(Subject, Pattern) -> Found when + Subject :: binary(), + Pattern :: binary() | [binary()] | cp(), + Found :: [part()]. + +matches(_, _) -> + erlang:nif_error(undef). + +-spec matches(Subject, Pattern, Options) -> Found when + Subject :: binary(), + Pattern :: binary() | [binary()] | cp(), + Found :: [part()], + Options :: [Option], + Option :: {scope, part()}. + +matches(_, _, _) -> + erlang:nif_error(undef). + +-spec part(Subject, PosLen) -> binary() when + Subject :: binary(), + PosLen :: part(). + +part(_, _) -> + erlang:nif_error(undef). + +-spec part(Subject, Pos, Len) -> binary() when + Subject :: binary(), + Pos :: non_neg_integer(), + Len :: non_neg_integer(). + +part(_, _, _) -> + erlang:nif_error(undef). + +-spec referenced_byte_size(Binary) -> non_neg_integer() when + Binary :: binary(). + +referenced_byte_size(_) -> + erlang:nif_error(undef). + +%%% End of BIFs. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% split %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl index afa914a456..817b397cc4 100644 --- a/lib/stdlib/src/ets.erl +++ b/lib/stdlib/src/ets.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -46,7 +46,12 @@ %%----------------------------------------------------------------------------- +-type access() :: public | protected | private. -type tab() :: atom() | tid(). +-type type() :: set | ordered_set | bag | duplicate_bag. +-type continuation() :: '$end_of_table' + | {tab(),integer(),integer(),binary(),list(),integer()} + | {tab(),_,_,integer(),binary(),list(),integer(),integer()}. %% a similar definition is also in erl_types -opaque tid() :: integer(). @@ -57,59 +62,398 @@ %%----------------------------------------------------------------------------- -%% The following functions used to be found in this module, but -%% are now BIFs (i.e. implemented in C). -%% -%% all/0 -%% new/2 -%% delete/1 -%% delete/2 -%% first/1 -%% info/1 -%% info/2 -%% safe_fixtable/2 -%% lookup/2 -%% lookup_element/3 -%% insert/2 -%% is_compiled_ms/1 -%% last/1 -%% member/2 -%% next/2 -%% prev/2 -%% rename/2 -%% slot/2 -%% match/1 -%% match/2 -%% match/3 -%% match_object/1 -%% match_object/2 -%% match_object/3 -%% match_spec_compile/1 -%% match_spec_run_r/3 -%% select/1 -%% select/2 -%% select/3 -%% select_count/2 -%% select_reverse/1 -%% select_reverse/2 -%% select_reverse/3 -%% select_delete/2 -%% setopts/2 -%% update_counter/3 -%% update_element/3 -%% +%%% BIFs + +-export([all/0, delete/1, delete/2, delete_all_objects/1, + delete_object/2, first/1, give_away/3, info/1, info/2, + insert/2, insert_new/2, is_compiled_ms/1, last/1, lookup/2, + lookup_element/3, match/1, match/2, match/3, match_object/1, + match_object/2, match_object/3, match_spec_compile/1, + match_spec_run_r/3, member/2, new/2, next/2, prev/2, + rename/2, safe_fixtable/2, select/1, select/2, select/3, + select_count/2, select_delete/2, select_reverse/1, + select_reverse/2, select_reverse/3, setopts/2, slot/2, + update_counter/3, update_element/3]). + +-spec all() -> [Tab] when + Tab :: tab(). + +all() -> + erlang:nif_error(undef). + +-spec delete(Tab) -> true when + Tab :: tab(). + +delete(_) -> + erlang:nif_error(undef). + +-spec delete(Tab, Key) -> true when + Tab :: tab(), + Key :: term(). + +delete(_, _) -> + erlang:nif_error(undef). + +-spec delete_all_objects(Tab) -> true when + Tab :: tab(). + +delete_all_objects(_) -> + erlang:nif_error(undef). + +-spec delete_object(Tab, Object) -> true when + Tab :: tab(), + Object :: tuple(). + +delete_object(_, _) -> + erlang:nif_error(undef). + +-spec first(Tab) -> Key | '$end_of_table' when + Tab :: tab(), + Key :: term(). + +first(_) -> + erlang:nif_error(undef). + +-spec give_away(Tab, Pid, GiftData) -> true when + Tab :: tab(), + Pid :: pid(), + GiftData :: term(). + +give_away(_, _, _) -> + erlang:nif_error(undef). + +-spec info(Tab) -> InfoList | undefined when + Tab :: tab(), + InfoList :: [InfoTuple], + InfoTuple :: {compressed, boolean()} + | {heir, pid() | none} + | {keypos, pos_integer()} + | {memory, non_neg_integer()} + | {name, atom()} + | {named_table, boolean()} + | {node, node()} + | {owner, pid()} + | {protection, access()} + | {size, non_neg_integer()} + | {type, type()}. + +info(_) -> + erlang:nif_error(undef). + +-spec info(Tab, Item) -> Value | undefined when + Tab :: tab(), + Item :: compressed | fixed | heir | keypos | memory + | name | named_table | node | owner | protection + | safe_fixed | size | stats | type, + Value :: term(). + +info(_, _) -> + erlang:nif_error(undef). + +-spec insert(Tab, ObjectOrObjects) -> true when + Tab :: tab(), + ObjectOrObjects :: tuple() | [tuple()]. + +insert(_, _) -> + erlang:nif_error(undef). + +-spec insert_new(Tab, ObjectOrObjects) -> boolean() when + Tab :: tab(), + ObjectOrObjects :: tuple() | [tuple()]. + +insert_new(_, _) -> + erlang:nif_error(undef). + +-spec is_compiled_ms(Term) -> boolean() when + Term :: term(). + +is_compiled_ms(_) -> + erlang:nif_error(undef). + +-spec last(Tab) -> Key | '$end_of_table' when + Tab :: tab(), + Key :: term(). + +last(_) -> + erlang:nif_error(undef). + +-spec lookup(Tab, Key) -> [Object] when + Tab :: tab(), + Key :: term(), + Object :: tuple(). + +lookup(_, _) -> + erlang:nif_error(undef). + +-spec lookup_element(Tab, Key, Pos) -> Elem when + Tab :: tab(), + Key :: term(), + Pos :: pos_integer(), + Elem :: term() | [term()]. + +lookup_element(_, _, _) -> + erlang:nif_error(undef). + +-spec match(Tab, Pattern) -> [Match] when + Tab :: tab(), + Pattern :: match_pattern(), + Match :: [term()]. + +match(_, _) -> + erlang:nif_error(undef). + +-spec match(Tab, Pattern, Limit) -> {[Match], Continuation} | + '$end_of_table' when + Tab :: tab(), + Pattern :: match_pattern(), + Limit :: pos_integer(), + Match :: [term()], + Continuation :: continuation(). + +match(_, _, _) -> + erlang:nif_error(undef). + +-spec match(Continuation) -> {[Match], Continuation} | + '$end_of_table' when + Match :: [term()], + Continuation :: continuation(). + +match(_) -> + erlang:nif_error(undef). + +-spec match_object(Tab, Pattern) -> [Object] when + Tab :: tab(), + Pattern :: match_pattern(), + Object :: tuple(). + +match_object(_, _) -> + erlang:nif_error(undef). + +-spec match_object(Tab, Pattern, Limit) -> {[Match], Continuation} | + '$end_of_table' when + Tab :: tab(), + Pattern :: match_pattern(), + Limit :: pos_integer(), + Match :: [term()], + Continuation :: continuation(). + +match_object(_, _, _) -> + erlang:nif_error(undef). + +-spec match_object(Continuation) -> {[Match], Continuation} | + '$end_of_table' when + Match :: [term()], + Continuation :: continuation(). + +match_object(_) -> + erlang:nif_error(undef). + +-spec match_spec_compile(MatchSpec) -> CompiledMatchSpec when + MatchSpec :: match_spec(), + CompiledMatchSpec :: comp_match_spec(). + +match_spec_compile(_) -> + erlang:nif_error(undef). + +-spec match_spec_run_r(List, CompiledMatchSpec, list()) -> list() when + List :: [tuple()], + CompiledMatchSpec :: comp_match_spec(). + +match_spec_run_r(_, _, _) -> + erlang:nif_error(undef). + +-spec member(Tab, Key) -> boolean() when + Tab :: tab(), + Key :: term(). + +member(_, _) -> + erlang:nif_error(undef). + +-spec new(Name, Options) -> tid() | atom() when + Name :: atom(), + Options :: [Option], + Option :: Type | Access | named_table | {keypos,Pos} + | {heir, Pid :: pid(), HeirData} | {heir, none} | Tweaks, + Type :: type(), + Access :: access(), + Tweaks :: {write_concurrency, boolean()} + | {read_concurrency, boolean()} + | compressed, + Pos :: pos_integer(), + HeirData :: term(). + +new(_, _) -> + erlang:nif_error(undef). + +-spec next(Tab, Key1) -> Key2 | '$end_of_table' when + Tab :: tab(), + Key1 :: term(), + Key2 :: term(). + +next(_, _) -> + erlang:nif_error(undef). + +-spec prev(Tab, Key1) -> Key2 | '$end_of_table' when + Tab :: tab(), + Key1 :: term(), + Key2 :: term(). + +prev(_, _) -> + erlang:nif_error(undef). + +%% Shadowed by erl_bif_types: ets:rename/2 +-spec rename(Tab, Name) -> Name when + Tab :: tab(), + Name :: atom(). + +rename(_, _) -> + erlang:nif_error(undef). + +-spec safe_fixtable(Tab, Fix) -> true when + Tab :: tab(), + Fix :: boolean(). + +safe_fixtable(_, _) -> + erlang:nif_error(undef). + +-spec select(Tab, MatchSpec) -> [Match] when + Tab :: tab(), + MatchSpec :: match_spec(), + Match :: term(). + +select(_, _) -> + erlang:nif_error(undef). + +-spec select(Tab, MatchSpec, Limit) -> {[Match],Continuation} | + '$end_of_table' when + Tab :: tab(), + MatchSpec :: match_spec(), + Limit :: pos_integer(), + Match :: term(), + Continuation :: continuation(). + +select(_, _, _) -> + erlang:nif_error(undef). + +-spec select(Continuation) -> {[Match],Continuation} | '$end_of_table' when + Match :: term(), + Continuation :: continuation(). + +select(_) -> + erlang:nif_error(undef). + +-spec select_count(Tab, MatchSpec) -> NumMatched when + Tab :: tab(), + MatchSpec :: match_spec(), + NumMatched :: non_neg_integer(). + +select_count(_, _) -> + erlang:nif_error(undef). + +-spec select_delete(Tab, MatchSpec) -> NumDeleted when + Tab :: tab(), + MatchSpec :: match_spec(), + NumDeleted :: non_neg_integer(). + +select_delete(_, _) -> + erlang:nif_error(undef). + +-spec select_reverse(Tab, MatchSpec) -> [Match] when + Tab :: tab(), + MatchSpec :: match_spec(), + Match :: term(). + +select_reverse(_, _) -> + erlang:nif_error(undef). + +-spec select_reverse(Tab, MatchSpec, Limit) -> {[Match],Continuation} | + '$end_of_table' when + Tab :: tab(), + MatchSpec :: match_spec(), + Limit :: pos_integer(), + Match :: term(), + Continuation :: continuation(). + +select_reverse(_, _, _) -> + erlang:nif_error(undef). + +-spec select_reverse(Continuation) -> {[Match],Continuation} | + '$end_of_table' when + Continuation :: continuation(), + Match :: term(). + +select_reverse(_) -> + erlang:nif_error(undef). + +-spec setopts(Tab, Opts) -> true when + Tab :: tab(), + Opts :: Opt | [Opt], + Opt :: {heir, pid(), HeirData} | {heir,none}, + HeirData :: term(). + +setopts(_, _) -> + erlang:nif_error(undef). + +-spec slot(Tab, I) -> [Object] | '$end_of_table' when + Tab :: tab(), + I :: non_neg_integer(), + Object :: tuple(). + +slot(_, _) -> + erlang:nif_error(undef). + +-spec update_counter(Tab, Key, UpdateOp) -> Result when + Tab :: tab(), + Key :: term(), + UpdateOp :: {Pos, Incr} | {Pos, Incr, Threshold, SetValue}, + Pos :: integer(), + Incr :: integer(), + Threshold :: integer(), + SetValue :: integer(), + Result :: integer(); + (Tab, Key, [UpdateOp]) -> [Result] when + Tab :: tab(), + Key :: term(), + UpdateOp :: {Pos, Incr} | {Pos, Incr, Threshold, SetValue}, + Pos :: integer(), + Incr :: integer(), + Threshold :: integer(), + SetValue :: integer(), + Result :: integer(); + (Tab, Key, Incr) -> Result when + Tab :: tab(), + Key :: term(), + Incr :: integer(), + Result :: integer(). + +update_counter(_, _, _) -> + erlang:nif_error(undef). + +-spec update_element(Tab, Key, ElementSpec :: {Pos, Value}) -> boolean() when + Tab :: tab(), + Key :: term(), + Pos :: pos_integer(), + Value :: term(); + (Tab, Key, ElementSpec :: [{Pos, Value}]) -> boolean() when + Tab :: tab(), + Key :: term(), + Pos :: pos_integer(), + Value :: term(). + +update_element(_, _, _) -> + erlang:nif_error(undef). + +%%% End of BIFs -opaque comp_match_spec() :: any(). %% this one is REALLY opaque --spec match_spec_run([tuple()], comp_match_spec()) -> [term()]. +-spec match_spec_run(List, CompiledMatchSpec) -> list() when + List :: [tuple()], + CompiledMatchSpec :: comp_match_spec(). match_spec_run(List, CompiledMS) -> lists:reverse(ets:match_spec_run_r(List, CompiledMS, [])). --type continuation() :: '$end_of_table' - | {tab(),integer(),integer(),binary(),list(),integer()} - | {tab(),_,_,integer(),binary(),list(),integer(),integer()}. - -spec repair_continuation(Continuation, MatchSpec) -> Continuation when Continuation :: continuation(), MatchSpec :: match_spec(). diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl index e73c087753..eb527471d5 100644 --- a/lib/stdlib/src/lists.erl +++ b/lib/stdlib/src/lists.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -33,9 +33,6 @@ keysort/2, keymerge/3, rkeymerge/3, rukeymerge/3, ukeysort/2, ukeymerge/3, keymap/3]). -%% Bifs: member/2, reverse/2 -%% Bifs: keymember/3, keysearch/3, keyfind/3 - -export([merge/3, rmerge/3, sort/2, umerge/3, rumerge/3, usort/2]). -export([all/2,any/2,map/2,flatmap/2,foldl/3,foldr/3,filter/2, @@ -43,6 +40,60 @@ mapfoldl/3,mapfoldr/3,foreach/2,takewhile/2,dropwhile/2,splitwith/2, split/2]). +%%% BIFs +-export([keyfind/3, keymember/3, keysearch/3, member/2, reverse/2]). + +%% Shadowed by erl_bif_types: lists:keyfind/3 +-spec keyfind(Key, N, TupleList) -> Tuple | false when + Key :: term(), + N :: pos_integer(), + TupleList :: [Tuple], + Tuple :: tuple(). + +keyfind(_, _, _) -> + erlang:nif_error(undef). + +%% Shadowed by erl_bif_types: lists:keymember/3 +-spec keymember(Key, N, TupleList) -> boolean() when + Key :: term(), + N :: pos_integer(), + TupleList :: [Tuple], + Tuple :: tuple(). + +keymember(_, _, _) -> + erlang:nif_error(undef). + +%% Shadowed by erl_bif_types: lists:keysearch/3 +-spec keysearch(Key, N, TupleList) -> {value, Tuple} | false when + Key :: term(), + N :: pos_integer(), + TupleList :: [Tuple], + Tuple :: tuple(). + +keysearch(_, _, _) -> + erlang:nif_error(undef). + +%% Shadowed by erl_bif_types: lists:member/2 +-spec member(Elem, List) -> boolean() when + Elem :: T, + List :: [T], + T :: term(). + +member(_, _) -> + erlang:nif_error(undef). + +%% Shadowed by erl_bif_types: lists:reverse/2 +-spec reverse(List1, Tail) -> List2 when + List1 :: [T], + Tail :: term(), + List2 :: [T], + T :: term(). + +reverse(_, _) -> + erlang:nif_error(undef). + +%%% End of BIFs + %% member(X, L) -> (true | false) %% test if X is a member of the list L %% Now a BIF! @@ -84,7 +135,7 @@ append([]) -> []. subtract(L1, L2) -> L1 -- L2. -%% reverse(L) reverse all elements in the list L. Is now a BIF! +%% reverse(L) reverse all elements in the list L. reverse/2 is now a BIF! -spec reverse(List1) -> List2 when List1 :: [T], @@ -581,6 +632,7 @@ flatlength([_|T], L) -> flatlength([], L) -> L. %% keymember(Key, Index, [Tuple]) Now a BIF! +%% keyfind(Key, Index, [Tuple]) A BIF! %% keysearch(Key, Index, [Tuple]) Now a BIF! %% keydelete(Key, Index, [Tuple]) %% keyreplace(Key, Index, [Tuple], NewTuple) diff --git a/lib/stdlib/src/math.erl b/lib/stdlib/src/math.erl index b2ea6195c5..c3fb684ec3 100644 --- a/lib/stdlib/src/math.erl +++ b/lib/stdlib/src/math.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -20,6 +20,116 @@ -export([pi/0]). +%%% BIFs + +-export([sin/1, cos/1, tan/1, asin/1, acos/1, atan/1, atan2/2, sinh/1, + cosh/1, tanh/1, asinh/1, acosh/1, atanh/1, exp/1, log/1, + log10/1, pow/2, sqrt/1, erf/1, erfc/1]). + +-spec acos(X) -> float() when + X :: number(). +acos(_) -> + erlang:nif_error(undef). + +-spec acosh(X) -> float() when + X :: number(). +acosh(_) -> + erlang:nif_error(undef). + +-spec asin(X) -> float() when + X :: number(). +asin(_) -> + erlang:nif_error(undef). + +-spec asinh(X) -> float() when + X :: number(). +asinh(_) -> + erlang:nif_error(undef). + +-spec atan(X) -> float() when + X :: number(). +atan(_) -> + erlang:nif_error(undef). + +-spec atan2(X, Y) -> float() when + X :: number(), + Y :: number(). +atan2(_, _) -> + erlang:nif_error(undef). + +-spec atanh(X) -> float() when + X :: number(). +atanh(_) -> + erlang:nif_error(undef). + +-spec cos(X) -> float() when + X :: number(). +cos(_) -> + erlang:nif_error(undef). + +-spec cosh(X) -> float() when + X :: number(). +cosh(_) -> + erlang:nif_error(undef). + +-spec erf(X) -> float() when + X :: number(). +erf(_) -> + erlang:nif_error(undef). + +-spec erfc(X) -> float() when + X :: number(). +erfc(_) -> + erlang:nif_error(undef). + +-spec exp(X) -> float() when + X :: number(). +exp(_) -> + erlang:nif_error(undef). + +-spec log(X) -> float() when + X :: number(). +log(_) -> + erlang:nif_error(undef). + +-spec log10(X) -> float() when + X :: number(). +log10(_) -> + erlang:nif_error(undef). + +-spec pow(X, Y) -> float() when + X :: number(), + Y :: number(). +pow(_, _) -> + erlang:nif_error(undef). + +-spec sin(X) -> float() when + X :: number(). +sin(_) -> + erlang:nif_error(undef). + +-spec sinh(X) -> float() when + X :: number(). +sinh(_) -> + erlang:nif_error(undef). + +-spec sqrt(X) -> float() when + X :: number(). +sqrt(_) -> + erlang:nif_error(undef). + +-spec tan(X) -> float() when + X :: number(). +tan(_) -> + erlang:nif_error(undef). + +-spec tanh(X) -> float() when + X :: number(). +tanh(_) -> + erlang:nif_error(undef). + +%%% End of BIFs + -spec pi() -> float(). pi() -> 3.1415926535897932. diff --git a/lib/stdlib/src/qlc_pt.erl b/lib/stdlib/src/qlc_pt.erl index 21504d707b..ad25fd559c 100644 --- a/lib/stdlib/src/qlc_pt.erl +++ b/lib/stdlib/src/qlc_pt.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -2186,7 +2186,7 @@ try_ms(E, P, Fltr, State) -> {function,L,foo,0,[{clause,L,[],[],[MS0]}]} = lists:last(X), MS = erl_parse:normalise(var2const(MS0)), XMS = ets:match_spec_compile(MS), - true = is_binary(XMS), + true = ets:is_compiled_ms(XMS), {ok, MS, MS0} end of {'EXIT', _Reason} -> diff --git a/lib/stdlib/src/re.erl b/lib/stdlib/src/re.erl index 246d535943..359afc8c14 100644 --- a/lib/stdlib/src/re.erl +++ b/lib/stdlib/src/re.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -30,11 +30,65 @@ | {newline, nl_spec()}| bsr_anycrlf | bsr_unicode. -%% Emulator builtins in this module: -%% re:compile/1 -%% re:compile/2 -%% re:run/2 -%% re:run/3 +%%% BIFs + +-export([compile/1, compile/2, run/2, run/3]). + +-spec compile(Regexp) -> {ok, MP} | {error, ErrSpec} when + Regexp :: iodata(), + MP :: mp(), + ErrSpec :: {ErrString :: string(), Position :: non_neg_integer()}. + +compile(_) -> + erlang:nif_error(undef). + +-spec compile(Regexp, Options) -> {ok, MP} | {error, ErrSpec} when + Regexp :: iodata() | unicode:charlist(), + Options :: [Option], + Option :: compile_option(), + MP :: mp(), + ErrSpec :: {ErrString :: string(), Position :: non_neg_integer()}. + +compile(_, _) -> + erlang:nif_error(undef). + +-spec run(Subject, RE) -> {match, Captured} | nomatch when + Subject :: iodata() | unicode:charlist(), + RE :: mp() | iodata(), + Captured :: [CaptureData], + CaptureData :: {integer(), integer()}. + +run(_, _) -> + erlang:nif_error(undef). + +-spec run(Subject, RE, Options) -> {match, Captured} | + match | + nomatch when + Subject :: iodata() | unicode:charlist(), + RE :: mp() | iodata() | unicode:charlist(), + Options :: [Option], + Option :: anchored | global | notbol | noteol | notempty + | {offset, non_neg_integer()} | + {newline, NLSpec :: nl_spec()} | + bsr_anycrlf | bsr_unicode | {capture, ValueSpec} | + {capture, ValueSpec, Type} | CompileOpt, + Type :: index | list | binary, + ValueSpec :: all | all_but_first | first | none | ValueList, + ValueList :: [ValueID], + ValueID :: integer() | string() | atom(), + CompileOpt :: compile_option(), + Captured :: [CaptureData] | [[CaptureData]], + CaptureData :: {integer(), integer()} + | ListConversionData + | binary(), + ListConversionData :: string() + | {error, string(), binary()} + | {incomplete, string(), binary()}. + +run(_, _, _) -> + erlang:nif_error(undef). + +%%% End of BIFs -spec split(Subject, RE) -> SplitList when Subject :: iodata() | unicode:charlist(), diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src index 94e81188b5..55c8087475 100644 --- a/lib/stdlib/src/stdlib.appup.src +++ b/lib/stdlib/src/stdlib.appup.src @@ -17,11 +17,11 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max two major revisions back - [{<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 - {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 - {<<"1\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13 + [{<<"1\\.19(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R14 %% Down to - max two major revisions back - [{<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 - {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 - {<<"1\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13 + [{<<"1\\.19(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R14 }. diff --git a/lib/stdlib/src/string.erl b/lib/stdlib/src/string.erl index 30eac4f07d..fc029a582f 100644 --- a/lib/stdlib/src/string.erl +++ b/lib/stdlib/src/string.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -29,6 +29,30 @@ %%--------------------------------------------------------------------------- +%%% BIFs + +-export([to_float/1, to_integer/1]). + +-spec to_float(String) -> {Float, Rest} | {error, Reason} when + String :: string(), + Float :: float(), + Rest :: string(), + Reason :: no_float | not_a_list. + +to_float(_) -> + erlang:nif_error(undef). + +-spec to_integer(String) -> {Int, Rest} | {error, Reason} when + String :: string(), + Int :: integer(), + Rest :: string(), + Reason :: no_integer | not_a_list. + +to_integer(_) -> + erlang:nif_error(undef). + +%%% End of BIFs + %% Robert's bit %% len(String) diff --git a/lib/stdlib/src/unicode.erl b/lib/stdlib/src/unicode.erl index e9b90befe6..8b9412fb1b 100644 --- a/lib/stdlib/src/unicode.erl +++ b/lib/stdlib/src/unicode.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -18,13 +18,6 @@ %% -module(unicode). -%% Implemented in the emulator: -%% characters_to_binary/2 (will trap to characters_to_binary_int/2 -%% if InEncoding is not {latin1 | unicode | utf8}) -%% characters_to_list/2 (will trap to characters_to_list_int/2 if -%% InEncoding is not {latin1 | unicode | utf8}) -%% - -export([characters_to_list/1, characters_to_list_int/2, characters_to_binary/1, characters_to_binary_int/2, characters_to_binary/3, @@ -52,6 +45,45 @@ -type latin1_charlist() :: [latin1_char() | latin1_binary() | latin1_charlist()]. +%%% BIFs +%%% +%%% characters_to_binary/2 (will trap to characters_to_binary_int/2 +%%% if InEncoding is not {latin1 | unicode | utf8}) +%%% characters_to_list/2 (will trap to characters_to_list_int/2 if +%%% InEncoding is not {latin1 | unicode | utf8}) + +-export([bin_is_7bit/1, characters_to_binary/2, characters_to_list/2]). + +-spec bin_is_7bit(Binary) -> boolean() when + Binary :: binary(). + +bin_is_7bit(_) -> + erlang:nif_error(undef). + +-spec characters_to_binary(Data, InEncoding) -> Result when + Data :: latin1_chardata() | chardata() | external_chardata(), + InEncoding :: encoding(), + Result :: binary() + | {error, binary(), RestData} + | {incomplete, binary(), binary()}, + RestData :: latin1_chardata() | chardata() | external_chardata(). + +characters_to_binary(_, _) -> + erlang:nif_error(undef). + +-spec characters_to_list(Data, InEncoding) -> Result when + Data :: latin1_chardata() | chardata() | external_chardata(), + InEncoding :: encoding(), + Result :: list() + | {error, list(), RestData} + | {incomplete, list(), binary()}, + RestData :: latin1_chardata() | chardata() | external_chardata(). + +characters_to_list(_, _) -> + erlang:nif_error(undef). + +%%% End of BIFs + -spec characters_to_list(Data) -> Result when Data :: latin1_chardata() | chardata() | external_chardata(), Result :: list() diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk index 694d39ce9c..33d7a57cc3 100644 --- a/lib/stdlib/vsn.mk +++ b/lib/stdlib/vsn.mk @@ -1 +1 @@ -STDLIB_VSN = 1.18.1 +STDLIB_VSN = 1.19 |