diff options
Diffstat (limited to 'erts')
105 files changed, 2992 insertions, 2080 deletions
diff --git a/erts/autoconf/vxworks/sed.general b/erts/autoconf/vxworks/sed.general index 0e99b4dba4..d32fbdc5c0 100644 --- a/erts/autoconf/vxworks/sed.general +++ b/erts/autoconf/vxworks/sed.general @@ -103,7 +103,6 @@ s|@INSTALL_PROGRAM@|${INSTALL}| s|@INSTALL_SCRIPT@|${INSTALL}| s|@INSTALL_DATA@|${INSTALL} -m 644| s|@INSTALL_DIR@|$(INSTALL) -d| -s|@RM@|/bin/rm| s|@MKDIR@|/bin/mkdir| s|@ERLANG_OSTYPE@|vxworks| s|@vxworks_reclaim@|reclaim.h| diff --git a/erts/configure.in b/erts/configure.in index 9245e4dc90..3ba8216a19 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -792,11 +792,6 @@ AC_SUBST(LIBCARBON) _search_path=/bin:/usr/bin:/usr/local/bin:$PATH -AC_PATH_PROG(RM, rm, false, $_search_path) -if test "$ac_cv_path_RM" = false; then - AC_MSG_ERROR([No 'rm' command found]) -fi - AC_PATH_PROG(MKDIR, mkdir, false, $_search_path) if test "$ac_cv_path_MKDIR" = false; then AC_MSG_ERROR([No 'mkdir' command found]) @@ -811,9 +806,9 @@ _search_path= # Remove old configuration information. -# Next line should be placed after AC_PATH_PROG(RM, ...), but before -# first output to CONN_INFO. So this is just the right place. -$RM -f "$ERL_TOP/erts/CONF_INFO" +# Next line should be before first output to CONN_INFO. So this is +# just the right place. +rm -f "$ERL_TOP/erts/CONF_INFO" dnl Check if we should/can build a sharing-preserving emulator AC_MSG_CHECKING(if we are building a sharing-preserving emulator) @@ -851,7 +846,7 @@ fi ## Delete previous failed configure results if test -f doc/CONF_INFO; then - $RM doc/CONF_INFO + rm -f doc/CONF_INFO fi AC_CHECK_PROGS(XSLTPROC, xsltproc) @@ -3288,14 +3283,14 @@ if test "$enable_dtrace_test" = "yes" ; then AC_MSG_CHECKING([for 2-stage DTrace precompilation]) AC_TRY_COMPILE([ #include "foo-dtrace.h" ], [ERLANG_DIST_PORT_BUSY_ENABLED();], - [$RM -f $DTRACE_2STEP_TEST + [rm -f $DTRACE_2STEP_TEST dtrace -G $DTRACE_CPP $DTRACE_BITS_FLAG -Iemulator/beam -o $DTRACE_2STEP_TEST -s emulator/beam/erlang_dtrace.d conftest.$OBJEXT 2>&AS_MESSAGE_LOG_FD if test -f $DTRACE_2STEP_TEST; then - $RM $DTRACE_2STEP_TEST + rm -f $DTRACE_2STEP_TEST DTRACE_ENABLED_2STEP=yes fi], []) - $RM -f foo-dtrace.h + rm -f foo-dtrace.h AS_IF([test "x$DTRACE_ENABLED_2STEP" = "xyes"], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) @@ -3499,7 +3494,7 @@ ssl_done=yes # Default only one run # Remove all SKIP files from previous runs for a in ssl crypto ssh; do - $RM -f $ERL_TOP/lib/$a/SKIP + rm -f $ERL_TOP/lib/$a/SKIP done SSL_DYNAMIC_ONLY=$enable_dynamic_ssl @@ -4120,7 +4115,7 @@ need_java="jinterface ic/java_src" # Remove all SKIP files from previous runs for a in $need_java ; do - $RM -f $ERL_TOP/lib/$a/SKIP + rm -f $ERL_TOP/lib/$a/SKIP done if test "X$with_javac" = "Xno"; then @@ -4171,7 +4166,7 @@ dnl this deliberately does not believe that 'gcc' is a C++ compiler AC_CHECK_TOOLS(CXX, [$CCC c++ g++ CC cxx cc++ cl], false) # Remove SKIP file from previous run -$RM -f $ERL_TOP/lib/orber/SKIP +rm -f $ERL_TOP/lib/orber/SKIP if test "$CXX" = false; then echo "No C++ compiler found" > $ERL_TOP/lib/orber/SKIP @@ -4326,7 +4321,6 @@ AC_CONFIG_FILES([../make/make_emakefile:../make/make_emakefile.in], dnl dnl The ones below should be moved to their respective lib dnl -dnl ../lib/ssl/c_src/$host/Makefile:../lib/ssl/c_src/Makefile.in AC_CONFIG_FILES([ ../lib/os_mon/c_src/$host/Makefile:../lib/os_mon/c_src/Makefile.in ../lib/crypto/c_src/$host/Makefile:../lib/crypto/c_src/Makefile.in @@ -4334,4 +4328,6 @@ AC_CONFIG_FILES([ ../lib/tools/c_src/$host/Makefile:../lib/tools/c_src/Makefile.in ]) +AC_CONFIG_FILES([../make/install_dir_data.sh:../make/install_dir_data.sh.in], [chmod +x ../make/install_dir_data.sh]) + AC_OUTPUT diff --git a/erts/doc/src/atomics.xml b/erts/doc/src/atomics.xml index 3fca92fb97..455973f011 100644 --- a/erts/doc/src/atomics.xml +++ b/erts/doc/src/atomics.xml @@ -23,14 +23,14 @@ <title>atomics</title> </header> - <module>atomics</module> + <module since="OTP 21.2">atomics</module> <modulesummary>Atomic Functions</modulesummary> <description> <p>This module provides a set of functions to do atomic operations towards mutable atomic variables. The implementation utilizes only atomic hardware instructions without any software level locking, which makes it very efficient for concurrent access. The atomics are organized into - arrays with the follwing semantics:</p> + arrays with the following semantics:</p> <list type="bulleted"> <item> <p>Atomics are 64 bit integers.</p> @@ -70,7 +70,7 @@ <funcs> <func> - <name name="new" arity="2"/> + <name name="new" arity="2" since="OTP 21.2"/> <fsummary>Create atomic array</fsummary> <desc> <p>Create a new atomic array of <c><anno>Arity</anno></c> atomics.</p> @@ -85,11 +85,13 @@ bsl 64)-1</c>.</p> </item> </taglist> + <p>Atomics are not tied to the current process and are automatically + garbage collected when they are no longer referenced.</p> </desc> </func> <func> - <name name="put" arity="3"/> + <name name="put" arity="3" since="OTP 21.2"/> <fsummary>Set atomic value</fsummary> <desc> <p>Set atomic to <c><anno>Value</anno></c>.</p> @@ -97,7 +99,7 @@ </func> <func> - <name name="get" arity="2"/> + <name name="get" arity="2" since="OTP 21.2"/> <fsummary>Read atomic value</fsummary> <desc> <p>Read atomic value.</p> @@ -105,7 +107,7 @@ </func> <func> - <name name="add" arity="3"/> + <name name="add" arity="3" since="OTP 21.2"/> <fsummary>Add to atomic</fsummary> <desc> <p>Add <c><anno>Incr</anno></c> to atomic.</p> @@ -113,7 +115,7 @@ </func> <func> - <name name="add_get" arity="3"/> + <name name="add_get" arity="3" since="OTP 21.2"/> <fsummary>Atomic add and get</fsummary> <desc> <p>Atomic addition and return of the result.</p> @@ -121,7 +123,7 @@ </func> <func> - <name name="sub" arity="3"/> + <name name="sub" arity="3" since="OTP 21.2"/> <fsummary>Subtract from atomic</fsummary> <desc> <p>Subtract <c><anno>Decr</anno></c> from atomic.</p> @@ -129,7 +131,7 @@ </func> <func> - <name name="sub_get" arity="3"/> + <name name="sub_get" arity="3" since="OTP 21.2"/> <fsummary>Atomic sub and get</fsummary> <desc> <p>Atomic subtraction and return of the result.</p> @@ -137,7 +139,7 @@ </func> <func> - <name name="exchange" arity="3"/> + <name name="exchange" arity="3" since="OTP 21.2"/> <fsummary>Atomic exchange.</fsummary> <desc> <p>Atomically replaces the value of the atomic with @@ -147,7 +149,7 @@ </func> <func> - <name name="compare_exchange" arity="4"/> + <name name="compare_exchange" arity="4" since="OTP 21.2"/> <fsummary>Atomic compare and exchange.</fsummary> <desc> <p>Atomically compares the atomic with <c><anno>Expected</anno></c>, @@ -158,7 +160,7 @@ </func> <func> - <name name="info" arity="1"/> + <name name="info" arity="1" since="OTP 21.2"/> <fsummary>Get information about atomic array.</fsummary> <desc> <p>Return information about an atomic array in a map. The map diff --git a/erts/doc/src/counters.xml b/erts/doc/src/counters.xml index ba4a22759f..36816bd68d 100644 --- a/erts/doc/src/counters.xml +++ b/erts/doc/src/counters.xml @@ -23,13 +23,13 @@ <title>counters</title> </header> - <module>counters</module> + <module since="OTP 21.2">counters</module> <modulesummary>Counter Functions</modulesummary> <description> <p>This module provides a set of functions to do operations towards shared mutable counter variables. The implementation does not utilize any software level locking, which makes it very efficient for concurrent - access. The counters are organized into arrays with the follwing + access. The counters are organized into arrays with the following semantics:</p> <list type="bulleted"> <item> @@ -71,7 +71,7 @@ <funcs> <func> - <name name="new" arity="2"/> + <name name="new" arity="2" since="OTP 21.2"/> <fsummary>Create counter array</fsummary> <desc> <p>Create a new counter array of <c><anno>Size</anno></c> counters.</p> @@ -80,7 +80,7 @@ <taglist> <tag><c>atomics</c> (Default)</tag> <item><p>Counters will be sequentially consistent. If write - operation A is done sequencially before write operation B, then a concurrent reader + operation A is done sequentially before write operation B, then a concurrent reader may see none of them, only A, or both A and B. It cannot see only B.</p> </item> <tag><c>write_concurrency</c></tag> @@ -90,7 +90,7 @@ inconsistency and memory consumption per counter.</p> <p>Read operations may see sequentially inconsistent results with regard to concurrent write operations. Even if write operation A is done - sequencially before write operation B, a concurrent reader may see any + sequentially before write operation B, a concurrent reader may see any combination of A and B, including only B. A read operation is only guaranteed to see all writes done sequentially before the read. No writes are ever lost, but will eventually all be seen.</p> @@ -103,11 +103,13 @@ acceptable.</p> </item> </taglist> + <p>Counters are not tied to the current process and are automatically + garbage collected when they are no longer referenced.</p> </desc> </func> <func> - <name name="get" arity="2"/> + <name name="get" arity="2" since="OTP 21.2"/> <fsummary>Read counter value</fsummary> <desc> <p>Read counter value.</p> @@ -115,7 +117,7 @@ </func> <func> - <name name="add" arity="3"/> + <name name="add" arity="3" since="OTP 21.2"/> <fsummary>Add to counter</fsummary> <desc> <p>Add <c><anno>Incr</anno></c> to counter at index @@ -124,7 +126,7 @@ </func> <func> - <name name="sub" arity="3"/> + <name name="sub" arity="3" since="OTP 21.2"/> <fsummary>Subtract from counter</fsummary> <desc> <p>Subtract <c><anno>Decr</anno></c> from counter at index @@ -133,25 +135,25 @@ </func> <func> - <name name="put" arity="3"/> + <name name="put" arity="3" since="OTP 21.2"/> <fsummary>Set counter to value</fsummary> <desc> <p>Write <c><anno>Value</anno></c> to counter at index <c><anno>Ix</anno></c>.</p> <note> <p>Despite its name, the <c>write_concurrency</c> optimization does not - improve <c>put</c>. A call to <c>put</c> is a relative heavy + improve <c>put</c>. A call to <c>put</c> is a relatively heavy operation compared to the very lightweight and scalable <seealso marker="#add/3"><c>add</c></seealso> and <seealso marker="#sub/3"> <c>sub</c></seealso>. The cost for a <c>put</c> with - <c>write_concurrency</c> is lika a <seealso marker="#get/2"><c>get</c> + <c>write_concurrency</c> is like a <seealso marker="#get/2"><c>get</c> </seealso> plus a <c>put</c> without <c>write_concurrency</c>.</p> </note> </desc> </func> <func> - <name name="info" arity="1"/> + <name name="info" arity="1" since="OTP 21.2"/> <fsummary>Get information about counter array.</fsummary> <desc> <p>Return information about a counter array in a map. The map diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index 05a9895687..133f160dc9 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -1552,6 +1552,15 @@ parameter determines. The lingering prevents repeated deletions and insertions in the tables from occurring.</p> </item> + <tag><marker id="+ztma"/><c>+ztma true | false</c></tag> + <item> + <p>Enables or disables support for tuple module apply in + the emulator. This is a transitional flag for running code + that uses parameterized modules and was compiled under OTP 20 + or earlier. For future compatibility, the modules will need + to be recompiled with the +tuple_calls compiler option. + Defaults to false.</p> + </item> </taglist> </item> </taglist> diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml index 7055889e4a..58678f2393 100644 --- a/erts/doc/src/erl_driver.xml +++ b/erts/doc/src/erl_driver.xml @@ -944,7 +944,7 @@ int suggested_stack_size;</code> <funcs> <func> - <name><ret>void</ret><nametext>add_driver_entry(ErlDrvEntry + <name since=""><ret>void</ret><nametext>add_driver_entry(ErlDrvEntry *de)</nametext></name> <fsummary>Add a driver entry.</fsummary> <desc> @@ -968,7 +968,7 @@ int suggested_stack_size;</code> </func> <func> - <name><ret>void *</ret> + <name since=""><ret>void *</ret> <nametext>driver_alloc(ErlDrvSizeT size)</nametext></name> <fsummary>Allocate memory.</fsummary> <desc> @@ -985,7 +985,7 @@ int suggested_stack_size;</code> </func> <func> - <name><ret>ErlDrvBinary *</ret> + <name since=""><ret>ErlDrvBinary *</ret> <nametext>driver_alloc_binary(ErlDrvSizeT size)</nametext></name> <fsummary>Allocate a driver binary.</fsummary> <desc> @@ -1008,7 +1008,7 @@ int suggested_stack_size;</code> </func> <func> - <name><ret>long</ret><nametext>driver_async(ErlDrvPort port, unsigned + <name since=""><ret>long</ret><nametext>driver_async(ErlDrvPort port, unsigned int* key, void (*async_invoke)(void*), void* async_data, void (*async_free)(void*))</nametext></name> <fsummary>Perform an asynchronous call within a driver.</fsummary> @@ -1076,7 +1076,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>unsigned int</ret><nametext>driver_async_port_key(ErlDrvPort + <name since="OTP R16B02"><ret>unsigned int</ret><nametext>driver_async_port_key(ErlDrvPort port)</nametext></name> <fsummary>Calculate an async key from an ErlDrvPort.</fsummary> <desc> @@ -1096,7 +1096,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>long</ret> + <name since=""><ret>long</ret> <nametext>driver_binary_dec_refc(ErlDrvBinary *bin)</nametext></name> <fsummary>Decrement the reference count of a driver binary.</fsummary> <desc> @@ -1117,7 +1117,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>long</ret> + <name since=""><ret>long</ret> <nametext>driver_binary_get_refc(ErlDrvBinary *bin)</nametext></name> <fsummary>Get the reference count of a driver binary.</fsummary> <desc> @@ -1128,7 +1128,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>long</ret> + <name since=""><ret>long</ret> <nametext>driver_binary_inc_refc(ErlDrvBinary *bin)</nametext></name> <fsummary>Increment the reference count of a driver binary.</fsummary> <desc> @@ -1140,7 +1140,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvTermData</ret><nametext>driver_caller(ErlDrvPort + <name since=""><ret>ErlDrvTermData</ret><nametext>driver_caller(ErlDrvPort port)</nametext></name> <fsummary>Return the process making the driver call.</fsummary> <desc> @@ -1183,7 +1183,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret> + <name since=""><ret>int</ret> <nametext>driver_cancel_timer(ErlDrvPort port)</nametext></name> <fsummary>Cancel a previously set timer.</fsummary> <desc> @@ -1196,7 +1196,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_compare_monitors(const ErlDrvMonitor + <name since=""><ret>int</ret><nametext>driver_compare_monitors(const ErlDrvMonitor *monitor1, const ErlDrvMonitor *monitor2)</nametext></name> <fsummary>Compare two monitors.</fsummary> <desc> @@ -1211,7 +1211,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvTermData</ret><nametext>driver_connected(ErlDrvPort + <name since=""><ret>ErlDrvTermData</ret><nametext>driver_connected(ErlDrvPort port)</nametext></name> <fsummary>Return the port owner process.</fsummary> <desc> @@ -1223,7 +1223,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvPort</ret><nametext>driver_create_port(ErlDrvPort port, + <name since=""><ret>ErlDrvPort</ret><nametext>driver_create_port(ErlDrvPort port, ErlDrvTermData owner_pid, char* name, ErlDrvData drv_data)</nametext></name> <fsummary>Create a new port (driver instance).</fsummary> @@ -1269,7 +1269,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_demonitor_process(ErlDrvPort port, + <name since=""><ret>int</ret><nametext>driver_demonitor_process(ErlDrvPort port, const ErlDrvMonitor *monitor)</nametext></name> <fsummary>Stop monitoring a process from a driver.</fsummary> <desc> @@ -1281,7 +1281,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvSizeT</ret><nametext>driver_deq(ErlDrvPort port, + <name since=""><ret>ErlDrvSizeT</ret><nametext>driver_deq(ErlDrvPort port, ErlDrvSizeT size)</nametext></name> <fsummary>Dequeue data from the head of the driver queue.</fsummary> <desc> @@ -1299,7 +1299,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_enq(ErlDrvPort port, char* buf, + <name since=""><ret>int</ret><nametext>driver_enq(ErlDrvPort port, char* buf, ErlDrvSizeT len)</nametext></name> <fsummary>Enqueue data in the driver queue.</fsummary> <desc> @@ -1325,7 +1325,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_enq_bin(ErlDrvPort port, + <name since=""><ret>int</ret><nametext>driver_enq_bin(ErlDrvPort port, ErlDrvBinary *bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext> </name> <fsummary>Enqueue binary in the driver queue.</fsummary> @@ -1346,7 +1346,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_enqv(ErlDrvPort port, ErlIOVec *ev, + <name since=""><ret>int</ret><nametext>driver_enqv(ErlDrvPort port, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> <fsummary>Enqueue vector in the driver queue.</fsummary> <desc> @@ -1365,11 +1365,11 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_failure(ErlDrvPort port, int + <name since=""><ret>int</ret><nametext>driver_failure(ErlDrvPort port, int error)</nametext></name> - <name><ret>int</ret><nametext>driver_failure_atom(ErlDrvPort port, char + <name since=""><ret>int</ret><nametext>driver_failure_atom(ErlDrvPort port, char *string)</nametext></name> - <name><ret>int</ret><nametext>driver_failure_posix(ErlDrvPort port, int + <name since=""><ret>int</ret><nametext>driver_failure_posix(ErlDrvPort port, int error)</nametext></name> <fsummary>Fail with error.</fsummary> <desc> @@ -1393,7 +1393,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_failure_eof(ErlDrvPort + <name since=""><ret>int</ret><nametext>driver_failure_eof(ErlDrvPort port)</nametext></name> <fsummary>Fail with EOF.</fsummary> <desc> @@ -1408,7 +1408,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret><nametext>driver_free(void *ptr)</nametext></name> + <name since=""><ret>void</ret><nametext>driver_free(void *ptr)</nametext></name> <fsummary>Free an allocated memory block.</fsummary> <desc> <marker id="driver_free"></marker> @@ -1422,7 +1422,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret> + <name since=""><ret>void</ret> <nametext>driver_free_binary(ErlDrvBinary *bin)</nametext></name> <fsummary>Free a driver binary.</fsummary> <desc> @@ -1436,7 +1436,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvTermData</ret> + <name since=""><ret>ErlDrvTermData</ret> <nametext>driver_get_monitored_process(ErlDrvPort port, const ErlDrvMonitor *monitor)</nametext></name> <fsummary>Retrieve the process ID from a monitor.</fsummary> @@ -1452,7 +1452,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret> + <name since=""><ret>int</ret> <nametext>driver_get_now(ErlDrvNowData *now)</nametext></name> <fsummary>Read a system time stamp.</fsummary> <desc> @@ -1473,7 +1473,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_lock_driver(ErlDrvPort + <name since=""><ret>int</ret><nametext>driver_lock_driver(ErlDrvPort port)</nametext></name> <fsummary>Ensure the driver is never unloaded.</fsummary> <desc> @@ -1486,7 +1486,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvTermData</ret><nametext>driver_mk_atom(char* + <name since=""><ret>ErlDrvTermData</ret><nametext>driver_mk_atom(char* string)</nametext></name> <fsummary>Make an atom from a name.</fsummary> <desc> @@ -1501,7 +1501,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvTermData</ret><nametext>driver_mk_port(ErlDrvPort + <name since=""><ret>ErlDrvTermData</ret><nametext>driver_mk_port(ErlDrvPort port)</nametext></name> <fsummary>Make an Erlang term port from a port.</fsummary> <desc> @@ -1517,7 +1517,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_monitor_process(ErlDrvPort port, + <name since=""><ret>int</ret><nametext>driver_monitor_process(ErlDrvPort port, ErlDrvTermData process, ErlDrvMonitor *monitor)</nametext></name> <fsummary>Monitor a process from a driver.</fsummary> <desc> @@ -1540,7 +1540,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_output(ErlDrvPort port, char *buf, + <name since=""><ret>int</ret><nametext>driver_output(ErlDrvPort port, char *buf, ErlDrvSizeT len)</nametext></name> <fsummary>Send data from driver to port owner.</fsummary> <desc> @@ -1560,7 +1560,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_output_binary(ErlDrvPort port, char + <name since=""><ret>int</ret><nametext>driver_output_binary(ErlDrvPort port, char *hbuf, ErlDrvSizeT hlen, ErlDrvBinary* bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext></name> <fsummary>Send data from a driver binary to port owner.</fsummary> @@ -1589,7 +1589,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_output_term(ErlDrvPort port, + <name since=""><ret>int</ret><nametext>driver_output_term(ErlDrvPort port, ErlDrvTermData* term, int n)</nametext></name> <fsummary>Send term data from driver to port owner.</fsummary> <desc> @@ -1608,7 +1608,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_output2(ErlDrvPort port, char *hbuf, + <name since=""><ret>int</ret><nametext>driver_output2(ErlDrvPort port, char *hbuf, ErlDrvSizeT hlen, char *buf, ErlDrvSizeT len)</nametext></name> <fsummary>Send data and binary data to port owner.</fsummary> <desc> @@ -1625,7 +1625,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_outputv(ErlDrvPort port, char* hbuf, + <name since=""><ret>int</ret><nametext>driver_outputv(ErlDrvPort port, char* hbuf, ErlDrvSizeT hlen, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> <fsummary>Send vectorized data to port owner.</fsummary> <desc> @@ -1654,7 +1654,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvPDL</ret> + <name since=""><ret>ErlDrvPDL</ret> <nametext>driver_pdl_create(ErlDrvPort port)</nametext></name> <fsummary>Create a port data lock.</fsummary> <desc> @@ -1672,7 +1672,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>long</ret><nametext>driver_pdl_dec_refc(ErlDrvPDL + <name since=""><ret>long</ret><nametext>driver_pdl_dec_refc(ErlDrvPDL pdl)</nametext></name> <fsummary></fsummary> <desc> @@ -1686,7 +1686,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>long</ret> + <name since=""><ret>long</ret> <nametext>driver_pdl_get_refc(ErlDrvPDL pdl)</nametext></name> <fsummary></fsummary> <desc> @@ -1698,7 +1698,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>long</ret> + <name since=""><ret>long</ret> <nametext>driver_pdl_inc_refc(ErlDrvPDL pdl)</nametext></name> <fsummary></fsummary> <desc> @@ -1712,7 +1712,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret> + <name since=""><ret>void</ret> <nametext>driver_pdl_lock(ErlDrvPDL pdl)</nametext></name> <fsummary>Lock port data lock.</fsummary> <desc> @@ -1723,7 +1723,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret> + <name since=""><ret>void</ret> <nametext>driver_pdl_unlock(ErlDrvPDL pdl)</nametext></name> <fsummary>Unlock port data lock.</fsummary> <desc> @@ -1734,7 +1734,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>SysIOVec *</ret><nametext>driver_peekq(ErlDrvPort port, int + <name since=""><ret>SysIOVec *</ret><nametext>driver_peekq(ErlDrvPort port, int *vlen)</nametext></name> <fsummary>Get the driver queue as a vector.</fsummary> <desc> @@ -1755,7 +1755,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvSizeT</ret><nametext>driver_peekqv(ErlDrvPort port, + <name since="OTP R15B"><ret>ErlDrvSizeT</ret><nametext>driver_peekqv(ErlDrvPort port, ErlIOVec *ev)</nametext></name> <fsummary>Get the driver queue as an I/O vector.</fsummary> <desc> @@ -1775,7 +1775,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_pushq(ErlDrvPort port, char* buf, + <name since=""><ret>int</ret><nametext>driver_pushq(ErlDrvPort port, char* buf, ErlDrvSizeT len)</nametext></name> <fsummary>Push data at the head of the driver queue.</fsummary> <desc> @@ -1792,7 +1792,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_pushq_bin(ErlDrvPort port, + <name since=""><ret>int</ret><nametext>driver_pushq_bin(ErlDrvPort port, ErlDrvBinary *bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext> </name> <fsummary>Push binary at the head of the driver queue.</fsummary> @@ -1812,7 +1812,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_pushqv(ErlDrvPort port, ErlIOVec + <name since=""><ret>int</ret><nametext>driver_pushqv(ErlDrvPort port, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> <fsummary>Push vector at the head of the driver queue.</fsummary> <desc> @@ -1831,7 +1831,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_read_timer(ErlDrvPort port, unsigned + <name since=""><ret>int</ret><nametext>driver_read_timer(ErlDrvPort port, unsigned long *time_left)</nametext></name> <fsummary>Read the time left before time-out.</fsummary> <desc> @@ -1844,7 +1844,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void *</ret> + <name since=""><ret>void *</ret> <nametext>driver_realloc(void *ptr, ErlDrvSizeT size)</nametext></name> <fsummary>Resize an allocated memory block.</fsummary> <desc> @@ -1859,7 +1859,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvBinary *</ret> + <name since=""><ret>ErlDrvBinary *</ret> <nametext>driver_realloc_binary(ErlDrvBinary *bin, ErlDrvSizeT size) </nametext></name> <fsummary>Resize a driver binary.</fsummary> @@ -1873,7 +1873,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_select(ErlDrvPort port, ErlDrvEvent + <name since=""><ret>int</ret><nametext>driver_select(ErlDrvPort port, ErlDrvEvent event, int mode, int on)</nametext></name> <fsummary>Provides an event for having the emulator call the driver. </fsummary> @@ -1932,7 +1932,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_send_term(ErlDrvPort port, + <name since=""><ret>int</ret><nametext>driver_send_term(ErlDrvPort port, ErlDrvTermData receiver, ErlDrvTermData* term, int n)</nametext></name> <fsummary>Send term data to other process than port owner process. </fsummary> @@ -1958,7 +1958,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>driver_set_timer(ErlDrvPort port, unsigned + <name since=""><ret>int</ret><nametext>driver_set_timer(ErlDrvPort port, unsigned long time)</nametext></name> <fsummary>Set a timer to call the driver.</fsummary> <desc> @@ -1977,7 +1977,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvSizeT</ret> + <name since=""><ret>ErlDrvSizeT</ret> <nametext>driver_sizeq(ErlDrvPort port)</nametext></name> <fsummary>Return the size of the driver queue.</fsummary> <desc> @@ -1991,7 +1991,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret><nametext>driver_system_info(ErlDrvSysInfo + <name since=""><ret>void</ret><nametext>driver_system_info(ErlDrvSysInfo *sys_info_ptr, size_t size)</nametext></name> <fsummary>Get information about the Erlang runtime system.</fsummary> <desc> @@ -2008,7 +2008,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvSizeT</ret><nametext>driver_vec_to_buf(ErlIOVec *ev, + <name since=""><ret>ErlDrvSizeT</ret><nametext>driver_vec_to_buf(ErlIOVec *ev, char *buf, ErlDrvSizeT len)</nametext></name> <fsummary>Collect data segments into a buffer.</fsummary> <desc> @@ -2029,7 +2029,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret><nametext>erl_drv_busy_msgq_limits(ErlDrvPort port, + <name since="OTP R16B"><ret>void</ret><nametext>erl_drv_busy_msgq_limits(ErlDrvPort port, ErlDrvSizeT *low, ErlDrvSizeT *high)</nametext></name> <fsummary>Set and get limits for busy port message queue.</fsummary> <desc> @@ -2083,7 +2083,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret><nametext>erl_drv_cond_broadcast(ErlDrvCond + <name since=""><ret>void</ret><nametext>erl_drv_cond_broadcast(ErlDrvCond *cnd)</nametext></name> <fsummary>Broadcast on a condition variable.</fsummary> <desc> @@ -2097,7 +2097,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvCond *</ret><nametext>erl_drv_cond_create(char + <name since=""><ret>ErlDrvCond *</ret><nametext>erl_drv_cond_create(char *name)</nametext></name> <fsummary>Create a condition variable.</fsummary> <desc> @@ -2114,7 +2114,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret><nametext>erl_drv_cond_destroy(ErlDrvCond + <name since=""><ret>void</ret><nametext>erl_drv_cond_destroy(ErlDrvCond *cnd)</nametext></name> <fsummary>Destroy a condition variable.</fsummary> <desc> @@ -2128,7 +2128,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>char *</ret><nametext>erl_drv_cond_name(ErlDrvCond + <name since="OTP R16B02"><ret>char *</ret><nametext>erl_drv_cond_name(ErlDrvCond *cnd)</nametext></name> <fsummary>Get name of driver mutex.</fsummary> <desc> @@ -2142,7 +2142,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret><nametext>erl_drv_cond_signal(ErlDrvCond + <name since=""><ret>void</ret><nametext>erl_drv_cond_signal(ErlDrvCond *cnd)</nametext></name> <fsummary>Signal on a condition variable.</fsummary> <desc> @@ -2156,7 +2156,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret><nametext>erl_drv_cond_wait(ErlDrvCond *cnd, + <name since=""><ret>void</ret><nametext>erl_drv_cond_wait(ErlDrvCond *cnd, ErlDrvMutex *mtx)</nametext></name> <fsummary>Wait on a condition variable.</fsummary> <desc> @@ -2185,7 +2185,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>erl_drv_consume_timeslice(ErlDrvPort port, + <name since="OTP R16B"><ret>int</ret><nametext>erl_drv_consume_timeslice(ErlDrvPort port, int percent)</nametext></name> <fsummary>Give the runtime system a hint about how much CPU time the current driver callback call has consumed.</fsummary> @@ -2228,7 +2228,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvTime</ret><nametext>erl_drv_convert_time_unit(ErlDrvTime + <name since="OTP 18.3"><ret>ErlDrvTime</ret><nametext>erl_drv_convert_time_unit(ErlDrvTime val, ErlDrvTimeUnit from, ErlDrvTimeUnit to)</nametext></name> <fsummary>Convert time unit of a time value.</fsummary> <desc> @@ -2254,7 +2254,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>erl_drv_equal_tids(ErlDrvTid tid1, + <name since=""><ret>int</ret><nametext>erl_drv_equal_tids(ErlDrvTid tid1, ErlDrvTid tid2)</nametext></name> <fsummary>Compare thread identifiers for equality.</fsummary> <desc> @@ -2276,7 +2276,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>erl_drv_getenv(const char *key, char + <name since=""><ret>int</ret><nametext>erl_drv_getenv(const char *key, char *value, size_t *value_size)</nametext></name> <fsummary>Get the value of an environment variable.</fsummary> <desc> @@ -2317,7 +2317,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret><nametext>erl_drv_init_ack(ErlDrvPort port, + <name since="OTP 19.0"><ret>void</ret><nametext>erl_drv_init_ack(ErlDrvPort port, ErlDrvData res)</nametext></name> <fsummary>Acknowledge the start of the port.</fsummary> <desc> @@ -2345,7 +2345,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvTime</ret> + <name since="OTP 18.3"><ret>ErlDrvTime</ret> <nametext>erl_drv_monotonic_time(ErlDrvTimeUnit time_unit)</nametext> </name> <fsummary>Get Erlang monotonic time.</fsummary> @@ -2365,7 +2365,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>ErlDrvMutex *</ret><nametext>erl_drv_mutex_create(char + <name since=""><ret>ErlDrvMutex *</ret><nametext>erl_drv_mutex_create(char *name)</nametext></name> <fsummary>Create a mutex.</fsummary> <desc> @@ -2380,7 +2380,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret><nametext>erl_drv_mutex_destroy(ErlDrvMutex + <name since=""><ret>void</ret><nametext>erl_drv_mutex_destroy(ErlDrvMutex *mtx)</nametext></name> <fsummary>Destroy a mutex.</fsummary> <desc> @@ -2395,7 +2395,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret><nametext>erl_drv_mutex_lock(ErlDrvMutex + <name since=""><ret>void</ret><nametext>erl_drv_mutex_lock(ErlDrvMutex *mtx)</nametext></name> <fsummary>Lock a mutex.</fsummary> <desc> @@ -2414,7 +2414,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>char *</ret><nametext>erl_drv_mutex_name(ErlDrvMutex + <name since="OTP R16B02"><ret>char *</ret><nametext>erl_drv_mutex_name(ErlDrvMutex *mtx)</nametext></name> <fsummary>Get name of driver mutex.</fsummary> <desc> @@ -2428,7 +2428,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>erl_drv_mutex_trylock(ErlDrvMutex + <name since=""><ret>int</ret><nametext>erl_drv_mutex_trylock(ErlDrvMutex *mtx)</nametext></name> <fsummary>Try lock a mutex.</fsummary> <desc> @@ -2447,7 +2447,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>void</ret><nametext>erl_drv_mutex_unlock(ErlDrvMutex + <name since=""><ret>void</ret><nametext>erl_drv_mutex_unlock(ErlDrvMutex *mtx)</nametext></name> <fsummary>Unlock a mutex.</fsummary> <desc> @@ -2460,7 +2460,7 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code> </func> <func> - <name><ret>int</ret><nametext>erl_drv_output_term(ErlDrvTermData port, + <name since="OTP R16B"><ret>int</ret><nametext>erl_drv_output_term(ErlDrvTermData port, ErlDrvTermData* term, int n)</nametext></name> <fsummary>Send term data from driver to port owner.</fsummary> <desc> @@ -2637,7 +2637,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>int</ret><nametext>erl_drv_putenv(const char *key, char + <name since=""><ret>int</ret><nametext>erl_drv_putenv(const char *key, char *value)</nametext></name> <fsummary>Set the value of an environment variable.</fsummary> <desc> @@ -2668,7 +2668,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>ErlDrvRWLock *</ret><nametext>erl_drv_rwlock_create(char + <name since=""><ret>ErlDrvRWLock *</ret><nametext>erl_drv_rwlock_create(char *name)</nametext></name> <fsummary>Create an rwlock.</fsummary> <desc> @@ -2684,7 +2684,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>void</ret><nametext>erl_drv_rwlock_destroy(ErlDrvRWLock + <name since=""><ret>void</ret><nametext>erl_drv_rwlock_destroy(ErlDrvRWLock *rwlck)</nametext></name> <fsummary>Destroy an rwlock.</fsummary> <desc> @@ -2699,7 +2699,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>char *</ret><nametext>erl_drv_rwlock_name(ErlDrvRWLock + <name since="OTP R16B02"><ret>char *</ret><nametext>erl_drv_rwlock_name(ErlDrvRWLock *rwlck)</nametext></name> <fsummary>Get name of driver mutex.</fsummary> <desc> @@ -2713,7 +2713,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>void</ret><nametext>erl_drv_rwlock_rlock(ErlDrvRWLock + <name since=""><ret>void</ret><nametext>erl_drv_rwlock_rlock(ErlDrvRWLock *rwlck)</nametext></name> <fsummary>Read lock an rwlock.</fsummary> <desc> @@ -2733,7 +2733,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>void</ret><nametext>erl_drv_rwlock_runlock(ErlDrvRWLock + <name since=""><ret>void</ret><nametext>erl_drv_rwlock_runlock(ErlDrvRWLock *rwlck)</nametext></name> <fsummary>Read unlock an rwlock.</fsummary> <desc> @@ -2746,7 +2746,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>void</ret><nametext>erl_drv_rwlock_rwlock(ErlDrvRWLock + <name since=""><ret>void</ret><nametext>erl_drv_rwlock_rwlock(ErlDrvRWLock *rwlck)</nametext></name> <fsummary>Read/write lock an rwlock.</fsummary> <desc> @@ -2766,7 +2766,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>void</ret><nametext>erl_drv_rwlock_rwunlock(ErlDrvRWLock + <name since=""><ret>void</ret><nametext>erl_drv_rwlock_rwunlock(ErlDrvRWLock *rwlck)</nametext></name> <fsummary>Read/write unlock an rwlock.</fsummary> <desc> @@ -2779,7 +2779,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>int</ret><nametext>erl_drv_rwlock_tryrlock(ErlDrvRWLock + <name since=""><ret>int</ret><nametext>erl_drv_rwlock_tryrlock(ErlDrvRWLock *rwlck)</nametext></name> <fsummary>Try to read lock an rwlock.</fsummary> <desc> @@ -2799,7 +2799,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>int</ret><nametext>erl_drv_rwlock_tryrwlock(ErlDrvRWLock + <name since=""><ret>int</ret><nametext>erl_drv_rwlock_tryrwlock(ErlDrvRWLock *rwlck)</nametext></name> <fsummary>Try to read/write lock an rwlock.</fsummary> <desc> @@ -2819,7 +2819,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>int</ret><nametext>erl_drv_send_term(ErlDrvTermData port, + <name since="OTP R16B"><ret>int</ret><nametext>erl_drv_send_term(ErlDrvTermData port, ErlDrvTermData receiver, ErlDrvTermData* term, int n)</nametext></name> <fsummary>Send term data to other process than port owner process. </fsummary> @@ -2843,7 +2843,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>void</ret><nametext>erl_drv_set_os_pid(ErlDrvPort port, + <name since="OTP 19.0"><ret>void</ret><nametext>erl_drv_set_os_pid(ErlDrvPort port, ErlDrvSInt pid)</nametext></name> <fsummary>Set the os_pid for the port.</fsummary> <desc> @@ -2857,7 +2857,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>int</ret><nametext>erl_drv_thread_create(char *name, ErlDrvTid + <name since=""><ret>int</ret><nametext>erl_drv_thread_create(char *name, ErlDrvTid *tid, void * (*func)(void *), void *arg, ErlDrvThreadOpts *opts)</nametext></name> <fsummary>Create a thread.</fsummary> @@ -2920,7 +2920,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>void</ret><nametext>erl_drv_thread_exit(void + <name since=""><ret>void</ret><nametext>erl_drv_thread_exit(void *exit_value)</nametext></name> <fsummary>Terminate calling thread.</fsummary> <desc> @@ -2939,7 +2939,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>int</ret><nametext>erl_drv_thread_join(ErlDrvTid tid, void + <name since=""><ret>int</ret><nametext>erl_drv_thread_join(ErlDrvTid tid, void **exit_value)</nametext></name> <fsummary>Join with another thread.</fsummary> <desc> @@ -2962,7 +2962,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>char *</ret><nametext>erl_drv_thread_name(ErlDrvTid + <name since="OTP R16B02"><ret>char *</ret><nametext>erl_drv_thread_name(ErlDrvTid tid)</nametext></name> <fsummary>Get name of driver mutex.</fsummary> <desc> @@ -2976,7 +2976,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>ErlDrvThreadOpts *</ret> + <name since=""><ret>ErlDrvThreadOpts *</ret> <nametext>erl_drv_thread_opts_create(char *name)</nametext></name> <fsummary>Create thread options.</fsummary> <desc> @@ -3005,7 +3005,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>void</ret> + <name since=""><ret>void</ret> <nametext>erl_drv_thread_opts_destroy(ErlDrvThreadOpts *opts)</nametext> </name> <fsummary>Destroy thread options.</fsummary> @@ -3020,7 +3020,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>ErlDrvTid</ret> + <name since=""><ret>ErlDrvTid</ret> <nametext>erl_drv_thread_self(void)</nametext></name> <fsummary>Get the thread identifier of the current thread.</fsummary> <desc> @@ -3031,7 +3031,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>ErlDrvTime</ret><nametext>erl_drv_time_offset(ErlDrvTimeUnit + <name since="OTP 18.3"><ret>ErlDrvTime</ret><nametext>erl_drv_time_offset(ErlDrvTimeUnit time_unit)</nametext></name> <fsummary>Get current time offset.</fsummary> <desc> @@ -3054,7 +3054,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>void *</ret><nametext>erl_drv_tsd_get(ErlDrvTSDKey + <name since=""><ret>void *</ret><nametext>erl_drv_tsd_get(ErlDrvTSDKey key)</nametext></name> <fsummary>Get thread-specific data.</fsummary> <desc> @@ -3069,7 +3069,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>int</ret><nametext>erl_drv_tsd_key_create(char *name, + <name since=""><ret>int</ret><nametext>erl_drv_tsd_key_create(char *name, ErlDrvTSDKey *key)</nametext></name> <fsummary>Create a thread-specific data key.</fsummary> <desc> @@ -3086,7 +3086,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>void</ret><nametext>erl_drv_tsd_key_destroy(ErlDrvTSDKey + <name since=""><ret>void</ret><nametext>erl_drv_tsd_key_destroy(ErlDrvTSDKey key)</nametext></name> <fsummary>Destroy a thread-specific data key.</fsummary> <desc> @@ -3111,7 +3111,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>void</ret><nametext>erl_drv_tsd_set(ErlDrvTSDKey key, void + <name since=""><ret>void</ret><nametext>erl_drv_tsd_set(ErlDrvTSDKey key, void *data)</nametext></name> <fsummary>Set thread-specific data.</fsummary> <desc> @@ -3138,7 +3138,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>char *</ret><nametext>erl_errno_id(int error)</nametext></name> + <name since=""><ret>char *</ret><nametext>erl_errno_id(int error)</nametext></name> <fsummary>Get Erlang error atom name from error number.</fsummary> <desc> <marker id="erl_errno_id"></marker> @@ -3150,7 +3150,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>int</ret><nametext>remove_driver_entry(ErlDrvEntry + <name since=""><ret>int</ret><nametext>remove_driver_entry(ErlDrvEntry *de)</nametext></name> <fsummary>Remove a driver entry.</fsummary> <desc> @@ -3164,7 +3164,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>void</ret><nametext>set_busy_port(ErlDrvPort port, int + <name since=""><ret>void</ret><nametext>set_busy_port(ErlDrvPort port, int on)</nametext></name> <fsummary>Signal or unsignal port as busy.</fsummary> <desc> @@ -3195,7 +3195,7 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0] </func> <func> - <name><ret>void</ret><nametext>set_port_control_flags(ErlDrvPort port, + <name since=""><ret>void</ret><nametext>set_port_control_flags(ErlDrvPort port, int flags)</nametext></name> <fsummary>Set flags on how to handle control entry function.</fsummary> <desc> diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index bbc12b0a56..5cbeddabd9 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -963,7 +963,7 @@ typedef struct { <funcs> <func> - <name><ret>void *</ret><nametext>enif_alloc(size_t size)</nametext></name> + <name since=""><ret>void *</ret><nametext>enif_alloc(size_t size)</nametext></name> <fsummary>Allocate dynamic memory.</fsummary> <desc> <p>Allocates memory of <c>size</c> bytes.</p> @@ -974,7 +974,7 @@ typedef struct { </func> <func> - <name><ret>int</ret> + <name since=""><ret>int</ret> <nametext>enif_alloc_binary(size_t size, ErlNifBinary* bin)</nametext> </name> <fsummary>Create a new binary.</fsummary> @@ -998,7 +998,7 @@ typedef struct { </func> <func> - <name><ret>ErlNifEnv *</ret><nametext>enif_alloc_env()</nametext></name> + <name since="OTP R14B"><ret>ErlNifEnv *</ret><nametext>enif_alloc_env()</nametext></name> <fsummary>Create a new environment.</fsummary> <desc> <p>Allocates a new process independent environment. The environment can @@ -1012,7 +1012,7 @@ typedef struct { </func> <func> - <name><ret>void *</ret><nametext>enif_alloc_resource(ErlNifResourceType* + <name since="OTP R13B04"><ret>void *</ret><nametext>enif_alloc_resource(ErlNifResourceType* type, unsigned size)</nametext></name> <fsummary>Allocate a memory-managed resource object.</fsummary> <desc> @@ -1022,7 +1022,7 @@ typedef struct { </func> <func> - <name><ret>size_t</ret><nametext>enif_binary_to_term(ErlNifEnv *env, + <name since="OTP 19.0"><ret>size_t</ret><nametext>enif_binary_to_term(ErlNifEnv *env, const unsigned char* data, size_t size, ERL_NIF_TERM *term, ErlNifBinaryToTerm opts)</nametext></name> <fsummary>Create a term from the external format.</fsummary> @@ -1047,7 +1047,7 @@ typedef struct { </func> <func> - <name><ret>void</ret><nametext>enif_clear_env(ErlNifEnv* env)</nametext> + <name since="OTP R14B"><ret>void</ret><nametext>enif_clear_env(ErlNifEnv* env)</nametext> </name> <fsummary>Clear an environment for reuse.</fsummary> <desc> @@ -1058,7 +1058,7 @@ typedef struct { </func> <func> - <name><ret>int</ret> + <name since="OTP R13B04"><ret>int</ret> <nametext>enif_compare(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)</nametext> </name> <fsummary>Compare two terms.</fsummary> @@ -1073,7 +1073,7 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>enif_compare_monitors(const ErlNifMonitor + <name since="OTP 20.0"><ret>int</ret><nametext>enif_compare_monitors(const ErlNifMonitor *monitor1, const ErlNifMonitor *monitor2)</nametext></name> <fsummary>Compare two monitors.</fsummary> <desc> @@ -1088,7 +1088,7 @@ typedef struct { </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_cond_broadcast(ErlNifCond *cnd)</nametext></name> <fsummary></fsummary> <desc> @@ -1098,7 +1098,7 @@ typedef struct { </func> <func> - <name><ret>ErlNifCond *</ret> + <name since="OTP R13B04"><ret>ErlNifCond *</ret> <nametext>enif_cond_create(char *name)</nametext></name> <fsummary></fsummary> <desc> @@ -1108,7 +1108,7 @@ typedef struct { </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_cond_destroy(ErlNifCond *cnd)</nametext></name> <fsummary></fsummary> <desc> @@ -1118,7 +1118,7 @@ typedef struct { </func> <func> - <name><ret>char*</ret> + <name since="OTP 21.0"><ret>char*</ret> <nametext>enif_cond_name(ErlNifCond* cnd)</nametext></name> <fsummary></fsummary> <desc> @@ -1128,7 +1128,7 @@ typedef struct { </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_cond_signal(ErlNifCond *cnd)</nametext></name> <fsummary></fsummary> <desc> @@ -1138,7 +1138,7 @@ typedef struct { </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_cond_wait(ErlNifCond *cnd, ErlNifMutex *mtx)</nametext> </name> <fsummary></fsummary> @@ -1149,7 +1149,7 @@ typedef struct { </func> <func> - <name><ret>int</ret> + <name since="OTP R16B"><ret>int</ret> <nametext>enif_consume_timeslice(ErlNifEnv *env, int percent)</nametext> </name> <fsummary></fsummary> @@ -1184,7 +1184,7 @@ typedef struct { </func> <func> - <name><ret>ErlNifTime</ret><nametext>enif_convert_time_unit(ErlNifTime + <name since="OTP 18.3"><ret>ErlNifTime</ret><nametext>enif_convert_time_unit(ErlNifTime val, ErlNifTimeUnit from, ErlNifTimeUnit to)</nametext></name> <fsummary>Convert time unit of a time value.</fsummary> <desc> @@ -1209,7 +1209,7 @@ typedef struct { </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP 19.0"><ret>ERL_NIF_TERM</ret> <nametext>enif_cpu_time(ErlNifEnv *)</nametext></name> <fsummary></fsummary> <desc> @@ -1225,8 +1225,8 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>enif_demonitor_process(ErlNifEnv* caller_env, void* obj, - const ErlNifMonitor* mon)</nametext></name> + <name since="OTP 20.0"><ret>int</ret><nametext>enif_demonitor_process(ErlNifEnv* caller_env, + void* obj, const ErlNifMonitor* mon)</nametext></name> <fsummary>Cancel a process monitor.</fsummary> <desc> <marker id="enif_demonitor_process"></marker> @@ -1252,7 +1252,7 @@ typedef struct { </func> <func> - <name><ret>int</ret> + <name since="OTP R13B04"><ret>int</ret> <nametext>enif_equal_tids(ErlNifTid tid1, ErlNifTid tid2)</nametext> </name> <fsummary></fsummary> @@ -1263,7 +1263,7 @@ typedef struct { </func> <func> - <name><ret>int</ret><nametext>enif_fprintf(FILE *stream, const char *format, ...)</nametext></name> + <name since="OTP 21.0"><ret>int</ret><nametext>enif_fprintf(FILE *stream, const char *format, ...)</nametext></name> <fsummary>Format strings and Erlang terms.</fsummary> <desc> <p>Similar to <c>fprintf</c> but this format string also accepts @@ -1276,7 +1276,7 @@ typedef struct { </func> <func> - <name><ret>void</ret><nametext>enif_free(void* ptr)</nametext></name> + <name since=""><ret>void</ret><nametext>enif_free(void* ptr)</nametext></name> <fsummary>Free dynamic memory.</fsummary> <desc> <p>Frees memory allocated by @@ -1285,7 +1285,7 @@ typedef struct { </func> <func> - <name><ret>void</ret> + <name since="OTP R14B"><ret>void</ret> <nametext>enif_free_env(ErlNifEnv* env)</nametext></name> <fsummary>Free an environment allocated with enif_alloc_env.</fsummary> <desc> @@ -1296,7 +1296,7 @@ typedef struct { </func> <func> - <name><ret>void</ret> + <name since="OTP 20.1"><ret>void</ret> <nametext>enif_free_iovec(ErlNifIOvec* iov)</nametext></name> <fsummary>Free an ErlIOVec</fsummary> <desc> @@ -1321,7 +1321,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_atom(ErlNifEnv* env, ERL_NIF_TERM + <name since="OTP R13B04"><ret>int</ret><nametext>enif_get_atom(ErlNifEnv* env, ERL_NIF_TERM term, char* buf, unsigned size, ErlNifCharEncoding encode)</nametext> </name> <fsummary>Get the text representation of an atom term.</fsummary> @@ -1337,7 +1337,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_atom_length(ErlNifEnv* env, + <name since="OTP R14B"><ret>int</ret><nametext>enif_get_atom_length(ErlNifEnv* env, ERL_NIF_TERM term, unsigned* len, ErlNifCharEncoding encode)</nametext> </name> <fsummary>Get the length of atom <c>term</c>.</fsummary> @@ -1351,7 +1351,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_double(ErlNifEnv* env, + <name since="OTP R13B04"><ret>int</ret><nametext>enif_get_double(ErlNifEnv* env, ERL_NIF_TERM term, double* dp)</nametext></name> <fsummary>Read a floating-point number term.</fsummary> <desc> @@ -1362,7 +1362,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_int(ErlNifEnv* env, ERL_NIF_TERM + <name since=""><ret>int</ret><nametext>enif_get_int(ErlNifEnv* env, ERL_NIF_TERM term, int* ip)</nametext></name> <fsummary>Read an integer term.</fsummary> <desc> @@ -1373,7 +1373,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_int64(ErlNifEnv* env, ERL_NIF_TERM + <name since="OTP R14B"><ret>int</ret><nametext>enif_get_int64(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifSInt64* ip)</nametext></name> <fsummary>Read a 64-bit integer term.</fsummary> <desc> @@ -1384,7 +1384,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_local_pid(ErlNifEnv* env, + <name since="OTP R14B"><ret>int</ret><nametext>enif_get_local_pid(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifPid* pid)</nametext></name> <fsummary>Read a local pid term.</fsummary> <desc> @@ -1396,7 +1396,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_local_port(ErlNifEnv* env, + <name since="OTP 19.0"><ret>int</ret><nametext>enif_get_local_port(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifPort* port_id)</nametext></name> <fsummary>Read a local port term.</fsummary> <desc> @@ -1408,7 +1408,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_list_cell(ErlNifEnv* env, + <name since=""><ret>int</ret><nametext>enif_get_list_cell(ErlNifEnv* env, ERL_NIF_TERM list, ERL_NIF_TERM* head, ERL_NIF_TERM* tail)</nametext> </name> <fsummary>Get head and tail from a list.</fsummary> @@ -1420,7 +1420,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_list_length(ErlNifEnv* env, + <name since="OTP R14B"><ret>int</ret><nametext>enif_get_list_length(ErlNifEnv* env, ERL_NIF_TERM term, unsigned* len)</nametext></name> <fsummary>Get the length of list <c>term</c>.</fsummary> <desc> @@ -1431,7 +1431,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_long(ErlNifEnv* env, ERL_NIF_TERM + <name since="OTP R13B04"><ret>int</ret><nametext>enif_get_long(ErlNifEnv* env, ERL_NIF_TERM term, long int* ip)</nametext></name> <fsummary>Read a long integer term.</fsummary> <desc> @@ -1442,7 +1442,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_map_size(ErlNifEnv* env, + <name since="OTP 18.0"><ret>int</ret><nametext>enif_get_map_size(ErlNifEnv* env, ERL_NIF_TERM term, size_t *size)</nametext></name> <fsummary>Read the size of a map term.</fsummary> <desc> @@ -1454,7 +1454,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_map_value(ErlNifEnv* env, + <name since="OTP 18.0"><ret>int</ret><nametext>enif_get_map_value(ErlNifEnv* env, ERL_NIF_TERM map, ERL_NIF_TERM key, ERL_NIF_TERM* value)</nametext> </name> <fsummary>Get the value of a key in a map.</fsummary> @@ -1467,7 +1467,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_resource(ErlNifEnv* env, + <name since="OTP R13B04"><ret>int</ret><nametext>enif_get_resource(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifResourceType* type, void** objp)</nametext> </name> <fsummary>Get the pointer to a resource object.</fsummary> @@ -1480,7 +1480,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_string(ErlNifEnv* env, + <name since="OTP R13B04"><ret>int</ret><nametext>enif_get_string(ErlNifEnv* env, ERL_NIF_TERM list, char* buf, unsigned size, ErlNifCharEncoding encode)</nametext></name> <fsummary>Get a C-string from a list.</fsummary> @@ -1504,7 +1504,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_tuple(ErlNifEnv* env, ERL_NIF_TERM + <name since="OTP R13B04"><ret>int</ret><nametext>enif_get_tuple(ErlNifEnv* env, ERL_NIF_TERM term, int* arity, const ERL_NIF_TERM** array)</nametext></name> <fsummary>Inspect the elements of a tuple.</fsummary> <desc> @@ -1520,7 +1520,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_uint(ErlNifEnv* env, ERL_NIF_TERM + <name since="OTP R13B04"><ret>int</ret><nametext>enif_get_uint(ErlNifEnv* env, ERL_NIF_TERM term, unsigned int* ip)</nametext></name> <fsummary>Read an unsigned integer term.</fsummary> <desc> @@ -1532,7 +1532,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_uint64(ErlNifEnv* env, + <name since="OTP R14B"><ret>int</ret><nametext>enif_get_uint64(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifUInt64* ip)</nametext></name> <fsummary>Read an unsigned 64-bit integer term.</fsummary> <desc> @@ -1544,7 +1544,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_get_ulong(ErlNifEnv* env, ERL_NIF_TERM + <name since=""><ret>int</ret><nametext>enif_get_ulong(ErlNifEnv* env, ERL_NIF_TERM term, unsigned long* ip)</nametext></name> <fsummary>Read an unsigned integer term.</fsummary> <desc> @@ -1557,7 +1557,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_getenv(const char* key, char* value, + <name since="OTP 18.2"><ret>int</ret><nametext>enif_getenv(const char* key, char* value, size_t *value_size)</nametext></name> <fsummary>Get the value of an environment variable.</fsummary> <desc> @@ -1567,7 +1567,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_has_pending_exception(ErlNifEnv* env, + <name since="OTP 18.0"><ret>int</ret><nametext>enif_has_pending_exception(ErlNifEnv* env, ERL_NIF_TERM* reason)</nametext></name> <fsummary>Check if an exception has been raised.</fsummary> <desc> @@ -1588,7 +1588,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name> + <name since="OTP 20.0"> <ret>ErlNifUInt64</ret> <nametext>enif_hash(ErlNifHash type, ERL_NIF_TERM term, ErlNifUInt64 salt)</nametext> </name> @@ -1601,7 +1601,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_inspect_binary(ErlNifEnv* env, + <name since=""><ret>int</ret><nametext>enif_inspect_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term, ErlNifBinary* bin)</nametext></name> <fsummary>Inspect the content of a binary.</fsummary> <desc> @@ -1613,7 +1613,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_inspect_iolist_as_binary(ErlNifEnv* + <name since="OTP R13B04"><ret>int</ret><nametext>enif_inspect_iolist_as_binary(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifBinary* bin)</nametext></name> <fsummary>Inspect the content of an iolist.</fsummary> <desc> @@ -1627,7 +1627,7 @@ enif_free_iovec(iovec);]]></code> </func> <func> - <name><ret>int</ret><nametext>enif_inspect_iovec(ErlNifEnv* + <name since="OTP 20.1"><ret>int</ret><nametext>enif_inspect_iovec(ErlNifEnv* env, size_t max_elements, ERL_NIF_TERM iovec_term, ERL_NIF_TERM* tail, ErlNifIOVec** iovec)</nametext></name> <fsummary>Inspect a list of binaries as an ErlNifIOVec.</fsummary> @@ -1667,7 +1667,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ErlNifIOQueue *</ret> + <name since="OTP 20.1"><ret>ErlNifIOQueue *</ret> <nametext>enif_ioq_create(ErlNifIOQueueOpts opts)</nametext></name> <fsummary>Create a new IO Queue</fsummary> <desc> @@ -1678,7 +1678,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>void</ret> + <name since="OTP 20.1"><ret>void</ret> <nametext>enif_ioq_destroy(ErlNifIOQueue *q)</nametext></name> <fsummary>Destroy an IO Queue and free it's content</fsummary> <desc> @@ -1687,7 +1687,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP 20.1"><ret>int</ret> <nametext>enif_ioq_deq(ErlNifIOQueue *q, size_t count, size_t *size)</nametext></name> <fsummary>Dequeue count bytes from the IO Queue</fsummary> <desc> @@ -1700,7 +1700,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP 20.1"><ret>int</ret> <nametext>enif_ioq_enq_binary(ErlNifIOQueue *q, ErlNifBinary *bin, size_t skip)</nametext></name> <fsummary>Enqueue the binary into the IO Queue</fsummary> <desc> @@ -1713,7 +1713,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP 20.1"><ret>int</ret> <nametext>enif_ioq_enqv(ErlNifIOQueue *q, ErlNifIOVec *iovec, size_t skip)</nametext></name> <fsummary>Enqueue the iovec into the IO Queue</fsummary> <desc> @@ -1724,7 +1724,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>SysIOVec *</ret> + <name since="OTP 20.1"><ret>SysIOVec *</ret> <nametext>enif_ioq_peek(ErlNifIOQueue *q, int *iovlen)</nametext></name> <fsummary>Peek inside the IO Queue</fsummary> <desc> @@ -1738,7 +1738,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP 21.0"><ret>int</ret> <nametext>enif_ioq_peek_head(ErlNifEnv *env, ErlNifIOQueue *q, size_t *size, ERL_NIF_TERM *bin_term)</nametext></name> <fsummary>Peek the head of the IO Queue.</fsummary> <desc> @@ -1753,7 +1753,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>size_t</ret> + <name since="OTP 20.1"><ret>size_t</ret> <nametext>enif_ioq_size(ErlNifIOQueue *q)</nametext></name> <fsummary>Get the current size of the IO Queue</fsummary> <desc> @@ -1762,7 +1762,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP R13B04"><ret>int</ret> <nametext>enif_is_atom(ErlNifEnv* env, ERL_NIF_TERM term)</nametext> </name> <fsummary>Determine if a term is an atom.</fsummary> @@ -1772,7 +1772,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since=""><ret>int</ret> <nametext>enif_is_binary(ErlNifEnv* env, ERL_NIF_TERM term)</nametext> </name> <fsummary>Determine if a term is a binary.</fsummary> @@ -1782,7 +1782,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP 19.0"><ret>int</ret> <nametext>enif_is_current_process_alive(ErlNifEnv* env)</nametext> </name> <fsummary>Determine if currently executing process is alive.</fsummary> @@ -1795,7 +1795,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_is_empty_list(ErlNifEnv* env, + <name since="OTP R13B04"><ret>int</ret><nametext>enif_is_empty_list(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> <fsummary>Determine if a term is an empty list.</fsummary> <desc> @@ -1804,7 +1804,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_is_exception(ErlNifEnv* env, + <name since="OTP R14B03"><ret>int</ret><nametext>enif_is_exception(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> <fsummary>Determine if a term is an exception.</fsummary> <desc><marker id="enif_is_exception"/> @@ -1813,7 +1813,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_is_fun(ErlNifEnv* env, ERL_NIF_TERM + <name since="OTP R13B04"><ret>int</ret><nametext>enif_is_fun(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> <fsummary>Determine if a term is a fun.</fsummary> <desc> @@ -1822,7 +1822,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_is_identical(ERL_NIF_TERM lhs, + <name since="OTP R13B04"><ret>int</ret><nametext>enif_is_identical(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)</nametext></name> <fsummary>Erlang operator =:=.</fsummary> <desc> @@ -1832,7 +1832,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP R14B"><ret>int</ret> <nametext>enif_is_list(ErlNifEnv* env, ERL_NIF_TERM term)</nametext> </name> <fsummary>Determine if a term is a list.</fsummary> @@ -1842,7 +1842,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_is_map(ErlNifEnv* env, ERL_NIF_TERM + <name since="OTP 18.0"><ret>int</ret><nametext>enif_is_map(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> <fsummary>Determine if a term is a map.</fsummary> <desc> @@ -1852,7 +1852,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_is_number(ErlNifEnv* env, ERL_NIF_TERM + <name since="OTP R15B"><ret>int</ret><nametext>enif_is_number(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> <fsummary>Determine if a term is a number (integer or float).</fsummary> <desc> @@ -1861,7 +1861,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP R13B04"><ret>int</ret> <nametext>enif_is_pid(ErlNifEnv* env, ERL_NIF_TERM term)</nametext> </name> <fsummary>Determine if a term is a pid.</fsummary> @@ -1871,7 +1871,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP R13B04"><ret>int</ret> <nametext>enif_is_port(ErlNifEnv* env, ERL_NIF_TERM term)</nametext> </name> <fsummary>Determine if a term is a port.</fsummary> @@ -1881,7 +1881,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_is_port_alive(ErlNifEnv* env, + <name since="OTP 19.0"><ret>int</ret><nametext>enif_is_port_alive(ErlNifEnv* env, ErlNifPort *port_id)</nametext></name> <fsummary>Determine if a local port is alive.</fsummary> <desc> @@ -1893,7 +1893,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_is_process_alive(ErlNifEnv* env, + <name since="OTP 19.0"><ret>int</ret><nametext>enif_is_process_alive(ErlNifEnv* env, ErlNifPid *pid)</nametext></name> <fsummary>Determine if a local process is alive.</fsummary> <desc> @@ -1905,7 +1905,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP R13B04"><ret>int</ret> <nametext>enif_is_ref(ErlNifEnv* env, ERL_NIF_TERM term)</nametext> </name> <fsummary>Determine if a term is a reference.</fsummary> @@ -1915,7 +1915,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP R14B"><ret>int</ret> <nametext>enif_is_tuple(ErlNifEnv* env, ERL_NIF_TERM term)</nametext> </name> <fsummary>Determine if a term is a tuple.</fsummary> @@ -1925,7 +1925,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP R14B"><ret>int</ret> <nametext>enif_keep_resource(void* obj)</nametext> </name> <fsummary>Add a reference to a resource object.</fsummary> @@ -1941,7 +1941,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since=""><ret>ERL_NIF_TERM</ret> <nametext>enif_make_atom(ErlNifEnv* env, const char* name)</nametext> </name> <fsummary>Create an atom term.</fsummary> @@ -1955,7 +1955,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_atom_len(ErlNifEnv* env, + <name since="OTP R14B"><ret>ERL_NIF_TERM</ret><nametext>enif_make_atom_len(ErlNifEnv* env, const char* name, size_t len)</nametext></name> <fsummary>Create an atom term.</fsummary> <desc> @@ -1969,7 +1969,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since=""><ret>ERL_NIF_TERM</ret> <nametext>enif_make_badarg(ErlNifEnv* env)</nametext></name> <fsummary>Make a badarg exception.</fsummary> <desc> @@ -1997,7 +1997,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since=""><ret>ERL_NIF_TERM</ret> <nametext>enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)</nametext> </name> <fsummary>Make a binary term.</fsummary> @@ -2010,7 +2010,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_copy(ErlNifEnv* dst_env, + <name since="OTP R14B"><ret>ERL_NIF_TERM</ret><nametext>enif_make_copy(ErlNifEnv* dst_env, ERL_NIF_TERM src_term)</nametext></name> <fsummary>Make a copy of a term.</fsummary> <desc> @@ -2021,7 +2021,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret> <nametext>enif_make_double(ErlNifEnv* env, double d)</nametext></name> <fsummary>Create a floating-point term.</fsummary> <desc> @@ -2033,7 +2033,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_make_existing_atom(ErlNifEnv* env, + <name since="OTP R13B04"><ret>int</ret><nametext>enif_make_existing_atom(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom, ErlNifCharEncoding encode)</nametext></name> <fsummary>Create an existing atom term.</fsummary> @@ -2049,7 +2049,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_make_existing_atom_len(ErlNifEnv* env, + <name since="OTP R14B"><ret>int</ret><nametext>enif_make_existing_atom_len(ErlNifEnv* env, const char* name, size_t len, ERL_NIF_TERM* atom, ErlNifCharEncoding encoding)</nametext></name> <fsummary>Create an existing atom term.</fsummary> @@ -2065,7 +2065,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </desc> </func> - <func><name><ret>ERL_NIF_TERM</ret> + <func><name since=""><ret>ERL_NIF_TERM</ret> <nametext>enif_make_int(ErlNifEnv* env, int i)</nametext></name> <fsummary>Create an integer term.</fsummary> <desc> @@ -2074,7 +2074,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP R14B"><ret>ERL_NIF_TERM</ret> <nametext>enif_make_int64(ErlNifEnv* env, ErlNifSInt64 i)</nametext> </name> <fsummary>Create an integer term.</fsummary> @@ -2084,7 +2084,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since=""><ret>ERL_NIF_TERM</ret> <nametext>enif_make_list(ErlNifEnv* env, unsigned cnt, ...)</nametext> </name> <fsummary>Create a list term.</fsummary> @@ -2097,24 +2097,24 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret> <nametext>enif_make_list1(ErlNifEnv* env, ERL_NIF_TERM e1)</nametext> </name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_list2(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_list2(ErlNifEnv* env, ERL_NIF_TERM e1, ERL_NIF_TERM e2)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_list3(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_list3(ErlNifEnv* env, ERL_NIF_TERM e1, ERL_NIF_TERM e2, ERL_NIF_TERM e3)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_list4(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_list4(ErlNifEnv* env, ERL_NIF_TERM e1, ..., ERL_NIF_TERM e4)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_list5(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_list5(ErlNifEnv* env, ERL_NIF_TERM e1, ..., ERL_NIF_TERM e5)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_list6(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_list6(ErlNifEnv* env, ERL_NIF_TERM e1, ..., ERL_NIF_TERM e6)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_list7(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_list7(ErlNifEnv* env, ERL_NIF_TERM e1, ..., ERL_NIF_TERM e7)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_list8(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_list8(ErlNifEnv* env, ERL_NIF_TERM e1, ..., ERL_NIF_TERM e8)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_list9(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_list9(ErlNifEnv* env, ERL_NIF_TERM e1, ..., ERL_NIF_TERM e9)</nametext></name> <fsummary>Create a list term.</fsummary> <desc> @@ -2126,7 +2126,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_list_cell(ErlNifEnv* + <name since=""><ret>ERL_NIF_TERM</ret><nametext>enif_make_list_cell(ErlNifEnv* env, ERL_NIF_TERM head, ERL_NIF_TERM tail)</nametext></name> <fsummary>Create a list cell.</fsummary> <desc> @@ -2135,7 +2135,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret> <nametext>enif_make_list_from_array(ErlNifEnv* env, const ERL_NIF_TERM arr[], unsigned cnt)</nametext></name> <fsummary>Create a list term from an array.</fsummary> @@ -2147,7 +2147,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret> <nametext>enif_make_long(ErlNifEnv* env, long int i)</nametext></name> <fsummary>Create an integer term from a long int.</fsummary> <desc> @@ -2156,7 +2156,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_make_map_put(ErlNifEnv* env, + <name since="OTP 18.0"><ret>int</ret><nametext>enif_make_map_put(ErlNifEnv* env, ERL_NIF_TERM map_in, ERL_NIF_TERM key, ERL_NIF_TERM value, ERL_NIF_TERM* map_out)</nametext></name> <fsummary>Insert key-value pair in map.</fsummary> @@ -2172,7 +2172,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_make_map_remove(ErlNifEnv* env, + <name since="OTP 18.0"><ret>int</ret><nametext>enif_make_map_remove(ErlNifEnv* env, ERL_NIF_TERM map_in, ERL_NIF_TERM key, ERL_NIF_TERM* map_out)</nametext> </name> <fsummary>Remove key from map.</fsummary> @@ -2188,7 +2188,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_make_map_update(ErlNifEnv* env, + <name since="OTP 18.0"><ret>int</ret><nametext>enif_make_map_update(ErlNifEnv* env, ERL_NIF_TERM map_in, ERL_NIF_TERM key, ERL_NIF_TERM new_value, ERL_NIF_TERM* map_out)</nametext></name> <fsummary>Replace value for key in map.</fsummary> @@ -2203,7 +2203,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP 21.0"><ret>int</ret> <nametext>enif_make_map_from_arrays(ErlNifEnv* env, ERL_NIF_TERM keys[], ERL_NIF_TERM values[], size_t cnt, ERL_NIF_TERM *map_out)</nametext></name> <fsummary>Make map term from the given keys and values.</fsummary> @@ -2217,7 +2217,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>unsigned char *</ret><nametext>enif_make_new_binary(ErlNifEnv* + <name since="OTP R14B"><ret>unsigned char *</ret><nametext>enif_make_new_binary(ErlNifEnv* env, size_t size, ERL_NIF_TERM* termp)</nametext></name> <fsummary>Allocate and create a new binary term.</fsummary> <desc> @@ -2233,7 +2233,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP 18.0"><ret>ERL_NIF_TERM</ret> <nametext>enif_make_new_map(ErlNifEnv* env)</nametext></name> <fsummary>Make an empty map term.</fsummary> <desc> @@ -2242,7 +2242,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP R14B"><ret>ERL_NIF_TERM</ret> <nametext>enif_make_pid(ErlNifEnv* env, const ErlNifPid* pid)</nametext> </name> <fsummary>Make a pid term.</fsummary> @@ -2252,7 +2252,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret> <nametext>enif_make_ref(ErlNifEnv* env)</nametext></name> <fsummary>Create a reference.</fsummary> <desc> @@ -2262,7 +2262,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret> <nametext>enif_make_resource(ErlNifEnv* env, void* obj)</nametext> </name> <fsummary>Create an opaque handle to a resource object.</fsummary> @@ -2310,7 +2310,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP R14B"><ret>ERL_NIF_TERM</ret> <nametext>enif_make_resource_binary(ErlNifEnv* env, void* obj, const void* data, size_t size)</nametext></name> <fsummary>Create a custom binary term.</fsummary> @@ -2336,7 +2336,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret> + <name since="OTP R15B"><ret>int</ret> <nametext>enif_make_reverse_list(ErlNifEnv* env, ERL_NIF_TERM list_in, ERL_NIF_TERM *list_out)</nametext></name> <fsummary>Create the reverse of a list.</fsummary> @@ -2352,7 +2352,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_string(ErlNifEnv* env, + <name since=""><ret>ERL_NIF_TERM</ret><nametext>enif_make_string(ErlNifEnv* env, const char* string, ErlNifCharEncoding encoding)</nametext></name> <fsummary>Create a string.</fsummary> <desc> @@ -2363,7 +2363,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_string_len(ErlNifEnv* + <name since="OTP R14B"><ret>ERL_NIF_TERM</ret><nametext>enif_make_string_len(ErlNifEnv* env, const char* string, size_t len, ErlNifCharEncoding encoding)</nametext></name> <fsummary>Create a string.</fsummary> @@ -2376,7 +2376,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_sub_binary(ErlNifEnv* + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_sub_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term, size_t pos, size_t size)</nametext></name> <fsummary>Make a subbinary term.</fsummary> <desc> @@ -2388,7 +2388,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple(ErlNifEnv* env, + <name since=""><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple(ErlNifEnv* env, unsigned cnt, ...)</nametext></name> <fsummary>Creates a tuple term.</fsummary> <desc> @@ -2399,23 +2399,23 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple1(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple1(ErlNifEnv* env, ERL_NIF_TERM e1)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple2(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple2(ErlNifEnv* env, ERL_NIF_TERM e1, ERL_NIF_TERM e2)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple3(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple3(ErlNifEnv* env, ERL_NIF_TERM e1, ERL_NIF_TERM e2, ERL_NIF_TERM e3)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple4(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple4(ErlNifEnv* env, ERL_NIF_TERM e1, ..., ERL_NIF_TERM e4)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple5(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple5(ErlNifEnv* env, ERL_NIF_TERM e1, ..., ERL_NIF_TERM e5)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple6(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple6(ErlNifEnv* env, ERL_NIF_TERM e1, ..., ERL_NIF_TERM e6)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple7(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple7(ErlNifEnv* env, ERL_NIF_TERM e1, ..., ERL_NIF_TERM e7)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple8(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple8(ErlNifEnv* env, ERL_NIF_TERM e1, ..., ERL_NIF_TERM e8)</nametext></name> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple9(ErlNifEnv* env, + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple9(ErlNifEnv* env, ERL_NIF_TERM e1, ..., ERL_NIF_TERM e9)</nametext></name> <fsummary>Create a tuple term.</fsummary> <desc> @@ -2427,7 +2427,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret> <nametext>enif_make_tuple_from_array(ErlNifEnv* env, const ERL_NIF_TERM arr[], unsigned cnt)</nametext></name> <fsummary>Create a tuple term from an array.</fsummary> @@ -2438,7 +2438,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP R13B04"><ret>ERL_NIF_TERM</ret> <nametext>enif_make_uint(ErlNifEnv* env, unsigned int i)</nametext> </name> <fsummary>Create an unsigned integer term.</fsummary> @@ -2448,7 +2448,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP R14B"><ret>ERL_NIF_TERM</ret> <nametext>enif_make_uint64(ErlNifEnv* env, ErlNifUInt64 i)</nametext> </name> <fsummary>Create an unsigned integer term.</fsummary> @@ -2458,7 +2458,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since=""><ret>ERL_NIF_TERM</ret> <nametext>enif_make_ulong(ErlNifEnv* env, unsigned long i)</nametext> </name> <fsummary>Create an integer term from an unsigned long int.</fsummary> @@ -2468,7 +2468,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_unique_integer(ErlNifEnv + <name since="OTP 19.0"><ret>ERL_NIF_TERM</ret><nametext>enif_make_unique_integer(ErlNifEnv *env, ErlNifUniqueInteger properties)</nametext></name> <fsummary></fsummary> <desc> @@ -2486,7 +2486,7 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> - <name><ret>int</ret><nametext>enif_map_iterator_create(ErlNifEnv *env, + <name since="OTP 18.0"><ret>int</ret><nametext>enif_map_iterator_create(ErlNifEnv *env, ERL_NIF_TERM map, ErlNifMapIterator *iter, ErlNifMapIteratorEntry entry)</nametext></name> <fsummary>Create a map iterator.</fsummary> @@ -2521,7 +2521,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>void</ret><nametext>enif_map_iterator_destroy(ErlNifEnv *env, + <name since="OTP 18.0"><ret>void</ret><nametext>enif_map_iterator_destroy(ErlNifEnv *env, ErlNifMapIterator *iter)</nametext></name> <fsummary>Destroy a map iterator.</fsummary> <desc> @@ -2532,7 +2532,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>int</ret><nametext>enif_map_iterator_get_pair(ErlNifEnv *env, + <name since="OTP 18.0"><ret>int</ret><nametext>enif_map_iterator_get_pair(ErlNifEnv *env, ErlNifMapIterator *iter, ERL_NIF_TERM *key, ERL_NIF_TERM *value)</nametext></name> <fsummary>Get key and value at current map iterator position.</fsummary> @@ -2545,7 +2545,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>int</ret><nametext>enif_map_iterator_is_head(ErlNifEnv *env, + <name since="OTP 18.0"><ret>int</ret><nametext>enif_map_iterator_is_head(ErlNifEnv *env, ErlNifMapIterator *iter)</nametext></name> <fsummary>Check if map iterator is positioned before first.</fsummary> <desc> @@ -2555,7 +2555,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>int</ret><nametext>enif_map_iterator_is_tail(ErlNifEnv *env, + <name since="OTP 18.0"><ret>int</ret><nametext>enif_map_iterator_is_tail(ErlNifEnv *env, ErlNifMapIterator *iter)</nametext></name> <fsummary>Check if map iterator is positioned after last.</fsummary> <desc> @@ -2565,7 +2565,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>int</ret><nametext>enif_map_iterator_next(ErlNifEnv *env, + <name since="OTP 18.0"><ret>int</ret><nametext>enif_map_iterator_next(ErlNifEnv *env, ErlNifMapIterator *iter)</nametext></name> <fsummary>Increment map iterator to point to next entry.</fsummary> <desc> @@ -2577,7 +2577,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>int</ret><nametext>enif_map_iterator_prev(ErlNifEnv *env, + <name since="OTP 18.0"><ret>int</ret><nametext>enif_map_iterator_prev(ErlNifEnv *env, ErlNifMapIterator *iter)</nametext></name> <fsummary>Decrement map iterator to point to previous entry.</fsummary> <desc> @@ -2589,8 +2589,8 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>int</ret><nametext>enif_monitor_process(ErlNifEnv* caller_env, void* obj, - const ErlNifPid* target_pid, ErlNifMonitor* mon)</nametext></name> + <name since="OTP 20.0"><ret>int</ret><nametext>enif_monitor_process(ErlNifEnv* caller_env, + void* obj, const ErlNifPid* target_pid, ErlNifMonitor* mon)</nametext></name> <fsummary>Monitor a process from a resource.</fsummary> <desc> <marker id="enif_monitor_process"></marker> @@ -2621,7 +2621,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>ErlNifTime</ret> + <name since="OTP 18.3"><ret>ErlNifTime</ret> <nametext>enif_monotonic_time(ErlNifTimeUnit time_unit)</nametext> </name> <fsummary>Get Erlang monotonic time.</fsummary> @@ -2642,7 +2642,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>ErlNifMutex *</ret> + <name since="OTP R13B04"><ret>ErlNifMutex *</ret> <nametext>enif_mutex_create(char *name)</nametext></name> <fsummary></fsummary> <desc> @@ -2652,7 +2652,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_mutex_destroy(ErlNifMutex *mtx)</nametext></name> <fsummary></fsummary> <desc> @@ -2662,7 +2662,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_mutex_lock(ErlNifMutex *mtx)</nametext></name> <fsummary></fsummary> <desc> @@ -2672,7 +2672,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>char*</ret> + <name since="OTP 21.0"><ret>char*</ret> <nametext>enif_mutex_name(ErlNifMutex* mtx)</nametext></name> <fsummary></fsummary> <desc> @@ -2682,7 +2682,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>int</ret> + <name since="OTP R13B04"><ret>int</ret> <nametext>enif_mutex_trylock(ErlNifMutex *mtx)</nametext></name> <fsummary></fsummary> <desc> @@ -2692,7 +2692,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_mutex_unlock(ErlNifMutex *mtx)</nametext></name> <fsummary></fsummary> <desc> @@ -2702,7 +2702,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>ERL_NIF_TERM</ret> + <name since="OTP 19.0"><ret>ERL_NIF_TERM</ret> <nametext>enif_now_time(ErlNifEnv *env)</nametext></name> <fsummary></fsummary> <desc> @@ -2713,7 +2713,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>ErlNifResourceType *</ret> + <name since="OTP R13B04"><ret>ErlNifResourceType *</ret> <nametext>enif_open_resource_type(ErlNifEnv* env, const char* module_str, const char* name, ErlNifResourceDtor* dtor, ErlNifResourceFlags flags, ErlNifResourceFlags* tried)</nametext> @@ -2752,7 +2752,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>ErlNifResourceType *</ret> + <name since="OTP 20.0"><ret>ErlNifResourceType *</ret> <nametext>enif_open_resource_type_x(ErlNifEnv* env, const char* name, const ErlNifResourceTypeInit* init, ErlNifResourceFlags flags, ErlNifResourceFlags* tried)</nametext> @@ -2771,7 +2771,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>int</ret><nametext>enif_port_command(ErlNifEnv* env, const + <name since="OTP 19.0"><ret>int</ret><nametext>enif_port_command(ErlNifEnv* env, const ErlNifPort* to_port, ErlNifEnv *msg_env, ERL_NIF_TERM msg)</nametext> </name> <fsummary>Send a port_command to to_port.</fsummary> @@ -2814,7 +2814,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>void *</ret> + <name since="OTP R13B04"><ret>void *</ret> <nametext>enif_priv_data(ErlNifEnv* env)</nametext></name> <fsummary>Get the private data of a NIF library.</fsummary> <desc> @@ -2825,7 +2825,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_raise_exception(ErlNifEnv* + <name since="OTP 18.0"><ret>ERL_NIF_TERM</ret><nametext>enif_raise_exception(ErlNifEnv* env, ERL_NIF_TERM reason)</nametext></name> <fsummary>Raise a NIF error exception.</fsummary> <desc> @@ -2848,7 +2848,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>void *</ret> + <name since="OTP 20.2"><ret>void *</ret> <nametext>enif_realloc(void* ptr, size_t size)</nametext></name> <fsummary>Reallocate dynamic memory.</fsummary> <desc> @@ -2862,7 +2862,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>int</ret> + <name since="OTP R13B04"><ret>int</ret> <nametext>enif_realloc_binary(ErlNifBinary* bin, size_t size)</nametext> </name> <fsummary>Change the size of a binary.</fsummary> @@ -2876,7 +2876,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>void</ret> + <name since=""><ret>void</ret> <nametext>enif_release_binary(ErlNifBinary* bin)</nametext></name> <fsummary>Release a binary.</fsummary> <desc> @@ -2887,7 +2887,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_release_resource(void* obj)</nametext></name> <fsummary>Release a resource object.</fsummary> <desc> @@ -2906,7 +2906,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>ErlNifRWLock *</ret> + <name since="OTP R13B04"><ret>ErlNifRWLock *</ret> <nametext>enif_rwlock_create(char *name)</nametext></name> <fsummary></fsummary> <desc> @@ -2916,7 +2916,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_rwlock_destroy(ErlNifRWLock *rwlck)</nametext></name> <fsummary></fsummary> <desc> @@ -2926,7 +2926,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>char*</ret> + <name since="OTP 21.0"><ret>char*</ret> <nametext>enif_rwlock_name(ErlNifRWLock* rwlck)</nametext></name> <fsummary></fsummary> <desc> @@ -2936,7 +2936,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_rwlock_rlock(ErlNifRWLock *rwlck)</nametext></name> <fsummary></fsummary> <desc> @@ -2946,7 +2946,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_rwlock_runlock(ErlNifRWLock *rwlck)</nametext></name> <fsummary></fsummary> <desc> @@ -2956,7 +2956,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_rwlock_rwlock(ErlNifRWLock *rwlck)</nametext></name> <fsummary></fsummary> <desc> @@ -2966,7 +2966,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_rwlock_rwunlock(ErlNifRWLock *rwlck)</nametext></name> <fsummary></fsummary> <desc> @@ -2976,7 +2976,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>int</ret> + <name since="OTP R13B04"><ret>int</ret> <nametext>enif_rwlock_tryrlock(ErlNifRWLock *rwlck)</nametext></name> <fsummary></fsummary> <desc> @@ -2986,7 +2986,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>int</ret> + <name since="OTP R13B04"><ret>int</ret> <nametext>enif_rwlock_tryrwlock(ErlNifRWLock *rwlck)</nametext></name> <fsummary></fsummary> <desc> @@ -2996,7 +2996,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>ERL_NIF_TERM</ret><nametext>enif_schedule_nif(ErlNifEnv* env, + <name since="OTP 17.3"><ret>ERL_NIF_TERM</ret><nametext>enif_schedule_nif(ErlNifEnv* env, const char* fun_name, int flags, ERL_NIF_TERM (*fp)(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]), int argc, const ERL_NIF_TERM argv[])</nametext></name> @@ -3041,7 +3041,7 @@ enif_map_iterator_destroy(env, &iter);</code> </func> <func> - <name><ret>int</ret> + <name since="OTP 20.0"><ret>int</ret> <nametext>enif_select(ErlNifEnv* env, ErlNifEvent event, enum ErlNifSelectFlags mode, void* obj, const ErlNifPid* pid, ERL_NIF_TERM ref)</nametext> </name> @@ -3135,7 +3135,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>ErlNifPid *</ret> + <name since="OTP R14B"><ret>ErlNifPid *</ret> <nametext>enif_self(ErlNifEnv* caller_env, ErlNifPid* pid)</nametext> </name> <fsummary>Get the pid of the calling process.</fsummary> @@ -3148,8 +3148,8 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>int</ret><nametext>enif_send(ErlNifEnv* caller_env, ErlNifPid* to_pid, - ErlNifEnv* msg_env, ERL_NIF_TERM msg)</nametext></name> + <name since="OTP R14B"><ret>int</ret><nametext>enif_send(ErlNifEnv* caller_env, + ErlNifPid* to_pid, ErlNifEnv* msg_env, ERL_NIF_TERM msg)</nametext></name> <fsummary>Send a message to a process.</fsummary> <desc> <p>Sends a message to a process.</p> @@ -3195,7 +3195,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>unsigned</ret> + <name since="OTP R13B04"><ret>unsigned</ret> <nametext>enif_sizeof_resource(void* obj)</nametext></name> <fsummary>Get the byte size of a resource object.</fsummary> <desc> @@ -3206,7 +3206,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>int</ret><nametext>enif_snprintf(char *str, size_t size, const + <name since="OTP 19.0"><ret>int</ret><nametext>enif_snprintf(char *str, size_t size, const char *format, ...)</nametext></name> <fsummary>Format strings and Erlang terms.</fsummary> <desc> @@ -3220,7 +3220,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>void</ret><nametext>enif_system_info(ErlNifSysInfo + <name since="OTP R13B04"><ret>void</ret><nametext>enif_system_info(ErlNifSysInfo *sys_info_ptr, size_t size)</nametext></name> <fsummary>Get information about the Erlang runtime system.</fsummary> <desc> @@ -3230,7 +3230,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>int</ret><nametext>enif_term_to_binary(ErlNifEnv *env, + <name since="OTP 19.0"><ret>int</ret><nametext>enif_term_to_binary(ErlNifEnv *env, ERL_NIF_TERM term, ErlNifBinary *bin)</nametext></name> <fsummary>Convert a term to the external format.</fsummary> <desc> @@ -3247,7 +3247,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>int</ret> + <name since="OTP R13B04"><ret>int</ret> <nametext>enif_thread_create(char *name,ErlNifTid *tid,void * (*func)(void *),void *args,ErlNifThreadOpts *opts)</nametext></name> @@ -3259,7 +3259,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_thread_exit(void *resp)</nametext></name> <fsummary></fsummary> <desc> @@ -3269,7 +3269,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>int</ret> + <name since="OTP R13B04"><ret>int</ret> <nametext>enif_thread_join(ErlNifTid, void **respp)</nametext></name> <fsummary></fsummary> <desc> @@ -3279,7 +3279,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>char*</ret> + <name since="OTP 21.0"><ret>char*</ret> <nametext>enif_thread_name(ErlNifTid tid)</nametext></name> <fsummary>Thread name</fsummary> <desc> @@ -3289,7 +3289,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>ErlNifThreadOpts *</ret> + <name since="OTP R13B04"><ret>ErlNifThreadOpts *</ret> <nametext>enif_thread_opts_create(char *name)</nametext></name> <fsummary></fsummary> <desc> @@ -3299,7 +3299,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_thread_opts_destroy(ErlNifThreadOpts *opts)</nametext> </name> <fsummary></fsummary> @@ -3310,7 +3310,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>ErlNifTid</ret> + <name since="OTP R13B04"><ret>ErlNifTid</ret> <nametext>enif_thread_self(void)</nametext></name> <fsummary></fsummary> <desc> @@ -3320,7 +3320,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>int</ret> + <name since="OTP 19.0"><ret>int</ret> <nametext>enif_thread_type(void)</nametext></name> <fsummary>Determine type of current thread</fsummary> <desc> @@ -3342,7 +3342,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>ErlNifTime</ret> + <name since="OTP 18.3"><ret>ErlNifTime</ret> <nametext>enif_time_offset(ErlNifTimeUnit time_unit)</nametext></name> <fsummary>Get current time offset.</fsummary> <desc> @@ -3364,7 +3364,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>void *</ret> + <name since="OTP R13B04"><ret>void *</ret> <nametext>enif_tsd_get(ErlNifTSDKey key)</nametext></name> <fsummary></fsummary> <desc> @@ -3374,7 +3374,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>int</ret> + <name since="OTP R13B04"><ret>int</ret> <nametext>enif_tsd_key_create(char *name, ErlNifTSDKey *key)</nametext> </name> <fsummary></fsummary> @@ -3385,7 +3385,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_tsd_key_destroy(ErlNifTSDKey key)</nametext></name> <fsummary></fsummary> <desc> @@ -3395,7 +3395,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>void</ret> + <name since="OTP R13B04"><ret>void</ret> <nametext>enif_tsd_set(ErlNifTSDKey key, void *data)</nametext></name> <fsummary></fsummary> <desc> @@ -3405,7 +3405,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>int</ret> + <name since="OTP 21.0"><ret>int</ret> <nametext>enif_vfprintf(FILE *stream, const char *format, va_list ap) </nametext></name> <fsummary>Format strings and Erlang terms.</fsummary> @@ -3417,7 +3417,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>int</ret> + <name since="OTP 21.0"><ret>int</ret> <nametext>enif_vsnprintf(char *str, size_t size, const char *format, va_list ap) </nametext></name> <fsummary>Format strings and Erlang terms.</fsummary> @@ -3429,7 +3429,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>int</ret> + <name since="OTP 20.0"><ret>int</ret> <nametext>enif_whereis_pid(ErlNifEnv *env, ERL_NIF_TERM name, ErlNifPid *pid)</nametext></name> <fsummary>Looks up a process by its registered name.</fsummary> @@ -3457,7 +3457,7 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { </func> <func> - <name><ret>int</ret> + <name since="OTP 20.0"><ret>int</ret> <nametext>enif_whereis_port(ErlNifEnv *env, ERL_NIF_TERM name, ErlNifPort *port)</nametext></name> <fsummary>Looks up a port by its registered name.</fsummary> diff --git a/erts/doc/src/erl_prim_loader.xml b/erts/doc/src/erl_prim_loader.xml index 286bac6c93..043d11b7b4 100644 --- a/erts/doc/src/erl_prim_loader.xml +++ b/erts/doc/src/erl_prim_loader.xml @@ -29,7 +29,7 @@ <rev></rev> <file>erl_prim_loader.xml</file> </header> - <module>erl_prim_loader</module> + <module since="">erl_prim_loader</module> <modulesummary>Low-level Erlang loader.</modulesummary> <description> <p>This module is used to load all Erlang modules into @@ -47,7 +47,7 @@ <funcs> <func> - <name name="get_file" arity="1"/> + <name name="get_file" arity="1" since=""/> <fsummary>Get a file.</fsummary> <desc> <p>Fetches a file using the low-level loader. @@ -65,7 +65,7 @@ </func> <func> - <name name="get_path" arity="0"/> + <name name="get_path" arity="0" since=""/> <fsummary>Get the path set in the loader.</fsummary> <desc> <p>Gets the path set in the loader. The path is @@ -75,7 +75,7 @@ </func> <func> - <name name="list_dir" arity="1"/> + <name name="list_dir" arity="1" since=""/> <fsummary>List files in a directory.</fsummary> <desc> <p>Lists all the files in a directory. Returns @@ -92,7 +92,7 @@ </func> <func> - <name name="read_file_info" arity="1"/> + <name name="read_file_info" arity="1" since=""/> <fsummary>Get information about a file.</fsummary> <desc> <p>Retrieves information about a file. Returns @@ -114,7 +114,7 @@ </func> <func> - <name name="read_link_info" arity="1"/> + <name name="read_link_info" arity="1" since="OTP 17.1.2"/> <fsummary>Get information about a link or file.</fsummary> <desc> <p>Works like @@ -131,7 +131,7 @@ </func> <func> - <name name="set_path" arity="1"/> + <name name="set_path" arity="1" since=""/> <fsummary>Set the path of the loader.</fsummary> <desc> <p>Sets the path of the loader if diff --git a/erts/doc/src/erl_tracer.xml b/erts/doc/src/erl_tracer.xml index fd3c17f337..fa4717bc2f 100644 --- a/erts/doc/src/erl_tracer.xml +++ b/erts/doc/src/erl_tracer.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>erl_tracer</module> + <module since="OTP 19.0">erl_tracer</module> <modulesummary>Erlang tracer behavior.</modulesummary> <description> <p>This behavior module implements the back end of the Erlang @@ -195,7 +195,7 @@ <funcs> <func> - <name>Module:enabled(TraceTag, TracerState, Tracee) -> Result</name> + <name since="OTP 19.0">Module:enabled(TraceTag, TracerState, Tracee) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> <v>TraceTag = <seealso marker="#type-trace_tag"> @@ -224,7 +224,7 @@ </func> <func> - <name>Module:enabled_call(TraceTag, TracerState, Tracee) -> Result</name> + <name since="OTP 19.0">Module:enabled_call(TraceTag, TracerState, Tracee) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> <v>TraceTag = <seealso marker="#type-trace_tag_call"> @@ -244,7 +244,7 @@ </func> <func> - <name>Module:enabled_garbage_collection(TraceTag, TracerState, Tracee) -> Result</name> + <name since="OTP 19.0">Module:enabled_garbage_collection(TraceTag, TracerState, Tracee) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> <v>TraceTag = <seealso marker="#type-trace_tag_gc"> @@ -264,7 +264,7 @@ </func> <func> - <name>Module:enabled_ports(TraceTag, TracerState, Tracee) -> Result</name> + <name since="OTP 19.0">Module:enabled_ports(TraceTag, TracerState, Tracee) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> <v>TraceTag = <seealso marker="#type-trace_tag_ports"> @@ -284,7 +284,7 @@ </func> <func> - <name>Module:enabled_procs(TraceTag, TracerState, Tracee) -> Result</name> + <name since="OTP 19.0">Module:enabled_procs(TraceTag, TracerState, Tracee) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> <v>TraceTag = <seealso marker="#type-trace_tag_procs"> @@ -304,7 +304,7 @@ </func> <func> - <name>Module:enabled_receive(TraceTag, TracerState, Tracee) -> Result + <name since="OTP 19.0">Module:enabled_receive(TraceTag, TracerState, Tracee) -> Result </name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> @@ -325,7 +325,7 @@ </func> <func> - <name>Module:enabled_running_ports(TraceTag, TracerState, Tracee) -> + <name since="OTP 19.0">Module:enabled_running_ports(TraceTag, TracerState, Tracee) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> @@ -346,7 +346,7 @@ </func> <func> - <name>Module:enabled_running_procs(TraceTag, TracerState, Tracee) -> + <name since="OTP 19.0">Module:enabled_running_procs(TraceTag, TracerState, Tracee) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> @@ -368,7 +368,7 @@ </func> <func> - <name>Module:enabled_send(TraceTag, TracerState, Tracee) -> Result</name> + <name since="OTP 19.0">Module:enabled_send(TraceTag, TracerState, Tracee) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> <v>TraceTag = <seealso marker="#type-trace_tag_send"> @@ -388,7 +388,7 @@ </func> <func> - <name>Module:trace(TraceTag, TracerState, Tracee, TraceTerm, + <name since="OTP 19.0">Module:trace(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> @@ -417,7 +417,7 @@ </func> <func> - <name name="trace">Module:trace(seq_trace, TracerState, Label, + <name name="trace" since="OTP 19.0">Module:trace(seq_trace, TracerState, Label, SeqTraceInfo, Opts) -> Result</name> <fsummary>Check if a sequence trace event is to be generated.</fsummary> <type> @@ -439,7 +439,7 @@ </func> <func> - <name>Module:trace_call(TraceTag, TracerState, Tracee, TraceTerm, + <name since="OTP 19.0">Module:trace_call(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> @@ -463,7 +463,7 @@ </func> <func> - <name>Module:trace_garbage_collection(TraceTag, TracerState, Tracee, + <name since="OTP 19.0">Module:trace_garbage_collection(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> @@ -487,7 +487,7 @@ </func> <func> - <name>Module:trace_ports(TraceTag, TracerState, Tracee, TraceTerm, + <name since="OTP 19.0">Module:trace_ports(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> @@ -511,7 +511,7 @@ </func> <func> - <name>Module:trace_procs(TraceTag, TracerState, Tracee, TraceTerm, + <name since="OTP 19.0">Module:trace_procs(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> @@ -535,7 +535,7 @@ </func> <func> - <name>Module:trace_receive(TraceTag, TracerState, Tracee, TraceTerm, + <name since="OTP 19.0">Module:trace_receive(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> @@ -559,7 +559,7 @@ </func> <func> - <name>Module:trace_running_ports(TraceTag, TracerState, Tracee, + <name since="OTP 19.0">Module:trace_running_ports(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> @@ -583,7 +583,7 @@ </func> <func> - <name>Module:trace_running_procs(TraceTag, TracerState, Tracee, + <name since="OTP 19.0">Module:trace_running_procs(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> @@ -607,7 +607,7 @@ </func> <func> - <name>Module:trace_send(TraceTag, TracerState, Tracee, TraceTerm, + <name since="OTP 19.0">Module:trace_send(TraceTag, TracerState, Tracee, TraceTerm, Opts) -> Result</name> <fsummary>Check if a trace event is to be generated.</fsummary> <type> diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 8e014c3010..6932b18571 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -29,7 +29,7 @@ <rev></rev> <file>erlang.xml</file> </header> - <module>erlang</module> + <module since="">erlang</module> <modulesummary>The Erlang BIFs.</modulesummary> <description> <p>By convention, most Built-In Functions (BIFs) are included @@ -210,8 +210,8 @@ <funcs> <func> - <name name="abs" arity="1" clause_i="1"/> - <name name="abs" arity="1" clause_i="2"/> + <name name="abs" arity="1" clause_i="1" since=""/> + <name name="abs" arity="1" clause_i="2" since=""/> <fsummary>Arithmetical absolute value.</fsummary> <desc> <p>Returns an integer or float that is the arithmetical @@ -227,7 +227,7 @@ </func> <func> - <name name="adler32" arity="1"/> + <name name="adler32" arity="1" since=""/> <fsummary>Compute adler32 checksum.</fsummary> <desc> <p>Computes and returns the adler32 checksum for @@ -236,7 +236,7 @@ </func> <func> - <name name="adler32" arity="2"/> + <name name="adler32" arity="2" since=""/> <fsummary>Compute adler32 checksum.</fsummary> <desc> <p>Continues computing the adler32 checksum by combining @@ -253,7 +253,7 @@ Y = erlang:adler32([Data1,Data2]).</code> </func> <func> - <name name="adler32_combine" arity="3"/> + <name name="adler32_combine" arity="3" since=""/> <fsummary>Combine two adler32 checksums.</fsummary> <desc> <p>Combines two previously computed adler32 checksums. @@ -272,7 +272,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="append_element" arity="2"/> + <name name="append_element" arity="2" since=""/> <fsummary>Append an extra element to a tuple.</fsummary> <desc> <p>Returns a new tuple that has one element more than @@ -289,7 +289,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="apply" arity="2"/> + <name name="apply" arity="2" since=""/> <fsummary>Apply a function to an argument list.</fsummary> <desc> <p>Calls a fun, passing the elements in <c><anno>Args</anno></c> @@ -307,7 +307,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="apply" arity="3"/> + <name name="apply" arity="3" since=""/> <fsummary>Apply a function to an argument list.</fsummary> <desc> <p>Returns the result of applying <c>Function</c> in @@ -337,7 +337,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="atom_to_binary" arity="2"/> + <name name="atom_to_binary" arity="2" since=""/> <fsummary>Return the binary representation of an atom.</fsummary> <desc> <p>Returns a binary corresponding to the text @@ -362,7 +362,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="atom_to_list" arity="1"/> + <name name="atom_to_list" arity="1" since=""/> <fsummary>Text representation of an atom.</fsummary> <desc> <p>Returns a string corresponding to the text @@ -374,7 +374,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="binary_part" arity="2"/> + <name name="binary_part" arity="2" since="OTP R14B"/> <fsummary>Extract a part of a binary.</fsummary> <desc> <p>Extracts the part of the binary described by @@ -399,7 +399,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="binary_part" arity="3"/> + <name name="binary_part" arity="3" since="OTP R14B"/> <fsummary>Extract a part of a binary.</fsummary> <desc> <p>The same as <c>binary_part(<anno>Subject</anno>, @@ -409,7 +409,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="binary_to_atom" arity="2"/> + <name name="binary_to_atom" arity="2" since=""/> <fsummary>Convert from text representation to an atom.</fsummary> <desc> <p>Returns the atom whose text representation is @@ -438,7 +438,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="binary_to_existing_atom" arity="2"/> + <name name="binary_to_existing_atom" arity="2" since=""/> <fsummary>Convert from text representation to an atom.</fsummary> <desc> <p>As @@ -459,7 +459,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="binary_to_float" arity="1"/> + <name name="binary_to_float" arity="1" since="OTP R16B"/> <fsummary>Convert from text representation to a float.</fsummary> <desc> <p>Returns the float whose text representation is @@ -473,7 +473,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="binary_to_integer" arity="1"/> + <name name="binary_to_integer" arity="1" since="OTP R16B"/> <fsummary>Convert from text representation to an integer.</fsummary> <desc> <p>Returns an integer whose text representation is @@ -487,7 +487,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="binary_to_integer" arity="2"/> + <name name="binary_to_integer" arity="2" since="OTP R16B"/> <fsummary>Convert from text representation to an integer.</fsummary> <desc> <p>Returns an integer whose text representation in base @@ -502,7 +502,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="binary_to_list" arity="1"/> + <name name="binary_to_list" arity="1" since=""/> <fsummary>Convert a binary to a list.</fsummary> <desc> <p>Returns a list of integers corresponding to the bytes of @@ -511,7 +511,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="binary_to_list" arity="3"/> + <name name="binary_to_list" arity="3" since=""/> <fsummary>Convert part of a binary to a list.</fsummary> <type_desc variable="Start">1..byte_size(<c><anno>Binary</anno></c>) </type_desc> @@ -533,7 +533,7 @@ Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="binary_to_term" arity="1"/> + <name name="binary_to_term" arity="1" since=""/> <fsummary>Decode an Erlang external term format binary.</fsummary> <desc> <p>Returns an Erlang term that is the result of decoding @@ -559,7 +559,7 @@ hello </func> <func> - <name name="binary_to_term" arity="2"/> + <name name="binary_to_term" arity="2" since="OTP R13B04"/> <fsummary>Decode an Erlang external term format binary.</fsummary> <desc> <p>As <c>binary_to_term/1</c>, but takes these options:</p> @@ -613,7 +613,7 @@ hello </func> <func> - <name name="bit_size" arity="1"/> + <name name="bit_size" arity="1" since=""/> <fsummary>Return the size of a bitstring.</fsummary> <desc> <p>Returns an integer that is the size in bits of @@ -628,7 +628,7 @@ hello </func> <func> - <name name="bitstring_to_list" arity="1"/> + <name name="bitstring_to_list" arity="1" since=""/> <fsummary>Convert a bitstring to a list.</fsummary> <desc> <p>Returns a list of integers corresponding to the bytes of @@ -639,7 +639,7 @@ hello </func> <func> - <name name="bump_reductions" arity="1"/> + <name name="bump_reductions" arity="1" since=""/> <fsummary>Increment the reduction counter.</fsummary> <desc> <p>This implementation-dependent function increments @@ -657,7 +657,7 @@ hello </func> <func> - <name name="byte_size" arity="1"/> + <name name="byte_size" arity="1" since=""/> <fsummary>Return the size of a bitstring (or binary).</fsummary> <desc> <p>Returns an integer that is the number of bytes needed to @@ -674,7 +674,7 @@ hello </func> <func> - <name name="cancel_timer" arity="1"/> + <name name="cancel_timer" arity="1" since=""/> <fsummary>Cancel a timer.</fsummary> <desc> <p>Cancels a timer. The same as calling @@ -684,7 +684,7 @@ hello </func> <func> - <name name="cancel_timer" arity="2"/> + <name name="cancel_timer" arity="2" since="OTP 18.0"/> <fsummary>Cancel a timer.</fsummary> <desc> <p>Cancels a timer that has been created by @@ -766,7 +766,7 @@ hello </func> <func> - <name name="ceil" arity="1"/> + <name name="ceil" arity="1" since="OTP 20.0"/> <fsummary>Returns the smallest integer not less than the argument</fsummary> <desc> <p>Returns the smallest integer not less than @@ -779,7 +779,7 @@ hello </desc> </func> <func> - <name name="check_old_code" arity="1"/> + <name name="check_old_code" arity="1" since="OTP R14B04"/> <fsummary>Check if a module has old code.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Module</anno></c> has old code, @@ -790,7 +790,7 @@ hello </func> <func> - <name name="check_process_code" arity="2"/> + <name name="check_process_code" arity="2" since=""/> <fsummary>Check if a process executes old code for a module.</fsummary> <desc> <p>The same as @@ -801,7 +801,7 @@ hello </func> <func> - <name name="check_process_code" arity="3"/> + <name name="check_process_code" arity="3" since="OTP 17.0"/> <fsummary>Check if a process executes old code for a module.</fsummary> <desc> <p>Checks if the node local process identified by @@ -904,7 +904,7 @@ hello </func> <func> - <name name="convert_time_unit" arity="3"/> + <name name="convert_time_unit" arity="3" since="OTP 18.0"/> <fsummary>Convert time unit of a time value.</fsummary> <desc> <p>Converts the <c><anno>Time</anno></c> value of time unit @@ -922,7 +922,7 @@ hello </func> <func> - <name name="crc32" arity="1"/> + <name name="crc32" arity="1" since=""/> <fsummary>Compute crc32 (IEEE 802.3) checksum.</fsummary> <desc> <p>Computes and returns the crc32 (IEEE 802.3 style) checksum @@ -931,7 +931,7 @@ hello </func> <func> - <name name="crc32" arity="2"/> + <name name="crc32" arity="2" since=""/> <fsummary>Compute crc32 (IEEE 802.3) checksum.</fsummary> <desc> <p>Continues computing the crc32 checksum by combining @@ -948,7 +948,7 @@ Y = erlang:crc32([Data1,Data2]).</code> </func> <func> - <name name="crc32_combine" arity="3"/> + <name name="crc32_combine" arity="3" since=""/> <fsummary>Combine two crc32 (IEEE 802.3) checksums.</fsummary> <desc> <p>Combines two previously computed crc32 checksums. @@ -967,7 +967,7 @@ Z = erlang:crc32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="date" arity="0"/> + <name name="date" arity="0" since=""/> <fsummary>Current date.</fsummary> <desc> <p>Returns the current date as <c>{Year, Month, Day}</c>.</p> @@ -980,7 +980,7 @@ Z = erlang:crc32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="decode_packet" arity="3"/> + <name name="decode_packet" arity="3" since=""/> <fsummary>Extract a protocol packet from a binary.</fsummary> <desc> <p>Decodes the binary <c><anno>Bin</anno></c> according to the packet @@ -1090,7 +1090,7 @@ Z = erlang:crc32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="delete_element" arity="2"/> + <name name="delete_element" arity="2" since="OTP R16B"/> <fsummary>Delete element at index in a tuple.</fsummary> <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno>)</type_desc> <desc> @@ -1103,7 +1103,7 @@ Z = erlang:crc32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="delete_module" arity="1"/> + <name name="delete_module" arity="1" since=""/> <fsummary>Make the current code for a module old.</fsummary> <desc> <p>Makes the current code for <c><anno>Module</anno></c> become old @@ -1121,7 +1121,7 @@ Z = erlang:crc32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="demonitor" arity="1"/> + <name name="demonitor" arity="1" since=""/> <fsummary>Stop monitoring.</fsummary> <desc> <p>If <c><anno>MonitorRef</anno></c> is a reference that the @@ -1163,7 +1163,7 @@ Z = erlang:crc32_combine(X,Y,iolist_size(Data2)).</code> </func> <func> - <name name="demonitor" arity="2"/> + <name name="demonitor" arity="2" since=""/> <fsummary>Stop monitoring.</fsummary> <desc> <p>The returned value is <c>true</c> unless <c>info</c> is part @@ -1231,7 +1231,7 @@ end</code> </func> <func> - <name name="disconnect_node" arity="1"/> + <name name="disconnect_node" arity="1" since=""/> <fsummary>Force the disconnection of a node.</fsummary> <desc> <p>Forces the disconnection of a node. This appears to @@ -1245,7 +1245,7 @@ end</code> </func> <func> - <name name="display" arity="1"/> + <name name="display" arity="1" since=""/> <fsummary>Print a term on standard output.</fsummary> <desc> <p>Prints a text representation of <c><anno>Term</anno></c> on the @@ -1257,7 +1257,7 @@ end</code> </func> <func> - <name name="dist_ctrl_get_data" arity="1"/> + <name name="dist_ctrl_get_data" arity="1" since="OTP 21.0"/> <fsummary>Get distribution channel data to pass to another node.</fsummary> <desc> <p> @@ -1290,7 +1290,7 @@ end</code> </func> <func> - <name name="dist_ctrl_get_data_notification" arity="1"/> + <name name="dist_ctrl_get_data_notification" arity="1" since="OTP 21.0"/> <fsummary>Request notification about available outgoing distribution channel data.</fsummary> <desc> <p> @@ -1326,7 +1326,7 @@ end</code> </func> <func> - <name name="dist_ctrl_input_handler" arity="2"/> + <name name="dist_ctrl_input_handler" arity="2" since="OTP 21.0"/> <fsummary>Register distribution channel input handler process.</fsummary> <desc> <p> @@ -1359,7 +1359,7 @@ end</code> </func> <func> - <name name="dist_ctrl_put_data" arity="2"/> + <name name="dist_ctrl_put_data" arity="2" since="OTP 21.0"/> <fsummary>Pass data into the VM from a distribution channel.</fsummary> <desc> <p> @@ -1392,7 +1392,7 @@ end</code> </func> <func> - <name name="element" arity="2"/> + <name name="element" arity="2" since=""/> <fsummary>Return the Nth element of a tuple.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> <desc> @@ -1406,7 +1406,7 @@ b</pre> </func> <func> - <name name="erase" arity="0"/> + <name name="erase" arity="0" since=""/> <fsummary>Return and delete the process dictionary.</fsummary> <desc> <p>Returns the process dictionary and deletes it, for @@ -1420,7 +1420,7 @@ b</pre> </func> <func> - <name name="erase" arity="1"/> + <name name="erase" arity="1" since=""/> <fsummary>Return and delete a value from the process dictionary. </fsummary> <desc> @@ -1437,7 +1437,7 @@ b</pre> </func> <func> - <name name="error" arity="1"/> + <name name="error" arity="1" since=""/> <fsummary>Stop execution with a specified reason.</fsummary> <desc> <p>Stops the execution of the calling process with the reason @@ -1461,7 +1461,7 @@ b</pre> </func> <func> - <name name="error" arity="2"/> + <name name="error" arity="2" since=""/> <fsummary>Stop execution with a specified reason.</fsummary> <desc> <p>Stops the execution of the calling process with the reason @@ -1478,7 +1478,7 @@ b</pre> </func> <func> - <name name="exit" arity="1"/> + <name name="exit" arity="1" since=""/> <fsummary>Stop execution with a specified reason.</fsummary> <desc> <p>Stops the execution of the calling process with exit reason @@ -1495,7 +1495,7 @@ b</pre> </func> <func> - <name name="exit" arity="2"/> + <name name="exit" arity="2" since=""/> <fsummary>Send an exit signal to a process or a port.</fsummary> <desc> <p>Sends an exit signal with exit reason <c><anno>Reason</anno></c> to @@ -1531,7 +1531,7 @@ b</pre> </func> <func> - <name name="external_size" arity="1"/> + <name name="external_size" arity="1" since="OTP R14B04"/> <fsummary>Calculate the maximum size for a term encoded in the Erlang external term format.</fsummary> <desc> @@ -1550,7 +1550,7 @@ erlang:external_size(<anno>Term</anno>, [])</code> </func> <func> - <name name="external_size" arity="2"/> + <name name="external_size" arity="2" since="OTP R14B04"/> <fsummary>Calculate the maximum size for a term encoded in the Erlang external term format.</fsummary> <desc> @@ -1570,7 +1570,7 @@ true</pre> </func> <func> - <name name="float" arity="1"/> + <name name="float" arity="1" since=""/> <fsummary>Convert a number to a float.</fsummary> <desc> <p>Returns a float by converting <c><anno>Number</anno></c> to a float, @@ -1592,7 +1592,7 @@ true</pre> </func> <func> - <name name="float_to_binary" arity="1"/> + <name name="float_to_binary" arity="1" since="OTP R16B"/> <fsummary>Text representation of a float.</fsummary> <desc> <p>The same as @@ -1601,7 +1601,7 @@ true</pre> </func> <func> - <name name="float_to_binary" arity="2"/> + <name name="float_to_binary" arity="2" since="OTP R16B"/> <fsummary>Text representation of a float formatted using specified options.</fsummary> <desc> @@ -1619,7 +1619,7 @@ true</pre> </func> <func> - <name name="float_to_list" arity="1"/> + <name name="float_to_list" arity="1" since=""/> <fsummary>Text representation of a float.</fsummary> <desc> <p>The same as @@ -1628,7 +1628,7 @@ true</pre> </func> <func> - <name name="float_to_list" arity="2"/> + <name name="float_to_list" arity="2" since="OTP R16B"/> <fsummary>Text representation of a float formatted using specified options.</fsummary> <desc> @@ -1664,7 +1664,7 @@ true</pre> </func> <func> - <name name="floor" arity="1"/> + <name name="floor" arity="1" since="OTP 20.0"/> <fsummary>Returns the largest integer not greater than the argument</fsummary> <desc> <p>Returns the largest integer not greater than @@ -1678,7 +1678,7 @@ true</pre> </func> <func> - <name name="fun_info" arity="1"/> + <name name="fun_info" arity="1" since=""/> <fsummary>Information about a fun.</fsummary> <desc> <p>Returns a list with information about the fun @@ -1779,7 +1779,7 @@ true</pre> </func> <func> - <name name="fun_info" arity="2"/> + <name name="fun_info" arity="2" since=""/> <fsummary>Information about a fun.</fsummary> <type name="fun_info_item"/> <desc> @@ -1799,7 +1799,7 @@ true</pre> </func> <func> - <name name="fun_to_list" arity="1"/> + <name name="fun_to_list" arity="1" since=""/> <fsummary>Text representation of a fun.</fsummary> <desc> <p>Returns a string corresponding to the text @@ -1808,7 +1808,7 @@ true</pre> </func> <func> - <name name="function_exported" arity="3"/> + <name name="function_exported" arity="3" since=""/> <fsummary>Check if a function is exported and loaded.</fsummary> <desc> <p>Returns <c>true</c> if the module <c><anno>Module</anno></c> is @@ -1824,7 +1824,7 @@ true</pre> </func> <func> - <name name="garbage_collect" arity="0"/> + <name name="garbage_collect" arity="0" since=""/> <fsummary>Force an immediate garbage collection of the calling process. </fsummary> <desc> @@ -1840,7 +1840,7 @@ true</pre> </func> <func> - <name name="garbage_collect" arity="1"/> + <name name="garbage_collect" arity="1" since=""/> <fsummary>Garbage collect a process.</fsummary> <desc> <p>The same as @@ -1850,7 +1850,7 @@ true</pre> </func> <func> - <name name="garbage_collect" arity="2"/> + <name name="garbage_collect" arity="2" since="OTP 17.0"/> <fsummary>Garbage collect a process.</fsummary> <desc> <p>Garbage collects the node local process identified by @@ -1915,7 +1915,7 @@ true</pre> </func> <func> - <name name="get" arity="0"/> + <name name="get" arity="0" since=""/> <fsummary>Return the process dictionary.</fsummary> <desc> <p>Returns the process dictionary as a list of @@ -1930,7 +1930,7 @@ true</pre> </func> <func> - <name name="get" arity="1"/> + <name name="get" arity="1" since=""/> <fsummary>Return a value from the process dictionary.</fsummary> <desc> <p>Returns the value <c><anno>Val</anno></c> associated with @@ -1946,7 +1946,7 @@ true</pre> </func> <func> - <name name="get_cookie" arity="0"/> + <name name="get_cookie" arity="0" since=""/> <fsummary>Get the magic cookie of the local node.</fsummary> <desc> <p>Returns the magic cookie of the local node if the node is @@ -1955,7 +1955,7 @@ true</pre> </func> <func> - <name name="get_keys" arity="0"/> + <name name="get_keys" arity="0" since="OTP 18.0"/> <fsummary>Return a list of all keys from the process dictionary. </fsummary> <desc> @@ -1971,7 +1971,7 @@ true</pre> </func> <func> - <name name="get_keys" arity="1"/> + <name name="get_keys" arity="1" since=""/> <fsummary>Return a list of keys from the process dictionary.</fsummary> <desc> <p>Returns a list of keys that are associated with the value @@ -1989,7 +1989,7 @@ true</pre> </func> <func> - <name name="get_stacktrace" arity="0"/> + <name name="get_stacktrace" arity="0" since=""/> <fsummary>Get the call stack back-trace of the last exception.</fsummary> <type name="stack_item"/> <desc> @@ -2054,7 +2054,7 @@ end</pre> </func> <func> - <name name="group_leader" arity="0"/> + <name name="group_leader" arity="0" since=""/> <fsummary>Get the group leader for the calling process.</fsummary> <desc> <p>Returns the process identifier of the group leader for the @@ -2069,7 +2069,7 @@ end</pre> </func> <func> - <name name="group_leader" arity="2"/> + <name name="group_leader" arity="2" since=""/> <fsummary>Set the group leader for a process.</fsummary> <desc> <p>Sets the group leader of <c><anno>Pid</anno></c> @@ -2090,7 +2090,7 @@ end</pre> </func> <func> - <name name="halt" arity="0"/> + <name name="halt" arity="0" since=""/> <fsummary>Halt the Erlang runtime system and indicate normal exit to the calling environment.</fsummary> <desc> @@ -2103,7 +2103,7 @@ os_prompt%</pre> </func> <func> - <name name="halt" arity="1"/> + <name name="halt" arity="1" since=""/> <fsummary>Halt the Erlang runtime system.</fsummary> <desc> <p>The same as <seealso marker="#halt/2"> @@ -2117,7 +2117,7 @@ os_prompt%</pre> </func> <func> - <name name="halt" arity="2"/> + <name name="halt" arity="2" since="OTP R15B01"/> <fsummary>Halt the Erlang runtime system.</fsummary> <desc> <p><c><anno>Status</anno></c> must be a non-negative integer, a string, @@ -2159,7 +2159,7 @@ os_prompt%</pre> </func> <func> - <name name="hd" arity="1"/> + <name name="hd" arity="1" since=""/> <fsummary>Head of a list.</fsummary> <desc> <p>Returns the head of <c><anno>List</anno></c>, that is, @@ -2174,7 +2174,7 @@ os_prompt%</pre> </func> <func> - <name name="hibernate" arity="3"/> + <name name="hibernate" arity="3" since=""/> <fsummary>Hibernate a process until a message is sent to it.</fsummary> <desc> <p>Puts the calling process into a wait state where its memory @@ -2215,7 +2215,7 @@ os_prompt%</pre> </func> <func> - <name name="insert_element" arity="3"/> + <name name="insert_element" arity="3" since="OTP R16B"/> <fsummary>Insert an element at index in a tuple.</fsummary> <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno>) + 1</type_desc> @@ -2233,7 +2233,7 @@ os_prompt%</pre> </func> <func> - <name name="integer_to_binary" arity="1"/> + <name name="integer_to_binary" arity="1" since="OTP R16B"/> <fsummary>Text representation of an integer.</fsummary> <desc> <p>Returns a binary corresponding to the text @@ -2245,7 +2245,7 @@ os_prompt%</pre> </func> <func> - <name name="integer_to_binary" arity="2"/> + <name name="integer_to_binary" arity="2" since="OTP R16B"/> <fsummary>Text representation of an integer.</fsummary> <desc> <p>Returns a binary corresponding to the text @@ -2258,7 +2258,7 @@ os_prompt%</pre> </func> <func> - <name name="integer_to_list" arity="1"/> + <name name="integer_to_list" arity="1" since=""/> <fsummary>Text representation of an integer.</fsummary> <desc> <p>Returns a string corresponding to the text @@ -2270,7 +2270,7 @@ os_prompt%</pre> </func> <func> - <name name="integer_to_list" arity="2"/> + <name name="integer_to_list" arity="2" since=""/> <fsummary>Text representation of an integer.</fsummary> <desc> <p>Returns a string corresponding to the text @@ -2283,7 +2283,7 @@ os_prompt%</pre> </func> <func> - <name name="iolist_size" arity="1"/> + <name name="iolist_size" arity="1" since=""/> <fsummary>Size of an iolist.</fsummary> <desc> <p>Returns an integer, that is the size in bytes, @@ -2296,7 +2296,7 @@ os_prompt%</pre> </func> <func> - <name name="iolist_to_binary" arity="1"/> + <name name="iolist_to_binary" arity="1" since=""/> <fsummary>Convert an iolist to a binary.</fsummary> <desc> <p>Returns a binary that is made from the integers and @@ -2314,7 +2314,7 @@ os_prompt%</pre> </func> <func> - <name name="iolist_to_iovec" arity="1"/> + <name name="iolist_to_iovec" arity="1" since="OTP 20.1"/> <fsummary>Converts an iolist to a iovec.</fsummary> <desc> <p>Returns an iovec that is made from the integers and binaries in @@ -2323,7 +2323,7 @@ os_prompt%</pre> </func> <func> - <name name="is_alive" arity="0"/> + <name name="is_alive" arity="0" since=""/> <fsummary>Check whether the local node is alive.</fsummary> <desc> <p>Returns <c>true</c> if the local node is alive (that is, if @@ -2333,7 +2333,7 @@ os_prompt%</pre> </func> <func> - <name name="is_atom" arity="1"/> + <name name="is_atom" arity="1" since=""/> <fsummary>Check whether a term is an atom.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an atom, @@ -2343,7 +2343,7 @@ os_prompt%</pre> </func> <func> - <name name="is_binary" arity="1"/> + <name name="is_binary" arity="1" since=""/> <fsummary>Check whether a term is a binary.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a binary, @@ -2354,7 +2354,7 @@ os_prompt%</pre> </func> <func> - <name name="is_bitstring" arity="1"/> + <name name="is_bitstring" arity="1" since=""/> <fsummary>Check whether a term is a bitstring.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a @@ -2364,7 +2364,7 @@ os_prompt%</pre> </func> <func> - <name name="is_boolean" arity="1"/> + <name name="is_boolean" arity="1" since=""/> <fsummary>Check whether a term is a boolean.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is the @@ -2375,7 +2375,7 @@ os_prompt%</pre> </func> <func> - <name name="is_builtin" arity="3"/> + <name name="is_builtin" arity="3" since=""/> <fsummary>Check if a function is a BIF implemented in C.</fsummary> <desc> <p>This BIF is useful for builders of cross-reference tools.</p> @@ -2386,7 +2386,7 @@ os_prompt%</pre> </func> <func> - <name name="is_float" arity="1"/> + <name name="is_float" arity="1" since=""/> <fsummary>Check whether a term is a float.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a floating point @@ -2396,7 +2396,7 @@ os_prompt%</pre> </func> <func> - <name name="is_function" arity="1"/> + <name name="is_function" arity="1" since=""/> <fsummary>Check whether a term is a fun.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a fun, otherwise @@ -2406,7 +2406,7 @@ os_prompt%</pre> </func> <func> - <name name="is_function" arity="2"/> + <name name="is_function" arity="2" since=""/> <fsummary>Check whether a term is a fun with a specified given arity. </fsummary> <desc> @@ -2418,7 +2418,7 @@ os_prompt%</pre> </func> <func> - <name name="is_integer" arity="1"/> + <name name="is_integer" arity="1" since=""/> <fsummary>Check whether a term is an integer.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an integer, @@ -2428,7 +2428,7 @@ os_prompt%</pre> </func> <func> - <name name="is_list" arity="1"/> + <name name="is_list" arity="1" since=""/> <fsummary>Check whether a term is a list.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a list with @@ -2438,7 +2438,7 @@ os_prompt%</pre> </func> <func> - <name name="is_map" arity="1"/> + <name name="is_map" arity="1" since="OTP 17.0"/> <fsummary>Check whether a term is a map.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a map, @@ -2448,7 +2448,7 @@ os_prompt%</pre> </func> <func> - <name name="is_map_key" arity="2"/> + <name name="is_map_key" arity="2" since="OTP 21.0"/> <fsummary></fsummary> <desc> <p>Returns <c>true</c> if map <c><anno>Map</anno></c> contains @@ -2468,7 +2468,7 @@ false</code> </func> <func> - <name name="is_number" arity="1"/> + <name name="is_number" arity="1" since=""/> <fsummary>Check whether a term is a number.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an integer or a @@ -2478,7 +2478,7 @@ false</code> </func> <func> - <name name="is_pid" arity="1"/> + <name name="is_pid" arity="1" since=""/> <fsummary>Check whether a term is a process identifier.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a process @@ -2488,7 +2488,7 @@ false</code> </func> <func> - <name name="is_port" arity="1"/> + <name name="is_port" arity="1" since=""/> <fsummary>Check whether a term is a port.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a port identifier, @@ -2498,7 +2498,7 @@ false</code> </func> <func> - <name name="is_process_alive" arity="1"/> + <name name="is_process_alive" arity="1" since=""/> <fsummary>Check whether a process is alive.</fsummary> <desc> <p><c><anno>Pid</anno></c> must refer to a process at the local @@ -2510,7 +2510,7 @@ false</code> </func> <func> - <name name="is_record" arity="2"/> + <name name="is_record" arity="2" since=""/> <fsummary>Check whether a term appears to be a record.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a tuple and its @@ -2531,7 +2531,7 @@ false</code> </func> <func> - <name name="is_record" arity="3"/> + <name name="is_record" arity="3" since=""/> <fsummary>Check whether a term appears to be a record.</fsummary> <desc> <p><c><anno>RecordTag</anno></c> must be an atom.</p> @@ -2550,7 +2550,7 @@ false</code> </func> <func> - <name name="is_reference" arity="1"/> + <name name="is_reference" arity="1" since=""/> <fsummary>Check whether a term is a reference.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a reference, @@ -2560,7 +2560,7 @@ false</code> </func> <func> - <name name="is_tuple" arity="1"/> + <name name="is_tuple" arity="1" since=""/> <fsummary>Check whether a term is a tuple.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a tuple, @@ -2570,7 +2570,7 @@ false</code> </func> <func> - <name name="length" arity="1"/> + <name name="length" arity="1" since=""/> <fsummary>Length of a list.</fsummary> <desc> <p>Returns the length of <c><anno>List</anno></c>, for example:</p> @@ -2582,7 +2582,7 @@ false</code> </func> <func> - <name name="link" arity="1"/> + <name name="link" arity="1" since=""/> <fsummary>Create a link to another process (or port).</fsummary> <desc> <p>Creates a link between the calling process and another @@ -2609,7 +2609,7 @@ false</code> </func> <func> - <name name="list_to_atom" arity="1"/> + <name name="list_to_atom" arity="1" since=""/> <fsummary>Convert from text representation to an atom.</fsummary> <desc> <p>Returns the atom whose text representation is @@ -2629,7 +2629,7 @@ false</code> </func> <func> - <name name="list_to_binary" arity="1"/> + <name name="list_to_binary" arity="1" since=""/> <fsummary>Convert a list to a binary.</fsummary> <desc> <p>Returns a binary that is made from the integers and @@ -2647,7 +2647,7 @@ false</code> </func> <func> - <name name="list_to_bitstring" arity="1"/> + <name name="list_to_bitstring" arity="1" since=""/> <fsummary>Convert a list to a bitstring.</fsummary> <type name="bitstring_list"/> <desc> @@ -2668,7 +2668,7 @@ false</code> </func> <func> - <name name="list_to_existing_atom" arity="1"/> + <name name="list_to_existing_atom" arity="1" since=""/> <fsummary>Convert from text representation to an atom.</fsummary> <desc> <p>Returns the atom whose text representation is @@ -2689,7 +2689,7 @@ false</code> </func> <func> - <name name="list_to_float" arity="1"/> + <name name="list_to_float" arity="1" since=""/> <fsummary>Convert from text representation to a float.</fsummary> <desc> <p>Returns the float whose text representation is @@ -2703,7 +2703,7 @@ false</code> </func> <func> - <name name="list_to_integer" arity="1"/> + <name name="list_to_integer" arity="1" since=""/> <fsummary>Convert from text representation to an integer.</fsummary> <desc> <p>Returns an integer whose text representation is @@ -2717,7 +2717,7 @@ false</code> </func> <func> - <name name="list_to_integer" arity="2"/> + <name name="list_to_integer" arity="2" since=""/> <fsummary>Convert from text representation to an integer.</fsummary> <desc> <p>Returns an integer whose text representation in base @@ -2732,7 +2732,7 @@ false</code> </func> <func> - <name name="list_to_pid" arity="1"/> + <name name="list_to_pid" arity="1" since=""/> <fsummary>Convert from text representation to a pid.</fsummary> <desc> <p>Returns a process identifier whose text representation is a @@ -2750,7 +2750,7 @@ false</code> </func> <func> - <name name="list_to_port" arity="1"/> + <name name="list_to_port" arity="1" since="OTP 20.0"/> <fsummary>Convert from text representation to a port.</fsummary> <desc> <p>Returns a port identifier whose text representation is a @@ -2768,7 +2768,7 @@ false</code> </func> <func> - <name name="list_to_ref" arity="1"/> + <name name="list_to_ref" arity="1" since="OTP 20.0"/> <fsummary>Convert from text representation to a ref.</fsummary> <desc> <p>Returns a reference whose text representation is a @@ -2786,7 +2786,7 @@ false</code> </func> <func> - <name name="list_to_tuple" arity="1"/> + <name name="list_to_tuple" arity="1" since=""/> <fsummary>Convert a list to a tuple.</fsummary> <desc> <p>Returns a tuple corresponding to <c><anno>List</anno></c>, @@ -2799,7 +2799,7 @@ false</code> </func> <func> - <name name="load_module" arity="2"/> + <name name="load_module" arity="2" since=""/> <fsummary>Load object code for a module.</fsummary> <desc> <p>If <c><anno>Binary</anno></c> contains the object code for module @@ -2832,7 +2832,7 @@ false</code> </func> <func> - <name name="load_nif" arity="2"/> + <name name="load_nif" arity="2" since=""/> <fsummary>Load NIF library.</fsummary> <desc> <p>Loads and links a dynamic library containing native @@ -2885,7 +2885,7 @@ false</code> </func> <func> - <name name="loaded" arity="0"/> + <name name="loaded" arity="0" since=""/> <fsummary>List all loaded modules.</fsummary> <desc> <p>Returns a list of all loaded Erlang modules (current and @@ -2896,7 +2896,7 @@ false</code> </func> <func> - <name name="localtime" arity="0"/> + <name name="localtime" arity="0" since=""/> <fsummary>Current local date and time.</fsummary> <desc> <p>Returns the current local date and time, @@ -2911,7 +2911,7 @@ false</code> </func> <func> - <name name="localtime_to_universaltime" arity="1"/> + <name name="localtime_to_universaltime" arity="1" since=""/> <fsummary>Convert from local to Universal Time Coordinated (UTC) date and time.</fsummary> <desc> @@ -2928,7 +2928,7 @@ false</code> </func> <func> - <name name="localtime_to_universaltime" arity="2"/> + <name name="localtime_to_universaltime" arity="2" since=""/> <fsummary>Convert from local to Universal Time Coordinated (UTC) date and time.</fsummary> <desc> @@ -2954,7 +2954,7 @@ false</code> </func> <func> - <name name="make_ref" arity="0"/> + <name name="make_ref" arity="0" since=""/> <fsummary>Return a unique reference.</fsummary> <desc> <p>Returns a @@ -2971,7 +2971,7 @@ false</code> </func> <func> - <name name="make_tuple" arity="2"/> + <name name="make_tuple" arity="2" since=""/> <fsummary>Create a new tuple of a specified arity.</fsummary> <desc> <p>Creates a new tuple of the specified <c><anno>Arity</anno></c>, where @@ -2983,7 +2983,7 @@ false</code> </func> <func> - <name name="make_tuple" arity="3"/> + <name name="make_tuple" arity="3" since=""/> <fsummary>Create a new tuple with specifed arity and contents.</fsummary> <desc> <p>Creates a tuple of size <c><anno>Arity</anno></c>, where each element @@ -3001,7 +3001,7 @@ false</code> </func> <func> - <name name="map_get" arity="2" /> + <name name="map_get" arity="2" since="OTP 21.0"/> <fsummary>Extract a value from a map</fsummary> <desc> <p>Returns value <c><anno>Value</anno></c> associated with @@ -3020,7 +3020,7 @@ false</code> </func> <func> - <name name="map_size" arity="1"/> + <name name="map_size" arity="1" since="OTP 17.0"/> <fsummary>Return the size of a map.</fsummary> <desc> <p>Returns an integer, which is the number of key-value pairs @@ -3033,7 +3033,7 @@ false</code> </func> <func> - <name name="match_spec_test" arity="3"/> + <name name="match_spec_test" arity="3" since="OTP 19.0"/> <fsummary>Test that a match specification works.</fsummary> <desc> <p>Tests a match specification used in calls to @@ -3071,7 +3071,7 @@ false</code> </func> <func> - <name name="max" arity="2"/> + <name name="max" arity="2" since=""/> <fsummary>Return the largest of two terms.</fsummary> <desc> <p>Returns the largest of <c><anno>Term1</anno></c> and @@ -3081,7 +3081,7 @@ false</code> </func> <func> - <name name="md5" arity="1"/> + <name name="md5" arity="1" since=""/> <fsummary>Compute an MD5 message digest.</fsummary> <desc> <p>Computes an MD5 message digest from <c><anno>Data</anno></c>, where @@ -3099,7 +3099,7 @@ false</code> </func> <func> - <name name="md5_final" arity="1"/> + <name name="md5_final" arity="1" since=""/> <fsummary>Finish the update of an MD5 context and return the computed MD5 message digest.</fsummary> <desc> @@ -3109,7 +3109,7 @@ false</code> </func> <func> - <name name="md5_init" arity="0"/> + <name name="md5_init" arity="0" since=""/> <fsummary>Create an MD5 context.</fsummary> <desc> <p>Creates an MD5 context, to be used in the following calls to @@ -3118,7 +3118,7 @@ false</code> </func> <func> - <name name="md5_update" arity="2"/> + <name name="md5_update" arity="2" since=""/> <fsummary>Update an MD5 context with data and return a new context. </fsummary> <desc> @@ -3129,7 +3129,7 @@ false</code> </func> <func> - <name name="memory" arity="0"/> + <name name="memory" arity="0" since=""/> <fsummary>Information about dynamically allocated memory.</fsummary> <type name="memory_type"/> <desc> @@ -3273,8 +3273,8 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="memory" arity="1" clause_i="1"/> - <name name="memory" arity="1" clause_i="2"/> + <name name="memory" arity="1" clause_i="1" since=""/> + <name name="memory" arity="1" clause_i="2" since=""/> <fsummary>Information about dynamically allocated memory.</fsummary> <type name="memory_type"/> <desc> @@ -3313,7 +3313,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="min" arity="2"/> + <name name="min" arity="2" since=""/> <fsummary>Return the smallest of two terms.</fsummary> <desc> <p>Returns the smallest of <c><anno>Term1</anno></c> and @@ -3323,7 +3323,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="module_loaded" arity="1"/> + <name name="module_loaded" arity="1" since=""/> <fsummary>Check if a module is loaded.</fsummary> <desc> <p>Returns <c>true</c> if the module <c><anno>Module</anno></c> @@ -3338,9 +3338,9 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="monitor" arity="2" clause_i="1"/> - <name name="monitor" arity="2" clause_i="2"/> - <name name="monitor" arity="2" clause_i="3"/> + <name name="monitor" arity="2" clause_i="1" since=""/> + <name name="monitor" arity="2" clause_i="2" since="OTP 19.0"/> + <name name="monitor" arity="2" clause_i="3" since="OTP 18.0"/> <fsummary>Start monitoring.</fsummary> <type name="registered_name"/> <type name="registered_process_identifier"/> @@ -3512,7 +3512,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="monitor_node" arity="2"/> + <name name="monitor_node" arity="2" since=""/> <fsummary>Monitor the status of a node.</fsummary> <desc> <p>Monitor the status of the node <c><anno>Node</anno></c>. @@ -3536,7 +3536,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="monitor_node" arity="3"/> + <name name="monitor_node" arity="3" since=""/> <fsummary>Monitor the status of a node.</fsummary> <desc> <p>Behaves as @@ -3562,7 +3562,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="monotonic_time" arity="0"/> + <name name="monotonic_time" arity="0" since="OTP 18.0"/> <fsummary>Current Erlang monotonic time.</fsummary> <desc> <p>Returns the current @@ -3596,7 +3596,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="monotonic_time" arity="1"/> + <name name="monotonic_time" arity="1" since="OTP 18.0"/> <fsummary>Current Erlang monotonic time.</fsummary> <desc> <p>Returns the current @@ -3614,7 +3614,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="nif_error" arity="1"/> + <name name="nif_error" arity="1" since="OTP R14B"/> <fsummary>Stop execution with a specified reason.</fsummary> <desc> <p>Works exactly like @@ -3627,7 +3627,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="nif_error" arity="2"/> + <name name="nif_error" arity="2" since="OTP R14B"/> <fsummary>Stop execution with a specified reason.</fsummary> <desc> <p>Works exactly like @@ -3640,7 +3640,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="node" arity="0"/> + <name name="node" arity="0" since=""/> <fsummary>Name of the local node.</fsummary> <desc> <p>Returns the name of the local node. If the node is not alive, @@ -3650,7 +3650,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="node" arity="1"/> + <name name="node" arity="1" since=""/> <fsummary>At which node a pid, port, or reference originates.</fsummary> <desc> <p>Returns the node where <c><anno>Arg</anno></c> originates. @@ -3663,7 +3663,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="nodes" arity="0"/> + <name name="nodes" arity="0" since=""/> <fsummary>All visible nodes in the system.</fsummary> <desc> <p>Returns a list of all visible nodes in the system, except @@ -3672,7 +3672,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="nodes" arity="1"/> + <name name="nodes" arity="1" since=""/> <fsummary>All nodes of a certain type in the system.</fsummary> <desc> <p>Returns a list of nodes according to the argument specified. @@ -3715,7 +3715,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="now" arity="0"/> + <name name="now" arity="0" since=""/> <fsummary>Elapsed time since 00:00 GMT.</fsummary> <type name="timestamp"/> <desc> @@ -3744,7 +3744,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="open_port" arity="2"/> + <name name="open_port" arity="2" since=""/> <fsummary>Open a port.</fsummary> <desc> <p>Returns a port identifier as the result of opening a @@ -4085,7 +4085,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="phash" arity="2"/> + <name name="phash" arity="2" since=""/> <fsummary>Portable hash function.</fsummary> <type_desc variable="Range">Range = 1..2^32, Hash = 1..Range</type_desc> <desc> @@ -4100,8 +4100,8 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="phash2" arity="1"/> - <name name="phash2" arity="2"/> + <name name="phash2" arity="1" since=""/> + <name name="phash2" arity="2" since=""/> <fsummary>Portable hash function.</fsummary> <type_desc variable="Range">1..2^32</type_desc> <type_desc variable="Hash">0..Range-1</type_desc> @@ -4125,7 +4125,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="pid_to_list" arity="1"/> + <name name="pid_to_list" arity="1" since=""/> <fsummary>Text representation of a pid.</fsummary> <desc> <p>Returns a string corresponding to the text @@ -4134,7 +4134,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_call" arity="3"/> + <name name="port_call" arity="3" since=""/> <fsummary>Perform a synchronous call to a port with term data.</fsummary> <desc> <p>Performs a synchronous call to a port. The meaning of @@ -4170,16 +4170,23 @@ RealSystem = system + MissedSystem</code> </item> <tag><c>badarg</c></tag> <item> - If the port driver so decides for any reason (probably + <p>If the port driver so decides for any reason (probably something wrong with <c><anno>Operation</anno></c> - or <c><anno>Data</anno></c>). + or <c><anno>Data</anno></c>).</p> + <warning> + <p>Do not call <c>port_call</c> with an unknown + <c><anno>Port</anno></c> identifier and expect <c>badarg</c> + exception. Any undefined behavior is possible (including node + crash) depending on how the port driver interprets the supplied + arguments.</p> + </warning> </item> </taglist> </desc> </func> <func> - <name name="port_close" arity="1"/> + <name name="port_close" arity="1" since=""/> <fsummary>Close an open port.</fsummary> <desc> <p>Closes an open port. Roughly the same as <c><anno>Port</anno> ! @@ -4219,7 +4226,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_command" arity="2"/> + <name name="port_command" arity="2" since=""/> <fsummary>Send data to a port.</fsummary> <desc> <p>Sends data to a port. Same as @@ -4262,11 +4269,16 @@ RealSystem = system + MissedSystem</code> <p>If <c><anno>Data</anno></c> is an invalid I/O list.</p> </item> </taglist> + <warning> + <p>Do not send data to an unknown port. Any undefined behavior is + possible (including node crash) depending on how the port driver + interprets the data.</p> + </warning> </desc> </func> <func> - <name name="port_command" arity="3"/> + <name name="port_command" arity="3" since=""/> <fsummary>Send data to a port.</fsummary> <desc> <p>Sends data to a port. <c>port_command(Port, Data, [])</c> @@ -4321,11 +4333,16 @@ RealSystem = system + MissedSystem</code> a busy port. </item> </taglist> + <warning> + <p>Do not send data to an unknown port. Any undefined behavior is + possible (including node crash) depending on how the port driver + interprets the data.</p> + </warning> </desc> </func> <func> - <name name="port_connect" arity="2"/> + <name name="port_connect" arity="2" since=""/> <fsummary>Set the owner of a port.</fsummary> <desc> <p>Sets the port owner (the connected port) to <c><anno>Pid</anno></c>. @@ -4394,7 +4411,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_control" arity="3"/> + <name name="port_control" arity="3" since=""/> <fsummary>Perform a synchronous control operation on a port.</fsummary> <desc> <p>Performs a synchronous control operation on a port. @@ -4425,13 +4442,20 @@ RealSystem = system + MissedSystem</code> If the port driver so decides for any reason (probably something wrong with <c><anno>Operation</anno></c> or <c><anno>Data</anno></c>). + <warning> + <p>Do not call <c>port_control/3</c> with an unknown + <c><anno>Port</anno></c> identifier and expect <c>badarg</c> + exception. Any undefined behavior is possible (including node + crash) depending on how the port driver interprets the supplied + arguments.</p> + </warning> </item> </taglist> </desc> </func> <func> - <name name="port_info" arity="1"/> + <name name="port_info" arity="1" since=""/> <fsummary>Information about a port.</fsummary> <desc> <p>Returns a list containing tuples with information about @@ -4462,7 +4486,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="1"/> + <name name="port_info" arity="2" clause_i="1" since=""/> <fsummary>Information about the connected process of a port.</fsummary> <desc> <p><c><anno>Pid</anno></c> is the process identifier of the process @@ -4478,7 +4502,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="2"/> + <name name="port_info" arity="2" clause_i="2" since=""/> <fsummary>Information about the internal index of a port.</fsummary> <desc> <p><c><anno>Index</anno></c> is the internal index of the port. This @@ -4494,7 +4518,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="3"/> + <name name="port_info" arity="2" clause_i="3" since=""/> <fsummary>Information about the input of a port.</fsummary> <desc> <p><c><anno>Bytes</anno></c> is the total number of bytes @@ -4510,7 +4534,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="4"/> + <name name="port_info" arity="2" clause_i="4" since=""/> <fsummary>Information about the links of a port.</fsummary> <desc> <p><c><anno>Pids</anno></c> is a list of the process identifiers @@ -4526,7 +4550,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="5"/> + <name name="port_info" arity="2" clause_i="5" since="OTP R16B"/> <fsummary>Information about the locking of a port.</fsummary> <desc> <p><c><anno>Locking</anno></c> is one of the following:</p> @@ -4547,7 +4571,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="6"/> + <name name="port_info" arity="2" clause_i="6" since="OTP R16B"/> <fsummary>Information about the memory size of a port.</fsummary> <desc> <p><c><anno>Bytes</anno></c> is the total number of @@ -4565,7 +4589,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="7"/> + <name name="port_info" arity="2" clause_i="7" since="OTP R16B"/> <fsummary>Information about the monitors of a port.</fsummary> <desc> <p><c><anno>Monitors</anno></c> represent processes monitored by @@ -4581,7 +4605,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="8"/> + <name name="port_info" arity="2" clause_i="8" since="OTP 19.0"/> <fsummary>Which processes are monitoring this port.</fsummary> <desc> <p>Returns list of pids that are monitoring given port at the @@ -4597,7 +4621,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="9"/> + <name name="port_info" arity="2" clause_i="9" since=""/> <fsummary>Information about the name of a port.</fsummary> <desc> <p><c><anno>Name</anno></c> is the command name set by @@ -4613,7 +4637,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="10"/> + <name name="port_info" arity="2" clause_i="10" since="OTP R16B"/> <fsummary>Information about the OS pid of a port.</fsummary> <desc> <p><c><anno>OsPid</anno></c> is the process identifier (or equivalent) @@ -4632,7 +4656,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="11"/> + <name name="port_info" arity="2" clause_i="11" since=""/> <fsummary>Information about the output of a port.</fsummary> <desc> <p><c><anno>Bytes</anno></c> is the total number of bytes written @@ -4651,7 +4675,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="12"/> + <name name="port_info" arity="2" clause_i="12" since="OTP R16B"/> <fsummary>Information about the parallelism hint of a port.</fsummary> <desc> <p><c><anno>Boolean</anno></c> corresponds to the port parallelism @@ -4662,7 +4686,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="13"/> + <name name="port_info" arity="2" clause_i="13" since="OTP R16B"/> <fsummary>Information about the queue size of a port.</fsummary> <desc> <p><c><anno>Bytes</anno></c> is the total number @@ -4679,7 +4703,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_info" arity="2" clause_i="14"/> + <name name="port_info" arity="2" clause_i="14" since=""/> <fsummary>Information about the registered name of a port.</fsummary> <desc> <p><c><anno>RegisteredName</anno></c> is the registered name of @@ -4696,7 +4720,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="port_to_list" arity="1"/> + <name name="port_to_list" arity="1" since=""/> <fsummary>Text representation of a port identifier.</fsummary> <desc> <p>Returns a string corresponding to the text @@ -4705,7 +4729,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="ports" arity="0"/> + <name name="ports" arity="0" since=""/> <fsummary>List all existing ports.</fsummary> <desc> <p>Returns a list of port identifiers corresponding to all the @@ -4715,7 +4739,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="pre_loaded" arity="0"/> + <name name="pre_loaded" arity="0" since=""/> <fsummary>List all preloaded modules.</fsummary> <desc> <p>Returns a list of Erlang modules that are preloaded in @@ -4726,7 +4750,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="process_display" arity="2"/> + <name name="process_display" arity="2" since=""/> <fsummary>Write information about a local process on standard error. </fsummary> <desc> @@ -4740,7 +4764,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="process_flag" arity="2" clause_i="1"/> + <name name="process_flag" arity="2" clause_i="1" since=""/> <fsummary>Set process flag trap_exit for the calling process.</fsummary> <desc> <p>When <c>trap_exit</c> is set to <c>true</c>, exit signals @@ -4757,7 +4781,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="process_flag" arity="2" clause_i="2"/> + <name name="process_flag" arity="2" clause_i="2" since=""/> <fsummary>Set process flag error_handler for the calling process. </fsummary> <desc> @@ -4772,7 +4796,7 @@ RealSystem = system + MissedSystem</code> <func> <name name="process_flag" arity="2" clause_i="3" - anchor="process_flag_min_heap_size"/> + anchor="process_flag_min_heap_size" since=""/> <fsummary>Set process flag min_heap_size for the calling process. </fsummary> <desc> @@ -4782,7 +4806,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="process_flag" arity="2" clause_i="4"/> + <name name="process_flag" arity="2" clause_i="4" since="OTP R13B04"/> <fsummary>Set process flag min_bin_vheap_size for the calling process. </fsummary> <desc> @@ -4794,7 +4818,7 @@ RealSystem = system + MissedSystem</code> <func> <name name="process_flag" arity="2" clause_i="5" - anchor="process_flag_max_heap_size"/> + anchor="process_flag_max_heap_size" since="OTP 19.0"/> <fsummary>Set process flag max_heap_size for the calling process. </fsummary> <type name="max_heap_size"/> @@ -4868,7 +4892,7 @@ RealSystem = system + MissedSystem</code> <func> <name name="process_flag" arity="2" clause_i="6" - anchor="process_flag_message_queue_data"/> + anchor="process_flag_message_queue_data" since="OTP 19.0"/> <fsummary>Set process flag message_queue_data for the calling process. </fsummary> <type name="message_queue_data"/> @@ -4910,7 +4934,7 @@ RealSystem = system + MissedSystem</code> <func> <name name="process_flag" arity="2" clause_i="7" - anchor="process_flag_priority"/> + anchor="process_flag_priority" since=""/> <fsummary>Set process flag priority for the calling process.</fsummary> <type name="priority_level"/> <desc> @@ -4982,7 +5006,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="process_flag" arity="2" clause_i="8"/> + <name name="process_flag" arity="2" clause_i="8" since=""/> <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. @@ -5013,7 +5037,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="process_flag" arity="2" clause_i="9"/> + <name name="process_flag" arity="2" clause_i="9" since=""/> <fsummary>Set process flag sensitive for the calling process.</fsummary> <desc> <p>Sets or clears flag <c>sensitive</c> for the current process. @@ -5047,7 +5071,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="process_flag" arity="3"/> + <name name="process_flag" arity="3" since=""/> <fsummary>Set process flags for a process.</fsummary> <desc> <p>Sets certain flags for the process <c><anno>Pid</anno></c>, @@ -5062,7 +5086,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="process_info" arity="1"/> + <name name="process_info" arity="1" since=""/> <fsummary>Information about a process.</fsummary> <type name="process_info_result_item"/> <type name="priority_level"/> @@ -5113,8 +5137,8 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="process_info" arity="2" clause_i="1"/> - <name name="process_info" arity="2" clause_i="2"/> + <name name="process_info" arity="2" clause_i="1" since=""/> + <name name="process_info" arity="2" clause_i="2" since=""/> <fsummary>Information about a process.</fsummary> <type name="process_info_item"/> <type name="process_info_result_item"/> @@ -5447,7 +5471,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="processes" arity="0"/> + <name name="processes" arity="0" since=""/> <fsummary>All processes.</fsummary> <desc> <p>Returns a list of process identifiers corresponding to @@ -5464,7 +5488,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="purge_module" arity="1"/> + <name name="purge_module" arity="1" since=""/> <fsummary>Remove old code for a module.</fsummary> <desc> <p>Removes old code for <c><anno>Module</anno></c>. @@ -5489,7 +5513,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="put" arity="2"/> + <name name="put" arity="2" since=""/> <fsummary>Add a new value to the process dictionary.</fsummary> <desc> <p>Adds a new <c><anno>Key</anno></c> to the process dictionary, @@ -5511,7 +5535,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="raise" arity="3"/> + <name name="raise" arity="3" since=""/> <fsummary>Stop execution with an exception of specified class, reason, and call stack backtrace.</fsummary> <type name="raise_stacktrace"/> @@ -5550,7 +5574,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="read_timer" arity="1"/> + <name name="read_timer" arity="1" since=""/> <fsummary>Read the state of a timer.</fsummary> <desc> <p>Reads the state of a timer. The same as calling @@ -5560,7 +5584,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="read_timer" arity="2"/> + <name name="read_timer" arity="2" since="OTP 18.0"/> <fsummary>Read the state of a timer.</fsummary> <desc> <p>Reads the state of a timer that has been created by either @@ -5616,7 +5640,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="ref_to_list" arity="1"/> + <name name="ref_to_list" arity="1" since=""/> <fsummary>Text representation of a reference.</fsummary> <desc> <p>Returns a string corresponding to the text @@ -5629,7 +5653,7 @@ RealSystem = system + MissedSystem</code> </func> <func> - <name name="register" arity="2"/> + <name name="register" arity="2" since=""/> <fsummary>Register a name for a pid (or port).</fsummary> <desc> <p>Associates the name <c><anno>RegName</anno></c> with a process @@ -5658,7 +5682,7 @@ true</pre> </func> <func> - <name name="registered" arity="0"/> + <name name="registered" arity="0" since=""/> <fsummary>All registered names.</fsummary> <desc> <p>Returns a list of names that have been registered using @@ -5671,7 +5695,7 @@ true</pre> </func> <func> - <name name="resume_process" arity="1"/> + <name name="resume_process" arity="1" since=""/> <fsummary>Resume a suspended process.</fsummary> <desc> <p>Decreases the suspend count on the process identified by @@ -5712,7 +5736,7 @@ true</pre> </func> <func> - <name name="round" arity="1"/> + <name name="round" arity="1" since=""/> <fsummary>Return an integer by rounding a number.</fsummary> <desc> <p>Returns an integer by rounding <c><anno>Number</anno></c>, @@ -5725,7 +5749,7 @@ true</pre> </func> <func> - <name name="self" arity="0"/> + <name name="self" arity="0" since=""/> <fsummary>Return pid of the calling process.</fsummary> <desc> <p>Returns the process identifier of the calling process, for @@ -5738,7 +5762,7 @@ true</pre> </func> <func> - <name name="send" arity="2"/> + <name name="send" arity="2" since=""/> <fsummary>Send a message.</fsummary> <type name="dst"/> <desc> @@ -5758,7 +5782,7 @@ true</pre> </func> <func> - <name name="send" arity="3"/> + <name name="send" arity="3" since=""/> <fsummary>Send a message conditionally.</fsummary> <type name="dst"/> <desc> @@ -5790,7 +5814,7 @@ true</pre> </func> <func> - <name name="send_after" arity="3"/> + <name name="send_after" arity="3" since=""/> <fsummary>Start a timer.</fsummary> <desc> <p>Starts a timer. The same as calling @@ -5801,7 +5825,7 @@ true</pre> </func> <func> - <name name="send_after" arity="4"/> + <name name="send_after" arity="4" since="OTP 18.0"/> <fsummary>Start a timer.</fsummary> <desc> <p>Starts a timer. When the timer expires, the message @@ -5814,7 +5838,7 @@ true</pre> </func> <func> - <name name="send_nosuspend" arity="2"/> + <name name="send_nosuspend" arity="2" since=""/> <fsummary>Try to send a message without ever blocking.</fsummary> <type name="dst"/> <desc> @@ -5864,7 +5888,7 @@ true</pre> </func> <func> - <name name="send_nosuspend" arity="3"/> + <name name="send_nosuspend" arity="3" since=""/> <fsummary>Try to send a message without ever blocking.</fsummary> <type name="dst"/> <desc> @@ -5897,7 +5921,7 @@ true</pre> </func> <func> - <name name="set_cookie" arity="2"/> + <name name="set_cookie" arity="2" since=""/> <fsummary>Set the magic cookie of a node.</fsummary> <desc> <p>Sets the magic cookie of <c><anno>Node</anno></c> to the atom @@ -5914,7 +5938,7 @@ true</pre> </func> <func> - <name name="setelement" arity="3"/> + <name name="setelement" arity="3" since=""/> <fsummary>Set the Nth element of a tuple.</fsummary> <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno></type_desc> <desc> @@ -5931,7 +5955,7 @@ true</pre> </func> <func> - <name name="size" arity="1"/> + <name name="size" arity="1" since=""/> <fsummary>Size of a tuple or binary.</fsummary> <desc> <p>Returns the number of elements in a tuple or the number of @@ -5954,7 +5978,7 @@ true</pre> </func> <func> - <name name="spawn" arity="1"/> + <name name="spawn" arity="1" since=""/> <fsummary>Create a new process with a fun as entry point.</fsummary> <desc> <p>Returns the process identifier of a new process started by the @@ -5965,7 +5989,7 @@ true</pre> </func> <func> - <name name="spawn" arity="2"/> + <name name="spawn" arity="2" since=""/> <fsummary>Create a new process with a fun as entry point on a specified node.</fsummary> <desc> @@ -5979,7 +6003,7 @@ true</pre> </func> <func> - <name name="spawn" arity="3"/> + <name name="spawn" arity="3" since=""/> <fsummary>Create a new process with a function as entry point.</fsummary> <desc> <p>Returns the process identifier of a new process started by @@ -6004,7 +6028,7 @@ true</pre> </func> <func> - <name name="spawn" arity="4"/> + <name name="spawn" arity="4" since=""/> <fsummary>Create a new process with a function as entry point on a specified node.</fsummary> <desc> @@ -6019,7 +6043,7 @@ true</pre> </func> <func> - <name name="spawn_link" arity="1"/> + <name name="spawn_link" arity="1" since=""/> <fsummary>Create and link to a new process with a fun as entry point. </fsummary> <desc> @@ -6033,7 +6057,7 @@ true</pre> </func> <func> - <name name="spawn_link" arity="2"/> + <name name="spawn_link" arity="2" since=""/> <fsummary>Create and link to a new process with a fun as entry point on a specified node.</fsummary> <desc> @@ -6050,7 +6074,7 @@ true</pre> </func> <func> - <name name="spawn_link" arity="3"/> + <name name="spawn_link" arity="3" since=""/> <fsummary>Create and link to a new process with a function as entry point. </fsummary> <desc> @@ -6064,7 +6088,7 @@ true</pre> </func> <func> - <name name="spawn_link" arity="4"/> + <name name="spawn_link" arity="4" since=""/> <fsummary>Create and link to a new process with a function as entry point on a specified node.</fsummary> <desc> @@ -6082,7 +6106,7 @@ true</pre> </func> <func> - <name name="spawn_monitor" arity="1"/> + <name name="spawn_monitor" arity="1" since=""/> <fsummary>Create and monitor a new process with a fun as entry point. </fsummary> <desc> @@ -6096,7 +6120,7 @@ true</pre> </func> <func> - <name name="spawn_monitor" arity="3"/> + <name name="spawn_monitor" arity="3" since=""/> <fsummary>Create and monitor a new process with a function as entry point. </fsummary> <desc> @@ -6110,7 +6134,7 @@ true</pre> </func> <func> - <name name="spawn_opt" arity="2"/> + <name name="spawn_opt" arity="2" since=""/> <fsummary>Create a new process with a fun as entry point.</fsummary> <type name="priority_level"/> <type name="max_heap_size"/> @@ -6128,7 +6152,7 @@ true</pre> </func> <func> - <name name="spawn_opt" arity="3"/> + <name name="spawn_opt" arity="3" since=""/> <fsummary>Create a new process with a fun as entry point on a specified node.</fsummary> <type name="priority_level"/> @@ -6146,7 +6170,7 @@ true</pre> </func> <func> - <name name="spawn_opt" arity="4"/> + <name name="spawn_opt" arity="4" since=""/> <fsummary>Create a new process with a function as entry point.</fsummary> <type name="priority_level"/> <type name="max_heap_size"/> @@ -6282,7 +6306,7 @@ true</pre> </func> <func> - <name name="spawn_opt" arity="5"/> + <name name="spawn_opt" arity="5" since=""/> <fsummary>Create a new process with a function as entry point on a specified node.</fsummary> <type name="priority_level"/> @@ -6305,7 +6329,7 @@ true</pre> </func> <func> - <name name="split_binary" arity="2"/> + <name name="split_binary" arity="2" since=""/> <fsummary>Split a binary into two.</fsummary> <type_desc variable="Pos">0..byte_size(Bin)</type_desc> <desc> @@ -6329,7 +6353,7 @@ true</pre> </func> <func> - <name name="start_timer" arity="3"/> + <name name="start_timer" arity="3" since=""/> <fsummary>Start a timer.</fsummary> <desc> <p>Starts a timer. The same as calling @@ -6340,7 +6364,7 @@ true</pre> </func> <func> - <name name="start_timer" arity="4"/> + <name name="start_timer" arity="4" since="OTP 18.0"/> <fsummary>Start a timer.</fsummary> <desc> <p>Starts a timer. When the timer expires, the message @@ -6399,7 +6423,7 @@ true</pre> <func> <name name="statistics" arity="1" clause_i="1" - anchor="statistics_active_tasks"/> + anchor="statistics_active_tasks" since="OTP 18.3"/> <fsummary>Information about active processes and ports.</fsummary> <desc> <p>Returns the same as @@ -6414,7 +6438,7 @@ true</pre> <func> <name name="statistics" arity="1" clause_i="2" - anchor="statistics_active_tasks_all"/> + anchor="statistics_active_tasks_all" since="OTP 20.0"/> <fsummary>Information about active processes and ports.</fsummary> <desc> <p>Returns a list where each element represents the amount @@ -6455,7 +6479,7 @@ true</pre> </func> <func> - <name name="statistics" arity="1" clause_i="3"/> + <name name="statistics" arity="1" clause_i="3" since=""/> <fsummary>Information about context switches.</fsummary> <desc> <p>Returns the total number of context switches since the @@ -6465,7 +6489,7 @@ true</pre> <func> <name name="statistics" arity="1" clause_i="4" - anchor="statistics_exact_reductions"/> + anchor="statistics_exact_reductions" since=""/> <fsummary>Information about exact reductions.</fsummary> <desc> <p>Returns the number of exact reductions.</p> @@ -6479,7 +6503,7 @@ true</pre> </func> <func> - <name name="statistics" arity="1" clause_i="5"/> + <name name="statistics" arity="1" clause_i="5" since=""/> <fsummary>Information about garbage collection.</fsummary> <desc> <p>Returns information about garbage collection, for example:</p> @@ -6491,7 +6515,7 @@ true</pre> </func> <func> - <name name="statistics" arity="1" clause_i="6"/> + <name name="statistics" arity="1" clause_i="6" since=""/> <fsummary>Information about I/O.</fsummary> <desc> <p>Returns <c><anno>Input</anno></c>, @@ -6503,7 +6527,7 @@ true</pre> <func> <name name="statistics" arity="1" clause_i="7" - anchor="statistics_microstate_accounting"/> + anchor="statistics_microstate_accounting" since="OTP 19.0"/> <fsummary>Information about microstate accounting.</fsummary> <desc> <p>Microstate accounting can be used to measure how much time the Erlang @@ -6646,7 +6670,7 @@ lists:map( <func> <name name="statistics" arity="1" clause_i="8" - anchor="statistics_reductions"/> + anchor="statistics_reductions" since=""/> <fsummary>Information about reductions.</fsummary> <desc> <p>Returns information about reductions, for example:</p> @@ -6665,7 +6689,7 @@ lists:map( <func> <name name="statistics" arity="1" clause_i="9" - anchor="statistics_run_queue"/> + anchor="statistics_run_queue" since=""/> <fsummary>Information about the run-queues.</fsummary> <desc> <p>Returns the total length of all normal run-queues. That is, the number @@ -6682,7 +6706,7 @@ lists:map( <func> <name name="statistics" arity="1" clause_i="10" - anchor="statistics_run_queue_lengths"/> + anchor="statistics_run_queue_lengths" since="OTP 18.3"/> <fsummary>Information about the run-queue lengths.</fsummary> <desc> <p>Returns the same as @@ -6697,7 +6721,7 @@ lists:map( <func> <name name="statistics" arity="1" clause_i="11" - anchor="statistics_run_queue_lengths_all"/> + anchor="statistics_run_queue_lengths_all" since="OTP 20.0"/> <fsummary>Information about the run-queue lengths.</fsummary> <desc> <p>Returns a list where each element represents the amount @@ -6739,7 +6763,7 @@ lists:map( </func> <func> - <name name="statistics" arity="1" clause_i="12"/> + <name name="statistics" arity="1" clause_i="12" since=""/> <fsummary>Information about runtime.</fsummary> <desc> <p>Returns information about runtime, in milliseconds.</p> @@ -6758,7 +6782,7 @@ lists:map( <func> <name name="statistics" arity="1" clause_i="13" - anchor="statistics_scheduler_wall_time"/> + anchor="statistics_scheduler_wall_time" since="OTP R15B01"/> <fsummary>Information about each schedulers work time.</fsummary> <desc> <p>Returns a list of tuples with @@ -6882,7 +6906,7 @@ ok <func> <name name="statistics" arity="1" clause_i="14" - anchor="statistics_scheduler_wall_time_all"/> + anchor="statistics_scheduler_wall_time_all" since="OTP 20.0"/> <fsummary>Information about each schedulers work time.</fsummary> <desc> <p>The same as @@ -6910,7 +6934,7 @@ ok </func> <func> <name name="statistics" arity="1" clause_i="15" - anchor="statistics_total_active_tasks"/> + anchor="statistics_total_active_tasks" since="OTP 18.3"/> <fsummary>Information about active processes and ports.</fsummary> <desc> <p>The same as calling @@ -6921,7 +6945,7 @@ ok <func> <name name="statistics" arity="1" clause_i="16" - anchor="statistics_total_active_tasks_all"/> + anchor="statistics_total_active_tasks_all" since="OTP 20.0"/> <fsummary>Information about active processes and ports.</fsummary> <desc> <p>The same as calling @@ -6932,7 +6956,7 @@ ok <func> <name name="statistics" arity="1" clause_i="17" - anchor="statistics_total_run_queue_lengths"/> + anchor="statistics_total_run_queue_lengths" since="OTP 18.3"/> <fsummary>Information about the run-queue lengths.</fsummary> <desc> <p>The same as calling @@ -6943,7 +6967,7 @@ ok <func> <name name="statistics" arity="1" clause_i="18" - anchor="statistics_total_run_queue_lengths_all"/> + anchor="statistics_total_run_queue_lengths_all" since="OTP 20.0"/> <fsummary>Information about the run-queue lengths.</fsummary> <desc> <p>The same as calling @@ -6953,7 +6977,7 @@ ok </func> <func> - <name name="statistics" arity="1" clause_i="19"/> + <name name="statistics" arity="1" clause_i="19" since=""/> <fsummary>Information about wall clock.</fsummary> <desc> <p>Returns information about wall clock. <c>wall_clock</c> can @@ -6964,7 +6988,7 @@ ok </func> <func> - <name name="suspend_process" arity="1"/> + <name name="suspend_process" arity="1" since=""/> <fsummary>Suspend a process.</fsummary> <desc> <p>Suspends the process identified by @@ -6979,7 +7003,7 @@ ok </func> <func> - <name name="suspend_process" arity="2"/> + <name name="suspend_process" arity="2" since=""/> <fsummary>Suspend a process.</fsummary> <desc> <p>Increases the suspend count on the process identified by @@ -7125,7 +7149,7 @@ ok </func> <func> - <name name="system_flag" arity="2" clause_i="1"/> + <name name="system_flag" arity="2" clause_i="1" since=""/> <fsummary>Set system flag <c>backtrace_depth</c>.</fsummary> <desc> <p>Sets the maximum depth of call stack back-traces in the @@ -7138,7 +7162,7 @@ ok <func> <name name="system_flag" arity="2" clause_i="2" - anchor="system_flag_cpu_topology"/> + anchor="system_flag_cpu_topology" since=""/> <fsummary>Set system flag <c>cpu_topology</c>.</fsummary> <type name="cpu_topology"/> <type name="level_entry"/> @@ -7186,7 +7210,7 @@ ok <func> <name name="system_flag" arity="2" clause_i="3" - anchor="system_flag_dirty_cpu_schedulers_online"/> + anchor="system_flag_dirty_cpu_schedulers_online" since="OTP 17.0"/> <fsummary>Set system_flag_dirty_cpu_schedulers_online.</fsummary> <desc> <p> @@ -7214,7 +7238,7 @@ ok </func> <func> - <name name="system_flag" arity="2" clause_i="4"/> + <name name="system_flag" arity="2" clause_i="4" since="OTP 20.2.3"/> <fsummary>Set system flag for erts_alloc.</fsummary> <desc> <p>Sets system flags for @@ -7231,7 +7255,7 @@ ok </func> <func> - <name name="system_flag" arity="2" clause_i="5"/> + <name name="system_flag" arity="2" clause_i="5" since=""/> <fsummary>Set system flag fullsweep_after.</fsummary> <desc> <p>Sets system flag <c>fullsweep_after</c>. @@ -7251,7 +7275,7 @@ ok <func> <name name="system_flag" arity="2" clause_i="6" - anchor="system_flag_microstate_accounting"/> + anchor="system_flag_microstate_accounting" since="OTP 19.0"/> <fsummary>Set system flag microstate_accounting.</fsummary> <desc> <p> @@ -7264,7 +7288,7 @@ ok </func> <func> - <name name="system_flag" arity="2" clause_i="7"/> + <name name="system_flag" arity="2" clause_i="7" since=""/> <fsummary>Set system flag min_heap_size.</fsummary> <desc> <p>Sets the default minimum heap size for processes. The size @@ -7279,7 +7303,7 @@ ok </func> <func> - <name name="system_flag" arity="2" clause_i="8"/> + <name name="system_flag" arity="2" clause_i="8" since="OTP R13B04"/> <fsummary>Set system flag min_bin_vheap_size.</fsummary> <desc> <p>Sets the default minimum binary virtual heap size for @@ -7297,7 +7321,7 @@ ok <func> <name name="system_flag" arity="2" clause_i="9" - anchor="system_flag_max_heap_size"/> + anchor="system_flag_max_heap_size" since="OTP 19.0"/> <fsummary>Set system flag max_heap_size.</fsummary> <type name="max_heap_size"/> <desc> @@ -7315,7 +7339,7 @@ ok <func> <name name="system_flag" arity="2" clause_i="10" - anchor="system_flag_multi_scheduling"/> + anchor="system_flag_multi_scheduling" since=""/> <fsummary>Set system flag multi_scheduling.</fsummary> <desc> <p> @@ -7371,7 +7395,7 @@ ok <func> <name name="system_flag" arity="2" clause_i="11" - anchor="system_flag_scheduler_bind_type"/> + anchor="system_flag_scheduler_bind_type" since=""/> <fsummary>Set system flag scheduler_bind_type.</fsummary> <type name="scheduler_bind_type"/> <desc> @@ -7498,7 +7522,7 @@ ok <func> <name name="system_flag" arity="2" clause_i="12" - anchor="system_flag_scheduler_wall_time"/> + anchor="system_flag_scheduler_wall_time" since="OTP R15B01"/> <fsummary>Set system flag scheduler_wall_time.</fsummary> <desc> <p> @@ -7511,7 +7535,7 @@ ok <func> <name name="system_flag" arity="2" clause_i="13" - anchor="system_flag_schedulers_online"/> + anchor="system_flag_schedulers_online" since=""/> <fsummary>Set system flag schedulers_online.</fsummary> <desc> <p> @@ -7539,7 +7563,39 @@ ok </func> <func> - <name name="system_flag" arity="2" clause_i="14"/> + <name name="system_flag" arity="2" clause_i="14" since="OTP 21.3"/> + <fsummary>Set system logger process.</fsummary> + <desc> + <p>Sets the process that will receive the logging + messages generated by ERTS. If set to <c>undefined</c>, + all logging messages generated by ERTS will be dropped. + The messages will be in the format:</p> + <code> +{log,Level,Format,ArgList,Metadata} where + +Level = atom(), +Format = string(), +ArgList = list(term()), +Metadata = #{ pid => pid(), + group_leader => pid(), + time := logger:timestamp(), + error_logger := #{ emulator := true, tag := atom() } + </code> + <p>If the <c>system_logger</c> process dies, + this flag will be reset to <c>logger</c>.</p> + <p>The default is the process named <c>logger</c>.</p> + <p>Returns the old value of the flag.</p> + <note><p>This function is designed to be used by the + KERNEL <seealso marker="kernel:logger"><c>logger</c></seealso>. + Be careful if you change it to something else as + log messages may be lost. If you want to intercept + emulator log messages, do it by adding a specialized handler + to the KERNEL logger.</p></note> + </desc> + </func> + + <func> + <name name="system_flag" arity="2" clause_i="15" since=""/> <fsummary>Set system flag trace_control_word.</fsummary> <desc> <p>Sets the value of the node trace control word to @@ -7553,8 +7609,8 @@ ok </func> <func> - <name name="system_flag" arity="2" clause_i="15" - anchor="system_flag_time_offset"/> + <name name="system_flag" arity="2" clause_i="16" + anchor="system_flag_time_offset" since="OTP 18.0"/> <fsummary>Finalize the time offset.</fsummary> <desc> <p> @@ -7583,7 +7639,7 @@ ok </func> <func> - <name name="system_info" arity="1" clause_i="76"/> + <name name="system_info" arity="1" clause_i="76" since=""/> <fsummary>System info overview.</fsummary> <desc> <p>Returns information about the current system. @@ -7703,8 +7759,9 @@ ok <seealso marker="#system_info_nif_version"><c>nif_version</c></seealso>, <seealso marker="#system_info_otp_release"><c>otp_release</c></seealso>, <seealso marker="#system_info_port_parallelism"><c>port_parallelism</c></seealso>, - <seealso marker="#system_info_system_version"><c>system_version</c></seealso>, <seealso marker="#system_info_system_architecture"><c>system_architecture</c></seealso>, + <seealso marker="#system_info_system_logger"><c>system_logger</c></seealso>, + <seealso marker="#system_info_system_version"><c>system_version</c></seealso>, <seealso marker="#system_info_trace_control_word"><c>trace_control_word</c></seealso>, <seealso marker="#system_info_version"><c>version</c></seealso>, <seealso marker="#system_info_wordsize"><c>wordsize</c></seealso> @@ -7716,12 +7773,12 @@ ok <func> <name name="system_info" arity="1" clause_i="1" - anchor="system_info_allocator"/> <!-- allocated_areas --> - <name name="system_info" arity="1" clause_i="2"/> <!-- allocator --> - <name name="system_info" arity="1" clause_i="3"/> <!-- {allocator, _} --> - <name name="system_info" arity="1" clause_i="4"/> <!-- alloc_util_allocators --> - <name name="system_info" arity="1" clause_i="5"/> <!-- {allocator_sizes, _} --> - <name name="system_info" arity="1" clause_i="27"/> <!-- elib_malloc --> + anchor="system_info_allocator" since=""/> <!-- allocated_areas --> + <name name="system_info" arity="1" clause_i="2" since=""/> <!-- allocator --> + <name name="system_info" arity="1" clause_i="3" since=""/> <!-- {allocator, _} --> + <name name="system_info" arity="1" clause_i="4" since=""/> <!-- alloc_util_allocators --> + <name name="system_info" arity="1" clause_i="5" since=""/> <!-- {allocator_sizes, _} --> + <name name="system_info" arity="1" clause_i="27" since=""/> <!-- elib_malloc --> <fsummary>Information about the system allocators.</fsummary> <type variable="Allocator" name_i="2"/> <type variable="Version" name_i="2"/> @@ -7873,10 +7930,10 @@ ok <func> <name name="system_info" arity="1" clause_i="12" - anchor="system_info_cpu_topology"/> <!-- cpu_topology --> - <name name="system_info" arity="1" clause_i="13"/> <!-- {cpu_topology, _} --> - <name name="system_info" arity="1" clause_i="38"/> <!-- logical_processors --> - <name name="system_info" arity="1" clause_i="73"/> <!-- update_cpu_info --> + anchor="system_info_cpu_topology" since=""/> <!-- cpu_topology --> + <name name="system_info" arity="1" clause_i="13" since=""/> <!-- {cpu_topology, _} --> + <name name="system_info" arity="1" clause_i="38" since=""/> <!-- logical_processors --> + <name name="system_info" arity="1" clause_i="74" since="OTP R14B"/> <!-- update_cpu_info --> <fsummary>Information about the CPU topology of the system.</fsummary> <type name="cpu_topology"/> <type name="level_entry"/> @@ -8028,15 +8085,15 @@ ok <func> <name name="system_info" arity="1" clause_i="31" - anchor="system_info_process"/> <!-- fullsweep_after --> - <name name="system_info" arity="1" clause_i="32"/> <!-- garbage_collection --> - <name name="system_info" arity="1" clause_i="33"/> <!-- heap_sizes --> - <name name="system_info" arity="1" clause_i="34"/> <!-- heap_type --> - <name name="system_info" arity="1" clause_i="40"/> <!-- max_heap_size --> - <name name="system_info" arity="1" clause_i="41"/> <!-- message_queue_data --> - <name name="system_info" arity="1" clause_i="42"/> <!-- min_heap_size --> - <name name="system_info" arity="1" clause_i="43"/> <!-- min_bin_vheap_size --> - <name name="system_info" arity="1" clause_i="57"/> <!-- procs --> + anchor="system_info_process" since=""/> <!-- fullsweep_after --> + <name name="system_info" arity="1" clause_i="32" since=""/> <!-- garbage_collection --> + <name name="system_info" arity="1" clause_i="33" since=""/> <!-- heap_sizes --> + <name name="system_info" arity="1" clause_i="34" since=""/> <!-- heap_type --> + <name name="system_info" arity="1" clause_i="40" since="OTP 19.0"/> <!-- max_heap_size --> + <name name="system_info" arity="1" clause_i="41" since="OTP 19.0"/> <!-- message_queue_data --> + <name name="system_info" arity="1" clause_i="42" since="OTP R13B04"/> <!-- min_heap_size --> + <name name="system_info" arity="1" clause_i="43" since="OTP R13B04"/> <!-- min_bin_vheap_size --> + <name name="system_info" arity="1" clause_i="57" since=""/> <!-- procs --> <fsummary>Information about the default process heap settings.</fsummary> <type name="message_queue_data"/> <type name="max_heap_size"/> @@ -8146,14 +8203,14 @@ ok </func> <func> - <name name="system_info" arity="1" clause_i="6" anchor="system_info_limits"/> <!-- atom_count --> - <name name="system_info" arity="1" clause_i="7"/> <!-- atom_limit --> - <name name="system_info" arity="1" clause_i="29"/> <!-- ets_count --> - <name name="system_info" arity="1" clause_i="30"/> <!-- ets_limit --> - <name name="system_info" arity="1" clause_i="53"/> <!-- port_count --> - <name name="system_info" arity="1" clause_i="54"/> <!-- port_limit --> - <name name="system_info" arity="1" clause_i="55"/> <!-- process_count --> - <name name="system_info" arity="1" clause_i="56"/> <!-- process_limit --> + <name name="system_info" arity="1" clause_i="6" anchor="system_info_limits" since="OTP 20.0"/> <!-- atom_count --> + <name name="system_info" arity="1" clause_i="7" since="OTP 20.0"/> <!-- atom_limit --> + <name name="system_info" arity="1" clause_i="29" since="OTP 21.1"/> <!-- ets_count --> + <name name="system_info" arity="1" clause_i="30" since="OTP R16B03"/> <!-- ets_limit --> + <name name="system_info" arity="1" clause_i="53" since="OTP R16B"/> <!-- port_count --> + <name name="system_info" arity="1" clause_i="54" since="OTP R16B"/> <!-- port_limit --> + <name name="system_info" arity="1" clause_i="55" since=""/> <!-- process_count --> + <name name="system_info" arity="1" clause_i="56" since=""/> <!-- process_limit --> <fsummary>Information about various system limits.</fsummary> <desc> <marker id="system_info_limits"/> @@ -8227,14 +8284,14 @@ ok <func> <name name="system_info" arity="1" clause_i="26" - anchor="system_info_time"/> <!-- end_time --> - <name name="system_info" arity="1" clause_i="50"/> <!-- os_monotonic_time_source --> - <name name="system_info" arity="1" clause_i="51"/> <!-- os_system_time_source --> - <name name="system_info" arity="1" clause_i="63"/> <!-- start_time --> - <name name="system_info" arity="1" clause_i="68"/> <!-- time_correction --> - <name name="system_info" arity="1" clause_i="69"/> <!-- time_offset --> - <name name="system_info" arity="1" clause_i="70"/> <!-- time_warp_mode --> - <name name="system_info" arity="1" clause_i="71"/> <!-- tolerant_timeofday --> + anchor="system_info_time" since="OTP 18.0"/> <!-- end_time --> + <name name="system_info" arity="1" clause_i="50" since="OTP 18.0"/> <!-- os_monotonic_time_source --> + <name name="system_info" arity="1" clause_i="51" since="OTP 18.0"/> <!-- os_system_time_source --> + <name name="system_info" arity="1" clause_i="63" since="OTP 18.0"/> <!-- start_time --> + <name name="system_info" arity="1" clause_i="69" since="OTP 18.0"/> <!-- time_correction --> + <name name="system_info" arity="1" clause_i="70" since="OTP 18.0"/> <!-- time_offset --> + <name name="system_info" arity="1" clause_i="71" since="OTP 18.0"/> <!-- time_warp_mode --> + <name name="system_info" arity="1" clause_i="72" since="OTP 17.1"/> <!-- tolerant_timeofday --> <fsummary>Information about system time.</fsummary> <desc> <marker id="system_info_time_tags"/> @@ -8324,7 +8381,7 @@ ok system time</seealso> that is used by the runtime system.</p> <p>The list contains two-tuples with <c>Key</c>s as first element, and <c>Value</c>s as second element. The - order if these tuples is undefined. The following + order of these tuples is undefined. The following tuples can be part of the list, but more tuples can be introduced in the future:</p> <taglist> @@ -8455,19 +8512,19 @@ ok <func> <name name="system_info" arity="1" clause_i="17" - anchor="system_info_scheduler"/> <!-- dirty_cpu_schedulers --> - <name name="system_info" arity="1" clause_i="18"/> <!-- dirty_cpu_schedulers_online --> - <name name="system_info" arity="1" clause_i="19"/> <!-- dirty_io_schedulers --> - <name name="system_info" arity="1" clause_i="45"/> <!-- multi_scheduling --> - <name name="system_info" arity="1" clause_i="46"/> <!-- multi_scheduling_blockers --> - <name name="system_info" arity="1" clause_i="49"/> <!-- normal_multi_scheduling_blockers --> - <name name="system_info" arity="1" clause_i="58"/> <!-- scheduler_bind_type --> - <name name="system_info" arity="1" clause_i="59"/> <!-- scheduler_bindings --> - <name name="system_info" arity="1" clause_i="60"/> <!-- scheduler_id --> - <name name="system_info" arity="1" clause_i="61"/> <!-- schedulers --> - <name name="system_info" arity="1" clause_i="62"/> <!-- smp_support --> - <name name="system_info" arity="1" clause_i="66"/> <!-- threads --> - <name name="system_info" arity="1" clause_i="67"/> <!-- thread_pool_size --> + anchor="system_info_scheduler" since="OTP 17.0"/> <!-- dirty_cpu_schedulers --> + <name name="system_info" arity="1" clause_i="18" since="OTP 17.0"/> <!-- dirty_cpu_schedulers_online --> + <name name="system_info" arity="1" clause_i="19" since="OTP 17.0"/> <!-- dirty_io_schedulers --> + <name name="system_info" arity="1" clause_i="45" since=""/> <!-- multi_scheduling --> + <name name="system_info" arity="1" clause_i="46" since=""/> <!-- multi_scheduling_blockers --> + <name name="system_info" arity="1" clause_i="49" since="OTP 19.0"/> <!-- normal_multi_scheduling_blockers --> + <name name="system_info" arity="1" clause_i="58" since=""/> <!-- scheduler_bind_type --> + <name name="system_info" arity="1" clause_i="59" since=""/> <!-- scheduler_bindings --> + <name name="system_info" arity="1" clause_i="60" since=""/> <!-- scheduler_id --> + <name name="system_info" arity="1" clause_i="61" since=""/> <!-- schedulers --> + <name name="system_info" arity="1" clause_i="62" since=""/> <!-- smp_support --> + <name name="system_info" arity="1" clause_i="67" since=""/> <!-- threads --> + <name name="system_info" arity="1" clause_i="68" since=""/> <!-- thread_pool_size --> <fsummary>Information about system schedulers.</fsummary> <desc> <marker id="system_info_scheduler_tags"/> @@ -8755,11 +8812,11 @@ ok <func> <name name="system_info" arity="1" clause_i="14" - anchor="system_info_dist"/> <!-- creation --> - <name name="system_info" arity="1" clause_i="16"/> <!-- delayed_node_table_gc --> - <name name="system_info" arity="1" clause_i="20"/> <!-- dist --> - <name name="system_info" arity="1" clause_i="21"/> <!-- dist_buf_busy_limit --> - <name name="system_info" arity="1" clause_i="22"/> <!-- dist_ctrl --> + anchor="system_info_dist" since=""/> <!-- creation --> + <name name="system_info" arity="1" clause_i="16" since="OTP 18.0"/> <!-- delayed_node_table_gc --> + <name name="system_info" arity="1" clause_i="20" since=""/> <!-- dist --> + <name name="system_info" arity="1" clause_i="21" since="OTP R14B01"/> <!-- dist_buf_busy_limit --> + <name name="system_info" arity="1" clause_i="22" since=""/> <!-- dist_ctrl --> <fsummary>Information about erlang distribution.</fsummary> <desc> <marker id="system_info_dist_tags"/> @@ -8833,14 +8890,14 @@ ok <!-- <name name="system_info" arity="1" clause_i="6"/> atom_count --> <!-- <name name="system_info" arity="1" clause_i="7"/> atom_limit --> <name name="system_info" arity="1" clause_i="8" - anchor="system_info_misc"/> <!-- build_type --> - <name name="system_info" arity="1" clause_i="9"/> <!-- c_compiler_used --> - <name name="system_info" arity="1" clause_i="10"/> <!-- check_io --> - <name name="system_info" arity="1" clause_i="11"/> <!-- compat_rel --> + anchor="system_info_misc" since="OTP R14B"/> <!-- build_type --> + <name name="system_info" arity="1" clause_i="9" since=""/> <!-- c_compiler_used --> + <name name="system_info" arity="1" clause_i="10" since=""/> <!-- check_io --> + <name name="system_info" arity="1" clause_i="11" since=""/> <!-- compat_rel --> <!-- <name name="system_info" arity="1" clause_i="12"/> cpu_topology --> <!-- <name name="system_info" arity="1" clause_i="13"/> {cpu_topology, _} --> <!-- <name name="system_info" arity="1" clause_i="14"/> creation --> - <name name="system_info" arity="1" clause_i="15"/> <!-- debug_compiled --> + <name name="system_info" arity="1" clause_i="15" since=""/> <!-- debug_compiled --> <!-- <name name="system_info" arity="1" clause_i="16"/> delayed_node_table_gc --> <!-- <name name="system_info" arity="1" clause_i="17"/> dirty_cpu_schedulers --> <!-- <name name="system_info" arity="1" clause_i="18"/> dirty_cpu_schedulers_online --> @@ -8848,9 +8905,9 @@ ok <!-- <name name="system_info" arity="1" clause_i="20"/> dist --> <!-- <name name="system_info" arity="1" clause_i="21"/> dist_buf_busy_limit --> <!-- <name name="system_info" arity="1" clause_i="22"/> dist_ctrl --> - <name name="system_info" arity="1" clause_i="23"/> <!-- driver_version --> - <name name="system_info" arity="1" clause_i="24"/> <!-- dynamic_trace --> - <name name="system_info" arity="1" clause_i="25"/> <!-- dynamic_trace_probes --> + <name name="system_info" arity="1" clause_i="23" since=""/> <!-- driver_version --> + <name name="system_info" arity="1" clause_i="24" since="OTP R15B01"/> <!-- dynamic_trace --> + <name name="system_info" arity="1" clause_i="25" since="OTP R15B01"/> <!-- dynamic_trace_probes --> <!-- <name name="system_info" arity="1" clause_i="26"/> end_time --> <!-- <name name="system_info" arity="1" clause_i="27"/> elib_malloc --> <!-- <name name="system_info" arity="1" clause_i="28"/> eager_check_io, removed --> @@ -8860,24 +8917,24 @@ ok <!-- <name name="system_info" arity="1" clause_i="32"/> garbage_collection --> <!-- <name name="system_info" arity="1" clause_i="33"/> heap_sizes --> <!-- <name name="system_info" arity="1" clause_i="34"/> heap_type --> - <name name="system_info" arity="1" clause_i="35"/> <!-- info --> - <name name="system_info" arity="1" clause_i="36"/> <!-- kernel_poll --> - <name name="system_info" arity="1" clause_i="37"/> <!-- loaded --> + <name name="system_info" arity="1" clause_i="35" since=""/> <!-- info --> + <name name="system_info" arity="1" clause_i="36" since=""/> <!-- kernel_poll --> + <name name="system_info" arity="1" clause_i="37" since=""/> <!-- loaded --> <!-- <name name="system_info" arity="1" clause_i="38"/> logical_processors --> - <name name="system_info" arity="1" clause_i="39"/> <!-- machine --> + <name name="system_info" arity="1" clause_i="39" since=""/> <!-- machine --> <!-- <name name="system_info" arity="1" clause_i="40"/> max_heap_size --> <!-- <name name="system_info" arity="1" clause_i="41"/> message_queue_data --> <!-- <name name="system_info" arity="1" clause_i="42"/> min_heap_size --> <!-- <name name="system_info" arity="1" clause_i="43"/> min_bin_vheap_size --> - <name name="system_info" arity="1" clause_i="44"/> <!-- modified_timing_level --> + <name name="system_info" arity="1" clause_i="44" since=""/> <!-- modified_timing_level --> <!-- <name name="system_info" arity="1" clause_i="45"/> multi_scheduling --> <!-- <name name="system_info" arity="1" clause_i="46"/> multi_scheduling_blockers --> - <name name="system_info" arity="1" clause_i="47"/> <!-- nif_version --> + <name name="system_info" arity="1" clause_i="47" since="OTP 17.4"/> <!-- nif_version --> <!-- n<name name="system_info" arity="1" clause_i="48"/> ormal_multi_scheduling_blockers --> - <name name="system_info" arity="1" clause_i="49"/> <!-- otp_release --> + <name name="system_info" arity="1" clause_i="49" since=""/> <!-- otp_release --> <!-- <name name="system_info" arity="1" clause_i="50"/> os_monotonic_time_source --> <!-- <name name="system_info" arity="1" clause_i="51"/> os_system_time_source --> - <name name="system_info" arity="1" clause_i="52"/> <!-- port_parallelism --> + <name name="system_info" arity="1" clause_i="52" since="OTP R16B"/> <!-- port_parallelism --> <!-- <name name="system_info" arity="1" clause_i="53"/> port_count --> <!-- <name name="system_info" arity="1" clause_i="54"/> port_limit --> <!-- <name name="system_info" arity="1" clause_i="55"/> process_count --> @@ -8889,19 +8946,20 @@ ok <!-- <name name="system_info" arity="1" clause_i="61"/> schedulers --> <!-- <name name="system_info" arity="1" clause_i="62"/> smp_support --> <!-- <name name="system_info" arity="1" clause_i="63"/> start_time --> - <name name="system_info" arity="1" clause_i="64"/> <!-- system_version --> - <name name="system_info" arity="1" clause_i="65"/> <!-- system_architecture --> - <!-- <name name="system_info" arity="1" clause_i="66"/> threads --> - <!-- <name name="system_info" arity="1" clause_i="67"/> thread_pool_size --> - <!-- <name name="system_info" arity="1" clause_i="68"/> time_correction --> - <!-- <name name="system_info" arity="1" clause_i="69"/> time_offset --> - <!-- <name name="system_info" arity="1" clause_i="70"/> time_warp_mode --> - <!-- <name name="system_info" arity="1" clause_i="71"/> tolerant_timeofday --> - <name name="system_info" arity="1" clause_i="72"/> <!-- trace_control_word --> - <!-- <name name="system_info" arity="1" clause_i="73"/> update_cpu_info --> - <name name="system_info" arity="1" clause_i="74"/> <!-- version --> - <name name="system_info" arity="1" clause_i="75"/> <!-- wordsize --> - <!-- <name name="system_info" arity="1" clause_i="76"/> overview --> + <name name="system_info" arity="1" clause_i="64" since=""/> <!-- system_architecture --> + <name name="system_info" arity="1" clause_i="65" since="OTP 21.3"/> <!-- system_logger --> + <name name="system_info" arity="1" clause_i="66" since=""/> <!-- system_version --> + <!-- <name name="system_info" arity="1" clause_i="67"/> threads --> + <!-- <name name="system_info" arity="1" clause_i="68"/> thread_pool_size --> + <!-- <name name="system_info" arity="1" clause_i="69"/> time_correction --> + <!-- <name name="system_info" arity="1" clause_i="70"/> time_offset --> + <!-- <name name="system_info" arity="1" clause_i="71"/> time_warp_mode --> + <!-- <name name="system_info" arity="1" clause_i="72"/> tolerant_timeofday --> + <name name="system_info" arity="1" clause_i="73" since=""/> <!-- trace_control_word --> + <!-- <name name="system_info" arity="1" clause_i="74"/> update_cpu_info --> + <name name="system_info" arity="1" clause_i="75" since=""/> <!-- version --> + <name name="system_info" arity="1" clause_i="76" since=""/> <!-- wordsize --> + <!-- <name name="system_info" arity="1" clause_i="77"/> overview --> <fsummary>Information about the system.</fsummary> <desc> <marker id="system_info_misc_tags"/> @@ -9057,18 +9115,24 @@ ok <seealso marker="erl#+spp"><c>+spp</c></seealso> in <c>erl(1)</c>.</p> </item> - <tag><marker id="system_info_system_version"/> - <c>system_version</c></tag> - <item> - <p>Returns a string containing version number and - some important properties, such as the number of schedulers.</p> - </item> <tag><marker id="system_info_system_architecture"/> <c>system_architecture</c></tag> <item> <p>Returns a string containing the processor and OS architecture the emulator is built for.</p> </item> + <tag><marker id="system_info_system_logger"/> + <c>system_logger</c></tag> + <item> + <p>Returns the current <c>system_logger</c> as set by + <seealso marker="#system_flag/2"><c>erlang:system_flag(system_logger, _)</c></seealso>.</p> + </item> + <tag><marker id="system_info_system_version"/> + <c>system_version</c></tag> + <item> + <p>Returns a string containing version number and + some important properties, such as the number of schedulers.</p> + </item> <tag><marker id="system_info_trace_control_word"/> <c>trace_control_word</c></tag> <item> @@ -9110,7 +9174,7 @@ ok </func> <func> - <name name="system_monitor" arity="0"/> + <name name="system_monitor" arity="0" since=""/> <fsummary>Current system performance monitoring settings.</fsummary> <type name="system_monitor_option"/> <desc> @@ -9124,7 +9188,7 @@ ok </func> <func> - <name name="system_monitor" arity="1"/> + <name name="system_monitor" arity="1" since=""/> <fsummary>Set or clear system performance monitoring options.</fsummary> <type name="system_monitor_option"/> <desc> @@ -9142,7 +9206,7 @@ ok </func> <func> - <name name="system_monitor" arity="2"/> + <name name="system_monitor" arity="2" since=""/> <fsummary>Set system performance monitoring options.</fsummary> <type name="system_monitor_option"/> <desc> @@ -9274,7 +9338,7 @@ ok </func> <func> - <name name="system_profile" arity="0"/> + <name name="system_profile" arity="0" since=""/> <fsummary>Current system profiling settings.</fsummary> <type name="system_profile_option"/> <desc> @@ -9289,7 +9353,7 @@ ok </func> <func> - <name name="system_profile" arity="2"/> + <name name="system_profile" arity="2" since=""/> <fsummary>Current system profiling settings.</fsummary> <type name="system_profile_option"/> <desc> @@ -9363,7 +9427,7 @@ ok </func> <func> - <name name="system_time" arity="0"/> + <name name="system_time" arity="0" since="OTP 18.0"/> <fsummary>Current Erlang system time.</fsummary> <desc> <p>Returns current @@ -9385,7 +9449,7 @@ ok </func> <func> - <name name="system_time" arity="1"/> + <name name="system_time" arity="1" since="OTP 18.0"/> <fsummary>Current Erlang system time.</fsummary> <desc> <p>Returns current @@ -9407,7 +9471,7 @@ ok </func> <func> - <name name="term_to_binary" arity="1"/> + <name name="term_to_binary" arity="1" since=""/> <fsummary>Encode a term to an Erlang external term format binary. </fsummary> <desc> @@ -9435,7 +9499,7 @@ hello </func> <func> - <name name="term_to_binary" arity="2"/> + <name name="term_to_binary" arity="2" since=""/> <fsummary>Encode a term to en Erlang external term format binary. </fsummary> <desc> @@ -9500,7 +9564,7 @@ hello </func> <func> - <name name="throw" arity="1"/> + <name name="throw" arity="1" since=""/> <fsummary>Throw an exception.</fsummary> <desc> <p>A non-local return from a function. If evaluated within a @@ -9514,7 +9578,7 @@ hello </func> <func> - <name name="time" arity="0"/> + <name name="time" arity="0" since=""/> <fsummary>Current time.</fsummary> <desc> <p>Returns the current time as <c>{Hour, Minute, Second}</c>.</p> @@ -9527,7 +9591,7 @@ hello </func> <func> - <name name="time_offset" arity="0"/> + <name name="time_offset" arity="0" since="OTP 18.0"/> <fsummary>Current time offset.</fsummary> <desc> <p>Returns the current time offset between @@ -9559,7 +9623,7 @@ hello </func> <func> - <name name="time_offset" arity="1"/> + <name name="time_offset" arity="1" since="OTP 18.0"/> <fsummary>Current time offset.</fsummary> <desc> <p>Returns the current time offset between @@ -9578,7 +9642,7 @@ hello </func> <func> - <name name="timestamp" arity="0"/> + <name name="timestamp" arity="0" since="OTP 18.0"/> <fsummary>Current Erlang System time.</fsummary> <type name="timestamp"/> <desc> @@ -9617,7 +9681,7 @@ timestamp() -> </func> <func> - <name name="tl" arity="1"/> + <name name="tl" arity="1" since=""/> <fsummary>Tail of a list.</fsummary> <desc> <p>Returns the tail of <c><anno>List</anno></c>, that is, @@ -9632,7 +9696,7 @@ timestamp() -> </func> <func> - <name name="trace" arity="3"/> + <name name="trace" arity="3" since=""/> <fsummary>Set trace flags for a process or processes.</fsummary> <type name="trace_flag"/> <desc> @@ -10288,7 +10352,7 @@ timestamp() -> </func> <func> - <name name="trace_delivered" arity="1"/> + <name name="trace_delivered" arity="1" since=""/> <fsummary>Notification when trace has been delivered.</fsummary> <desc> <p>The delivery of trace messages (generated by @@ -10343,7 +10407,7 @@ timestamp() -> </func> <func> - <name name="trace_info" arity="2"/> + <name name="trace_info" arity="2" since=""/> <fsummary>Trace information about a process or function.</fsummary> <type name="trace_info_return"/> <type name="trace_info_item_result"/> @@ -10479,7 +10543,7 @@ timestamp() -> </func> <func> - <name name="trace_pattern" arity="2" clause_i="1"/> + <name name="trace_pattern" arity="2" clause_i="1" since=""/> <fsummary>Set trace patterns for call, send, or 'receive' tracing. </fsummary> <type name="trace_pattern_mfa"/> @@ -10497,7 +10561,7 @@ timestamp() -> </func> <func> - <name name="trace_pattern" arity="3" clause_i="1"/> + <name name="trace_pattern" arity="3" clause_i="1" since="OTP 19.0"/> <fsummary>Set trace pattern for message sending.</fsummary> <type name="trace_match_spec"/> <type name="match_variable"/> @@ -10568,7 +10632,7 @@ timestamp() -> </func> <func> - <name name="trace_pattern" arity="3" clause_i="2"/> + <name name="trace_pattern" arity="3" clause_i="2" since="OTP 19.0"/> <fsummary>Set trace pattern for tracing of message receiving.</fsummary> <type name="trace_match_spec"/> <type name="match_variable"/> @@ -10640,7 +10704,7 @@ timestamp() -> </func> <func> - <name name="trace_pattern" arity="3" clause_i="3"/> + <name name="trace_pattern" arity="3" clause_i="3" since=""/> <fsummary>Set trace patterns for tracing of function calls.</fsummary> <type name="trace_pattern_mfa"/> <type name="trace_match_spec"/> @@ -10831,7 +10895,7 @@ timestamp() -> </func> <func> - <name name="trunc" arity="1"/> + <name name="trunc" arity="1" since=""/> <fsummary>Return an integer by truncating a number.</fsummary> <desc> <p>Returns an integer by truncating <c><anno>Number</anno></c>, @@ -10844,7 +10908,7 @@ timestamp() -> </func> <func> - <name name="tuple_size" arity="1"/> + <name name="tuple_size" arity="1" since=""/> <fsummary>Return the size of a tuple.</fsummary> <desc> <p>Returns an integer that is the number of elements in @@ -10857,7 +10921,7 @@ timestamp() -> </func> <func> - <name name="tuple_to_list" arity="1"/> + <name name="tuple_to_list" arity="1" since=""/> <fsummary>Convert a tuple to a list.</fsummary> <desc> <p>Returns a list corresponding to <c><anno>Tuple</anno></c>. @@ -10870,7 +10934,7 @@ timestamp() -> </func> <func> - <name name="unique_integer" arity="0"/> + <name name="unique_integer" arity="0" since="OTP 18.0"/> <fsummary>Get a unique integer value.</fsummary> <desc> <p>Generates and returns an @@ -10883,7 +10947,7 @@ timestamp() -> </func> <func> - <name name="unique_integer" arity="1"/> + <name name="unique_integer" arity="1" since="OTP 18.0"/> <fsummary>Get a unique integer value.</fsummary> <desc> <p>Generates and returns an @@ -10965,7 +11029,7 @@ timestamp() -> </func> <func> - <name name="universaltime" arity="0"/> + <name name="universaltime" arity="0" since=""/> <fsummary>Current date and time according to Universal Time Coordinated (UTC).</fsummary> <desc> @@ -10982,7 +11046,7 @@ timestamp() -> </func> <func> - <name name="universaltime_to_localtime" arity="1"/> + <name name="universaltime_to_localtime" arity="1" since=""/> <fsummary>Convert from Universal Time Coordinated (UTC) to local date and time.</fsummary> <desc> @@ -11001,7 +11065,7 @@ timestamp() -> </func> <func> - <name name="unlink" arity="1"/> + <name name="unlink" arity="1" since=""/> <fsummary>Remove a link to another process or port.</fsummary> <desc> <p>Removes the link, if there is one, between the calling @@ -11047,7 +11111,7 @@ end</code> </func> <func> - <name name="unregister" arity="1"/> + <name name="unregister" arity="1" since=""/> <fsummary>Remove the registered name for a process (or port).</fsummary> <desc> <p>Removes the registered name <c><anno>RegName</anno></c> @@ -11063,7 +11127,7 @@ true</pre> </func> <func> - <name name="whereis" arity="1"/> + <name name="whereis" arity="1" since=""/> <fsummary>Get the pid (or port) with a specified registered name. </fsummary> <desc> @@ -11077,7 +11141,7 @@ true</pre> </func> <func> - <name name="yield" arity="0"/> + <name name="yield" arity="0" since=""/> <fsummary>Let other processes get a chance to execute.</fsummary> <desc> <p>Voluntarily lets other processes (if any) get a chance to diff --git a/erts/doc/src/init.xml b/erts/doc/src/init.xml index c14f0a558d..c824e37976 100644 --- a/erts/doc/src/init.xml +++ b/erts/doc/src/init.xml @@ -29,7 +29,7 @@ <rev></rev> <file>init.xml</file> </header> - <module>init</module> + <module since="">init</module> <modulesummary>Coordination of system startup.</modulesummary> <description> <p>This module is preloaded and contains the code for @@ -50,7 +50,7 @@ <funcs> <func> - <name name="boot" arity="1"/> + <name name="boot" arity="1" since=""/> <fsummary>Start the Erlang runtime system.</fsummary> <desc> <p>Starts the Erlang runtime system. This function is called @@ -69,7 +69,7 @@ </func> <func> - <name name="get_argument" arity="1"/> + <name name="get_argument" arity="1" since=""/> <fsummary>Get the values associated with a command-line user flag. </fsummary> <desc> @@ -112,7 +112,7 @@ </func> <func> - <name name="get_arguments" arity="0"/> + <name name="get_arguments" arity="0" since=""/> <fsummary>Get all command-line user flags.</fsummary> <desc> <p>Returns all command-line flags and the system-defined flags, see @@ -121,7 +121,7 @@ </func> <func> - <name name="get_plain_arguments" arity="0"/> + <name name="get_plain_arguments" arity="0" since=""/> <fsummary>Get all non-flag command-line arguments.</fsummary> <desc> <p>Returns any plain command-line arguments as a list of strings @@ -130,7 +130,7 @@ </func> <func> - <name name="get_status" arity="0"/> + <name name="get_status" arity="0" since=""/> <fsummary>Get system status information.</fsummary> <type name="internal_status"/> <desc> @@ -146,7 +146,7 @@ </func> <func> - <name name="reboot" arity="0"/> + <name name="reboot" arity="0" since=""/> <fsummary>Take down and restart an Erlang node smoothly.</fsummary> <desc> <p>All applications are taken down smoothly, all code is @@ -162,7 +162,7 @@ </func> <func> - <name name="restart" arity="0"/> + <name name="restart" arity="0" since=""/> <fsummary>Restart the running Erlang node.</fsummary> <desc> <p>The system is restarted <em>inside</em> the running Erlang @@ -178,7 +178,7 @@ </func> <func> - <name name="script_id" arity="0"/> + <name name="script_id" arity="0" since=""/> <fsummary>Get the identity of the used boot script.</fsummary> <desc> <p>Gets the identity of the boot script used to boot the system. @@ -189,7 +189,7 @@ </func> <func> - <name name="stop" arity="0"/> + <name name="stop" arity="0" since=""/> <fsummary>Take down an Erlang node smoothly.</fsummary> <desc> <p>The same as @@ -198,7 +198,7 @@ </func> <func> - <name name="stop" arity="1"/> + <name name="stop" arity="1" since=""/> <fsummary>Take down an Erlang node smoothly.</fsummary> <desc> <p>All applications are taken down smoothly, all code is diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index a34b3edd7a..4c70101358 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -31,6 +31,402 @@ </header> <p>This document describes the changes made to the ERTS application.</p> +<section><title>Erts 10.3.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Fixed a bug in <c>seq_trace:reset_trace/0</c> that + could crash the emulator.</p> + <p> + Own Id: OTP-15704</p> + </item> + <item> + <p> + Fixed bug in <c>process_info(reductions)</c> causing it + to sometimes return invalid results.</p> + <p> + Own Id: OTP-15709 Aux Id: ERIERL-337 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.3.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>If a suspend/resume signal pair was sent to a process + while it was executing dirty, the receiving process could + later end up in a suspended state indefinitely. This bug + was introduced in ERTS version 10.0 (OTP 21.0).</p> + <p>Suspend/resume signals are sent from <seealso + marker="erts:erlang#suspend_process/1"><c>erlang:suspend_process()</c></seealso>/<seealso + marker="erts:erlang#resume_process/1"><c>erlang:resume_process()</c></seealso>. + The <seealso + marker="runtime_tools:dbg"><c>dbg</c></seealso> trace + tool utilize this functionality and could thus trigger + this bug.</p> + <p> + Own Id: OTP-15688</p> + </item> + <item> + <p> + Fix a possible deadlock when terminating the ERTS caused + by a dirty scheduler not releasing it's run-queue lock + when terminating.</p> + <p> + Own Id: OTP-15690 Aux Id: PR-2172 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>When multiplying a number by itself, a word beyond the + number on the heap could be read (and ignored). This bug + was extremely unlikely to actually cause a real + problem.</p> + <p> + Own Id: OTP-15484</p> + </item> + <item> + <p> + Fix bug where doing <c>seq_trace:reset_trace()</c> while + another process was doing a garbage collection could + cause the run-time system to segfault.</p> + <p> + Own Id: OTP-15490</p> + </item> + <item> + <p> + Fix reading of ancillary data from packet oriented + sockets on old Linux kernel versions. Without this fix, + getting the data would cause the port to enter an + infinite loop.</p> + <p> + Own Id: OTP-15494</p> + </item> + <item> + <p> + Fix bug where crash dumping or doing + <c>erlang:system_info(procs)</c> while another process + was doing a garbage collection could cause the run-time + system to segfault.</p> + <p> + Own Id: OTP-15527</p> + </item> + <item> + <p> + Fix <c>erlang:system_info(kernel_poll)</c> to return + correct value. Before this fix, the call always returned + <c>false</c>.</p> + <p> + Own Id: OTP-15556</p> + </item> + <item> + <p> + Fix bug in <c>enif_make_map_from_arrays</c> that would + produce broken maps when number of keys were 32. Bug + exists since OTP 21.0.</p> + <p> + Own Id: OTP-15567</p> + </item> + <item> + <p> + Fix a bug in <c>binary:encode_unsigned</c> that may cause + a read of uninitialized memory.</p> + <p> + The bug existed since the function was added (OTP + R16B02).</p> + <p> + Own Id: OTP-15583 Aux Id: PR-2118 </p> + </item> + <item> + <p> + Fixed a bug that could cause <c>heart</c> to kill an + exiting node before it had time to flush all buffered + writes. If environment variable + <c>HEART_KILL_SIGNAL=SIGABRT</c> was set a superfluous + core dump could also be generated.</p> + <p> + Own Id: OTP-15599 Aux Id: ERIERL-298 </p> + </item> + <item> + <p> + Fix <c>enif_consume_timeslice</c> to be a no-op on dirty + scheduler and not crash debug compiled emulator.</p> + <p> + Own Id: OTP-15604</p> + </item> + <item> + <p> + Fixed macro redefinition warnings.</p> + <p> + Own Id: OTP-15629</p> + </item> + <item> + <p> + <c>to_erl</c> fixed to not garble terminal input beyond + 7-bit ASCII.</p> + <p> + Own Id: OTP-15650 Aux Id: ERL-854, PR-2161 </p> + </item> + <item> + <p> + Minor fixes for <c>make clean</c>.</p> + <p> + Own Id: OTP-15657</p> + </item> + <item> + <p> + Fixed a bug in all <c>ets:select*</c> and + <c>ets:match*</c> functions that could in some rare cases + lead to very poor performance.</p> + <p> + Own Id: OTP-15660 Aux Id: ERL-869 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add <c>erlang:system_flag(system_logger, Pid)</c> and + <c>erlang:system_info(system_logger)</c>. This + system_flag can be used to set the process that will + receive the logging messages generated by ERTS.</p> + <p> + Own Id: OTP-15375</p> + </item> + <item> + <p><c>integer_to_list/2</c> and + <c>integer_to_binary/2</c> are now implemented in C, + improving their performance.</p> + <p> + Own Id: OTP-15503 Aux Id: PR-2052 </p> + </item> + <item> + <p> + Improved <c>term_to_binary</c> to do more fair reduction + count and yielding when encoding large byte lists + (strings).</p> + <p> + Own Id: OTP-15514 Aux Id: ERL-774 </p> + </item> + <item> + <p> + Made internal port drivers more robust against + <c>erlang:port_control</c> with invalid arguments and + added documentation warnings about such abuse.</p> + <p> + Own Id: OTP-15555 Aux Id: ERIERL-231 </p> + </item> + <item> + <p> + Fix bug on NetBSD where the <c>exit_status</c> from a + port program would never be sent.</p> + <p> + Own Id: OTP-15558 Aux Id: ERL-725 </p> + </item> + <item> + <p>There is a new function <c>persistent:term(Key, + Default)</c> to allow specifying a default when looking + up a persistent term.</p> + <p> + Own Id: OTP-15576 Aux Id: ERL-843 </p> + </item> + <item> + <p>A transitory emulator option '<c>+ztma true</c>' has + been added to allow running existing BEAM code that + relies on "tuple calls" (dispatch on parameterized + modules) which has been compiled under OTP 20 or earlier. + This option will be removed in OTP 22, so such modules + should eventually be recompiled with the + <c>+tuple_calls</c> option.</p> + <p> + Own Id: OTP-15580 Aux Id: PR-2113 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.2.5</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Fixes of install/release phase in build system.</p> + <list> <item>The source tree was modified when + installing/releasing and/or applying a patch.</item> + <item>Some files were installed with wrong access + rights.</item> <item>If applying a patch (using + <c>otp_patch_apply</c>) as another user (except root) + than the user that built the source, the documentation + was not properly updated.</item> </list> + <p> + Own Id: OTP-15551</p> + </item> + <item> + <p> + Setting the <c>recbuf</c> size of an inet socket the + <c>buffer</c> is also automatically increased. Fix a bug + where the auto adjustment of inet buffer size would be + triggered even if an explicit inet buffer size had + already been set.</p> + <p> + Own Id: OTP-15651 Aux Id: ERIERL-304 </p> + </item> + <item> + <p> + Reading from UDP using active <c>true</c> or active + <c>N</c> mode has been optimized when more packets than + specified by <c>read_packets</c> are available on the + socket.</p> + <p> + Own Id: OTP-15652 Aux Id: ERIERL-304 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.2.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + When using the <c>{linger,{true,T}}</c> option; + <c>gen_tcp:listen/2</c> used the full linger time before + returning for example <c>eaddrinuse</c>. This bug has now + been corrected.</p> + <p> + Own Id: OTP-14728 Aux Id: ERIERL-303 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.2.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix bug where doing a <c>gen_tcp:send</c> on a socket + with <c>delay_send</c> set to true could cause a segfault + if the other side closes the connection.</p> + <p> + Bug was introduced in erts-10.2 (OTP-21.2).</p> + <p> + Own Id: OTP-15536 Aux Id: ERL-827 </p> + </item> + <item> + <p> + Fix a race condition when a port program closes that + could result in the next started port to hang during + startup.</p> + <p> + When this fault happens the following error is normally + (but not always) logged:</p> + <p> + <c> =ERROR REPORT==== 14-Jan-2019::10:45:52.868246 + ===</c><br/><c> Bad input fd in erts_poll()! fd=11, + port=#Port<0.505>, driver=spawn, name=/bin/sh -s + unix:cmd </c></p> + <p> + Bug was introduced in erts-10.0 (OTP-21.0).</p> + <p> + Own Id: OTP-15537</p> + </item> + <item> + <p> + Fix a bug where polling for external events could be + delayed for a very long time if all active schedulers + were 100% loaded.</p> + <p> + Bug was introduced in erts-10.2 (OTP-21.2).</p> + <p> + Own Id: OTP-15538 Aux Id: ERIERL-229 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.2.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Fixed a crash when dangling files were closed after + <c>init:restart/0</c>.</p> + <p> + Own Id: OTP-15495 Aux Id: ERL-821 </p> + </item> + <item> + <p> + A bug that could cause dirty schedulers to become + unresponsive has been fixed.</p> + <p> + Own Id: OTP-15509 Aux Id: PR-2027, PR-2093 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed bug on big endian architectures when changing file + permissions or ownership with <c>file:change_mode</c>, + <c>change_owner</c>, <c>change_group</c> or + <c>write_file_info</c>. Bug exists since OTP-21.0.</p> + <p> + Own Id: OTP-15485</p> + </item> + <item> + <p> + Fixed bug in <c>atomics</c> with option + <c>{signed,false}</c> when returned values are <c>(1 bsl + 63)</c> or larger. Could cause heap corruption leading to + VM crash or other unpleasant symptoms. Bug exists since + OTP-21.2 when module <c>atomics</c> was introduced.</p> + <p> + Own Id: OTP-15486 Aux Id: PR-2061 </p> + </item> + <item> + <p> + Fixed bug in operator <c>band</c> of two negative + operands causing erroneous result if the absolute value + of one of the operands have the lowest <c>N*W</c> bits as + zero and the other absolute value is not larger than + <c>N*W</c> bits. <c>N</c> is an integer of 1 or larger + and <c>W</c> is 32 or 64 depending on word size.</p> + <p> + Own Id: OTP-15487 Aux Id: ERL-804 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 10.2</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -1586,6 +1982,62 @@ </section> +<section><title>Erts 9.3.3.9</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Added an optional <c>./configure</c> flag to compile + the emulator with spectre mitigation: + <c>--with-spectre-mitigation</c></p> + <p>Note that this requires a recent version of GCC with + support for spectre mitigation and the + <c>--mindirect-branch=thunk</c> flag, such as + <c>8.1</c>.</p> + <p> + Own Id: OTP-15430 Aux Id: ERIERL-237 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 9.3.3.8</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + A bug that could cause dirty schedulers to become + unresponsive has been fixed.</p> + <p> + Own Id: OTP-15509 Aux Id: PR-2027, PR-2093 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 9.3.3.7</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed bug in operator <c>band</c> of two negative + operands causing erroneous result if the absolute value + of one of the operands have the lowest <c>N*W</c> bits as + zero and the other absolute value is not larger than + <c>N*W</c> bits. <c>N</c> is an integer of 1 or larger + and <c>W</c> is 32 or 64 depending on word size.</p> + <p> + Own Id: OTP-15487 Aux Id: ERL-804 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 9.3.3.6</title> <section><title>Improvements and New Features</title> @@ -1947,6 +2399,22 @@ </section> +<section><title>Erts 9.2.0.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Extra internal consistency checks wrt communication with + erl_child_setup process.</p> + <p> + Own Id: OTP-15488 Aux Id: ERIERL-231 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 9.2</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -3145,6 +3613,43 @@ </section> +<section><title>Erts 8.3.5.7</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed bug in operator <c>band</c> of two negative + operands causing erroneous result if the absolute value + of one of the operands have the lowest <c>N*W</c> bits as + zero and the other absolute value is not larger than + <c>N*W</c> bits. <c>N</c> is an integer of 1 or larger + and <c>W</c> is 32 or 64 depending on word size.</p> + <p> + Own Id: OTP-15487 Aux Id: ERL-804 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Added an optional <c>./configure</c> flag to compile + the emulator with spectre mitigation: + <c>--with-spectre-mitigation</c></p> + <p>Note that this requires a recent version of GCC with + support for spectre mitigation and the + <c>--mindirect-branch=thunk</c> flag, such as + <c>8.1</c>.</p> + <p> + Own Id: OTP-15430 Aux Id: ERIERL-237 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 8.3.5.6</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/erts/doc/src/persistent_term.xml b/erts/doc/src/persistent_term.xml index 29a6c67051..9d3c9afd80 100644 --- a/erts/doc/src/persistent_term.xml +++ b/erts/doc/src/persistent_term.xml @@ -29,7 +29,7 @@ <rev></rev> <file>persistent_term.xml</file> </header> - <module>persistent_term</module> + <module since="OTP 21.2">persistent_term</module> <modulesummary>Persistent terms.</modulesummary> <description> <p>This module is similar to <seealso @@ -213,7 +213,7 @@ will be slower as the number of persistent terms increases.</pre> <funcs> <func> - <name name="erase" arity="1"/> + <name name="erase" arity="1" since="OTP 21.2"/> <fsummary>Erase the name for a persistent term.</fsummary> <desc> <p>Erase the name for the persistent term with key @@ -229,7 +229,7 @@ will be slower as the number of persistent terms increases.</pre> </func> <func> - <name name="get" arity="0"/> + <name name="get" arity="0" since="OTP 21.2"/> <fsummary>Get all persistent terms.</fsummary> <desc> <p>Retrieve the keys and values for all persistent terms. @@ -239,7 +239,7 @@ will be slower as the number of persistent terms increases.</pre> </func> <func> - <name name="get" arity="1"/> + <name name="get" arity="1" since="OTP 21.2"/> <fsummary>Get the value for a persistent term.</fsummary> <desc> <p>Retrieve the value for the persistent term associated with @@ -256,7 +256,23 @@ will be slower as the number of persistent terms increases.</pre> </func> <func> - <name name="info" arity="0"/> + <name name="get" arity="2" since="OTP 21.3"/> + <fsummary>Get the value for a persistent term.</fsummary> + <desc> + <p>Retrieve the value for the persistent term associated with + the key <c><anno>Key</anno></c>. The lookup will be made in + constant time and the value will not be copied to the heap + of the calling process.</p> + <p>This function returns <c><anno>Default</anno></c> if no + term has been stored with the key <c><anno>Key</anno></c>.</p> + <p>If the calling process holds on to the value of the + persistent term and the persistent term is deleted in the future, + the term will be copied to the process.</p> + </desc> + </func> + + <func> + <name name="info" arity="0" since="OTP 21.2"/> <fsummary>Get information about persistent terms.</fsummary> <desc> <p>Return information about persistent terms in a map. The map @@ -272,7 +288,7 @@ will be slower as the number of persistent terms increases.</pre> </func> <func> - <name name="put" arity="2"/> + <name name="put" arity="2" since="OTP 21.2"/> <fsummary>Store a term.</fsummary> <desc> <p>Store the value <c><anno>Value</anno></c> as a persistent term and diff --git a/erts/doc/src/zlib.xml b/erts/doc/src/zlib.xml index 6f4c42da27..38229456c9 100644 --- a/erts/doc/src/zlib.xml +++ b/erts/doc/src/zlib.xml @@ -29,7 +29,7 @@ <rev></rev> <file>zlib.xml</file> </header> - <module>zlib</module> + <module since="">zlib</module> <modulesummary>zlib compression interface.</modulesummary> <description> <p>This module provides an API for the zlib library @@ -120,7 +120,7 @@ list_to_binary([Compressed|Last])</pre> <funcs> <func> - <name name="adler32" arity="2"/> + <name name="adler32" arity="2" since=""/> <fsummary>Calculate the Adler checksum.</fsummary> <desc> <p>Calculates the Adler-32 checksum for <c><anno>Data</anno></c>.</p> @@ -133,7 +133,7 @@ list_to_binary([Compressed|Last])</pre> </func> <func> - <name name="adler32" arity="3"/> + <name name="adler32" arity="3" since=""/> <fsummary>Calculate the Adler checksum.</fsummary> <desc> <p>Updates a running Adler-32 checksum for <c><anno>Data</anno></c>. @@ -153,7 +153,7 @@ Crc = lists:foldl(fun(Data,Crc0) -> </func> <func> - <name name="adler32_combine" arity="4"/> + <name name="adler32_combine" arity="4" since=""/> <fsummary>Combine two Adler-32 checksums.</fsummary> <desc> <p>Combines two Adler-32 checksums into one. For two binaries or @@ -172,7 +172,7 @@ Crc = lists:foldl(fun(Data,Crc0) -> </func> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a stream.</fsummary> <desc> <p>Closes the stream referenced by <c><anno>Z</anno></c>.</p> @@ -180,7 +180,7 @@ Crc = lists:foldl(fun(Data,Crc0) -> </func> <func> - <name name="compress" arity="1"/> + <name name="compress" arity="1" since=""/> <fsummary>Compress data with standard zlib functionality.</fsummary> <desc> <p>Compresses data with zlib headers and checksum.</p> @@ -188,7 +188,7 @@ Crc = lists:foldl(fun(Data,Crc0) -> </func> <func> - <name name="crc32" arity="1"/> + <name name="crc32" arity="1" since=""/> <fsummary>Get current CRC.</fsummary> <desc> <p>Gets the current calculated CRC checksum.</p> @@ -202,7 +202,7 @@ Crc = lists:foldl(fun(Data,Crc0) -> </func> <func> - <name name="crc32" arity="2"/> + <name name="crc32" arity="2" since=""/> <fsummary>Calculate CRC.</fsummary> <desc> <p>Calculates the CRC checksum for <c><anno>Data</anno></c>.</p> @@ -215,7 +215,7 @@ Crc = lists:foldl(fun(Data,Crc0) -> </func> <func> - <name name="crc32" arity="3"/> + <name name="crc32" arity="3" since=""/> <fsummary>Calculate CRC.</fsummary> <desc> <p>Updates a running CRC checksum for <c><anno>Data</anno></c>. @@ -235,7 +235,7 @@ Crc = lists:foldl(fun(Data,Crc0) -> </func> <func> - <name name="crc32_combine" arity="4"/> + <name name="crc32_combine" arity="4" since=""/> <fsummary>Combine two CRCs.</fsummary> <desc> <p>Combines two CRC checksums into one. For two binaries or iolists, @@ -254,7 +254,7 @@ Crc = lists:foldl(fun(Data,Crc0) -> </func> <func> - <name name="deflate" arity="2"/> + <name name="deflate" arity="2" since=""/> <fsummary>Compress data.</fsummary> <desc> <p>Same as <c>deflate(<anno>Z</anno>, <anno>Data</anno>, none)</c>.</p> @@ -262,7 +262,7 @@ Crc = lists:foldl(fun(Data,Crc0) -> </func> <func> - <name name="deflate" arity="3"/> + <name name="deflate" arity="3" since=""/> <fsummary>Compress data.</fsummary> <desc> <p>Compresses as much data as possible, and @@ -300,7 +300,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="deflateEnd" arity="1"/> + <name name="deflateEnd" arity="1" since=""/> <fsummary>End deflate session.</fsummary> <desc> <p>Ends the deflate session and cleans all data used. Notice that this @@ -311,7 +311,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="deflateInit" arity="1"/> + <name name="deflateInit" arity="1" since=""/> <fsummary>Initialize a session for compression.</fsummary> <desc> <p>Same as <c>zlib:deflateInit(<anno>Z</anno>, default)</c>.</p> @@ -319,7 +319,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="deflateInit" arity="2"/> + <name name="deflateInit" arity="2" since=""/> <fsummary>Initialize a session for compression.</fsummary> <desc> <p>Initializes a zlib stream for compression.</p> @@ -334,7 +334,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="deflateInit" arity="6"/> + <name name="deflateInit" arity="6" since=""/> <fsummary>Initialize a session for compression.</fsummary> <desc> <p>Initiates a zlib stream for compression.</p> @@ -410,7 +410,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="deflateParams" arity="3"/> + <name name="deflateParams" arity="3" since=""/> <fsummary>Dynamicly update deflate parameters.</fsummary> <desc> <p>Dynamically updates the compression level and compression @@ -432,7 +432,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="deflateReset" arity="1"/> + <name name="deflateReset" arity="1" since=""/> <fsummary>Reset the deflate session.</fsummary> <desc> <p>Equivalent to @@ -446,7 +446,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="deflateSetDictionary" arity="2"/> + <name name="deflateSetDictionary" arity="2" since=""/> <fsummary>Initialize the compression dictionary.</fsummary> <desc> <p>Initializes the compression dictionary from the specified byte @@ -464,7 +464,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="getBufSize" arity="1"/> + <name name="getBufSize" arity="1" since=""/> <fsummary>Get buffer size.</fsummary> <desc> <p>Gets the size of the intermediate buffer.</p> @@ -476,7 +476,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="gunzip" arity="1"/> + <name name="gunzip" arity="1" since=""/> <fsummary>Uncompress data with gz header.</fsummary> <desc> <p>Uncompresses data with gz headers and checksum.</p> @@ -484,7 +484,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="gzip" arity="1"/> + <name name="gzip" arity="1" since=""/> <fsummary>Compress data with gz header.</fsummary> <desc> <p>Compresses data with gz headers and checksum.</p> @@ -492,7 +492,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="inflate" arity="2"/> + <name name="inflate" arity="2" since=""/> <fsummary>Decompress data.</fsummary> <desc> <p>Equivalent to @@ -502,7 +502,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="inflate" arity="3"/> + <name name="inflate" arity="3" since="OTP 20.1"/> <fsummary>Decompress data.</fsummary> <desc> <p>Decompresses as much data as possible. It can introduce some output @@ -524,7 +524,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="inflateChunk" arity="1"/> + <name name="inflateChunk" arity="1" since="OTP 18.0"/> <fsummary>Read next uncompressed chunk.</fsummary> <desc> <warning> @@ -540,7 +540,7 @@ list_to_binary([B1,B2])</pre> </func> <func> - <name name="inflateChunk" arity="2"/> + <name name="inflateChunk" arity="2" since="OTP 18.0"/> <fsummary>Decompress data with limited output size.</fsummary> <desc> <warning> @@ -584,7 +584,7 @@ loop(Z, Handler, Uncompressed) -> </func> <func> - <name name="inflateEnd" arity="1"/> + <name name="inflateEnd" arity="1" since=""/> <fsummary>End inflate session.</fsummary> <desc> <p>Ends the inflate session and cleans all data used. Notice @@ -595,7 +595,7 @@ loop(Z, Handler, Uncompressed) -> </func> <func> - <name name="inflateGetDictionary" arity="1"/> + <name name="inflateGetDictionary" arity="1" since="OTP 20.0"/> <fsummary>Return the decompression dictionary.</fsummary> <desc> <p>Returns the decompression dictionary currently in use @@ -607,7 +607,7 @@ loop(Z, Handler, Uncompressed) -> </func> <func> - <name name="inflateInit" arity="1"/> + <name name="inflateInit" arity="1" since=""/> <fsummary>Initialize a session for decompression.</fsummary> <desc> <p>Initializes a zlib stream for decompression.</p> @@ -615,7 +615,7 @@ loop(Z, Handler, Uncompressed) -> </func> <func> - <name name="inflateInit" arity="2"/> + <name name="inflateInit" arity="2" since=""/> <fsummary>Initialize a session for decompression.</fsummary> <desc> <p>Initializes a decompression session on zlib stream.</p> @@ -634,7 +634,7 @@ loop(Z, Handler, Uncompressed) -> </func> <func> - <name name="inflateReset" arity="1"/> + <name name="inflateReset" arity="1" since=""/> <fsummary>>Reset the inflate session.</fsummary> <desc> <p>Equivalent to @@ -648,7 +648,7 @@ loop(Z, Handler, Uncompressed) -> </func> <func> - <name name="inflateSetDictionary" arity="2"/> + <name name="inflateSetDictionary" arity="2" since=""/> <fsummary>Initialize the decompression dictionary.</fsummary> <desc> <p>Initializes the decompression dictionary from the specified @@ -688,7 +688,7 @@ new_unpack(Z, Compressed, Dict) -> </func> <func> - <name name="open" arity="0"/> + <name name="open" arity="0" since=""/> <fsummary>Open a stream and return a stream reference.</fsummary> <desc> <p>Opens a zlib stream.</p> @@ -696,7 +696,7 @@ new_unpack(Z, Compressed, Dict) -> </func> <func> - <name name="safeInflate" arity="2"/> + <name name="safeInflate" arity="2" since="OTP 20.1"/> <fsummary>Decompress data with limited output size.</fsummary> <desc> <p>Like <seealso marker="#inflate/2"><c>inflate/2</c></seealso>, @@ -733,7 +733,7 @@ loop(Z, Handler, {finished, Output}) -> </func> <func> - <name name="setBufSize" arity="2"/> + <name name="setBufSize" arity="2" since=""/> <fsummary>Set buffer size.</fsummary> <desc> <p>Sets the intermediate buffer size.</p> @@ -745,7 +745,7 @@ loop(Z, Handler, {finished, Output}) -> </func> <func> - <name name="set_controlling_process" arity="2"/> + <name name="set_controlling_process" arity="2" since="OTP 20.1.3"/> <fsummary>Transfers ownership of a zlib stream.</fsummary> <desc> <p>Changes the controlling process of <c><anno>Z</anno></c> to @@ -754,7 +754,7 @@ loop(Z, Handler, {finished, Output}) -> </func> <func> - <name name="uncompress" arity="1"/> + <name name="uncompress" arity="1" since=""/> <fsummary>Uncompress data with standard zlib functionality.</fsummary> <desc> <p>Uncompresses data with zlib headers and checksum.</p> @@ -762,7 +762,7 @@ loop(Z, Handler, {finished, Output}) -> </func> <func> - <name name="unzip" arity="1"/> + <name name="unzip" arity="1" since=""/> <fsummary>Uncompress data without the zlib headers.</fsummary> <desc> <p>Uncompresses data without zlib headers and checksum.</p> @@ -770,7 +770,7 @@ loop(Z, Handler, {finished, Output}) -> </func> <func> - <name name="zip" arity="1"/> + <name name="zip" arity="1" since=""/> <fsummary>Compress data without the zlib headers.</fsummary> <desc> <p>Compresses data without zlib headers and checksum.</p> diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index 57a9d45887..e7648f2396 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -266,7 +266,6 @@ DEXPORT = @DEXPORT@ RANLIB = @RANLIB@ STRIP = strip PERL = @PERL@ -RM = @RM@ MKDIR = @MKDIR@ USING_MINGW=@MIXED_CYGWIN_MINGW@ @@ -467,13 +466,13 @@ $(ERTS_LIB): .PHONY: clean clean: - $(RM) -f $(GENERATE) - $(RM) -rf $(TARGET)/*.c $(TARGET)/*.h $(TARGET)/*-GENERATED - $(RM) -rf $(TARGET)/*/* - $(RM) -rf obj/$(TARGET) - $(RM) -rf pcre/obj/$(TARGET) $(PCRE_GENINC) - $(RM) -rf zlib/obj/$(TARGET) - $(RM) -rf bin/$(TARGET) + $(RM) $(GENERATE) + $(RM) -r $(TARGET)/*.c $(TARGET)/*.h $(TARGET)/*-GENERATED + $(RM) -r $(TARGET)/*/* + $(RM) -r obj/$(TARGET) + $(RM) -r pcre/obj/$(TARGET) $(PCRE_GENINC) + $(RM) -r zlib/obj/$(TARGET) + $(RM) -r bin/$(TARGET) cd $(ERTS_LIB_DIR) && $(MAKE) clean .PHONY: docs diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index a14f22b19e..291bc95604 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -546,6 +546,7 @@ atom reload atom rem atom report_errors atom reset +atom reset_seq_trace atom restart atom return_from atom return_to diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index e909a0b4da..10d70a96e8 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -379,6 +379,7 @@ do { \ # define NOINLINE #endif +int tuple_module_apply; /* * The following functions are called directly by process_main(). @@ -2210,6 +2211,7 @@ apply(Process* p, Eterm* reg, BeamInstr *I, Uint stack_offset) Eterm module = reg[0]; Eterm function = reg[1]; Eterm args = reg[2]; + Eterm this; /* * Check the arguments which should be of the form apply(Module, @@ -2232,8 +2234,20 @@ apply(Process* p, Eterm* reg, BeamInstr *I, Uint stack_offset) while (1) { Eterm m, f, a; - - if (is_not_atom(module)) goto error; + /* The module argument may be either an atom or an abstract module + * (currently implemented using tuples, but this might change). + */ + this = THE_NON_VALUE; + if (is_not_atom(module)) { + Eterm* tp; + + if (!tuple_module_apply || is_not_tuple(module)) goto error; + tp = tuple_val(module); + if (arityval(tp[0]) < 1) goto error; + this = module; + module = tp[1]; + if (is_not_atom(module)) goto error; + } if (module != am_erlang || function != am_apply) break; @@ -2268,7 +2282,9 @@ apply(Process* p, Eterm* reg, BeamInstr *I, Uint stack_offset) } /* * Walk down the 3rd parameter of apply (the argument list) and copy - * the parameters to the x registers (reg[]). + * the parameters to the x registers (reg[]). If the module argument + * was an abstract module, add 1 to the function arity and put the + * module argument in the n+1st x register as a THIS reference. */ tmp = args; @@ -2285,6 +2301,9 @@ apply(Process* p, Eterm* reg, BeamInstr *I, Uint stack_offset) if (is_not_nil(tmp)) { /* Must be well-formed list */ goto error; } + if (this != THE_NON_VALUE) { + reg[arity++] = this; + } /* * Get the index into the export table, or failing that the export @@ -2323,7 +2342,18 @@ fixed_apply(Process* p, Eterm* reg, Uint arity, return 0; } - if (is_not_atom(module)) goto error; + /* The module argument may be either an atom or an abstract module + * (currently implemented using tuples, but this might change). + */ + if (is_not_atom(module)) { + Eterm* tp; + if (!tuple_module_apply || is_not_tuple(module)) goto error; + tp = tuple_val(module); + if (arityval(tp[0]) < 1) goto error; + module = tp[1]; + if (is_not_atom(module)) goto error; + ++arity; + } /* Handle apply of apply/3... */ if (module == am_erlang && function == am_apply && arity == 3) { @@ -3231,20 +3261,23 @@ erts_is_builtin(Eterm Mod, Eterm Name, int arity) /* - * Return the current number of reductions for the given process. + * Return the current number of reductions consumed by the given process. * To get the total number of reductions, p->reds must be added. */ Uint -erts_current_reductions(Process *current, Process *p) +erts_current_reductions(Process *c_p, Process *p) { - if (current != p) { + Sint reds_left; + if (c_p != p || !(erts_atomic32_read_nob(&c_p->state) + & ERTS_PSFLG_RUNNING)) { return 0; - } else if (current->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(current)) { - return current->fcalls + CONTEXT_REDS; + } else if (c_p->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) { + reds_left = c_p->fcalls + CONTEXT_REDS; } else { - return REDS_IN(current) - current->fcalls; + reds_left = c_p->fcalls; } + return REDS_IN(c_p) - reds_left; } int diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 015c051cc1..000397e790 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -2810,38 +2810,110 @@ BIF_RETTYPE list_to_existing_atom_1(BIF_ALIST_1) /* convert an integer to a list of ascii integers */ -BIF_RETTYPE integer_to_list_1(BIF_ALIST_1) +static Eterm integer_to_list(Process *c_p, Eterm num, int base) { - Eterm* hp; + Eterm *hp; + Eterm res; Uint need; + if (is_small(num)) { + char s[128]; + char *c = s; + Uint digits; + + digits = Sint_to_buf(signed_val(num), base, &c, sizeof(s)); + need = 2 * digits; + + hp = HAlloc(c_p, need); + res = buf_to_intlist(&hp, c, digits, NIL); + } else { + const int DIGITS_PER_RED = 16; + Eterm *hp_end; + Uint digits; + + digits = big_integer_estimate(num, base); + + if ((digits / DIGITS_PER_RED) > ERTS_BIF_REDS_LEFT(c_p)) { + ErtsSchedulerData *esdp = erts_get_scheduler_data(); + + /* This could take a very long time, tell the caller to reschedule + * us to a dirty CPU scheduler if we aren't already on one. */ + if (esdp->type == ERTS_SCHED_NORMAL) { + return THE_NON_VALUE; + } + } else { + BUMP_REDS(c_p, digits / DIGITS_PER_RED); + } + + need = 2 * digits; + + hp = HAlloc(c_p, need); + hp_end = hp + need; + + res = erts_big_to_list(num, base, &hp); + HRelease(c_p, hp_end, hp); + } + + return res; +} + +BIF_RETTYPE integer_to_list_1(BIF_ALIST_1) +{ + Eterm res; + if (is_not_integer(BIF_ARG_1)) { - BIF_ERROR(BIF_P, BADARG); + BIF_ERROR(BIF_P, BADARG); } - if (is_small(BIF_ARG_1)) { - char *c; - int n; - struct Sint_buf ibuf; + res = integer_to_list(BIF_P, BIF_ARG_1, 10); - c = Sint_to_buf(signed_val(BIF_ARG_1), &ibuf); - n = sys_strlen(c); - need = 2*n; - hp = HAlloc(BIF_P, need); - BIF_RET(buf_to_intlist(&hp, c, n, NIL)); + if (is_non_value(res)) { + Eterm args[1]; + args[0] = BIF_ARG_1; + return erts_schedule_bif(BIF_P, + args, + BIF_I, + integer_to_list_1, + ERTS_SCHED_DIRTY_CPU, + am_erlang, + am_integer_to_list, + 1); } - else { - int n = big_decimal_estimate(BIF_ARG_1); - Eterm res; - Eterm* hp_end; - need = 2*n; - hp = HAlloc(BIF_P, need); - hp_end = hp + need; - res = erts_big_to_list(BIF_ARG_1, &hp); - HRelease(BIF_P,hp_end,hp); - BIF_RET(res); + return res; +} + +BIF_RETTYPE integer_to_list_2(BIF_ALIST_2) +{ + Eterm res; + SWord base; + + if (is_not_integer(BIF_ARG_1) || is_not_small(BIF_ARG_2)) { + BIF_ERROR(BIF_P, BADARG); } + + base = signed_val(BIF_ARG_2); + if (base < 2 || base > 36) { + BIF_ERROR(BIF_P, BADARG); + } + + res = integer_to_list(BIF_P, BIF_ARG_1, base); + + if (is_non_value(res)) { + Eterm args[2]; + args[0] = BIF_ARG_1; + args[1] = BIF_ARG_2; + return erts_schedule_bif(BIF_P, + args, + BIF_I, + integer_to_list_2, + ERTS_SCHED_DIRTY_CPU, + am_erlang, + am_integer_to_list, + 2); + } + + return res; } /**********************************************************************/ @@ -4490,11 +4562,12 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) ERTS_TRACER_CLEAR(&old_seq_tracer); BIF_RET(ret); - } else if (BIF_ARG_1 == make_small(1)) { + } else if (BIF_ARG_1 == am_reset_seq_trace) { int i, max; - erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_thr_progress_block(); + erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_thr_progress_block(); + max = erts_ptab_max(&erts_proc); for (i = 0; i < max; i++) { Process *p = erts_pix2proc(i); @@ -4506,13 +4579,14 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) #endif p->seq_trace_clock = 0; p->seq_trace_lastcnt = 0; - + erts_proc_lock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_MSGQ); erts_proc_sig_clear_seq_trace_tokens(p); + erts_proc_unlock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_MSGQ); } } - erts_thr_progress_unblock(); - erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + erts_thr_progress_unblock(); + erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); BIF_RET(am_true); } else if (BIF_ARG_1 == am_scheduler_wall_time) { @@ -4627,6 +4701,9 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) return erts_bind_schedulers(BIF_P, BIF_ARG_2); } else if (ERTS_IS_ATOM_STR("erts_alloc", BIF_ARG_1)) { return erts_alloc_set_dyn_param(BIF_P, BIF_ARG_2); + } else if (ERTS_IS_ATOM_STR("system_logger", BIF_ARG_1)) { + Eterm res = erts_set_system_logger(BIF_ARG_2); + if (is_value(res)) BIF_RET(res); } error: BIF_ERROR(BIF_P, BADARG); @@ -5129,61 +5206,6 @@ erts_call_dirty_bif(ErtsSchedulerData *esdp, Process *c_p, BeamInstr *I, Eterm * return exiting; } - - -#ifdef HARDDEBUG -/* -You'll need this line in bif.tab to be able to use this debug bif - -bif erlang:send_to_logger/2 - -*/ -BIF_RETTYPE send_to_logger_2(BIF_ALIST_2) -{ - byte *buf; - ErlDrvSizeT len; - if (!is_atom(BIF_ARG_1) || !(is_list(BIF_ARG_2) || - is_nil(BIF_ARG_1))) { - BIF_ERROR(BIF_P,BADARG); - } - if (erts_iolist_size(BIF_ARG_2, &len) != 0) - BIF_ERROR(BIF_P,BADARG); - else if (len == 0) - buf = ""; - else { -#ifdef DEBUG - ErlDrvSizeT len2; -#endif - buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, len+1); -#ifdef DEBUG - len2 = -#else - (void) -#endif - erts_iolist_to_buf(BIF_ARG_2, buf, len); - ASSERT(len2 == len); - buf[len] = '\0'; - switch (BIF_ARG_1) { - case am_info: - erts_send_info_to_logger(BIF_P->group_leader, buf, len); - break; - case am_warning: - erts_send_warning_to_logger(BIF_P->group_leader, buf, len); - break; - case am_error: - erts_send_error_to_logger(BIF_P->group_leader, buf, len); - break; - default: - { - BIF_ERROR(BIF_P,BADARG); - } - } - erts_free(ERTS_ALC_T_TMP, (void *) buf); - } - BIF_RET(am_true); -} -#endif /* HARDDEBUG */ - BIF_RETTYPE get_module_info_1(BIF_ALIST_1) { Eterm ret = erts_module_info_0(BIF_P, BIF_ARG_1); diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index d4ba90a61a..8419244832 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -725,3 +725,17 @@ bif erts_internal:counters_get/2 bif erts_internal:counters_add/3 bif erts_internal:counters_put/3 bif erts_internal:counters_info/1 + +# +# New in 21.2.3 +# + +bif erts_internal:spawn_system_process/3 + +# +# New in 21.3 +# + +bif erlang:integer_to_list/2 +bif erlang:integer_to_binary/2 +bif persistent_term:get/2 diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c index 84338769e0..522f50287a 100644 --- a/erts/emulator/beam/big.c +++ b/erts/emulator/beam/big.c @@ -429,6 +429,7 @@ static const byte digits_per_sint_lookup[36-1]; static const byte digits_per_small_lookup[36-1]; static const Sint largest_power_of_base_lookup[36-1]; +static const double lg2_lookup[36-1]; static ERTS_INLINE byte get_digits_per_signed_int(Uint base) { return digits_per_sint_lookup[base-2]; @@ -442,6 +443,10 @@ static ERTS_INLINE Sint get_largest_power_of_base(Uint base) { return largest_power_of_base_lookup[base-2]; } +static ERTS_INLINE double lookup_log2(Uint base) { + return lg2_lookup[base - 2]; +} + /* ** compare two number vectors */ @@ -668,27 +673,25 @@ static dsize_t I_mul(ErtsDigit* x, dsize_t xl, ErtsDigit* y, dsize_t yl, ErtsDig static dsize_t I_sqr(ErtsDigit* x, dsize_t xl, ErtsDigit* r) { - ErtsDigit d_next = *x; ErtsDigit d; ErtsDigit* r0 = r; ErtsDigit* s = r; if ((r + xl) == x) /* "Inline" operation */ *x = 0; - x++; while(xl--) { - ErtsDigit* y = x; + ErtsDigit* y; ErtsDigit y_0 = 0, y_1 = 0, y_2 = 0, y_3 = 0; ErtsDigit b0, b1; ErtsDigit z0, z1, z2; ErtsDigit t; dsize_t y_l = xl; - + + d = *x; + x++; + y = x; s = r; - d = d_next; - d_next = *x; - x++; DMUL(d, d, b1, b0); DSUMc(*s, b0, y_3, t); @@ -1159,8 +1162,11 @@ static dsize_t I_band(ErtsDigit* x, dsize_t xl, short xsgn, *r++ = ~c1 & ~c2; x++; y++; } - while(xl--) - *r++ = ~*x++; + while(xl--) { + DSUBb(*x,0,b1,c1); + *r++ = ~c1; + x++; + } } } return I_btrail(r0, r, sign); @@ -1719,23 +1725,23 @@ double_to_big(double x, Eterm *heap, Uint hsz) /* - ** Estimate the number of decimal digits (include sign) + ** Estimate the number of digits in given base (include sign) */ -int big_decimal_estimate(Wterm x) +int big_integer_estimate(Wterm x, Uint base) { Eterm* xp = big_val(x); int lg = I_lg(BIG_V(xp), BIG_SIZE(xp)); - int lg10 = ((lg+1)*28/93)+1; + int lgBase = ((lg + 1) / lookup_log2(base)) + 1; - if (BIG_SIGN(xp)) lg10++; /* add sign */ - return lg10+1; /* add null */ + if (BIG_SIGN(xp)) lgBase++; /* add sign */ + return lgBase + 1; /* add null */ } /* -** Convert a bignum into a string of decimal numbers +** Convert a bignum into a string of numbers in given base */ - -static Uint write_big(Wterm x, void (*write_func)(void *, char), void *arg) +static Uint write_big(Wterm x, int base, void (*write_func)(void *, char), + void *arg) { Eterm* xp = big_val(x); ErtsDigit* dx = BIG_V(xp); @@ -1743,48 +1749,72 @@ static Uint write_big(Wterm x, void (*write_func)(void *, char), void *arg) short sign = BIG_SIGN(xp); ErtsDigit rem; Uint n = 0; - const Uint digits_per_Sint = get_digits_per_signed_int(10); - const Sint largest_pow_of_base = get_largest_power_of_base(10); + const Uint digits_per_Sint = get_digits_per_signed_int(base); + const Sint largest_pow_of_base = get_largest_power_of_base(base); if (xl == 1 && *dx < largest_pow_of_base) { - rem = *dx; - if (rem == 0) { - (*write_func)(arg, '0'); n++; - } else { - while(rem) { - (*write_func)(arg, (rem % 10) + '0'); n++; - rem /= 10; - } - } + rem = *dx; + if (rem == 0) { + (*write_func)(arg, '0'); n++; + } else { + while(rem) { + int digit = rem % base; + + if (digit < 10) { + (*write_func)(arg, digit + '0'); n++; + } else { + (*write_func)(arg, 'A' + (digit - 10)); n++; + } + + rem /= base; + } + } } else { - ErtsDigit* tmp = (ErtsDigit*) erts_alloc(ERTS_ALC_T_TMP, - sizeof(ErtsDigit)*xl); - dsize_t tmpl = xl; + ErtsDigit* tmp = (ErtsDigit*) erts_alloc(ERTS_ALC_T_TMP, + sizeof(ErtsDigit) * xl); + dsize_t tmpl = xl; - MOVE_DIGITS(tmp, dx, xl); + MOVE_DIGITS(tmp, dx, xl); - while(1) { + while(1) { tmpl = D_div(tmp, tmpl, largest_pow_of_base, tmp, &rem); - if (tmpl == 1 && *tmp == 0) { - while(rem) { - (*write_func)(arg, (rem % 10)+'0'); n++; - rem /= 10; - } - break; - } else { + + if (tmpl == 1 && *tmp == 0) { + while(rem) { + int digit = rem % base; + + if (digit < 10) { + (*write_func)(arg, digit + '0'); n++; + } else { + (*write_func)(arg, 'A' + (digit - 10)); n++; + } + + rem /= base; + } + break; + } else { Uint i = digits_per_Sint; - while(i--) { - (*write_func)(arg, (rem % 10)+'0'); n++; - rem /= 10; - } - } - } - erts_free(ERTS_ALC_T_TMP, (void *) tmp); + + while(i--) { + int digit = rem % base; + + if (digit < 10) { + (*write_func)(arg, digit + '0'); n++; + } else { + (*write_func)(arg, 'A' + (digit - 10)); n++; + } + + rem /= base; + } + } + } + erts_free(ERTS_ALC_T_TMP, (void *) tmp); } if (sign) { - (*write_func)(arg, '-'); n++; + (*write_func)(arg, '-'); n++; } + return n; } @@ -1801,12 +1831,12 @@ write_list(void *arg, char c) blp->hp += 2; } -Eterm erts_big_to_list(Eterm x, Eterm **hpp) +Eterm erts_big_to_list(Eterm x, int base, Eterm **hpp) { struct big_list__ bl; bl.hp = *hpp; bl.res = NIL; - write_big(x, write_list, (void *) &bl); + write_big(x, base, write_list, (void *) &bl); *hpp = bl.hp; return bl.res; } @@ -1817,11 +1847,11 @@ write_string(void *arg, char c) *(--(*((char **) arg))) = c; } -char *erts_big_to_string(Wterm x, char *buf, Uint buf_sz) +char *erts_big_to_string(Wterm x, int base, char *buf, Uint buf_sz) { char *big_str = buf + buf_sz - 1; *big_str = '\0'; - write_big(x, write_string, (void *) &big_str); + write_big(x, base, write_string, (void*)&big_str); ASSERT(buf <= big_str && big_str <= buf + buf_sz - 1); return big_str; } @@ -1830,11 +1860,11 @@ char *erts_big_to_string(Wterm x, char *buf, Uint buf_sz) * e.g. 1 bsl 64 -> "18446744073709551616" */ -Uint erts_big_to_binary_bytes(Eterm x, char *buf, Uint buf_sz) +Uint erts_big_to_binary_bytes(Eterm x, int base, char *buf, Uint buf_sz) { char *big_str = buf + buf_sz; Uint n; - n = write_big(x, write_string, (void *) &big_str); + n = write_big(x, base, write_string, (void *) &big_str); ASSERT(buf <= big_str && big_str <= buf + buf_sz); return n; } @@ -2577,9 +2607,6 @@ static const double lg2_lookup[36-1] = { 4.32193, 4.39232, 4.45943, 4.52356, 4.58496, 4.64386, 4.70044, 4.75489, 4.80735, 4.85798, 4.90689, 4.9542, 5.0, 5.04439, 5.08746, 5.12928, 5.16993 }; -static ERTS_INLINE double lookup_log2(Uint base) { - return lg2_lookup[base - 2]; -} /* * How many digits can fit into a signed int (Sint) for given base, we take diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h index 7556205063..274482a0d2 100644 --- a/erts/emulator/beam/big.h +++ b/erts/emulator/beam/big.h @@ -81,7 +81,11 @@ typedef Uint dsize_t; /* Vector size type */ * a Uint64 argument. Therefore, we must test the size of the argument * to ensure that the cast does not discard the high-order 32 bits. */ -#define _IS_SSMALL32(x) (((Uint32) ((((x)) >> (SMALL_BITS-1)) + 1)) < 2) +#if defined(ARCH_32) +# define _IS_SSMALL32(x) (((Uint32) ((((x)) >> (SMALL_BITS-1)) + 1)) < 2) +#else +# define _IS_SSMALL32(x) (1) +#endif #define _IS_SSMALL64(x) (((Uint64) ((((x)) >> (SMALL_BITS-1)) + 1)) < 2) #define IS_SSMALL(x) (sizeof(x) == sizeof(Uint32) ? _IS_SSMALL32(x) : _IS_SSMALL64(x)) @@ -119,10 +123,10 @@ typedef Uint dsize_t; /* Vector size type */ #endif -int big_decimal_estimate(Wterm); -Eterm erts_big_to_list(Eterm, Eterm**); -char *erts_big_to_string(Wterm x, char *buf, Uint buf_sz); -Uint erts_big_to_binary_bytes(Eterm x, char *buf, Uint buf_sz); +int big_integer_estimate(Wterm, Uint base); +Eterm erts_big_to_list(Eterm, int base, Eterm**); +char *erts_big_to_string(Wterm x, int base, char *buf, Uint buf_sz); +Uint erts_big_to_binary_bytes(Eterm x, int base, char *buf, Uint buf_sz); Eterm small_times(Sint, Sint, Eterm*); diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c index 6a349764b2..a18228b84a 100644 --- a/erts/emulator/beam/binary.c +++ b/erts/emulator/beam/binary.c @@ -322,40 +322,102 @@ BIF_RETTYPE binary_to_integer_2(BIF_ALIST_2) } +static Eterm integer_to_binary(Process *c_p, Eterm num, int base) +{ + Eterm res; + + if (is_small(num)) { + char s[128]; + char *c = s; + Uint digits; + + digits = Sint_to_buf(signed_val(num), base, &c, sizeof(s)); + res = new_binary(c_p, (byte*)c, digits); + } else { + const int DIGITS_PER_RED = 16; + Uint digits, n; + byte *bytes; + + digits = big_integer_estimate(num, base); + + if ((digits / DIGITS_PER_RED) > ERTS_BIF_REDS_LEFT(c_p)) { + ErtsSchedulerData *esdp = erts_get_scheduler_data(); + + /* This could take a very long time, tell the caller to reschedule + * us to a dirty CPU scheduler if we aren't already on one. */ + if (esdp->type == ERTS_SCHED_NORMAL) { + return THE_NON_VALUE; + } + } else { + BUMP_REDS(c_p, digits / DIGITS_PER_RED); + } + + bytes = (byte*)erts_alloc(ERTS_ALC_T_TMP, sizeof(byte) * digits); + n = erts_big_to_binary_bytes(num, base, (char*)bytes, digits); + res = new_binary(c_p, bytes + digits - n, n); + erts_free(ERTS_ALC_T_TMP, (void*)bytes); + } + + return res; +} + BIF_RETTYPE integer_to_binary_1(BIF_ALIST_1) -{ - Uint size; +{ Eterm res; if (is_not_integer(BIF_ARG_1)) { - BIF_ERROR(BIF_P, BADARG); + BIF_ERROR(BIF_P, BADARG); } - if (is_small(BIF_ARG_1)) { - char *c; - struct Sint_buf ibuf; + res = integer_to_binary(BIF_P, BIF_ARG_1, 10); + + if (is_non_value(res)) { + Eterm args[1]; + args[0] = BIF_ARG_1; + return erts_schedule_bif(BIF_P, + args, + BIF_I, + integer_to_binary_1, + ERTS_SCHED_DIRTY_CPU, + am_erlang, + am_integer_to_binary, + 1); + } - /* Enhancement: If we can calculate the buffer size exactly - * we could avoid an unnecessary copy of buffers. - * Useful if size determination is faster than a copy. - */ - c = Sint_to_buf(signed_val(BIF_ARG_1), &ibuf); - size = sys_strlen(c); - res = new_binary(BIF_P, (byte *)c, size); - } else { - byte* bytes; - Uint n = 0; + return res; +} - /* Here we also have multiple copies of buffers - * due to new_binary interface - */ - size = big_decimal_estimate(BIF_ARG_1) - 1; /* remove null */ - bytes = (byte*) erts_alloc(ERTS_ALC_T_TMP, sizeof(byte)*size); - n = erts_big_to_binary_bytes(BIF_ARG_1, (char *)bytes, size); - res = new_binary(BIF_P, bytes + size - n, n); - erts_free(ERTS_ALC_T_TMP, (void *) bytes); +BIF_RETTYPE integer_to_binary_2(BIF_ALIST_2) +{ + Eterm res; + SWord base; + + if (is_not_integer(BIF_ARG_1) || is_not_small(BIF_ARG_2)) { + BIF_ERROR(BIF_P, BADARG); + } + + base = signed_val(BIF_ARG_2); + if (base < 2 || base > 36) { + BIF_ERROR(BIF_P, BADARG); } - BIF_RET(res); + + res = integer_to_binary(BIF_P, BIF_ARG_1, base); + + if (is_non_value(res)) { + Eterm args[2]; + args[0] = BIF_ARG_1; + args[1] = BIF_ARG_2; + return erts_schedule_bif(BIF_P, + args, + BIF_I, + integer_to_binary_2, + ERTS_SCHED_DIRTY_CPU, + am_erlang, + am_integer_to_binary, + 2); + } + + return res; } #define ERTS_B2L_BYTES_PER_REDUCTION 256 diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 9ff52c92b8..92009c2345 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -82,7 +82,7 @@ process_info(fmtfn_t to, void *to_arg) * they are most likely just created and has invalid data */ if (!ERTS_PROC_IS_EXITING(p) && p->heap != NULL) - print_process_info(to, to_arg, p); + print_process_info(to, to_arg, p, 0); } } @@ -101,7 +101,7 @@ process_killer(void) rp = erts_pix2proc(i); if (rp && rp->i != ENULL) { int br; - print_process_info(ERTS_PRINT_STDOUT, NULL, rp); + print_process_info(ERTS_PRINT_STDOUT, NULL, rp, 0); erts_printf("(k)ill (n)ext (r)eturn:\n"); while(1) { if ((j = sys_get_key(0)) <= 0) @@ -199,13 +199,14 @@ static void doit_print_monitor(ErtsMonitor *mon, void *vpcontext) /* Display info about an individual Erlang process */ void -print_process_info(fmtfn_t to, void *to_arg, Process *p) +print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_locks) { int garbing = 0; int running = 0; Sint len; struct saved_calls *scb; erts_aint32_t state; + ErtsProcLocks locks = orig_locks; /* display the PID */ erts_print(to, to_arg, "=proc:%T\n", p->common.id); @@ -222,6 +223,22 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p) | ERTS_PSFLG_DIRTY_RUNNING)) running = 1; + if (!(locks & ERTS_PROC_LOCK_MAIN)) { + locks |= ERTS_PROC_LOCK_MAIN; + if (ERTS_IS_CRASH_DUMPING && running) { + if (erts_proc_trylock(p, locks)) { + /* crash dumping and main lock taken, this probably means that + the process is doing a GC on a dirty-scheduler... so we cannot + do erts_proc_sig_fetch as that would potentially cause a segfault */ + locks = 0; + } + } else { + erts_proc_lock(p, locks); + } + } else { + ERTS_ASSERT(locks == ERTS_PROC_LOCK_MAIN && "Only main lock should be held"); + } + /* * If the process is registered as a global process, display the * registered name @@ -251,13 +268,19 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p) erts_print(to, to_arg, "Spawned by: %T\n", p->parent); - erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); - len = erts_proc_sig_fetch(p); - erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); + if (locks & ERTS_PROC_LOCK_MAIN) { + erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); + len = erts_proc_sig_fetch(p); + erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); + } else { + len = p->sig_qs.len; + } erts_print(to, to_arg, "Message queue length: %d\n", len); - /* display the message queue only if there is anything in it */ - if (!ERTS_IS_CRASH_DUMPING && p->sig_qs.first != NULL && !garbing) { + /* display the message queue only if there is anything in it + and we can do it safely */ + if (!ERTS_IS_CRASH_DUMPING && p->sig_qs.first != NULL && !garbing + && (locks & ERTS_PROC_LOCK_MAIN)) { erts_print(to, to_arg, "Message queue: ["); ERTS_FOREACH_SIG_PRIVQS( p, mp, @@ -357,6 +380,8 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p) /* Display all states */ erts_print(to, to_arg, "Internal State: "); erts_dump_extended_process_state(to, to_arg, state); + + erts_proc_unlock(p, locks & ~orig_locks); } static void diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.c b/erts/emulator/beam/erl_ao_firstfit_alloc.c index 3f0ab33597..917cb1cf10 100644 --- a/erts/emulator/beam/erl_ao_firstfit_alloc.c +++ b/erts/emulator/beam/erl_ao_firstfit_alloc.c @@ -100,8 +100,8 @@ #define AOFF_BLK_SZ(B) MBC_FBLK_SZ(&(B)->hdr) -#define LIST_NEXT(N) (((AOFF_RBTree_t*)(N))->u.next) -#define LIST_PREV(N) (((AOFF_RBTree_t*)(N))->parent) +#define AOFF_LIST_NEXT(N) (((AOFF_RBTree_t*)(N))->u.next) +#define AOFF_LIST_PREV(N) (((AOFF_RBTree_t*)(N))->parent) typedef struct AOFF_Carrier_t_ AOFF_Carrier_t; @@ -152,13 +152,13 @@ static ERTS_INLINE Uint node_max_size(AOFF_RBTree_t *x) static ERTS_INLINE void lower_max_size(AOFF_RBTree_t *node, AOFF_RBTree_t* stop_at) { - AOFF_RBTree_t* x = node; + AOFF_RBTree_t* x = node; Uint old_max = x->max_sz; Uint new_max = node_max_size(x); if (new_max < old_max) { x->max_sz = new_max; - while ((x=x->parent) != stop_at && x->max_sz == old_max) { + while ((x=x->parent) != stop_at && x->max_sz == old_max) { x->max_sz = node_max_size(x); } ASSERT(x == stop_at || x->max_sz > old_max); @@ -352,7 +352,7 @@ left_rotate(AOFF_RBTree_t **root, AOFF_RBTree_t *x) x->parent = y; y->max_sz = x->max_sz; - x->max_sz = node_max_size(x); + x->max_sz = node_max_size(x); ASSERT(y->max_sz >= x->max_sz); } @@ -377,7 +377,7 @@ right_rotate(AOFF_RBTree_t **root, AOFF_RBTree_t *x) y->right = x; x->parent = y; y->max_sz = x->max_sz; - x->max_sz = node_max_size(x); + x->max_sz = node_max_size(x); ASSERT(y->max_sz >= x->max_sz); } @@ -523,23 +523,23 @@ aoff_unlink_free_block(Allctr_t *allctr, Block_t *blk) ASSERT(del->flags & IS_BF_FLG); if (IS_LIST_ELEM(del)) { /* Remove from list */ - ASSERT(LIST_PREV(del)); - ASSERT(LIST_PREV(del)->flags & IS_BF_FLG); - LIST_NEXT(LIST_PREV(del)) = LIST_NEXT(del); - if (LIST_NEXT(del)) { - ASSERT(LIST_NEXT(del)->flags & IS_BF_FLG); - LIST_PREV(LIST_NEXT(del)) = LIST_PREV(del); + ASSERT(AOFF_LIST_PREV(del)); + ASSERT(AOFF_LIST_PREV(del)->flags & IS_BF_FLG); + AOFF_LIST_NEXT(AOFF_LIST_PREV(del)) = AOFF_LIST_NEXT(del); + if (AOFF_LIST_NEXT(del)) { + ASSERT(AOFF_LIST_NEXT(del)->flags & IS_BF_FLG); + AOFF_LIST_PREV(AOFF_LIST_NEXT(del)) = AOFF_LIST_PREV(del); } return; } - else if (LIST_NEXT(del)) { + else if (AOFF_LIST_NEXT(del)) { /* Replace tree node by next element in list... */ - - ASSERT(AOFF_BLK_SZ(LIST_NEXT(del)) == AOFF_BLK_SZ(del)); - ASSERT(IS_LIST_ELEM(LIST_NEXT(del))); - - replace(&crr->root, (AOFF_RBTree_t*)del, LIST_NEXT(del)); - + + ASSERT(AOFF_BLK_SZ(AOFF_LIST_NEXT(del)) == AOFF_BLK_SZ(del)); + ASSERT(IS_LIST_ELEM(AOFF_LIST_NEXT(del))); + + replace(&crr->root, (AOFF_RBTree_t*)del, AOFF_LIST_NEXT(del)); + HARD_CHECK_TREE(&crr->crr, alc->blk_order, crr->root, 0); return; } @@ -550,13 +550,13 @@ aoff_unlink_free_block(Allctr_t *allctr, Block_t *blk) HARD_CHECK_TREE(&crr->crr, alc->blk_order, crr->root, 0); /* Update the carrier tree with a potentially new (lower) max_sz - */ + */ if (crr->root) { if (crr->rbt_node.hdr.bhdr == crr->root->max_sz) { return; } ASSERT(crr->rbt_node.hdr.bhdr > crr->root->max_sz); - crr->rbt_node.hdr.bhdr = crr->root->max_sz; + crr->rbt_node.hdr.bhdr = crr->root->max_sz; } else { crr->rbt_node.hdr.bhdr = 0; @@ -773,7 +773,7 @@ rbt_insert(enum AOFFSortOrder order, AOFF_RBTree_t** root, AOFF_RBTree_t* blk) #ifdef DEBUG blk->flags = (order == FF_BF) ? IS_BF_FLG : 0; #else - blk->flags = 0; + blk->flags = 0; #endif blk->left = NULL; blk->right = NULL; @@ -787,7 +787,7 @@ rbt_insert(enum AOFFSortOrder order, AOFF_RBTree_t** root, AOFF_RBTree_t* blk) else { AOFF_RBTree_t *x = *root; while (1) { - SWord diff; + SWord diff; if (x->max_sz < blk_sz) { x->max_sz = blk_sz; } @@ -810,14 +810,14 @@ rbt_insert(enum AOFFSortOrder order, AOFF_RBTree_t** root, AOFF_RBTree_t* blk) } else { ASSERT(order == FF_BF); - ASSERT(blk->flags & IS_BF_FLG); - ASSERT(x->flags & IS_BF_FLG); + ASSERT(blk->flags & IS_BF_FLG); + ASSERT(x->flags & IS_BF_FLG); SET_LIST_ELEM(blk); - LIST_NEXT(blk) = LIST_NEXT(x); - LIST_PREV(blk) = x; - if (LIST_NEXT(x)) - LIST_PREV(LIST_NEXT(x)) = blk; - LIST_NEXT(x) = blk; + AOFF_LIST_NEXT(blk) = AOFF_LIST_NEXT(x); + AOFF_LIST_PREV(blk) = x; + if (AOFF_LIST_NEXT(x)) + AOFF_LIST_PREV(AOFF_LIST_NEXT(x)) = blk; + AOFF_LIST_NEXT(x) = blk; return; } } @@ -831,7 +831,7 @@ rbt_insert(enum AOFFSortOrder order, AOFF_RBTree_t** root, AOFF_RBTree_t* blk) } if (order == FF_BF) { SET_TREE_NODE(blk); - LIST_NEXT(blk) = NULL; + AOFF_LIST_NEXT(blk) = NULL; } } @@ -878,7 +878,7 @@ aoff_get_free_block(Allctr_t *allctr, Uint size, #ifdef HARD_DEBUG AOFF_RBTree_t* dbg_blk; #endif - + ASSERT(!cand_blk || cand_size >= size); /* Get first-fit carrier @@ -964,7 +964,7 @@ static void aoff_add_mbc(Allctr_t *allctr, Carrier_t *carrier) AOFF_RBTree_t **root = &alc->mbc_root; ASSERT(!IS_CRR_IN_TREE(crr, *root)); - HARD_CHECK_TREE(NULL, alc->crr_order, *root, 0); + HARD_CHECK_TREE(NULL, alc->crr_order, *root, 0); rbt_insert(alc->crr_order, root, &crr->rbt_node); @@ -1105,7 +1105,7 @@ info_options(Allctr_t *allctr, } if (hpp || szp) { - + if (!atoms_initialized) erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error: Atoms not initialized", __FILE__, __LINE__);; @@ -1132,7 +1132,7 @@ erts_aoffalc_test(UWord op, UWord a1, UWord a2) switch (op) { case 0x500: return (UWord) ((AOFFAllctr_t *) a1)->blk_order == FF_AOBF; case 0x501: { - AOFF_RBTree_t *node = ((AOFFAllctr_t *) a1)->mbc_root; + AOFF_RBTree_t *node = ((AOFFAllctr_t *) a1)->mbc_root; Uint size = (Uint) a2; node = node ? rbt_search(node, size) : NULL; return (UWord) (node ? RBT_NODE_TO_MBC(node)->root : NULL); @@ -1140,13 +1140,13 @@ erts_aoffalc_test(UWord op, UWord a1, UWord a2) case 0x502: return (UWord) ((AOFF_RBTree_t *) a1)->parent; case 0x503: return (UWord) ((AOFF_RBTree_t *) a1)->left; case 0x504: return (UWord) ((AOFF_RBTree_t *) a1)->right; - case 0x505: return (UWord) LIST_NEXT(a1); + case 0x505: return (UWord) AOFF_LIST_NEXT(a1); case 0x506: return (UWord) IS_BLACK((AOFF_RBTree_t *) a1); case 0x507: return (UWord) IS_TREE_NODE((AOFF_RBTree_t *) a1); case 0x508: return (UWord) 0; /* IS_BF_ALGO */ case 0x509: return (UWord) ((AOFF_RBTree_t *) a1)->max_sz; case 0x50a: return (UWord) ((AOFFAllctr_t *) a1)->blk_order == FF_BF; - case 0x50b: return (UWord) LIST_PREV(a1); + case 0x50b: return (UWord) AOFF_LIST_PREV(a1); default: ASSERT(0); return ~((UWord) 0); } } @@ -1166,7 +1166,7 @@ static int rbt_is_member(AOFF_RBTree_t* root, AOFF_RBTree_t* node) return 0; } node = node->parent; - } + } return 1; } @@ -1279,15 +1279,15 @@ check_tree(Carrier_t* within_crr, enum AOFFSortOrder order, AOFF_RBTree_t* root, } if (order == FF_BF) { AOFF_RBTree_t* y = x; - AOFF_RBTree_t* nxt = LIST_NEXT(y); + AOFF_RBTree_t* nxt = AOFF_LIST_NEXT(y); ASSERT(IS_TREE_NODE(x)); while (nxt) { ASSERT(IS_LIST_ELEM(nxt)); ASSERT(AOFF_BLK_SZ(nxt) == AOFF_BLK_SZ(x)); ASSERT(FBLK_TO_MBC(&nxt->hdr) == within_crr); - ASSERT(LIST_PREV(nxt) == y); + ASSERT(AOFF_LIST_PREV(nxt) == y); y = nxt; - nxt = LIST_NEXT(nxt); + nxt = AOFF_LIST_NEXT(nxt); } } @@ -1301,13 +1301,13 @@ check_tree(Carrier_t* within_crr, enum AOFFSortOrder order, AOFF_RBTree_t* root, if (x->left) { ASSERT(x->left->parent == x); ASSERT(cmp_blocks(order, x->left, x) < 0); - ASSERT(x->left->max_sz <= x->max_sz); + ASSERT(x->left->max_sz <= x->max_sz); } if (x->right) { ASSERT(x->right->parent == x); ASSERT(cmp_blocks(order, x->right, x) > 0); - ASSERT(x->right->max_sz <= x->max_sz); + ASSERT(x->right->max_sz <= x->max_sz); } ASSERT(x->max_sz >= AOFF_BLK_SZ(x)); ASSERT(x->max_sz == AOFF_BLK_SZ(x) @@ -1327,7 +1327,7 @@ check_tree(Carrier_t* within_crr, enum AOFFSortOrder order, AOFF_RBTree_t* root, x = x->parent; --depth; } - ASSERT(depth == 0 || (!root && depth==1)); + ASSERT(depth == 0 || (!root && depth==1)); ASSERT(curr_blacks == 0); ASSERT((1 << (max_depth/2)) <= node_cnt); @@ -1373,4 +1373,3 @@ print_tree(AOFF_RBTree_t* root) #endif /* PRINT_TREE */ #endif /* HARD_DEBUG */ - diff --git a/erts/emulator/beam/erl_bestfit_alloc.c b/erts/emulator/beam/erl_bestfit_alloc.c index 9cb1199c2a..3f981ca2bc 100644 --- a/erts/emulator/beam/erl_bestfit_alloc.c +++ b/erts/emulator/beam/erl_bestfit_alloc.c @@ -122,8 +122,8 @@ typedef struct { RBTree_t *next; } RBTreeList_t; -#define LIST_NEXT(N) (((RBTreeList_t *) (N))->next) -#define LIST_PREV(N) (((RBTreeList_t *) (N))->t.parent) +#define BF_LIST_NEXT(N) (((RBTreeList_t *) (N))->next) +#define BF_LIST_PREV(N) (((RBTreeList_t *) (N))->t.parent) #ifdef DEBUG @@ -593,7 +593,6 @@ aobf_link_free_block(Allctr_t *allctr, Block_t *block) RBTree_t *blk = (RBTree_t *) block; Uint blk_sz = BF_BLK_SZ(blk); - blk->flags = 0; blk->left = NULL; @@ -673,7 +672,7 @@ aobf_get_free_block(Allctr_t *allctr, Uint size, x = x->left; } } - + if (!blk) return NULL; @@ -729,11 +728,11 @@ bf_link_free_block(Allctr_t *allctr, Block_t *block) if (blk_sz == size) { SET_LIST_ELEM(blk); - LIST_NEXT(blk) = LIST_NEXT(x); - LIST_PREV(blk) = x; - if (LIST_NEXT(x)) - LIST_PREV(LIST_NEXT(x)) = blk; - LIST_NEXT(x) = blk; + BF_LIST_NEXT(blk) = BF_LIST_NEXT(x); + BF_LIST_PREV(blk) = x; + if (BF_LIST_NEXT(x)) + BF_LIST_PREV(BF_LIST_NEXT(x)) = blk; + BF_LIST_NEXT(x) = blk; return; /* Finnished */ } @@ -764,7 +763,7 @@ bf_link_free_block(Allctr_t *allctr, Block_t *block) } SET_TREE_NODE(blk); - LIST_NEXT(blk) = NULL; + BF_LIST_NEXT(blk) = NULL; #ifdef HARD_DEBUG check_tree(root, 0, 0); @@ -780,22 +779,22 @@ bf_unlink_free_block(Allctr_t *allctr, Block_t *block) if (IS_LIST_ELEM(x)) { /* Remove from list */ - ASSERT(LIST_PREV(x)); - LIST_NEXT(LIST_PREV(x)) = LIST_NEXT(x); - if (LIST_NEXT(x)) - LIST_PREV(LIST_NEXT(x)) = LIST_PREV(x); + ASSERT(BF_LIST_PREV(x)); + BF_LIST_NEXT(BF_LIST_PREV(x)) = BF_LIST_NEXT(x); + if (BF_LIST_NEXT(x)) + BF_LIST_PREV(BF_LIST_NEXT(x)) = BF_LIST_PREV(x); } - else if (LIST_NEXT(x)) { + else if (BF_LIST_NEXT(x)) { /* Replace tree node by next element in list... */ - ASSERT(BF_BLK_SZ(LIST_NEXT(x)) == BF_BLK_SZ(x)); + ASSERT(BF_BLK_SZ(BF_LIST_NEXT(x)) == BF_BLK_SZ(x)); ASSERT(IS_TREE_NODE(x)); - ASSERT(IS_LIST_ELEM(LIST_NEXT(x))); + ASSERT(IS_LIST_ELEM(BF_LIST_NEXT(x))); #ifdef HARD_DEBUG check_tree(root, 0, 0); #endif - replace(root, x, LIST_NEXT(x)); + replace(root, x, BF_LIST_NEXT(x)); #ifdef HARD_DEBUG check_tree(bfallctr, 0); @@ -834,7 +833,7 @@ bf_get_free_block(Allctr_t *allctr, Uint size, x = x->left; } } - + if (!blk) return NULL; @@ -853,7 +852,7 @@ bf_get_free_block(Allctr_t *allctr, Uint size, /* Use next block if it exist in order to avoid replacing the tree node */ - blk = LIST_NEXT(blk) ? LIST_NEXT(blk) : blk; + blk = BF_LIST_NEXT(blk) ? BF_LIST_NEXT(blk) : blk; bf_unlink_free_block(allctr, (Block_t *) blk); return (Block_t *) blk; @@ -938,7 +937,7 @@ info_options(Allctr_t *allctr, } if (hpp || szp) { - + if (!atoms_initialized) erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error: Atoms not initialized", __FILE__, __LINE__);; @@ -969,12 +968,12 @@ erts_bfalc_test(UWord op, UWord a1, UWord a2) case 0x202: return (UWord) ((RBTree_t *) a1)->parent; case 0x203: return (UWord) ((RBTree_t *) a1)->left; case 0x204: return (UWord) ((RBTree_t *) a1)->right; - case 0x205: return (UWord) LIST_NEXT(a1); + case 0x205: return (UWord) BF_LIST_NEXT(a1); case 0x206: return (UWord) IS_BLACK((RBTree_t *) a1); case 0x207: return (UWord) IS_TREE_NODE((RBTree_t *) a1); case 0x208: return (UWord) 1; /* IS_BF_ALGO */ case 0x20a: return (UWord) !((BFAllctr_t *) a1)->address_order; /* IS_BF */ - case 0x20b: return (UWord) LIST_PREV(a1); + case 0x20b: return (UWord) BF_LIST_PREV(a1); default: ASSERT(0); return ~((UWord) 0); } } diff --git a/erts/emulator/beam/erl_bif_atomics.c b/erts/emulator/beam/erl_bif_atomics.c index 092dbb3bd3..029831bd95 100644 --- a/erts/emulator/beam/erl_bif_atomics.c +++ b/erts/emulator/beam/erl_bif_atomics.c @@ -133,7 +133,7 @@ static ERTS_INLINE Eterm bld_atomic(Process* proc, AtomicsRef* p, if ((Uint64)val <= MAX_SMALL) return make_small((Sint) val); else { - Uint hsz = ERTS_UINT64_HEAP_SIZE(val); + Uint hsz = ERTS_UINT64_HEAP_SIZE((Uint64)val); Eterm* hp = HAlloc(proc, hsz); return erts_uint64_to_big(val, &hp); } diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c index a2610bf2e1..ae1bf6e652 100644 --- a/erts/emulator/beam/erl_bif_binary.c +++ b/erts/emulator/beam/erl_bif_binary.c @@ -2762,7 +2762,7 @@ static BIF_RETTYPE do_encode_unsigned(Process *p, Eterm uns, Eterm endianess) dsize_t num_parts = BIG_SIZE(bigp); Eterm res; byte *b; - ErtsDigit d; + ErtsDigit d = 0; if(BIG_SIGN(bigp)) { goto badarg; @@ -2778,26 +2778,22 @@ static BIF_RETTYPE do_encode_unsigned(Process *p, Eterm uns, Eterm endianess) if (endianess == am_big) { Sint i,j; j = 0; - d = BIG_DIGIT(bigp,0); for (i=n-1;i>=0;--i) { - b[i] = d & 0xFF; - if (!((++j) % sizeof(ErtsDigit))) { + if (!((j++) % sizeof(ErtsDigit))) { d = BIG_DIGIT(bigp,j / sizeof(ErtsDigit)); - } else { - d >>= 8; } + b[i] = d & 0xFF; + d >>= 8; } } else { Sint i,j; j = 0; - d = BIG_DIGIT(bigp,0); for (i=0;i<n;++i) { - b[i] = d & 0xFF; - if (!((++j) % sizeof(ErtsDigit))) { + if (!((j++) % sizeof(ErtsDigit))) { d = BIG_DIGIT(bigp,j / sizeof(ErtsDigit)); - } else { - d >>= 8; } + b[i] = d & 0xFF; + d >>= 8; } } diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 7fada0d548..16c06766fb 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -2967,7 +2967,7 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) } else if (ERTS_IS_ATOM_STR("context_reductions", BIF_ARG_1)) { BIF_RET(make_small(CONTEXT_REDS)); } else if (ERTS_IS_ATOM_STR("kernel_poll", BIF_ARG_1)) { -#ifdef ERTS_ENABLE_KERNEL_POLL +#if ERTS_ENABLE_KERNEL_POLL BIF_RET(am_true); #else BIF_RET(am_false); @@ -3139,6 +3139,8 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) DECL_AM(tag); BIF_RET(AM_tag); #endif + } else if (ERTS_IS_ATOM_STR("system_logger", BIF_ARG_1)) { + BIF_RET(erts_get_system_logger()); } BIF_ERROR(BIF_P, BADARG); @@ -4608,6 +4610,7 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) } } else if (ERTS_IS_ATOM_STR("broken_halt", BIF_ARG_1)) { + erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); broken_halt_test(BIF_ARG_2); } else if (ERTS_IS_ATOM_STR("unique_monotonic_integer_state", BIF_ARG_1)) { @@ -4671,6 +4674,16 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) BIF_RET(am_notsup); #endif } + else if (ERTS_IS_ATOM_STR("mbuf", BIF_ARG_1)) { + Uint sz = size_object(BIF_ARG_2); + ErlHeapFragment* frag = new_message_buffer(sz); + Eterm *hp = frag->mem; + Eterm copy = copy_struct(BIF_ARG_2, sz, &hp, &frag->off_heap); + frag->next = BIF_P->mbuf; + BIF_P->mbuf = frag; + BIF_P->mbuf_sz += sz; + BIF_RET(copy); + } } BIF_ERROR(BIF_P, BADARG); diff --git a/erts/emulator/beam/erl_bif_persistent.c b/erts/emulator/beam/erl_bif_persistent.c index 9dca768a18..5a78a043ce 100644 --- a/erts/emulator/beam/erl_bif_persistent.c +++ b/erts/emulator/beam/erl_bif_persistent.c @@ -332,6 +332,23 @@ BIF_RETTYPE persistent_term_get_1(BIF_ALIST_1) BIF_ERROR(BIF_P, BADARG); } +BIF_RETTYPE persistent_term_get_2(BIF_ALIST_2) +{ + Eterm key = BIF_ARG_1; + Eterm result = BIF_ARG_2; + HashTable* hash_table = (HashTable *) erts_atomic_read_nob(&the_hash_table); + Uint entry_index; + Eterm term; + + entry_index = lookup(hash_table, key); + term = hash_table->term[entry_index]; + if (is_boxed(term)) { + ASSERT(is_tuple_arity(term, 2)); + result = tuple_val(term)[2]; + } + BIF_RET(result); +} + BIF_RETTYPE persistent_term_erase_1(BIF_ALIST_1) { Eterm key = BIF_ARG_1; diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c index 7fe4e02782..ed825d3dda 100644 --- a/erts/emulator/beam/erl_bif_port.c +++ b/erts/emulator/beam/erl_bif_port.c @@ -891,10 +891,6 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) driver = &spawn_driver; } else if (*tp == am_fd) { /* An fd port */ - int n; - struct Sint_buf sbuf; - char* p; - if (arity != make_arityval(3)) { goto badarg; } @@ -904,15 +900,9 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) opts.ifd = unsigned_val(tp[1]); opts.ofd = unsigned_val(tp[2]); - /* Syntesize name from input and output descriptor. */ - name_buf = erts_alloc(ERTS_ALC_T_TMP, - 2*sizeof(struct Sint_buf) + 2); - p = Sint_to_buf(opts.ifd, &sbuf); - n = sys_strlen(p); - sys_strncpy(name_buf, p, n); - name_buf[n] = '/'; - p = Sint_to_buf(opts.ofd, &sbuf); - sys_strcpy(name_buf+n+1, p); + /* Syntesize name from input and output descriptor. */ + name_buf = erts_alloc(ERTS_ALC_T_TMP, 256); + erts_snprintf(name_buf, 256, "%i/%i", opts.ifd, opts.ofd); driver = &fd_driver; } else { diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c index 752d3ae3a8..42d7909a08 100644 --- a/erts/emulator/beam/erl_db_hash.c +++ b/erts/emulator/beam/erl_db_hash.c @@ -1323,11 +1323,7 @@ static int match_traverse(Process* p, DbTableHash* tb, unlock_hash_function(lck); break; } - if (iterations_left <= 0 || MBUF(p)) { - /* - * We have either reached our limit, or just created some heap fragments. - * Since many heap fragments will make the GC slower, trap and GC now. - */ + if (iterations_left <= 0) { unlock_hash_function(lck); ret_value = ctx->on_trap(ctx, slot_ix, got, &mpi.mp, ret); goto done; @@ -1433,11 +1429,7 @@ static int match_traverse_continue(Process* p, DbTableHash* tb, unlock_hash_function(lck); break; } - if (iterations_left <= 0 || MBUF(p)) { - /* - * We have either reached our limit, or just created some heap fragments. - * Since many heap fragments will make the GC slower, trap and GC now. - */ + if (iterations_left <= 0) { unlock_hash_function(lck); ret_value = ctx->on_trap(ctx, slot_ix, got, mpp, ret); goto done; diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c index 45e4be2426..8c5fc0acb2 100644 --- a/erts/emulator/beam/erl_db_tree.c +++ b/erts/emulator/beam/erl_db_tree.c @@ -3310,13 +3310,6 @@ static int doit_select(DbTableTree *tb, TreeDbTerm *this, void *ptr, if (is_value(ret)) { sc->accum = CONS(hp, ret, sc->accum); } - if (MBUF(sc->p)) { - /* - * Force a trap and GC if a heap fragment was created. Many heap fragments - * make the GC slow. - */ - sc->max = 0; - } if (--(sc->max) <= 0) { return 0; } @@ -3371,13 +3364,6 @@ static int doit_select_chunk(DbTableTree *tb, TreeDbTerm *this, void *ptr, ++(sc->got); sc->accum = CONS(hp, ret, sc->accum); } - if (MBUF(sc->p)) { - /* - * Force a trap and GC if a heap fragment was created. Many heap fragments - * make the GC slow. - */ - sc->max = 0; - } if (--(sc->max) <= 0 || sc->got == sc->chunk_size) { return 0; } diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index f1d47326b4..e2c029c244 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -2470,7 +2470,7 @@ restart: case matchProcessDump: { erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(0); ASSERT(c_p == self); - print_process_info(ERTS_PRINT_DSBUF, (void *) dsbufp, c_p); + print_process_info(ERTS_PRINT_DSBUF, (void *) dsbufp, c_p, ERTS_PROC_LOCK_MAIN); *esp++ = new_binary(build_proc, (byte *)dsbufp->str, dsbufp->str_len); erts_destroy_tmp_dsbuf(dsbufp); diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index d5dfb096b1..3a50b294d1 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -2438,27 +2438,9 @@ erts_copy_one_frag(Eterm** hpp, ErlOffHeap* off_heap, cpy_words: ASSERT(sz >= cpy_sz); sz -= cpy_sz; - while (cpy_sz >= 8) { - cpy_sz -= 8; - *hp++ = *fhp++; - *hp++ = *fhp++; - *hp++ = *fhp++; - *hp++ = *fhp++; - *hp++ = *fhp++; - *hp++ = *fhp++; - *hp++ = *fhp++; - *hp++ = *fhp++; - } - switch (cpy_sz) { - case 7: *hp++ = *fhp++; - case 6: *hp++ = *fhp++; - case 5: *hp++ = *fhp++; - case 4: *hp++ = *fhp++; - case 3: *hp++ = *fhp++; - case 2: *hp++ = *fhp++; - case 1: *hp++ = *fhp++; - default: break; - } + sys_memcpy(hp, fhp, cpy_sz * sizeof(Eterm)); + hp += cpy_sz; + fhp += cpy_sz; if (oh) { /* Add to offheap list */ oh->next = off_heap->first; @@ -2477,7 +2459,7 @@ erts_copy_one_frag(Eterm** hpp, ErlOffHeap* off_heap, *hpp = hp; for (i = 0; i < nrefs; i++) { - if (is_not_immed(refs[i]) && !erts_is_literal(refs[i],boxed_val(refs[i]))) + if (is_not_immed(refs[i]) && !erts_is_literal(refs[i],ptr_val(refs[i]))) refs[i] = offset_ptr(refs[i], offs); } bp->off_heap.first = NULL; diff --git a/erts/emulator/beam/erl_hl_timer.c b/erts/emulator/beam/erl_hl_timer.c index ef7a55fa38..75ad6de2c9 100644 --- a/erts/emulator/beam/erl_hl_timer.c +++ b/erts/emulator/beam/erl_hl_timer.c @@ -29,8 +29,6 @@ # include "config.h" #endif -/* #define ERTS_MAGIC_REF_BIF_TIMERS */ - #include "sys.h" #include "global.h" #include "bif.h" @@ -39,9 +37,6 @@ #include "erl_time.h" #include "erl_hl_timer.h" #include "erl_proc_sig_queue.h" -#ifdef ERTS_MAGIC_REF_BIF_TIMERS -#include "erl_binary.h" -#endif #define ERTS_TMR_CHECK_CANCEL_ON_CREATE 0 @@ -195,14 +190,9 @@ struct ErtsBifTimer_ { } type; struct { erts_atomic32_t state; -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - ErtsMagicBinary *mbin; - ErtsHLTimerList proc_list; -#else Uint32 refn[ERTS_REF_NUMBERS]; ErtsBifTimerTree proc_tree; ErtsBifTimerTree tree; -#endif Eterm message; ErlHeapFragment *bp; } btm; @@ -220,11 +210,7 @@ typedef ErtsTimer *(*ErtsCreateTimerFunc)(ErtsSchedulerData *esdp, int short_time, ErtsTmrType type, void *rcvrp, Eterm rcvr, Eterm msg, -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - ErtsMagicBinary *mbin, -#else Uint32 *refn, -#endif void (*callback)(void *), void *arg); #ifdef SMALL_MEMORY @@ -303,16 +289,12 @@ typedef struct { struct ErtsHLTimerService_ { ErtsHLTCncldTmrQ canceled_queue; ErtsHLTimer *time_tree; -#ifndef ERTS_MAGIC_REF_BIF_TIMERS ErtsBifTimer *btm_tree; -#endif ErtsHLTimer *next_timeout; ErtsYieldingTimeoutState yield; ErtsTWheelTimer service_timer; }; -#ifndef ERTS_MAGIC_REF_BIF_TIMERS - static ERTS_INLINE int refn_is_lt(Uint32 *x, Uint32 *y) { @@ -334,8 +316,6 @@ refn_is_eq(Uint32 *x, Uint32 *y) return (x[0] == y[0]) & (x[1] == y[1]) & (x[2] == y[2]); } -#endif - #define ERTS_RBT_PREFIX time #define ERTS_RBT_T ErtsHLTimer #define ERTS_RBT_KEY_T ErtsMonotonicTime @@ -525,13 +505,7 @@ same_time_list_lookup(ErtsHLTimer *root, ErtsHLTimer *x) #endif /* ERTS_HLT_HARD_DEBUG */ -#ifdef ERTS_MAGIC_REF_BIF_TIMERS -#define ERTS_BTM_HLT2REFN(T) ((T)->btm.mbin->refn) -#else #define ERTS_BTM_HLT2REFN(T) ((T)->btm.refn) -#endif - -#ifndef ERTS_MAGIC_REF_BIF_TIMERS #define ERTS_RBT_PREFIX btm #define ERTS_RBT_T ErtsBifTimer @@ -576,87 +550,12 @@ same_time_list_lookup(ErtsHLTimer *root, ErtsHLTimer *x) #define ERTS_RBT_IS_EQ(KX, KY) refn_is_eq((KX), (KY)) #define ERTS_RBT_WANT_DELETE #define ERTS_RBT_WANT_INSERT -#ifndef ERTS_MAGIC_REF_BIF_TIMERS #define ERTS_RBT_WANT_LOOKUP -#endif #define ERTS_RBT_WANT_FOREACH #define ERTS_RBT_UNDEF #include "erl_rbtree.h" -#endif /* !ERTS_MAGIC_REF_BIF_TIMERS */ - -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - -static ERTS_INLINE void -proc_btm_list_insert(ErtsBifTimer **list, ErtsBifTimer *x) -{ - ErtsBifTimer *y = *list; - if (!y) { - x->btm.proc_list.next = x; - x->btm.proc_list.prev = x; - *list = x; - } - else { - ERTS_HLT_ASSERT(y->btm.proc_list.prev->btm.proc_list.next == y); - x->btm.proc_list.next = y; - x->btm.proc_list.prev = y->btm.proc_list.prev; - y->btm.proc_list.prev->btm.proc_list.next = x; - y->btm.proc_list.prev = x; - } -} - -static ERTS_INLINE void -proc_btm_list_delete(ErtsBifTimer **list, ErtsBifTimer *x) -{ - ErtsBifTimer *y = *list; - if (y == x && x->btm.proc_list.next == x) { - ERTS_HLT_ASSERT(x->btm.proc_list.prev == x); - *list = NULL; - } - else { - if (y == x) - *list = x->btm.proc_list.next; - ERTS_HLT_ASSERT(x->btm.proc_list.prev->btm.proc_list.next == x); - ERTS_HLT_ASSERT(x->btm.proc_list.next->btm.proc_list.prev == x); - x->btm.proc_list.prev->btm.proc_list.next = x->btm.proc_list.next; - x->btm.proc_list.next->btm.proc_list.prev = x->btm.proc_list.prev; - } - x->btm.proc_list.next = NULL; -} - -static ERTS_INLINE int -proc_btm_list_foreach_destroy_yielding(ErtsBifTimer **list, - void (*destroy)(ErtsBifTimer *, void *), - void *arg, - int limit) -{ - int i; - ErtsBifTimer *first, *last; - - first = *list; - if (!first) - return 0; - - last = first->btm.proc_list.prev; - for (i = 0; i < limit; i++) { - ErtsBifTimer *x = last; - last = last->btm.proc_list.prev; - (*destroy)(x, arg); - x->btm.proc_list.next = NULL; - if (x == first) { - *list = NULL; - return 0; - } - } - - last->btm.proc_list.next = first; - first->btm.proc_list.prev = last; - return 1; -} - -#else /* !ERTS_MAGIC_REF_BIF_TIMERS */ - #define ERTS_RBT_PREFIX proc_btm #define ERTS_RBT_T ErtsBifTimer #define ERTS_RBT_KEY_T Uint32 * @@ -700,16 +599,12 @@ proc_btm_list_foreach_destroy_yielding(ErtsBifTimer **list, #define ERTS_RBT_IS_EQ(KX, KY) refn_is_eq((KX), (KY)) #define ERTS_RBT_WANT_DELETE #define ERTS_RBT_WANT_INSERT -#ifndef ERTS_MAGIC_REF_BIF_TIMERS #define ERTS_RBT_WANT_LOOKUP -#endif #define ERTS_RBT_WANT_FOREACH_DESTROY_YIELDING #define ERTS_RBT_UNDEF #include "erl_rbtree.h" -#endif /* !ERTS_MAGIC_REF_BIF_TIMERS */ - static void init_canceled_queue(ErtsHLTCncldTmrQ *cq); void @@ -728,9 +623,7 @@ erts_create_timer_service(void) srv = erts_alloc_permanent_cache_aligned(ERTS_ALC_T_TIMER_SERVICE, sizeof(ErtsHLTimerService)); srv->time_tree = NULL; -#ifndef ERTS_MAGIC_REF_BIF_TIMERS srv->btm_tree = NULL; -#endif srv->next_timeout = NULL; srv->yield = init_yield; erts_twheel_init_timer(&srv->service_timer); @@ -805,40 +698,10 @@ port_timeout_common(Port *port, void *tmr) return 0; } -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - -static erts_atomic_t * -mbin_to_btmref__(ErtsMagicBinary *mbin) -{ - return erts_binary_to_magic_indirection((Binary *) mbin); -} - -static ERTS_INLINE void -magic_binary_init(ErtsMagicBinary *mbin, ErtsBifTimer *tmr) -{ - erts_atomic_t *aptr = mbin_to_btmref__(mbin); - erts_atomic_init_nob(aptr, (erts_aint_t) tmr); -} - -static ERTS_INLINE ErtsBifTimer * -magic_binary_to_btm(ErtsMagicBinary *mbin) -{ - erts_atomic_t *aptr = mbin_to_btmref__(mbin); - ErtsBifTimer *tmr = (ErtsBifTimer *) erts_atomic_read_nob(aptr); - ERTS_HLT_ASSERT(!tmr || tmr->btm.mbin == mbin); - return tmr; -} - -#endif /* ERTS_MAGIC_REF_BIF_TIMERS */ - static ERTS_INLINE erts_aint_t init_btm_specifics(ErtsSchedulerData *esdp, ErtsBifTimer *tmr, Eterm msg, -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - ErtsMagicBinary *mbin -#else Uint32 *refn -#endif ) { Uint hsz = is_immed(msg) ? ((Uint) 0) : size_object(msg); @@ -853,13 +716,6 @@ init_btm_specifics(ErtsSchedulerData *esdp, tmr->btm.message = copy_struct(msg, hsz, &hp, &bp->off_heap); tmr->btm.bp = bp; } -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - refc = 1; - tmr->btm.mbin = mbin; - erts_refc_inc(&mbin->refc, 1); - magic_binary_init(mbin, tmr); - tmr->btm.proc_list.next = NULL; -#else refc = 0; tmr->btm.refn[0] = refn[0]; tmr->btm.refn[1] = refn[1]; @@ -868,7 +724,6 @@ init_btm_specifics(ErtsSchedulerData *esdp, tmr->btm.proc_tree.parent = ERTS_HLT_PFIELD_NOT_IN_TABLE; btm_rbt_insert(&esdp->timer_service->btm_tree, tmr); -#endif erts_atomic32_init_nob(&tmr->btm.state, ERTS_TMR_STATE_ACTIVE); return refc; /* refc from magic binary... */ @@ -886,11 +741,6 @@ timer_destroy(ErtsTimer *tmr, int twt, int btm) erts_free(ERTS_ALC_T_HL_PTIMER, tmr); } else { -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - Binary *bp = (Binary *) tmr->btm.btm.mbin; - if (erts_refc_dectest(&bp->refc, 0) == 0) - erts_bin_free(bp); -#endif if (tmr->head.roflgs & ERTS_TMR_ROFLG_PRE_ALC) bif_timer_pre_free(&tmr->btm); else @@ -940,9 +790,6 @@ schedule_tw_timer_destroy(ErtsTWTimer *tmr) else { /* Message buffer already dropped... */ size = sizeof(ErtsBifTimer); -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - size += sizeof(ErtsMagicIndirectionWord); -#endif } erts_schedule_thr_prgr_later_cleanup_op( @@ -1006,11 +853,7 @@ create_tw_timer(ErtsSchedulerData *esdp, int short_time, ErtsTmrType type, void *rcvrp, Eterm rcvr, Eterm msg, -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - ErtsMagicBinary *mbin, -#else Uint32 *refn, -#endif void (*callback)(void *), void *arg) { ErtsTWTimer *tmr; @@ -1087,11 +930,7 @@ create_tw_timer(ErtsSchedulerData *esdp, refc += init_btm_specifics(esdp, (ErtsBifTimer *) tmr, msg, -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - mbin -#else refn -#endif ); break; @@ -1152,9 +991,6 @@ schedule_hl_timer_destroy(ErtsHLTimer *tmr, Uint32 roflgs) else { /* Message buffer already dropped... */ size = sizeof(ErtsBifTimer); -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - size += sizeof(ErtsMagicIndirectionWord); -#endif } erts_schedule_thr_prgr_later_cleanup_op( @@ -1192,34 +1028,6 @@ check_canceled_queue(ErtsSchedulerData *esdp, ErtsHLTimerService *srv) #endif } -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - -static int -bif_timer_ref_destructor(Binary *unused) -{ - return 1; -} - -static ERTS_INLINE void -btm_clear_magic_binary(ErtsBifTimer *tmr) -{ - erts_atomic_t *aptr = mbin_to_btmref__(tmr->btm.mbin); - Uint32 roflgs = tmr->type.head.roflgs; -#ifdef ERTS_HLT_DEBUG - erts_aint_t tval = erts_atomic_xchg_nob(aptr, - (erts_aint_t) NULL); - ERTS_HLT_ASSERT(tval == (erts_aint_t) tmr); -#else - erts_atomic_set_nob(aptr, (erts_aint_t) NULL); -#endif - if (roflgs & ERTS_TMR_ROFLG_HLT) - hl_timer_dec_refc(&tmr->type.hlt, roflgs); - else - tw_timer_dec_refc(&tmr->type.twt); -} - -#endif /* ERTS_MAGIC_REF_BIF_TIMERS */ - static ERTS_INLINE void bif_timer_timeout(ErtsHLTimerService *srv, ErtsBifTimer *tmr, @@ -1240,10 +1048,6 @@ bif_timer_timeout(ErtsHLTimerService *srv, if (state == ERTS_TMR_STATE_ACTIVE) { Process *proc; -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - btm_clear_magic_binary(tmr); -#endif - if (roflgs & ERTS_TMR_ROFLG_REG_NAME) { Eterm term; term = tmr->type.head.receiver.name; @@ -1266,18 +1070,11 @@ bif_timer_timeout(ErtsHLTimerService *srv, erts_proc_lock(proc, ERTS_PROC_LOCK_BTM); /* If the process is exiting do not disturb the cleanup... */ if (!ERTS_PROC_IS_EXITING(proc)) { -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - if (tmr->btm.proc_list.next) { - proc_btm_list_delete(&proc->bif_timers, tmr); - dec_refc = 1; - } -#else if (tmr->btm.proc_tree.parent != ERTS_HLT_PFIELD_NOT_IN_TABLE) { proc_btm_rbt_delete(&proc->bif_timers, tmr); tmr->btm.proc_tree.parent = ERTS_HLT_PFIELD_NOT_IN_TABLE; dec_refc = 1; } -#endif } erts_proc_unlock(proc, ERTS_PROC_LOCK_BTM); if (dec_refc) @@ -1287,25 +1084,18 @@ bif_timer_timeout(ErtsHLTimerService *srv, free_message_buffer(tmr->btm.bp); } -#ifndef ERTS_MAGIC_REF_BIF_TIMERS if (tmr->btm.tree.parent != ERTS_HLT_PFIELD_NOT_IN_TABLE) { btm_rbt_delete(&srv->btm_tree, tmr); tmr->btm.tree.parent = ERTS_HLT_PFIELD_NOT_IN_TABLE; } -#endif - } static void tw_bif_timer_timeout(void *vbtmp) { -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - ErtsHLTimerService *srv = NULL; -#else ErtsSchedulerData *esdp = erts_get_scheduler_data(); ErtsHLTimerService *srv = esdp->timer_service; -#endif ErtsBifTimer *btmp = (ErtsBifTimer *) vbtmp; bif_timer_timeout(srv, btmp, btmp->type.head.roflgs); tw_timer_dec_refc(&btmp->type.twt); @@ -1317,11 +1107,7 @@ create_hl_timer(ErtsSchedulerData *esdp, int short_time, ErtsTmrType type, void *rcvrp, Eterm rcvr, Eterm msg, -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - ErtsMagicBinary *mbin, -#else Uint32 *refn, -#endif void (*callback)(void *), void *arg) { ErtsHLTimerService *srv = esdp->timer_service; @@ -1407,11 +1193,7 @@ create_hl_timer(ErtsSchedulerData *esdp, refc += init_btm_specifics(esdp, (ErtsBifTimer *) tmr, msg, -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - mbin -#else refn -#endif ); } @@ -1628,7 +1410,6 @@ cleanup_sched_local_canceled_timer(ErtsSchedulerData *esdp, ERTS_HLT_ASSERT((tmr->head.roflgs & ERTS_TMR_ROFLG_SID_MASK) == (Uint32) esdp->no); -#ifndef ERTS_MAGIC_REF_BIF_TIMERS if (roflgs & ERTS_TMR_ROFLG_BIF_TMR) { ErtsBifTimer *btm = (ErtsBifTimer *) tmr; if (btm->btm.tree.parent != ERTS_HLT_PFIELD_NOT_IN_TABLE) { @@ -1636,7 +1417,6 @@ cleanup_sched_local_canceled_timer(ErtsSchedulerData *esdp, btm->btm.tree.parent = ERTS_HLT_PFIELD_NOT_IN_TABLE; } } -#endif if (roflgs & ERTS_TMR_ROFLG_HLT) { hlt_delete_timer(esdp, &tmr->hlt); @@ -1909,9 +1689,6 @@ setup_bif_timer(Process *c_p, int twheel, ErtsMonotonicTime timeout_pos, Eterm ref, tmo_msg, *hp; ErtsBifTimer *tmr; ErtsSchedulerData *esdp; -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - Binary *mbin; -#endif Eterm tmp_hp[4]; ErtsCreateTimerFunc create_timer; @@ -1920,18 +1697,10 @@ setup_bif_timer(Process *c_p, int twheel, ErtsMonotonicTime timeout_pos, esdp = erts_proc_sched_data(c_p); -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - mbin = erts_create_magic_indirection(bif_timer_ref_destructor); - hp = HAlloc(c_p, ERTS_MAGIC_REF_THING_SIZE); - ref = erts_mk_magic_ref(&hp, &c_p->off_heap, mbin); - ASSERT(erts_get_ref_numbers_thr_id(((ErtsMagicBinary *)mbin)->refn) - == (Uint32) esdp->no); -#else hp = HAlloc(c_p, ERTS_REF_THING_SIZE); ref = erts_sched_make_ref_in_buffer(esdp, hp); ASSERT(erts_get_ref_numbers_thr_id(internal_ordinary_ref_numbers(ref)) == (Uint32) esdp->no); -#endif tmo_msg = wrap ? TUPLE3(tmp_hp, am_timeout, ref, msg) : msg; @@ -1939,11 +1708,7 @@ setup_bif_timer(Process *c_p, int twheel, ErtsMonotonicTime timeout_pos, tmr = (ErtsBifTimer *) create_timer(esdp, timeout_pos, short_time, ERTS_TMR_BIF, NULL, rcvr, tmo_msg, -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - (ErtsMagicBinary *) mbin, -#else internal_ordinary_ref_numbers(ref), -#endif NULL, NULL); if (is_internal_pid(rcvr)) { @@ -1951,14 +1716,10 @@ setup_bif_timer(Process *c_p, int twheel, ErtsMonotonicTime timeout_pos, rcvr, ERTS_PROC_LOCK_BTM, ERTS_P2P_FLG_INC_REFC); if (!proc) { -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - btm_clear_magic_binary(tmr); -#else if (tmr->btm.tree.parent != ERTS_HLT_PFIELD_NOT_IN_TABLE) { btm_rbt_delete(&esdp->timer_service->btm_tree, tmr); tmr->btm.tree.parent = ERTS_HLT_PFIELD_NOT_IN_TABLE; } -#endif if (tmr->btm.bp) free_message_buffer(tmr->btm.bp); if (twheel) @@ -1968,11 +1729,7 @@ setup_bif_timer(Process *c_p, int twheel, ErtsMonotonicTime timeout_pos, timer_destroy((ErtsTimer *) tmr, twheel, 1); } else { -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - proc_btm_list_insert(&proc->bif_timers, tmr); -#else proc_btm_rbt_insert(&proc->bif_timers, tmr); -#endif erts_proc_unlock(proc, ERTS_PROC_LOCK_BTM); tmr->type.head.receiver.proc = proc; } @@ -2000,10 +1757,6 @@ cancel_bif_timer(ErtsBifTimer *tmr) if (state != ERTS_TMR_STATE_ACTIVE) return 0; -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - btm_clear_magic_binary(tmr); -#endif - if (tmr->btm.bp) free_message_buffer(tmr->btm.bp); @@ -2022,19 +1775,12 @@ cancel_bif_timer(ErtsBifTimer *tmr) * the btm tree by itself (it may be in * the middle of tree destruction). */ -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - if (!ERTS_PROC_IS_EXITING(proc) && tmr->btm.proc_list.next) { - proc_btm_list_delete(&proc->bif_timers, tmr); - res = 1; - } -#else if (!ERTS_PROC_IS_EXITING(proc) && tmr->btm.proc_tree.parent != ERTS_HLT_PFIELD_NOT_IN_TABLE) { proc_btm_rbt_delete(&proc->bif_timers, tmr); tmr->btm.proc_tree.parent = ERTS_HLT_PFIELD_NOT_IN_TABLE; res = 1; } -#endif erts_proc_unlock(proc, ERTS_PROC_LOCK_BTM); } @@ -2075,12 +1821,10 @@ access_btm(ErtsBifTimer *tmr, Uint32 sid, ErtsSchedulerData *esdp, int cancel) queue_canceled_timer(esdp, sid, (ErtsTimer *) tmr); } else { -#ifndef ERTS_MAGIC_REF_BIF_TIMERS if (tmr->btm.tree.parent != ERTS_HLT_PFIELD_NOT_IN_TABLE) { btm_rbt_delete(&esdp->timer_service->btm_tree, tmr); tmr->btm.tree.parent = ERTS_HLT_PFIELD_NOT_IN_TABLE; } -#endif if (is_hlt) { if (cncl_res > 0) hl_timer_dec_refc(&tmr->type.hlt, tmr->type.hlt.head.roflgs); @@ -2157,52 +1901,6 @@ send_async_info(Process *proc, ErtsProcLocks initial_locks, return am_ok; } -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - -static BIF_RETTYPE -access_bif_timer(Process *c_p, Eterm tref, int cancel, int async, int info) -{ - BIF_RETTYPE ret; - Eterm res; - Sint64 time_left; - - if (!is_internal_magic_ref(tref)) { - if (is_not_ref(tref)) { - ERTS_BIF_PREP_ERROR(ret, c_p, BADARG); - return ret; - } - time_left = -1; - } - else { - ErtsMagicBinary *mbin; - mbin = (ErtsMagicBinary *) erts_magic_ref2bin(tref); - if (mbin->destructor != bif_timer_ref_destructor) - time_left = -1; - else { - ErtsBifTimer *tmr; - Uint32 sid; - tmr = magic_binary_to_btm(mbin); - sid = erts_get_ref_numbers_thr_id(internal_magic_ref_numbers(tref)); - ASSERT(1 <= sid && sid <= erts_no_schedulers); - time_left = access_btm(tmr, sid, erts_proc_sched_data(c_p), cancel); - } - } - - if (!info) - res = am_ok; - else if (!async) - res = return_info(c_p, time_left); - else - res = send_async_info(c_p, ERTS_PROC_LOCK_MAIN, - tref, cancel, time_left); - - ERTS_BIF_PREP_RET(ret, res); - - return ret; -} - -#else /* !ERTS_MAGIC_REF_BIF_TIMERS */ - static ERTS_INLINE Eterm send_sync_info(Process *proc, ErtsProcLocks initial_locks, Uint32 *refn, int cancel, Sint64 time_left) @@ -2505,8 +2203,6 @@ no_timer: return no_timer_result(c_p, tref, cancel, async, info); } -#endif /* !ERTS_MAGIC_REF_BIF_TIMERS */ - static ERTS_INLINE int bool_arg(Eterm val, int *argp) { @@ -2584,18 +2280,11 @@ exit_cancel_bif_timer(ErtsBifTimer *tmr, void *vesdp) is_hlt = !!(roflgs & ERTS_TMR_ROFLG_HLT); ERTS_HLT_ASSERT(sid == erts_get_ref_numbers_thr_id(ERTS_BTM_HLT2REFN(tmr))); -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - ERTS_HLT_ASSERT(tmr->btm.proc_list.next); -#else ERTS_HLT_ASSERT(tmr->btm.proc_tree.parent != ERTS_HLT_PFIELD_NOT_IN_TABLE); tmr->btm.proc_tree.parent = ERTS_HLT_PFIELD_NOT_IN_TABLE; -#endif if (state == ERTS_TMR_STATE_ACTIVE) { -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - btm_clear_magic_binary(tmr); -#endif if (tmr->btm.bp) free_message_buffer(tmr->btm.bp); @@ -2604,12 +2293,10 @@ exit_cancel_bif_timer(ErtsBifTimer *tmr, void *vesdp) return; } -#ifndef ERTS_MAGIC_REF_BIF_TIMERS if (tmr->btm.tree.parent != ERTS_HLT_PFIELD_NOT_IN_TABLE) { btm_rbt_delete(&esdp->timer_service->btm_tree, tmr); tmr->btm.tree.parent = ERTS_HLT_PFIELD_NOT_IN_TABLE; } -#endif if (is_hlt) hlt_delete_timer(esdp, &tmr->type.hlt); else @@ -2627,28 +2314,17 @@ exit_cancel_bif_timer(ErtsBifTimer *tmr, void *vesdp) # define ERTS_BTM_MAX_DESTROY_LIMIT 50 #endif -#ifndef ERTS_MAGIC_REF_BIF_TIMERS typedef struct { ErtsBifTimers *bif_timers; union { proc_btm_rbt_yield_state_t proc_btm_yield_state; } u; } ErtsBifTimerYieldState; -#endif int erts_cancel_bif_timers(Process *p, ErtsBifTimers **btm, void **vyspp) { ErtsSchedulerData *esdp = erts_proc_sched_data(p); -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - - return proc_btm_list_foreach_destroy_yielding(btm, - exit_cancel_bif_timer, - (void *) esdp, - ERTS_BTM_MAX_DESTROY_LIMIT); - -#else /* !ERTS_MAGIC_REF_BIF_TIMERS */ - ErtsBifTimerYieldState ys = {*btm, {ERTS_RBT_YIELD_STAT_INITER}}; ErtsBifTimerYieldState *ysp; int res; @@ -2682,7 +2358,6 @@ int erts_cancel_bif_timers(Process *p, ErtsBifTimers **btm, void **vyspp) return res; -#endif /* !ERTS_MAGIC_REF_BIF_TIMERS */ } static ERTS_INLINE int @@ -3116,11 +2791,6 @@ btm_print(ErtsBifTimer *tmr, void *vbtmp, ErtsMonotonicTime tpos, int is_hlt) ErtsMonotonicTime left; Eterm receiver; -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - if (!(tmr->type.head.roflgs & ERTS_TMR_ROFLG_BIF_TMR)) - return; -#endif - if (is_hlt) { ERTS_HLT_ASSERT(tmr->type.head.roflgs & ERTS_TMR_ROFLG_HLT); if (tmr->type.hlt.timeout <= btmp->now) @@ -3149,22 +2819,6 @@ btm_print(ErtsBifTimer *tmr, void *vbtmp, ErtsMonotonicTime tpos, int is_hlt) (Sint64) left); } -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - -static void -hlt_btm_print(ErtsHLTimer *tmr, void *vbtmp) -{ - btm_print((ErtsBifTimer *) tmr, vbtmp, 0, 1); -} - -static void -twt_btm_print(void *vbtmp, ErtsMonotonicTime tpos, void *vtwtp) -{ - btm_print((ErtsBifTimer *) vtwtp, vbtmp, tpos, 0); -} - -#else - static void btm_tree_print(ErtsBifTimer *tmr, void *vbtmp) { @@ -3177,8 +2831,6 @@ btm_tree_print(ErtsBifTimer *tmr, void *vbtmp) btm_print(tmr, vbtmp, tpos, is_hlt); } -#endif - void erts_print_bif_timer_info(fmtfn_t to, void *to_arg) { @@ -3196,15 +2848,7 @@ erts_print_bif_timer_info(fmtfn_t to, void *to_arg) for (six = 0; six < erts_no_schedulers; six++) { ErtsHLTimerService *srv = erts_aligned_scheduler_data[six].esd.timer_service; -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - ErtsTimerWheel *twheel = - erts_aligned_scheduler_data[six].esd.timer_wheel; - erts_twheel_debug_foreach(twheel, tw_bif_timer_timeout, - twt_btm_print, (void *) &btmp); - time_rbt_foreach(srv->time_tree, hlt_btm_print, (void *) &btmp); -#else btm_rbt_foreach(srv->btm_tree, btm_tree_print, (void *) &btmp); -#endif } } @@ -3219,10 +2863,6 @@ typedef struct { static void debug_btm_foreach(ErtsBifTimer *tmr, void *vbtmfd) { -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - if (!(tmr->type.head.roflgs & ERTS_TMR_ROFLG_BIF_TMR)) - return; -#endif if (erts_atomic32_read_nob(&tmr->btm.state) == ERTS_TMR_STATE_ACTIVE) { ErtsBTMForeachDebug *btmfd = (ErtsBTMForeachDebug *) vbtmfd; Eterm id = ((tmr->type.head.roflgs & ERTS_TMR_ROFLG_REG_NAME) @@ -3232,22 +2872,6 @@ debug_btm_foreach(ErtsBifTimer *tmr, void *vbtmfd) } } -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - -static void -hlt_debug_btm_foreach(ErtsHLTimer *tmr, void *vbtmfd) -{ - debug_btm_foreach((ErtsBifTimer *) tmr, vbtmfd); -} - -static void -twt_debug_btm_foreach(void *vbtmfd, ErtsMonotonicTime tpos, void *vtwtp) -{ - debug_btm_foreach((ErtsBifTimer *) vtwtp, vbtmfd); -} - -#endif - void erts_debug_bif_timer_foreach(void (*func)(Eterm, Eterm, @@ -3267,20 +2891,9 @@ erts_debug_bif_timer_foreach(void (*func)(Eterm, for (six = 0; six < erts_no_schedulers; six++) { ErtsHLTimerService *srv = erts_aligned_scheduler_data[six].esd.timer_service; -#ifdef ERTS_MAGIC_REF_BIF_TIMERS - ErtsTimerWheel *twheel = - erts_aligned_scheduler_data[six].esd.timer_wheel; - erts_twheel_debug_foreach(twheel, tw_bif_timer_timeout, - twt_debug_btm_foreach, - (void *) &btmfd); - time_rbt_foreach(srv->time_tree, - hlt_debug_btm_foreach, - (void *) &btmfd); -#else btm_rbt_foreach(srv->btm_tree, debug_btm_foreach, (void *) &btmfd); -#endif } } @@ -3403,9 +3016,7 @@ st_hdbg_func(ErtsHLTimer *tmr, void *vhdbg) } ERTS_HLT_ASSERT(tmr->time.tree.u.l.next->time.tree.u.l.prev == tmr); ERTS_HLT_ASSERT(tmr->time.tree.u.l.prev->time.tree.u.l.next == tmr); -#ifndef ERTS_MAGIC_REF_BIF_TIMERS ERTS_HLT_ASSERT(btm_rbt_lookup(hdbg->srv->btm_tree, ERTS_BTM_HLT2REFN(tmr)) == tmr); -#endif } static void @@ -3434,10 +3045,8 @@ tt_hdbg_func(ErtsHLTimer *tmr, void *vhdbg) & ~ERTS_HLT_PFLGS_MASK); ERTS_HLT_ASSERT(tmr == prnt); } -#ifndef ERTS_MAGIC_REF_BIF_TIMERS if (tmr->head.roflgs & ERTS_TMR_ROFLG_BIF_TMR) ERTS_HLT_ASSERT(btm_rbt_lookup(hdbg->srv->btm_tree, ERTS_BTM_HLT2REFN(tmr)) == tmr); -#endif if (tmr->time.tree.same_time) { ErtsHdbgHLT st_hdbg; st_hdbg.srv = hdbg->srv; @@ -3503,7 +3112,6 @@ hdbg_chk_srv(ErtsHLTimerService *srv) time_rbt_foreach(srv->time_tree, tt_hdbg_func, (void *) &hdbg); ERTS_HLT_ASSERT(hdbg.found_root); } -#ifndef ERTS_MAGIC_REF_BIF_TIMERS if (srv->btm_tree) { ErtsHdbgHLT hdbg; hdbg.srv = srv; @@ -3512,7 +3120,6 @@ hdbg_chk_srv(ErtsHLTimerService *srv) btm_rbt_foreach(srv->btm_tree, bt_hdbg_func, (void *) &hdbg); ERTS_HLT_ASSERT(hdbg.found_root); } -#endif } #endif /* ERTS_HLT_HARD_DEBUG */ diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 99e788c718..163724ed3c 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -78,7 +78,7 @@ const char etp_erts_version[] = ERLANG_VERSION; const char etp_otp_release[] = ERLANG_OTP_RELEASE; const char etp_compile_date[] = ERLANG_COMPILE_DATE; const char etp_arch[] = ERLANG_ARCHITECTURE; -#ifdef ERTS_ENABLE_KERNEL_POLL +#if ERTS_ENABLE_KERNEL_POLL const int erts_use_kernel_poll = 1; const int etp_kernel_poll_support = 1; #else @@ -376,6 +376,27 @@ erl_init(int ncpu, } static Eterm +erl_spawn_system_process(Process* parent, Eterm mod, Eterm func, Eterm args, + ErlSpawnOpts *so) +{ + Eterm res; + int arity; + + ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(parent)); + arity = erts_list_length(args); + + if (erts_find_function(mod, func, arity, erts_active_code_ix()) == NULL) { + erts_exit(ERTS_ERROR_EXIT, "No function %T:%T/%i\n", mod, func, arity); + } + + so->flags |= SPO_SYSTEM_PROC; + + res = erl_create_process(parent, mod, func, args, so); + + return res; +} + +static Eterm erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char** argv) { int i; @@ -386,12 +407,6 @@ erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char** Process parent; ErlSpawnOpts so; Eterm env; - - start_mod = erts_atom_put((byte *) modname, sys_strlen(modname), ERTS_ATOM_ENC_LATIN1, 1); - if (erts_find_function(start_mod, am_start, 2, - erts_active_code_ix()) == NULL) { - erts_exit(ERTS_ERROR_EXIT, "No function %s:start/2\n", modname); - } /* * We need a dummy parent process to be able to call erl_create_process(). @@ -399,6 +414,7 @@ erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char** erts_init_empty_process(&parent); erts_proc_lock(&parent, ERTS_PROC_LOCK_MAIN); + hp = HAlloc(&parent, argc*2 + 4); args = NIL; for (i = argc-1; i >= 0; i--) { @@ -411,44 +427,73 @@ erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char** hp += 2; args = CONS(hp, env, args); - so.flags = erts_default_spo_flags|SPO_SYSTEM_PROC; - res = erl_create_process(&parent, start_mod, am_start, args, &so); + start_mod = erts_atom_put((byte *) modname, sys_strlen(modname), + ERTS_ATOM_ENC_LATIN1, 1); + + so.flags = erts_default_spo_flags; + res = erl_spawn_system_process(&parent, start_mod, am_start, args, &so); + ASSERT(is_internal_pid(res)); + erts_proc_unlock(&parent, ERTS_PROC_LOCK_MAIN); erts_cleanup_empty_process(&parent); + return res; } static Eterm erl_system_process_otp(Eterm parent_pid, char* modname, int off_heap_msgq, int prio) -{ - Eterm start_mod; - Process* parent; +{ + Process *parent; ErlSpawnOpts so; - Eterm res; - - start_mod = erts_atom_put((byte *) modname, sys_strlen(modname), ERTS_ATOM_ENC_LATIN1, 1); - if (erts_find_function(start_mod, am_start, 0, - erts_active_code_ix()) == NULL) { - erts_exit(ERTS_ERROR_EXIT, "No function %s:start/0\n", modname); - } + Eterm mod, res; parent = erts_pid2proc(NULL, 0, parent_pid, ERTS_PROC_LOCK_MAIN); + mod = erts_atom_put((byte *) modname, sys_strlen(modname), + ERTS_ATOM_ENC_LATIN1, 1); + + so.flags = erts_default_spo_flags|SPO_USE_ARGS; - so.flags = erts_default_spo_flags|SPO_SYSTEM_PROC|SPO_USE_ARGS; - if (off_heap_msgq) + if (off_heap_msgq) { so.flags |= SPO_OFF_HEAP_MSGQ; - so.min_heap_size = H_MIN_SIZE; - so.min_vheap_size = BIN_VH_MIN_SIZE; - so.max_heap_size = H_MAX_SIZE; - so.max_heap_flags = H_MAX_FLAGS; - so.priority = prio; - so.max_gen_gcs = (Uint16) erts_atomic32_read_nob(&erts_max_gen_gcs); - so.scheduler = 0; - res = erl_create_process(parent, start_mod, am_start, NIL, &so); + } + + so.min_heap_size = H_MIN_SIZE; + so.min_vheap_size = BIN_VH_MIN_SIZE; + so.max_heap_size = H_MAX_SIZE; + so.max_heap_flags = H_MAX_FLAGS; + so.priority = prio; + so.max_gen_gcs = (Uint16) erts_atomic32_read_nob(&erts_max_gen_gcs); + so.scheduler = 0; + + res = erl_spawn_system_process(parent, mod, am_start, NIL, &so); + ASSERT(is_internal_pid(res)); + erts_proc_unlock(parent, ERTS_PROC_LOCK_MAIN); + return res; } +Eterm erts_internal_spawn_system_process_3(BIF_ALIST_3) { + Eterm mod, func, args, res; + ErlSpawnOpts so; + + mod = BIF_ARG_1; + func = BIF_ARG_2; + args = BIF_ARG_3; + + ASSERT(is_atom(mod)); + ASSERT(is_atom(func)); + ASSERT(erts_list_length(args) >= 0); + + so.flags = erts_default_spo_flags; + res = erl_spawn_system_process(BIF_P, mod, func, args, &so); + + if (is_non_value(res)) { + BIF_ERROR(BIF_P, so.error_code); + } + + BIF_RET(res); +} Eterm erts_preloaded(Process* p) @@ -684,6 +729,9 @@ void erts_usage(void) erts_fprintf(stderr, "-zebwt val set ets busy wait threshold, valid values are:\n"); erts_fprintf(stderr, " none|very_short|short|medium|long|very_long|extremely_long\n"); #endif + erts_fprintf(stderr, "-ztma bool enable/disable tuple module apply support in emulator\n"); + erts_fprintf(stderr, " (transitional flag for parameterized modules; recompile\n"); + erts_fprintf(stderr, " with +tuple_calls for compatibility with future versions)\n"); erts_fprintf(stderr, "\n"); erts_fprintf(stderr, "Note that if the emulator is started with erlexec (typically\n"); erts_fprintf(stderr, "from the erl script), these flags should be specified with +.\n"); @@ -2167,6 +2215,17 @@ erl_start(int argc, char **argv) erts_usage(); } } + else if (has_prefix("tma", sub_param)) { + arg = get_arg(sub_param+3, argv[i+1], &i); + if (sys_strcmp(arg,"true") == 0) { + tuple_module_apply = 1; + } else if (sys_strcmp(arg,"false") == 0) { + tuple_module_apply = 0; + } else { + erts_fprintf(stderr, "bad tuple module apply %s\n", arg); + erts_usage(); + } + } else { erts_fprintf(stderr, "bad -z option %s\n", argv[i]); erts_usage(); diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c index cba17d3e6a..8f96dc3d23 100644 --- a/erts/emulator/beam/erl_map.c +++ b/erts/emulator/beam/erl_map.c @@ -475,7 +475,7 @@ Eterm erts_hashmap_from_array(ErtsHeapFactory* factory, Eterm *leafs, Uint n, Eterm erts_map_from_ks_and_vs(ErtsHeapFactory *factory, Eterm *ks0, Eterm *vs0, Uint n) { - if (n < MAP_SMALL_MAP_LIMIT) { + if (n <= MAP_SMALL_MAP_LIMIT) { Eterm *ks, *vs, *hp; flatmap_t *mp; Eterm keys; diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index ee6e6085b6..ebef485b04 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -2354,6 +2354,13 @@ static void dtor_demonitor(ErtsMonitor* mon, void* context) erts_proc_sig_send_demonitor(mon); } +#ifdef DEBUG +int erts_dbg_is_resource_dying(ErtsResource* resource) +{ + return resource->monitors && rmon_is_dying(resource->monitors); +} +#endif + # define NIF_RESOURCE_DTOR &nif_resource_dtor static int nif_resource_dtor(Binary* bin) @@ -2694,8 +2701,12 @@ int enif_consume_timeslice(ErlNifEnv* env, int percent) { Process *proc; Sint reds; + int sched; - execution_state(env, &proc, NULL); + execution_state(env, &proc, &sched); + + if (sched < 0) + return 0; /* no-op on dirty scheduler */ ASSERT(is_proc_bound(env) && percent >= 1 && percent <= 100); if (percent < 1) percent = 1; diff --git a/erts/emulator/beam/erl_port.h b/erts/emulator/beam/erl_port.h index 25976d38cc..039d8cf67a 100644 --- a/erts/emulator/beam/erl_port.h +++ b/erts/emulator/beam/erl_port.h @@ -1018,6 +1018,6 @@ int erts_port_output_async(Port *, Eterm, Eterm); /* * Signals from ports to ports. Used by sys drivers. */ -int erl_drv_port_control(Eterm, char, char*, ErlDrvSizeT); +int erl_drv_port_control(Eterm, unsigned int, char*, ErlDrvSizeT); #endif diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c index 990a01b96f..9cfb7fc681 100644 --- a/erts/emulator/beam/erl_printf_term.c +++ b/erts/emulator/beam/erl_printf_term.c @@ -364,13 +364,13 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount) { int print_res; char def_buf[64]; char *buf, *big_str; - Uint sz = (Uint) big_decimal_estimate(wobj); + Uint sz = (Uint) big_integer_estimate(wobj, 10); sz++; if (sz <= 64) buf = &def_buf[0]; else buf = erts_alloc(ERTS_ALC_T_TMP, sz); - big_str = erts_big_to_string(wobj, buf, sz); + big_str = erts_big_to_string(wobj, 10, buf, sz); print_res = erts_printf_string(fn, arg, big_str); if (buf != &def_buf[0]) erts_free(ERTS_ALC_T_TMP, (void *) buf); diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c index f343e984f7..d475a0a634 100644 --- a/erts/emulator/beam/erl_proc_sig_queue.c +++ b/erts/emulator/beam/erl_proc_sig_queue.c @@ -3247,9 +3247,15 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep, erts_nif_demonitored((ErtsResource *) tmon->other.ptr); cnt++; break; - case ERTS_MON_TYPE_SUSPEND: - erts_resume(c_p, ERTS_PROC_LOCK_MAIN); + case ERTS_MON_TYPE_SUSPEND: { + ErtsMonitorSuspend *msp; + erts_aint_t mstate; + msp = (ErtsMonitorSuspend *) erts_monitor_to_data(tmon); + mstate = erts_atomic_read_acqb(&msp->state); + if (mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE) + erts_resume(c_p, ERTS_PROC_LOCK_MAIN); break; + } default: break; } @@ -3784,6 +3790,9 @@ clear_seq_trace_token(ErtsMessage *sig) case ERTS_MON_TYPE_PROC: case ERTS_MON_TYPE_DIST_PROC: case ERTS_MON_TYPE_NODE: + case ERTS_MON_TYPE_NODES: + case ERTS_MON_TYPE_SUSPEND: + case ERTS_MON_TYPE_TIME_OFFSET: break; default: ERTS_INTERNAL_ERROR("Unexpected sig type"); @@ -3800,6 +3809,11 @@ clear_seq_trace_token(ErtsMessage *sig) case ERTS_SIG_Q_OP_LINK: case ERTS_SIG_Q_OP_UNLINK: case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE: + case ERTS_SIG_Q_OP_GROUP_LEADER: + case ERTS_SIG_Q_OP_IS_ALIVE: + case ERTS_SIG_Q_OP_PROCESS_INFO: + case ERTS_SIG_Q_OP_SYNC_SUSPEND: + case ERTS_SIG_Q_OP_RPC: break; default: @@ -3812,7 +3826,6 @@ clear_seq_trace_token(ErtsMessage *sig) void erts_proc_sig_clear_seq_trace_tokens(Process *c_p) { - ASSERT(erts_thr_progress_is_blocking()); erts_proc_sig_fetch(c_p); ERTS_FOREACH_SIG_PRIVQS(c_p, sig, clear_seq_trace_token(sig)); } diff --git a/erts/emulator/beam/erl_proc_sig_queue.h b/erts/emulator/beam/erl_proc_sig_queue.h index 3fc2d06b2d..6b065a7add 100644 --- a/erts/emulator/beam/erl_proc_sig_queue.h +++ b/erts/emulator/beam/erl_proc_sig_queue.h @@ -989,8 +989,7 @@ erts_proc_sig_fetch(Process *proc) Sint res = 0; ErtsSignal *sig; - ERTS_LC_ASSERT(erts_thr_progress_is_blocking() - || ERTS_PROC_IS_EXITING(proc) + ERTS_LC_ASSERT(ERTS_PROC_IS_EXITING(proc) || ((erts_proc_lc_my_proc_locks(proc) & (ERTS_PROC_LOCK_MAIN | ERTS_PROC_LOCK_MSGQ)) diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 2427d87f66..1f464e2e5a 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -92,10 +92,6 @@ #undef HARDDEBUG #endif -#ifdef HARDDEBUG -#define HARDDEBUG_RUNQS -#endif - #ifdef HIPE #include "hipe_mode_switch.h" /* for hipe_init_process() */ #include "hipe_signal.h" /* for hipe_thread_signal_init() */ @@ -344,6 +340,7 @@ erts_sched_stat_t erts_sched_stat; static erts_tsd_key_t ERTS_WRITE_UNLIKELY(sched_data_key); #if ERTS_POLL_USE_SCHEDULER_POLLING +static erts_atomic32_t function_calls; static erts_atomic32_t doing_sys_schedule; #endif static erts_atomic32_t no_empty_run_queues; @@ -2465,6 +2462,13 @@ handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) erts_port_lock(prt); + if (prt->common.u.alive.reg && + prt->common.u.alive.reg->name == am_heart_port) { + /* Leave heart port to not get killed before flushing is done*/ + erts_port_release(prt); + continue; + } + state = erts_atomic32_read_nob(&prt->state); if (!(state & (ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP | ERTS_PORT_SFLG_HALT))) { @@ -3251,6 +3255,7 @@ poll_thread(void *arg) static ERTS_INLINE void clear_sys_scheduling(void) { + erts_atomic32_set_relb(&function_calls, 0); erts_atomic32_set_mb(&doing_sys_schedule, 0); } @@ -3273,31 +3278,49 @@ prepare_for_sys_schedule(void) return 0; } -static void -check_io_timer(void *null) +#else +#define clear_sys_scheduling() +#define prepare_for_sys_schedule() 0 +#endif + +#ifdef HARDDEBUG +#define ERTS_HDBG_CHK_SLEEP_LIST(SL, L, F, FN) \ + check_sleepers_list((SL), (L), (F), (FN)) +static void check_sleepers_list(ErtsSchedulerSleepList *sl, + int lock, + ErtsSchedulerSleepInfo *find, + ErtsSchedulerSleepInfo *find_not) { - ErtsSchedulerData *esdp = erts_get_scheduler_data(); - if (prepare_for_sys_schedule()) { - erts_check_io(esdp->ssi->psi, ERTS_POLL_NO_TIMEOUT); - clear_sys_scheduling(); - } + ErtsSchedulerSleepInfo *last_out; + int found = 0; - /* The timer is cleared if this schedulers run-queue became empty - or if the CHECKIO flag was cleared. The CHECKIO flags is cleared - when a check_balance assigns another scheduler to be the poller in - the overload scenario. */ - if ((ERTS_RUNQ_FLGS_GET_NOB(esdp->run_queue) & (ERTS_RUNQ_FLG_OUT_OF_WORK|ERTS_RUNQ_FLG_CHECKIO)) - == ERTS_RUNQ_FLG_CHECKIO) { - erts_start_timer_callback(ERTS_POLL_SCHEDULER_POLLING_TIMEOUT, - check_io_timer, NULL); - } else { - ERTS_RUNQ_FLGS_UNSET(esdp->run_queue, ERTS_RUNQ_FLG_CHECKIO); - } -} + if (lock) + erts_spin_lock(&sl->lock); + ERTS_ASSERT(!find_not || (!find_not->next && !find_not->prev)); + + last_out = sl->list; + if (last_out) { + ErtsSchedulerSleepInfo *tmp = last_out; + do { + ERTS_ASSERT(tmp->next); + ERTS_ASSERT(tmp->prev); + ERTS_ASSERT(tmp->next->prev == tmp); + ERTS_ASSERT(tmp->prev->next == tmp); + ERTS_ASSERT(tmp != find_not); + if (tmp == find) + found = !0; + tmp = tmp->next; + + } while (tmp != last_out); + } + ERTS_ASSERT(!find || found); + + if (lock) + erts_spin_unlock(&sl->lock); +} #else -#define clear_sys_scheduling() -#define prepare_for_sys_schedule() 0 +#define ERTS_HDBG_CHK_SLEEP_LIST(SL, L, F, FN) ((void) 0) #endif static void @@ -3313,23 +3336,29 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) ERTS_LC_ASSERT(erts_lc_runq_is_locked(rq)); - if (ERTS_RUNQ_IX_IS_DIRTY(rq->ix)) - erts_spin_lock(&rq->sleepers.lock); flgs = sched_prep_spin_wait(ssi); if (flgs & ERTS_SSI_FLG_SUSPENDED) { /* Go suspend instead... */ - if (ERTS_RUNQ_IX_IS_DIRTY(rq->ix)) - erts_spin_unlock(&rq->sleepers.lock); return; } if (ERTS_RUNQ_IX_IS_DIRTY(rq->ix)) { - ssi->prev = NULL; - ssi->next = rq->sleepers.list; - if (rq->sleepers.list) - rq->sleepers.list->prev = ssi; - rq->sleepers.list = ssi; - erts_spin_unlock(&rq->sleepers.lock); + erts_spin_lock(&rq->sleepers.lock); + ERTS_HDBG_CHK_SLEEP_LIST(&rq->sleepers, 0, NULL, ssi); + ASSERT(!ssi->next); /* Not in sleepers list */ + ASSERT(!ssi->prev); + if (!rq->sleepers.list) { + ssi->next = ssi->prev = ssi; + rq->sleepers.list = ssi; + } + else { + ssi->prev = rq->sleepers.list; + ssi->next = rq->sleepers.list->next; + ssi->prev->next = ssi; + ssi->next->prev = ssi; + } + ERTS_HDBG_CHK_SLEEP_LIST(&rq->sleepers, 0, ssi, NULL); + erts_spin_unlock(&rq->sleepers.lock); dirty_active(esdp, -1); } @@ -3406,6 +3435,7 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) current_time = erts_get_monotonic_time(esdp); } } + *fcalls = 0; clear_sys_scheduling(); } else { if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) { @@ -3470,8 +3500,28 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) (ERTS_SSI_FLG_SUSPENDED | ERTS_SSI_FLG_MSB_EXEC)); - if (ERTS_SCHEDULER_IS_DIRTY(esdp)) + if (ERTS_SCHEDULER_IS_DIRTY(esdp)) { dirty_sched_wall_time_change(esdp, working = 1); + erts_spin_lock(&rq->sleepers.lock); + ERTS_HDBG_CHK_SLEEP_LIST(&rq->sleepers, 0, ssi->next ? ssi : NULL, NULL); + if (ssi->next) { /* Still in list... */ + if (ssi->next == ssi) { + ASSERT(rq->sleepers.list == ssi); + ASSERT(ssi->prev == ssi); + rq->sleepers.list = NULL; + } + else { + ASSERT(ssi->prev != ssi); + if (rq->sleepers.list == ssi) + rq->sleepers.list = ssi->next; + ssi->prev->next = ssi->next; + ssi->next->prev = ssi->prev; + } + ssi->next = ssi->prev = NULL; + } + ERTS_HDBG_CHK_SLEEP_LIST(&rq->sleepers, 0, NULL, ssi); + erts_spin_unlock(&rq->sleepers.lock); + } else if (!thr_prgr_active) { erts_thr_progress_active(erts_thr_prgr_data(esdp), thr_prgr_active = 1); sched_wall_time_change(esdp, 1); @@ -3559,56 +3609,44 @@ wake_scheduler(ErtsRunQueue *rq) } static void -wake_dirty_schedulers(ErtsRunQueue *rq, int one) +wake_dirty_scheduler(ErtsRunQueue *rq) { - ErtsSchedulerSleepInfo *ssi; + ErtsSchedulerSleepInfo *lo_ssi, *fo_ssi; ErtsSchedulerSleepList *sl; ASSERT(ERTS_RUNQ_IX_IS_DIRTY(rq->ix)); sl = &rq->sleepers; erts_spin_lock(&sl->lock); - ssi = sl->list; - if (!ssi) { + ERTS_HDBG_CHK_SLEEP_LIST(&rq->sleepers, 0, NULL, NULL); + lo_ssi = sl->list; + if (!lo_ssi) { erts_spin_unlock(&sl->lock); - if (one) - wake_scheduler(rq); - } else if (one) { + wake_scheduler(rq); + } + else { erts_aint32_t flgs; - if (ssi->prev) - ssi->prev->next = ssi->next; - else { - ASSERT(sl->list == ssi); - sl->list = ssi->next; + fo_ssi = lo_ssi->next; + ASSERT(fo_ssi->prev == lo_ssi); + if (fo_ssi == lo_ssi) { + ASSERT(lo_ssi->prev == lo_ssi); + sl->list = NULL; + } + else { + ASSERT(lo_ssi->prev != lo_ssi); + lo_ssi->next = fo_ssi->next; + fo_ssi->next->prev = fo_ssi->prev; } - if (ssi->next) - ssi->next->prev = ssi->prev; - - erts_spin_unlock(&sl->lock); - - ERTS_THR_MEMORY_BARRIER; - flgs = ssi_flags_set_wake(ssi); - erts_sched_finish_poke(ssi, flgs); - } else { - sl->list = NULL; + fo_ssi->next = fo_ssi->prev = NULL; + ERTS_HDBG_CHK_SLEEP_LIST(&rq->sleepers, 0, NULL, fo_ssi); erts_spin_unlock(&sl->lock); ERTS_THR_MEMORY_BARRIER; - do { - ErtsSchedulerSleepInfo *wake_ssi = ssi; - ssi = ssi->next; - erts_sched_finish_poke(wake_ssi, ssi_flags_set_wake(wake_ssi)); - } while (ssi); + flgs = ssi_flags_set_wake(fo_ssi); + erts_sched_finish_poke(fo_ssi, flgs); } } -static void -wake_dirty_scheduler(ErtsRunQueue *rq) -{ - wake_dirty_schedulers(rq, 1); -} - - #define ERTS_NO_USED_RUNQS_SHIFT 16 #define ERTS_NO_RUNQS_MASK 0xffffU @@ -4661,15 +4699,6 @@ check_balance(ErtsRunQueue *c_rq) if (blnc_no_rqs == 1) { c_rq->check_balance_reds = INT_MAX; erts_atomic32_set_nob(&balance_info.checking_balance, 0); -#if ERTS_POLL_USE_SCHEDULER_POLLING - c_rq->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS; - if ((ERTS_RUNQ_FLGS_GET_NOB(c_rq) & (ERTS_RUNQ_FLG_OUT_OF_WORK|ERTS_RUNQ_FLG_CHECKIO)) - == 0) { - ERTS_RUNQ_FLGS_SET(c_rq, ERTS_RUNQ_FLG_CHECKIO); - erts_start_timer_callback(ERTS_POLL_SCHEDULER_POLLING_TIMEOUT, check_io_timer, NULL); - } - ERTS_RUNQ_FLGS_UNSET(c_rq, ERTS_RUNQ_FLGS_MIGRATION_INFO); -#endif return; } @@ -5189,19 +5218,6 @@ erts_fprintf(stderr, "--------------------------------\n"); /* Publish new migration paths... */ erts_atomic_set_wb(&erts_migration_paths, (erts_aint_t) new_mpaths); -#if ERTS_POLL_USE_SCHEDULER_POLLING - if (full_scheds == current_active) { - ERTS_ASSERT(full_scheds <= current_active); - /* All active schedulers ran for full, we need to do active polling, - so we setup a timer that does active polling */ - if (!(ERTS_RUNQ_FLGS_GET_NOB(c_rq) & ERTS_RUNQ_FLG_CHECKIO)) { - /* Active polling is not running, start it */ - erts_start_timer_callback(ERTS_POLL_SCHEDULER_POLLING_TIMEOUT, check_io_timer, NULL); - } - run_queue_info[c_rq->ix].flags |= ERTS_RUNQ_FLG_CHECKIO; - } -#endif - /* Reset balance statistics in all online queues */ for (qix = 0; qix < blnc_no_rqs; qix++) { Uint32 flags = run_queue_info[qix].flags; @@ -5211,8 +5227,6 @@ erts_fprintf(stderr, "--------------------------------\n"); ASSERT(!(flags & ERTS_RUNQ_FLG_OUT_OF_WORK)); if (rq->waiting) flags |= ERTS_RUNQ_FLG_OUT_OF_WORK; - if (rq != c_rq) - flags &= ~ERTS_RUNQ_FLG_CHECKIO; rq->full_reds_history_sum = run_queue_info[qix].full_reds_history_sum; @@ -5222,7 +5236,7 @@ erts_fprintf(stderr, "--------------------------------\n"); ERTS_DBG_CHK_FULL_REDS_HISTORY(rq); rq->out_of_work_count = 0; - (void) ERTS_RUNQ_FLGS_READ_BSET(rq, ERTS_RUNQ_FLGS_MIGRATION_INFO|ERTS_RUNQ_FLG_CHECKIO, flags); + (void) ERTS_RUNQ_FLGS_READ_BSET(rq, ERTS_RUNQ_FLGS_MIGRATION_INFO, flags); rq->max_len = erts_atomic32_read_dirty(&rq->len); for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) { ErtsRunQueueInfo *rqi; @@ -5873,6 +5887,7 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online, int no_poll_th erts_alloc_permanent_cache_aligned(ERTS_ALC_T_RUNQS, size_runqs); #if ERTS_POLL_USE_SCHEDULER_POLLING erts_atomic32_init_nob(&doing_sys_schedule, 0); + erts_atomic32_init_nob(&function_calls, 0); #endif erts_atomic32_init_nob(&no_empty_run_queues, 0); @@ -5988,6 +6003,8 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online, int no_poll_th for (ix = 0; ix < no_dirty_cpu_schedulers; ix++) { ErtsSchedulerSleepInfo *ssi = &aligned_dirty_cpu_sched_sleep_info[ix].ssi; erts_atomic32_init_nob(&ssi->flags, 0); + ssi->next = NULL; + ssi->prev = NULL; ssi->event = NULL; /* initialized in sched_dirty_cpu_thread_func */ erts_atomic32_init_nob(&ssi->aux_work, 0); } @@ -5998,6 +6015,8 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online, int no_poll_th for (ix = 0; ix < no_dirty_io_schedulers; ix++) { ErtsSchedulerSleepInfo *ssi = &aligned_dirty_io_sched_sleep_info[ix].ssi; erts_atomic32_init_nob(&ssi->flags, 0); + ssi->next = NULL; + ssi->prev = NULL; ssi->event = NULL; /* initialized in sched_dirty_io_thread_func */ erts_atomic32_init_nob(&ssi->aux_work, 0); } @@ -7517,7 +7536,13 @@ suspend_scheduler(ErtsSchedulerData *esdp) return; } +#ifdef HARDDEBUG + if (sched_type != ERTS_SCHED_NORMAL) + ERTS_HDBG_CHK_SLEEP_LIST(&esdp->run_queue->sleepers, !0, NULL, ssi); +#endif + if (erts_atomic32_read_nob(&ssi->flags) & ERTS_SSI_FLG_MSB_EXEC) { + ASSERT(no == 1); if (!msb_scheduler_type_switch(sched_type, esdp, no)) return; @@ -9217,7 +9242,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) Process *proxy_p = NULL; ErtsRunQueue *rq; int context_reds; - int fcalls; + int fcalls = 0; int actual_reds; int reds; Uint32 flags; @@ -9291,6 +9316,10 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) reds = ERTS_PROC_MIN_CONTEXT_SWITCH_REDS_COST; esdp->virtual_reds = 0; +#if ERTS_POLL_USE_SCHEDULER_POLLING + fcalls = (int) erts_atomic32_add_read_acqb(&function_calls, reds); +#endif + ASSERT(esdp && esdp == erts_get_scheduler_data()); rq = erts_get_runq_current(esdp); @@ -9445,6 +9474,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) if (!is_normal_sched & !!(flags & ERTS_RUNQ_FLG_HALTING)) { /* Wait for emulator to terminate... */ + erts_runq_unlock(rq); while (1) erts_milli_sleep(1000*1000); } @@ -9507,7 +9537,33 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) non_empty_runq(rq); goto check_activities_to_run; - } + } else if (is_normal_sched && + fcalls > (2 * context_reds) && + prepare_for_sys_schedule()) { + ErtsMonotonicTime current_time; + /* + * Schedule system-level activities. + */ + + ERTS_MSACC_PUSH_STATE_CACHED_M(); + + erts_runq_unlock(rq); + + ERTS_MSACC_SET_STATE_CACHED_M(ERTS_MSACC_STATE_CHECK_IO); + LTTNG2(scheduler_poll, esdp->no, 1); + + erts_check_io(esdp->ssi->psi, ERTS_POLL_NO_TIMEOUT); + ERTS_MSACC_POP_STATE_M(); + + current_time = erts_get_monotonic_time(esdp); + if (current_time >= erts_next_timeout_time(esdp->next_tmo_ref)) + erts_bump_timers(esdp->timer_wheel, current_time); + + erts_runq_lock(rq); + fcalls = 0; + clear_sys_scheduling(); + goto continue_check_activities_to_run; + } if (flags & ERTS_RUNQ_FLG_MISC_OP) exec_misc_ops(rq); @@ -13026,10 +13082,10 @@ void erts_halt(int code) if (-1 == erts_atomic32_cmpxchg_acqb(&erts_halt_progress, erts_no_schedulers, -1)) { + notify_reap_ports_relb(); ERTS_RUNQ_FLGS_SET(ERTS_DIRTY_CPU_RUNQ, ERTS_RUNQ_FLG_HALTING); ERTS_RUNQ_FLGS_SET(ERTS_DIRTY_IO_RUNQ, ERTS_RUNQ_FLG_HALTING); erts_halt_code = code; - notify_reap_ports_relb(); } } diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index a1b029adbe..43937f216c 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -173,8 +173,6 @@ extern int erts_dio_sched_thread_suggested_stack_size; (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 9)) #define ERTS_RUNQ_FLG_HALTING \ (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 10)) -#define ERTS_RUNQ_FLG_CHECKIO \ - (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 11)) #define ERTS_RUNQ_FLG_MAX (ERTS_RUNQ_FLG_BASE2 + 12) @@ -359,7 +357,7 @@ typedef struct ErtsSchedulerSleepInfo_ ErtsSchedulerSleepInfo; typedef struct { erts_spinlock_t lock; - ErtsSchedulerSleepInfo *list; + ErtsSchedulerSleepInfo *list; /* circular lifo list; points to last out */ } ErtsSchedulerSleepList; struct ErtsSchedulerSleepInfo_ { diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index 2350d4c02f..ae7084b7f4 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -72,6 +72,7 @@ static ErtsTracer default_port_tracer; static Eterm system_monitor; static Eterm system_profile; +static erts_atomic_t system_logger; #ifdef HAVE_ERTS_NOW_CPU int erts_cpu_timestamp; @@ -340,6 +341,7 @@ void erts_init_trace(void) { default_port_trace_flags = F_INITIAL_TRACE_FLAGS; default_port_tracer = erts_tracer_nil; system_seq_tracer = erts_tracer_nil; + erts_atomic_init_nob(&system_logger, am_logger); init_sys_msg_dispatcher(); init_tracer_nif(); } @@ -2027,10 +2029,24 @@ enqueue_sys_msg(enum ErtsSysMsgType type, erts_mtx_unlock(&smq_mtx); } +Eterm +erts_get_system_logger(void) +{ + return (Eterm)erts_atomic_read_nob(&system_logger); +} + +Eterm +erts_set_system_logger(Eterm logger) +{ + if (logger != am_logger && logger != am_undefined && !is_internal_pid(logger)) + return THE_NON_VALUE; + return (Eterm)erts_atomic_xchg_nob(&system_logger, logger); +} + void erts_queue_error_logger_message(Eterm from, Eterm msg, ErlHeapFragment *bp) { - enqueue_sys_msg(SYS_MSG_TYPE_ERRLGR, from, am_logger, msg, bp); + enqueue_sys_msg(SYS_MSG_TYPE_ERRLGR, from, erts_get_system_logger(), msg, bp); } void @@ -2271,7 +2287,7 @@ sys_msg_dispatcher_func(void *unused) } break; case SYS_MSG_TYPE_ERRLGR: - receiver = am_logger; + receiver = smqp->to; break; default: receiver = NIL; @@ -2285,8 +2301,15 @@ sys_msg_dispatcher_func(void *unused) if (is_internal_pid(receiver)) { proc = erts_pid2proc(NULL, 0, receiver, proc_locks); if (!proc) { - /* Bad tracer */ - goto failure; + if (smqp->type == SYS_MSG_TYPE_ERRLGR) { + /* Bad logger process, send to kernel 'logger' process */ + erts_set_system_logger(am_logger); + receiver = erts_get_system_logger(); + goto logger; + } else { + /* Bad tracer */ + goto failure; + } } else { ErtsMessage *mp; @@ -2299,9 +2322,9 @@ sys_msg_dispatcher_func(void *unused) #endif erts_proc_unlock(proc, proc_locks); } - } - else if (receiver == am_logger) { - proc = erts_whereis_process(NULL,0,receiver,proc_locks,0); + } else if (receiver == am_logger) { + logger: + proc = erts_whereis_process(NULL,0,am_logger,proc_locks,0); if (!proc) goto failure; else if (smqp->from == proc->common.id) @@ -2309,7 +2332,10 @@ sys_msg_dispatcher_func(void *unused) else goto queue_proc_msg; } - else if (is_internal_port(receiver)) { + else if (receiver == am_undefined) { + goto drop_sys_msg; + } + else if (is_internal_port(receiver)) { port = erts_thr_id2port_sflgs(receiver, ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP); if (!port) @@ -2366,7 +2392,7 @@ erts_foreach_sys_msg_in_q(void (*func)(Eterm, to = erts_get_system_profile(); break; case SYS_MSG_TYPE_ERRLGR: - to = am_logger; + to = erts_get_system_logger(); break; default: to = NIL; diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h index bccf31606e..b7844d1cb0 100644 --- a/erts/emulator/beam/erl_trace.h +++ b/erts/emulator/beam/erl_trace.h @@ -94,6 +94,8 @@ void erts_foreach_sys_msg_in_q(void (*func)(Eterm, Eterm, Eterm, ErlHeapFragment *)); +Eterm erts_set_system_logger(Eterm); +Eterm erts_get_system_logger(void); void erts_queue_error_logger_message(Eterm, Eterm, ErlHeapFragment *); void erts_send_sys_msg_proc(Eterm, Eterm, Eterm, ErlHeapFragment *); diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h index 4089fac48e..d37c2940c4 100644 --- a/erts/emulator/beam/erl_vm.h +++ b/erts/emulator/beam/erl_vm.h @@ -167,6 +167,8 @@ extern const int num_instructions; /* Number of instruction in opc[]. */ extern Uint erts_instr_count[]; +extern int tuple_module_apply; + /* some constants for various table sizes etc */ #define ATOM_TEXT_SIZE 32768 /* Increment for allocating atom text space */ diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index 9a66e491f3..1ded5f031c 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -102,7 +102,7 @@ static byte* enc_term(ErtsAtomCacheMap *, Eterm, byte*, Uint32, struct erl_off_h struct TTBEncodeContext_; static int enc_term_int(struct TTBEncodeContext_*,ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags, struct erl_off_heap_header** off_heap, Sint *reds, byte **res); -static Uint is_external_string(Eterm obj, int* p_is_string); +static int is_external_string(Eterm obj, Uint* lenp); static byte* enc_atom(ErtsAtomCacheMap *, Eterm, byte*, Uint32); static byte* enc_pid(ErtsAtomCacheMap *, Eterm, byte*, Uint32); struct B2TContext_t; @@ -2481,11 +2481,21 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, { Eterm* cons = list_val(obj); Eterm tl; + Uint len_cnt = WSTACK_POP(s); obj = CAR(cons); tl = CDR(cons); - WSTACK_PUSH2(s, (is_list(tl) ? ENC_ONE_CONS : ENC_TERM), - tl); + if (is_list(tl)) { + len_cnt++; + WSTACK_PUSH3(s, len_cnt, ENC_ONE_CONS, tl); + } + else { + byte* list_lenp = (byte*) WSTACK_POP(s); + ASSERT(list_lenp[-1] == LIST_EXT); + put_int32(len_cnt, list_lenp); + + WSTACK_PUSH2(s, ENC_TERM, tl); + } } break; case ENC_PATCH_FUN_SIZE: @@ -2689,10 +2699,7 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, } case LIST_DEF: { - int is_str; - - i = is_external_string(obj, &is_str); - if (is_str) { + if (is_external_string(obj, &i)) { *ep++ = STRING_EXT; put_int16(i, ep); ep += 2; @@ -2701,9 +2708,12 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, *ep++ = unsigned_val(CAR(cons)); obj = CDR(cons); } + r -= i; } else { + r -= i/2; *ep++ = LIST_EXT; - put_int32(i, ep); + /* Patch list length when we find end of list */ + WSTACK_PUSH2(s, (UWord)ep, 1); ep += 4; goto encode_one_cons; } @@ -2961,9 +2971,13 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, return 0; } +/** @brief Is it a list of bytes not longer than MAX_STRING_LEN? + * @param lenp out: string length or number of list cells traversed + * @return true/false + */ static -Uint -is_external_string(Eterm list, int* p_is_string) +int +is_external_string(Eterm list, Uint* lenp) { Uint len = 0; @@ -2975,29 +2989,15 @@ is_external_string(Eterm list, int* p_is_string) Eterm* consp = list_val(list); Eterm hd = CAR(consp); - if (!is_byte(hd)) { - break; + if (!is_byte(hd) || ++len > MAX_STRING_LEN) { + *lenp = len; + return 0; } - len++; list = CDR(consp); } - /* - * If we have reached the end of the list, and we have - * not exceeded the maximum length of a string, this - * is a string. - */ - *p_is_string = is_nil(list) && len < MAX_STRING_LEN; - - /* - * Continue to calculate the length. - */ - while (is_list(list)) { - Eterm* consp = list_val(list); - len++; - list = CDR(consp); - } - return len; + *lenp = len; + return is_nil(list); } @@ -4075,8 +4075,8 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, for (;;) { ASSERT(!is_header(obj)); - if (ctx && --r == 0) { - *reds = r; + if (ctx && --r <= 0) { + *reds = 0; ctx->obj = obj; ctx->result = result; WSTACK_SAVE(s, &ctx->wstack); @@ -4166,8 +4166,10 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, result += (1 + encode_size_struct2(acmp, port_node_name(obj), dflags) + 4 + 1); break; - case LIST_DEF: - if ((m = is_string(obj)) && (m < MAX_STRING_LEN)) { + case LIST_DEF: { + int is_str = is_external_string(obj, &m); + r -= m/2; + if (is_str) { result += m + 2 + 1; } else { result += 5; @@ -4176,6 +4178,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, continue; /* big loop */ } break; + } case TUPLE_DEF: { Eterm* ptr = tuple_val(obj); @@ -4317,7 +4320,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, if (is_header(obj)) { switch (obj) { - case LIST_TAIL_OP: + case LIST_TAIL_OP: obj = (Eterm) WSTACK_POP(s); if (is_list(obj)) { Eterm* cons = list_val(obj); @@ -4343,7 +4346,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, WSTACK_DESTROY(s); if (ctx) { ASSERT(ctx->wstack.wstart == NULL); - *reds = r; + *reds = r < 0 ? 0 : r; } *res = result; return 0; diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 0631404599..f564472081 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -113,6 +113,9 @@ extern Eterm erts_bld_resource_ref(Eterm** hp, ErlOffHeap*, ErtsResource*); extern void erts_pre_nif(struct enif_environment_t*, Process*, struct erl_module_nif*, Process* tracee); extern void erts_post_nif(struct enif_environment_t* env); +#ifdef DEBUG +int erts_dbg_is_resource_dying(ErtsResource*); +#endif extern void erts_resource_stop(ErtsResource*, ErlNifEvent, int is_direct_call); void erts_fire_nif_monitor(ErtsMonitor *tmon); void erts_nif_demonitored(ErtsResource* resource); @@ -962,7 +965,7 @@ void init_break_handler(void); void erts_set_ignore_break(void); void erts_replace_intr(void); void process_info(fmtfn_t, void *); -void print_process_info(fmtfn_t, void *, Process*); +void print_process_info(fmtfn_t, void *, Process*, ErtsProcLocks); void info(fmtfn_t, void *); void loaded(fmtfn_t, void *); void erts_print_base64(fmtfn_t to, void *to_arg, byte* src, Uint size); @@ -1303,14 +1306,7 @@ Sint intlist_to_buf(Eterm, char*, Sint); /* most callers pass plain char*'s */ int erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len, Sint* written); Sint erts_unicode_list_to_buf_len(Eterm list); -struct Sint_buf { -#if defined(ARCH_64) - char s[22]; -#else - char s[12]; -#endif -}; -char* Sint_to_buf(Sint, struct Sint_buf*); +int Sint_to_buf(Sint num, int base, char **buf_p, size_t buf_size); #define ERTS_IOLIST_STATE_INITER(C_P, OBJ) \ {(C_P), 0, 0, (OBJ), {NULL, NULL, NULL, ERTS_ALC_T_INVALID}, 0, 0} diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 5325480901..7322239a73 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -4073,7 +4073,7 @@ done: * to the caller. */ int -erl_drv_port_control(Eterm port_num, char cmd, char* buff, ErlDrvSizeT size) +erl_drv_port_control(Eterm port_num, unsigned int cmd, char* buff, ErlDrvSizeT size) { ErtsProc2PortSigData *sigdp = erts_port_task_alloc_p2p_sig_data(); diff --git a/erts/emulator/beam/msg_instrs.tab b/erts/emulator/beam/msg_instrs.tab index 9bf3aefaca..a6a0dec451 100644 --- a/erts/emulator/beam/msg_instrs.tab +++ b/erts/emulator/beam/msg_instrs.tab @@ -105,6 +105,7 @@ i_loop_rec(Dest) { $SET_CP_I_ABS(I); c_p->arity = 0; c_p->current = NULL; + c_p->fcalls = FCALLS; FCALLS -= erts_proc_sig_receive_helper(c_p, FCALLS, neg_o_reds, &msgp, &get_out); SWAPIN; diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index 869a575cb4..a69da4d762 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -1291,4 +1291,13 @@ erts_raw_env_next_char(byte *p, int encoding) #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */ +/* + * Magic numbers for our driver port_control callbacks. + * Kept them below 1<<27 to not inflict extra bignum garbage on 32-bit. + */ +#define ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER 0x018b0900U +#define ERTS_INET_DRV_CONTROL_MAGIC_NUMBER 0x03f1a300U +#define ERTS_SPAWN_DRV_CONTROL_MAGIC_NUMBER 0x04c76a00U +#define ERTS_FORKER_DRV_CONTROL_MAGIC_NUMBER 0x050a7800U + #endif diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index d81bd89a48..c5deed38ad 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -1946,7 +1946,7 @@ do_allocate_logger_message(Eterm gleader, ErtsMonotonicTime *ts, Eterm *pid, else sz += MAP4_SZ /* metadata map w gl w pid*/; - *ts = ERTS_MONOTONIC_TO_USEC(erts_get_monotonic_time(NULL) + erts_get_time_offset()); + *ts = ERTS_MONOTONIC_TO_USEC(erts_os_system_time()); erts_bld_sint64(NULL, &sz, *ts); *bp = new_message_buffer(sz); @@ -3681,30 +3681,47 @@ erts_unicode_list_to_buf_len(Eterm list) } } -/* -** Convert an integer to a byte list -** return pointer to converted stuff (need not to be at start of buf!) -*/ -char* Sint_to_buf(Sint n, struct Sint_buf *buf) +/* Prints an integer in the given base, returning the number of digits printed. + * + * (*buf) is a pointer to the buffer, and is set to the start of the string + * when returning. */ +int Sint_to_buf(Sint n, int base, char **buf, size_t buf_size) { - char* p = &buf->s[sizeof(buf->s)-1]; - int sign = 0; - - *p-- = '\0'; /* null terminate */ - if (n == 0) - *p-- = '0'; - else if (n < 0) { - sign = 1; - n = -n; + char *p = &(*buf)[buf_size - 1]; + int sign = 0, size = 0; + + ASSERT(base >= 2 && base <= 36); + + if (n == 0) { + *p-- = '0'; + size++; + } else if (n < 0) { + sign = 1; + n = -n; } while (n != 0) { - *p-- = (n % 10) + '0'; - n /= 10; + int digit = n % base; + + if (digit < 10) { + *p-- = '0' + digit; + } else { + *p-- = 'A' + (digit - 10); + } + + size++; + + n /= base; } - if (sign) - *p-- = '-'; - return p+1; + + if (sign) { + *p-- = '-'; + size++; + } + + *buf = p + 1; + + return size; } /* Build a list of integers in some safe memory area @@ -4771,58 +4788,3 @@ erts_ptr_id(void *ptr) return ptr; } -#ifdef DEBUG -/* - * Handy functions when using a debugger - don't use in the code! - */ - -void upp(byte *buf, size_t sz) -{ - bin_write(ERTS_PRINT_STDERR, NULL, buf, sz); -} - -void pat(Eterm atom) -{ - upp(atom_tab(atom_val(atom))->name, - atom_tab(atom_val(atom))->len); -} - - -void pinfo() -{ - process_info(ERTS_PRINT_STDOUT, NULL); -} - - -void pp(p) -Process *p; -{ - if(p) - print_process_info(ERTS_PRINT_STDERR, NULL, p); -} - -void ppi(Eterm pid) -{ - pp(erts_proc_lookup(pid)); -} - -void td(Eterm x) -{ - erts_fprintf(stderr, "%T\n", x); -} - -void -ps(Process* p, Eterm* stop) -{ - Eterm* sp = STACK_START(p) - 1; - - if (stop <= STACK_END(p)) { - stop = STACK_END(p) + 1; - } - - while(sp >= stop) { - erts_printf("%p: %.75T\n", sp, *sp); - sp--; - } -} -#endif diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 47eb5df7dd..b71ce0389d 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -574,7 +574,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) driver_select(port, e, mode | (on?ERL_DRV_USE:0), on) #define sock_select(d, flags, onoff) do { \ - ASSERT(!(d)->is_ignored); \ + ASSERT(!INET_IGNORED(d)); \ (d)->event_mask = (onoff) ? \ ((d)->event_mask | (flags)) : \ ((d)->event_mask & ~(flags)); \ @@ -634,9 +634,13 @@ static size_t my_strnlen(const char *s, size_t maxlen) * header length. To get the header length we use * the pointer difference from the cmsg start pointer * to the CMSG_DATA(cmsg) pointer. + * + * Some platforms (seen on ppc Linux 2.6.29-3.ydl61.3) + * may return 0 as the cmsg_len if the cmsg is to be ignored. */ #define LEN_CMSG_DATA(cmsg) \ - ((cmsg)->cmsg_len - ((char*)CMSG_DATA(cmsg) - (char*)(cmsg))) + ((cmsg)->cmsg_len < sizeof (struct cmsghdr) ? 0 : \ + (cmsg)->cmsg_len - ((char*)CMSG_DATA(cmsg) - (char*)(cmsg))) #define NXT_CMSG_HDR(cmsg) \ ((struct cmsghdr*)(((char*)(cmsg)) + CMSG_SPACE(LEN_CMSG_DATA(cmsg)))) #endif @@ -894,6 +898,15 @@ static size_t my_strnlen(const char *s, size_t maxlen) #define INET_CMSG_RECVTCLASS (1 << 1) /* am_recvtclass, am_tclass */ #define INET_CMSG_RECVTTL (1 << 2) /* am_recvttl, am_ttl */ +/* Inet flags */ +#define INET_FLG_BUFFER_SET (1 << 0) /* am_buffer has been set by user */ +#define INET_FLG_IS_IGNORED (1 << 1) /* If a fd is ignored by the inet_drv. + This flag should be set to true when + the fd is used outside of inet_drv. */ +#define INET_FLG_IS_IGNORED_RD (1 << 2) +#define INET_FLG_IS_IGNORED_WR (1 << 3) +#define INET_FLG_IS_IGNORED_PASS (1 << 4) + /* ** End of interface constants. **--------------------------------------------------------------------------*/ @@ -939,10 +952,11 @@ static size_t my_strnlen(const char *s, size_t maxlen) #define INET_IFNAMSIZ 16 /* INET Ignore states */ -#define INET_IGNORE_NONE 0 -#define INET_IGNORE_READ (1 << 0) -#define INET_IGNORE_WRITE (1 << 1) -#define INET_IGNORE_PASSIVE (1 << 2) +#define INET_IGNORE_CLEAR(desc) ((desc)->flags & ~(INET_IGNORE_READ|INET_IGNORE_WRITE|INET_IGNORE_PASSIVE)) +#define INET_IGNORED(desc) ((desc)->flags & INET_FLG_IS_IGNORED) +#define INET_IGNORE_READ (INET_FLG_IS_IGNORED|INET_FLG_IS_IGNORED_RD) +#define INET_IGNORE_WRITE (INET_FLG_IS_IGNORED|INET_FLG_IS_IGNORED_WR) +#define INET_IGNORE_PASSIVE (INET_FLG_IS_IGNORED|INET_FLG_IS_IGNORED_PASS) /* Max length of Erlang Term Buffer (for outputting structured terms): */ #ifdef HAVE_SCTP @@ -1124,9 +1138,7 @@ typedef struct { double send_avg; /* average packet size sent */ subs_list empty_out_q_subs; /* Empty out queue subscribers */ - int is_ignored; /* if a fd is ignored by the inet_drv. - This flag should be set to true when - the fd is used outside of inet_drv. */ + int flags; #ifdef HAVE_SETNS char *netns; /* Socket network namespace name as full file path */ @@ -4547,7 +4559,7 @@ static void desc_close(inet_descriptor* desc) * We should close the fd here, but the other driver might still * be selecting on it. */ - if (!desc->is_ignored) + if (!INET_IGNORED(desc)) driver_select(desc->port,(ErlDrvEvent)(long)desc->event, ERL_DRV_USE, 0); else @@ -6308,6 +6320,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) (long)desc->port, desc->s, ival)); if (ival < INET_MIN_BUFFER) ival = INET_MIN_BUFFER; desc->bufsz = ival; + desc->flags |= INET_FLG_BUFFER_SET; continue; case INET_LOPT_ACTIVE: @@ -6503,6 +6516,16 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) case INET_OPT_RCVBUF: type = SO_RCVBUF; DEBUGF(("inet_set_opts(%ld): s=%d, SO_RCVBUF=%d\r\n", (long)desc->port, desc->s, ival)); + if (!(desc->flags & INET_FLG_BUFFER_SET)) { + /* make sure we have desc->bufsz >= SO_RCVBUF */ + if (ival > (1 << 16) && desc->stype == SOCK_DGRAM && !IS_SCTP(desc)) + /* For UDP we don't want to automatically + set the buffer size to be larger than + the theoretical max MTU */ + desc->bufsz = 1 << 16; + else if (ival > desc->bufsz) + desc->bufsz = ival; + } break; case INET_OPT_LINGER: type = SO_LINGER; if (len < 4) @@ -6748,23 +6771,17 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) } DEBUGF(("inet_set_opts(%ld): s=%d returned %d\r\n", (long)desc->port, desc->s, res)); - if (type == SO_RCVBUF) { - /* make sure we have desc->bufsz >= SO_RCVBUF */ - if (ival > (1 << 16) && desc->stype == SOCK_DGRAM && !IS_SCTP(desc)) - /* For UDP we don't want to automatically - set the buffer size to be larger than - the theoretical max MTU */ - desc->bufsz = 1 << 16; - else if (ival > desc->bufsz) - desc->bufsz = ival; - } } if ( ((desc->stype == SOCK_STREAM) && IS_CONNECTED(desc)) || ((desc->stype == SOCK_DGRAM) && IS_OPEN(desc))) { - if (desc->active != old_active) + if (desc->active != old_active) { + /* Need to cancel the read_packet timer if we go from active to passive. */ + if (desc->active == INET_PASSIVE && desc->stype == SOCK_DGRAM) + driver_cancel_timer(desc->port); sock_select(desc, (FD_READ|FD_CLOSE), (desc->active>0)); + } /* XXX: UDP sockets could also trigger immediate read here NIY */ if ((desc->stype==SOCK_STREAM) && desc->active) { @@ -6906,6 +6923,7 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) if (desc->bufsz < INET_MIN_BUFFER) desc->bufsz = INET_MIN_BUFFER; + desc->flags |= INET_FLG_BUFFER_SET; res = 0; /* This does not affect the kernel buffer size */ continue; @@ -7027,6 +7045,7 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) smaller than the kernel one: */ if (desc->bufsz <= arg.ival) desc->bufsz = arg.ival; + desc->flags |= INET_FLG_BUFFER_SET; break; } case INET_OPT_SNDBUF: @@ -7037,10 +7056,6 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) arg_ptr = (char*) (&arg.ival); arg_sz = sizeof ( arg.ival); - /* Adjust the size of the user-level recv buffer, so it's not - smaller than the kernel one: */ - if (desc->bufsz <= arg.ival) - desc->bufsz = arg.ival; break; } case INET_OPT_REUSEADDR: @@ -9097,7 +9112,7 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) sys_memzero((char *)&desc->remote,sizeof(desc->remote)); - desc->is_ignored = 0; + desc->flags = 0; #ifdef HAVE_SETNS desc->netns = NULL; @@ -9499,19 +9514,19 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, if (desc->stype != SOCK_STREAM) return ctl_error(EINVAL, rbuf, rsize); - if (*buf == 1 && !desc->is_ignored) { + if (*buf == 1 && !INET_IGNORED(desc)) { sock_select(desc, (FD_READ|FD_WRITE|FD_CLOSE|ERL_DRV_USE_NO_CALLBACK), 0); if (desc->active) - desc->is_ignored = INET_IGNORE_READ; + desc->flags |= INET_IGNORE_READ; else - desc->is_ignored = INET_IGNORE_PASSIVE; - } else if (*buf == 0 && desc->is_ignored) { + desc->flags |= INET_IGNORE_PASSIVE; + } else if (*buf == 0 && INET_IGNORED(desc)) { int flags = FD_CLOSE; - if (desc->is_ignored & INET_IGNORE_READ) + if (desc->flags & INET_IGNORE_READ) flags |= FD_READ; - if (desc->is_ignored & INET_IGNORE_WRITE) + if (desc->flags & INET_IGNORE_WRITE) flags |= FD_WRITE; - desc->is_ignored = INET_IGNORE_NONE; + desc->flags = INET_IGNORE_CLEAR(desc); if (flags != FD_CLOSE) sock_select(desc, flags, 1); } else @@ -9951,6 +9966,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, { tcp_descriptor* desc = (tcp_descriptor*)e; + cmd -= ERTS_INET_DRV_CONTROL_MAGIC_NUMBER; switch(cmd) { case INET_REQ_OPEN: { /* open socket and return internal index */ int domain; @@ -10226,17 +10242,17 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, if (enq_async(INETP(desc), tbuf, TCP_REQ_RECV) < 0) return ctl_error(EALREADY, rbuf, rsize); - if (INETP(desc)->is_ignored || tcp_recv(desc, n) == 0) { + if (INET_IGNORED(INETP(desc)) || tcp_recv(desc, n) == 0) { if (timeout == 0) async_error_am(INETP(desc), am_timeout); else { if (timeout != INET_INFINITY) add_multi_timer(desc, INETP(desc)->port, 0, timeout, &tcp_inet_recv_timeout); - if (!INETP(desc)->is_ignored) + if (!INET_IGNORED(INETP(desc))) sock_select(INETP(desc),(FD_READ|FD_CLOSE),1); else - INETP(desc)->is_ignored |= INET_IGNORE_READ; + INETP(desc)->flags |= INET_IGNORE_READ; } } return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize); @@ -11103,7 +11119,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event) #ifdef DEBUG long port = (long) desc->inet.port; /* Used after driver_exit() */ #endif - ASSERT(!INETP(desc)->is_ignored); + ASSERT(!INET_IGNORED(INETP(desc))); DEBUGF(("tcp_inet_input(%ld) {s=%d\r\n", port, desc->inet.s)); /* XXX fprintf(stderr,"tcp_inet_input(%ld) {s=%d}\r\n",(long) desc->inet.port, desc->inet.s); */ if (desc->inet.state == INET_STATE_ACCEPTING) { @@ -11438,8 +11454,8 @@ static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev) DEBUGF(("tcp_sendv(%ld): s=%d, about to send "LLU","LLU" bytes\r\n", (long)desc->inet.port, desc->inet.s, (llu_t)h_len, (llu_t)len)); - if (INETP(desc)->is_ignored) { - INETP(desc)->is_ignored |= INET_IGNORE_WRITE; + if (INET_IGNORED(INETP(desc))) { + INETP(desc)->flags |= INET_IGNORE_WRITE; n = 0; } else if (desc->tcp_add_flags & TCP_ADDF_DELAY_SEND) { driver_enqv(ix, ev, 0); @@ -11474,7 +11490,7 @@ static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev) DEBUGF(("tcp_sendv(%ld): s=%d, Send failed, queuing\r\n", (long)desc->inet.port, desc->inet.s)); driver_enqv(ix, ev, n); - if (!INETP(desc)->is_ignored) + if (!INET_IGNORED(INETP(desc))) sock_select(INETP(desc),(FD_WRITE|FD_CLOSE), 1); } return 0; @@ -11543,8 +11559,8 @@ static int tcp_send(tcp_descriptor* desc, char* ptr, ErlDrvSizeT len) DEBUGF(("tcp_send(%ld): s=%d, about to send "LLU","LLU" bytes\r\n", (long)desc->inet.port, desc->inet.s, (llu_t)h_len, (llu_t)len)); - if (INETP(desc)->is_ignored) { - INETP(desc)->is_ignored |= INET_IGNORE_WRITE; + if (INET_IGNORED(INETP(desc))) { + INETP(desc)->flags |= INET_IGNORE_WRITE; n = 0; } else if (desc->tcp_add_flags & TCP_ADDF_DELAY_SEND) { sock_send(desc->inet.s, buf, 0, 0); @@ -11577,7 +11593,7 @@ static int tcp_send(tcp_descriptor* desc, char* ptr, ErlDrvSizeT len) n -= h_len; driver_enq(ix, ptr+n, len-n); } - if (!INETP(desc)->is_ignored) + if (!INET_IGNORED(INETP(desc))) sock_select(INETP(desc),(FD_WRITE|FD_CLOSE), 1); } return 0; @@ -11858,7 +11874,7 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) int ret = 0; ErlDrvPort ix = desc->inet.port; - ASSERT(!INETP(desc)->is_ignored); + ASSERT(!INET_IGNORED(INETP(desc))); DEBUGF(("tcp_inet_output(%ld) {s=%d\r\n", (long)desc->inet.port, desc->inet.s)); if (desc->inet.state == INET_STATE_CONNECTING) { @@ -12180,6 +12196,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int type = SOCK_DGRAM; int af = AF_INET; + cmd -= ERTS_INET_DRV_CONTROL_MAGIC_NUMBER; switch(cmd) { case INET_REQ_OPEN: /* open socket and return internal index */ DEBUGF(("packet_inet_ctl(%ld): OPEN\r\n", (long)desc->port)); @@ -12532,9 +12549,12 @@ static void packet_inet_timeout(ErlDrvData e) { udp_descriptor * udesc = (udp_descriptor*) e; inet_descriptor * desc = INETP(udesc); - if (!(desc->active)) + if (!(desc->active)) { sock_select(desc, FD_READ, 0); - async_error_am (desc, am_timeout); + async_error_am (desc, am_timeout); + } else { + (void)packet_inet_input(udesc, desc->s); + } } @@ -12890,6 +12910,15 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event) sock_select(desc, FD_READ, 1); } #endif + + /* We set a timer on the port to trigger now. + This emulates a "yield" operation as that is + what we want to do here. We do *NOT* do a deselect + as that is expensive, instead we check if the + socket it still active when the timeout triggers + and if it is not, then we just ignore the timeout */ + driver_set_timer(desc->port, 0); + return count; } @@ -12956,38 +12985,40 @@ make_noninheritable_handle(SOCKET s) static void fire_multi_timers(tcp_descriptor *desc, ErlDrvPort port, ErlDrvData data) { - ErlDrvTime next_timeout; - MultiTimerData *curr = desc->mtd; - if (!curr) { - ASSERT(0); - return; + ErlDrvTime next_timeout = 0; + if (!desc->mtd) { + ASSERT(0); + return; } #ifdef DEBUG { ErlDrvTime chk = erl_drv_monotonic_time(ERL_DRV_MSEC); - ASSERT(chk >= curr->when); + ASSERT(chk >= desc->mtd->when); } #endif do { - MultiTimerData *save = curr; + MultiTimerData save = *desc->mtd; - (*(save->timeout_function))(data,save->caller); + /* We first remove the timer so that the timeout_functions has + can call clean_multi_timers without breaking anything */ + if (desc->mtd_cache == NULL) { + desc->mtd_cache = desc->mtd; + } else { + FREE(desc->mtd); + } - curr = curr->next; + desc->mtd = save.next; + if (desc->mtd != NULL) + desc->mtd->prev = NULL; - if (desc->mtd_cache == NULL) - desc->mtd_cache = save; - else - FREE(save); + (*(save.timeout_function))(data,save.caller); - if (curr == NULL) { - desc->mtd = NULL; + if (desc->mtd == NULL) return; - } - curr->prev = NULL; - next_timeout = curr->when - erl_drv_monotonic_time(ERL_DRV_MSEC); + + next_timeout = desc->mtd->when - erl_drv_monotonic_time(ERL_DRV_MSEC); } while (next_timeout <= 0); - desc->mtd = curr; + driver_set_timer(port, (unsigned long) next_timeout); } diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index 28c6cc0f94..d2a524cb6c 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -394,6 +394,8 @@ static ErlDrvSSizeT ttysl_control(ErlDrvData drv_data, { char resbuff[2*sizeof(Uint32)]; ErlDrvSizeT res_size; + + command -= ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER; switch (command) { case CTRL_OP_GET_WINSIZE: { @@ -419,7 +421,7 @@ static ErlDrvSSizeT ttysl_control(ErlDrvData drv_data, } break; default: - return 0; + return -1; } if (rlen < res_size) { *rbuf = driver_alloc(res_size); diff --git a/erts/emulator/drivers/win32/ttsl_drv.c b/erts/emulator/drivers/win32/ttsl_drv.c index 99e7fb25a4..d19bfa3079 100644 --- a/erts/emulator/drivers/win32/ttsl_drv.c +++ b/erts/emulator/drivers/win32/ttsl_drv.c @@ -176,6 +176,8 @@ static ErlDrvSSizeT ttysl_control(ErlDrvData drv_data, { char resbuff[2*sizeof(Uint32)]; ErlDrvSizeT res_size; + + command -= ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER; switch (command) { case CTRL_OP_GET_WINSIZE: { @@ -201,7 +203,7 @@ static ErlDrvSSizeT ttysl_control(ErlDrvData drv_data, } break; default: - return 0; + return -1; } if (rlen < res_size) { *rbuf = driver_alloc(res_size); diff --git a/erts/emulator/nifs/common/prim_file_nif.c b/erts/emulator/nifs/common/prim_file_nif.c index b34bf11205..a78ee62677 100644 --- a/erts/emulator/nifs/common/prim_file_nif.c +++ b/erts/emulator/nifs/common/prim_file_nif.c @@ -38,7 +38,6 @@ static void unload(ErlNifEnv *env, void* priv_data); static ErlNifResourceType *efile_resource_type; -static ERL_NIF_TERM am_erts_prim_file; static ERL_NIF_TERM am_close; static ERL_NIF_TERM am_ok; @@ -220,7 +219,6 @@ static int load(ErlNifEnv *env, void** priv_data, ERL_NIF_TERM prim_file_pid) ASSERT(!"bad pid passed to prim_file_nif"); } - am_erts_prim_file = enif_make_atom(env, "erts_prim_file"); am_close = enif_make_atom(env, "close"); am_ok = enif_make_atom(env, "ok"); @@ -933,7 +931,7 @@ static ERL_NIF_TERM set_permissions_nif(ErlNifEnv *env, int argc, const ERL_NIF_ posix_errno_t posix_errno; efile_path_t path; - Uint permissions; + unsigned int permissions; if(argc != 2 || !enif_get_uint(env, argv[1], &permissions)) { return enif_make_badarg(env); @@ -952,7 +950,7 @@ static ERL_NIF_TERM set_owner_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM a posix_errno_t posix_errno; efile_path_t path; - Sint uid, gid; + int uid, gid; if(argc != 3 || !enif_get_int(env, argv[1], &uid) || !enif_get_int(env, argv[2], &gid)) { diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c index c681fa481f..c39cd01e1c 100644 --- a/erts/emulator/sys/common/erl_check_io.c +++ b/erts/emulator/sys/common/erl_check_io.c @@ -962,7 +962,7 @@ enif_select(ErlNifEnv* env, ErtsDrvSelectDataState *free_select = NULL; ErtsNifSelectDataState *free_nif = NULL; - ASSERT(!resource->monitors); + ASSERT(!erts_dbg_is_resource_dying(resource)); #ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS if (!grow_drv_ev_state(fd)) { @@ -2262,14 +2262,14 @@ erts_check_io_info(void *proc) #if ERTS_POLL_USE_FALLBACK erts_poll_info_flbk(get_fallback_pollset(), &piv[0]); - piv[0].poll_threads = 1; + piv[0].poll_threads = 0; piv[0].active_fds = 0; piv++; #endif #if ERTS_POLL_USE_SCHEDULER_POLLING erts_poll_info(get_scheduler_pollset(0), &piv[0]); - piv[0].poll_threads = 1; + piv[0].poll_threads = 0; piv[0].active_fds = 0; piv++; #endif diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c index 51d50933ff..c71d23f58c 100644 --- a/erts/emulator/sys/common/erl_poll.c +++ b/erts/emulator/sys/common/erl_poll.c @@ -872,8 +872,8 @@ update_pollset(ErtsPollSet *ps, int fd, ErtsPollOp op, ErtsPollEvents events) } } -#if defined(EV_DISPATCH) && !defined(__OpenBSD__) - /* If we have EV_DISPATCH we use it, unless we are on OpenBSD as the +#if defined(EV_DISPATCH) && !(defined(__OpenBSD__) || defined(__NetBSD__)) + /* If we have EV_DISPATCH we use it, unless we are on OpenBSD/NetBSD as the behavior of EV_EOF seems to be edge triggered there and we need it to be level triggered. @@ -2326,6 +2326,7 @@ uint32_t epoll_events(int kp_fd, int fd) { /* For epoll we read the information about what is selected upon from the proc fs.*/ char fname[30]; + char s[256]; FILE *f; unsigned int pos, flags, mnt_id; int line = 0; @@ -2343,12 +2344,12 @@ uint32_t epoll_events(int kp_fd, int fd) } if (fscanf(f,"\nmnt_id:\t%x\n", &mnt_id)); line += 3; - while (!feof(f)) { + while (fgets(s, sizeof(s) / sizeof(*s), f)) { /* tfd: 10 events: 40000019 data: 180000000a */ int ev_fd; uint32_t events; uint64_t data; - if (fscanf(f,"tfd:%d events:%x data:%llx\n", &ev_fd, &events, + if (sscanf(s,"tfd:%d events:%x data:%llx", &ev_fd, &events, (unsigned long long*)&data) != 3) { fprintf(stderr,"failed to parse file %s on line %d, errno = %d\n", fname, line, @@ -2392,6 +2393,7 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps, /* For epoll we read the information about what is selected upon from the proc fs.*/ char fname[30]; + char s[256]; FILE *f; unsigned int pos, flags, mnt_id; int line = 0; @@ -2410,12 +2412,12 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps, } if (fscanf(f,"\nmnt_id:\t%x\n", &mnt_id)); line += 3; - while (!feof(f)) { + while (fgets(s, sizeof(s) / sizeof(*s), f)) { /* tfd: 10 events: 40000019 data: 180000000a */ int fd; uint32_t events; uint64_t data; - if (fscanf(f,"tfd:%d events:%x data:%llx\n", &fd, &events, + if (sscanf(s,"tfd:%d events:%x data:%llx", &fd, &events, (unsigned long long*)&data) != 3) { fprintf(stderr,"failed to parse file %s on line %d, errno = %d\n", fname, line, errno); diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c index 816bdea9c5..042a091db1 100644 --- a/erts/emulator/sys/unix/sys_drivers.c +++ b/erts/emulator/sys/unix/sys_drivers.c @@ -732,7 +732,8 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name, proto->u.start.fds[1] = ifd[1]; proto->u.start.fds[2] = stderrfd; proto->u.start.port_id = opts->exit_status ? erts_drvport2id(port_num) : THE_NON_VALUE; - if (erl_drv_port_control(forker_port, 'S', (char*)proto, sizeof(*proto))) { + if (erl_drv_port_control(forker_port, ERTS_FORKER_DRV_CONTROL_MAGIC_NUMBER, + (char*)proto, sizeof(*proto))) { /* The forker port has been killed, we close both fd's which will make open_port throw an epipe error */ close(ofd[0]); @@ -759,6 +760,9 @@ static ErlDrvSSizeT spawn_control(ErlDrvData e, unsigned int cmd, char *buf, ErtsSysDriverData *dd = (ErtsSysDriverData*)e; ErtsSysForkerProto *proto = (ErtsSysForkerProto *)buf; + if (cmd != ERTS_SPAWN_DRV_CONTROL_MAGIC_NUMBER) + return -1; + ASSERT(len == sizeof(*proto)); ASSERT(proto->action == ErtsSysForkerProtoAction_SigChld); @@ -799,6 +803,8 @@ static ErlDrvSSizeT fd_control(ErlDrvData drv_data, { int fd = (int)(long)drv_data; char resbuff[2*sizeof(Uint32)]; + + command -= ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER; switch (command) { case FD_CTRL_OP_GET_WINSIZE: { @@ -810,7 +816,7 @@ static ErlDrvSSizeT fd_control(ErlDrvData drv_data, } break; default: - return 0; + return -1; } if (rlen < 2*sizeof(Uint32)) { *rbuf = driver_alloc(2*sizeof(Uint32)); @@ -998,9 +1004,9 @@ static void clear_fd_data(ErtsSysFdData *fdd) fdd->psz = 0; } -static void nbio_stop_fd(ErlDrvPort prt, ErtsSysFdData *fdd) +static void nbio_stop_fd(ErlDrvPort prt, ErtsSysFdData *fdd, int use) { - driver_select(prt, abs(fdd->fd), ERL_DRV_USE_NO_CALLBACK|DO_READ|DO_WRITE, 0); + driver_select(prt, abs(fdd->fd), use ? ERL_DRV_USE_NO_CALLBACK : 0|DO_READ|DO_WRITE, 0); clear_fd_data(fdd); SET_BLOCKING(abs(fdd->fd)); @@ -1020,11 +1026,11 @@ static void fd_stop(ErlDrvData ev) /* Does not close the fds */ if (dd->ifd) { sz += sizeof(ErtsSysFdData); - nbio_stop_fd(prt, dd->ifd); + nbio_stop_fd(prt, dd->ifd, 1); } if (dd->ofd && dd->ofd != dd->ifd) { sz += sizeof(ErtsSysFdData); - nbio_stop_fd(prt, dd->ofd); + nbio_stop_fd(prt, dd->ofd, 1); } erts_free(ERTS_ALC_T_DRV_TAB, dd); @@ -1070,12 +1076,12 @@ static void stop(ErlDrvData ev) ErlDrvPort prt = dd->port_num; if (dd->ifd) { - nbio_stop_fd(prt, dd->ifd); + nbio_stop_fd(prt, dd->ifd, 0); driver_select(prt, abs(dd->ifd->fd), ERL_DRV_USE, 0); /* close(ifd); */ } if (dd->ofd && dd->ofd != dd->ifd) { - nbio_stop_fd(prt, dd->ofd); + nbio_stop_fd(prt, dd->ofd, 0); driver_select(prt, abs(dd->ofd->fd), ERL_DRV_USE, 0); /* close(ofd); */ } @@ -1693,7 +1699,8 @@ static void forker_sigchld(Eterm port_id, int error) already used by the spawn_driver, we use control instead. Note that when using erl_drv_port_control it is an asynchronous control. */ - erl_drv_port_control(port_id, 'S', (char*)proto, sizeof(*proto)); + erl_drv_port_control(port_id, ERTS_SPAWN_DRV_CONTROL_MAGIC_NUMBER, + (char*)proto, sizeof(*proto)); } static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd) @@ -1778,6 +1785,9 @@ static ErlDrvSSizeT forker_control(ErlDrvData e, unsigned int cmd, char *buf, ErlDrvPort port_num = (ErlDrvPort)e; int res; + if (cmd != ERTS_FORKER_DRV_CONTROL_MAGIC_NUMBER) + return -1; + if (first_call) { /* * Do driver_select here when schedulers and their pollsets have started. diff --git a/erts/emulator/test/atomics_SUITE.erl b/erts/emulator/test/atomics_SUITE.erl index 8c42354770..a5407c42ee 100644 --- a/erts/emulator/test/atomics_SUITE.erl +++ b/erts/emulator/test/atomics_SUITE.erl @@ -126,6 +126,9 @@ unsigned_limits(Config) when is_list(Config) -> Min = atomics:add_get(Ref, 1, 1), Max = atomics:sub_get(Ref, 1, 1), + atomics:put(Ref, 1, Max), + io:format("Max=~p~n", [atomics:get(Ref, 1)]), + {'EXIT',{badarg,_}} = (catch atomics:add(Ref, 1, Max+1)), IncrMin = -(1 bsl (Bits-1)), ok = atomics:put(Ref, 1, -IncrMin), diff --git a/erts/emulator/test/big_SUITE.erl b/erts/emulator/test/big_SUITE.erl index 0a42b09903..3b9b9e5989 100644 --- a/erts/emulator/test/big_SUITE.erl +++ b/erts/emulator/test/big_SUITE.erl @@ -24,7 +24,7 @@ -export([t_div/1, eq_28/1, eq_32/1, eq_big/1, eq_math/1, big_literals/1, borders/1, negative/1, big_float_1/1, big_float_2/1, - bxor_2pow/1, + bxor_2pow/1, band_2pow/1, shift_limit_1/1, powmod/1, system_limit/1, toobig/1, otp_6692/1]). %% Internal exports. @@ -43,7 +43,7 @@ suite() -> all() -> [t_div, eq_28, eq_32, eq_big, eq_math, big_literals, borders, negative, {group, big_float}, shift_limit_1, - bxor_2pow, + bxor_2pow, band_2pow, powmod, system_limit, toobig, otp_6692]. groups() -> @@ -168,7 +168,11 @@ eval({op,_,Op,A0,B0}, LFH) -> Res = eval_op(Op, A, B), erlang:garbage_collect(), Res; -eval({integer,_,I}, _) -> I; +eval({integer,_,I}, _) -> + %% "Parasitic" ("symbiotic"?) test of squaring all numbers + %% found in the test data. + test_squaring(I), + I; eval({call,_,{atom,_,Local},Args0}, LFH) -> Args = eval_list(Args0, LFH), LFH(Local, Args). @@ -192,6 +196,18 @@ eval_op('bxor', A, B) -> A bxor B; eval_op('bsl', A, B) -> A bsl B; eval_op('bsr', A, B) -> A bsr B. +test_squaring(I) -> + %% Multiplying an integer by itself is specially optimized, so we + %% should take special care to test squaring. The optimization + %% will kick in when the two operands have the same address. + Sqr = I * I, + + %% This expression will be multiplied in the usual way, because + %% the the two operands for '*' are stored at different addresses. + Sqr = I * ((I + id(1)) - id(1)), + + ok. + %% Built in test functions fac(0) -> 1; @@ -456,3 +472,38 @@ my_bxor(A, B, N, Acc0) -> false -> Acc0 bor (1 bsl N) end, my_bxor(A bsr 1, B bsr 1, N+1, Acc1). + + +%% ERL-804 +band_2pow(_Config) -> + IL = lists:seq(8*3, 8*16, 4), + JL = lists:seq(0, 64), + [band_2pow_1((1 bsl I), (1 bsl J)) + || I <- IL, J <- JL], + ok. + +band_2pow_1(A, B) -> + for(-1,1, fun(Ad) -> + for(-1,1, fun(Bd) -> + band_2pow_2(A+Ad, B+Bd), + band_2pow_2(-A+Ad, B+Bd), + band_2pow_2(A+Ad, -B+Bd), + band_2pow_2(-A+Ad, -B+Bd) + end) + end). + +band_2pow_2(A, B) -> + Correct = my_band(A, B), + case A band B of + Correct -> ok; + Wrong -> + io:format("~.16# band ~.16#\n", [A,B]), + io:format("Expected ~.16#\n", [Correct]), + io:format("Got ~.16#\n", [Wrong]), + ct:fail({failed, 'band'}) + + end. + +%% Implement band without band +my_band(A, B) -> + bnot ((bnot A) bor (bnot B)). diff --git a/erts/emulator/test/dirty_bif_SUITE.erl b/erts/emulator/test/dirty_bif_SUITE.erl index 46eb0cba58..4f5ad0295a 100644 --- a/erts/emulator/test/dirty_bif_SUITE.erl +++ b/erts/emulator/test/dirty_bif_SUITE.erl @@ -38,7 +38,8 @@ dirty_process_info/1, dirty_process_register/1, dirty_process_trace/1, - code_purge/1]). + code_purge/1, + otp_15688/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -64,7 +65,8 @@ all() -> dirty_process_info, dirty_process_register, dirty_process_trace, - code_purge]. + code_purge, + otp_15688]. init_per_suite(Config) -> case erlang:system_info(dirty_cpu_schedulers) of @@ -498,10 +500,58 @@ code_purge(Config) when is_list(Config) -> true = Time =< 1000, ok. +otp_15688(Config) when is_list(Config) -> + ImBack = make_ref(), + {See, SeeMon} = spawn_monitor(fun () -> + erts_debug:dirty_io(wait, 2000), + exit(ImBack) + end), + wait_until(fun () -> + [{current_function, {erts_debug, dirty_io, 2}}, + {status, running}] + == process_info(See, + [current_function, status]) + end), + {Ser1, Ser1Mon} = spawn_monitor(fun () -> + erlang:suspend_process(See, + [asynchronous]) + end), + erlang:suspend_process(See, [asynchronous]), + receive {'DOWN', Ser1Mon, process, Ser1, normal} -> ok end, + + %% Verify that we sent the suspend request while it was executing dirty... + [{current_function, {erts_debug, dirty_io, 2}}, + {status, running}] = process_info(See, [current_function, status]), + + wait_until(fun () -> + {status, suspended} == process_info(See, status) + end), + erlang:resume_process(See), + + receive + {'DOWN', SeeMon, process, See, Reason} -> + ImBack = Reason + after 4000 -> + %% Resume bug seems to have hit us... + PI = process_info(See), + exit(See, kill), + ct:fail({suspendee_stuck, PI}) + end. + + %% %% Internal... %% +wait_until(Fun) -> + case Fun() of + true -> + ok; + _ -> + receive after 100 -> ok end, + wait_until(Fun) + end. + access_dirty_process(Config, Start, Test, Finish) -> {ok, Node} = start_node(Config, ""), [ok] = mcall(Node, diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl index bd62708aa7..1d2ae4fb51 100644 --- a/erts/emulator/test/driver_SUITE.erl +++ b/erts/emulator/test/driver_SUITE.erl @@ -1069,14 +1069,19 @@ get_stable_check_io_info(N) -> get_check_io_total(ChkIo) -> ct:log("ChkIo = ~p~n",[ChkIo]), {Fallback, Rest} = get_fallback(ChkIo), + OnlyPollThreads = [PS || PS <- Rest, not is_scheduler_pollset(PS)], add_fallback_infos(Fallback, - lists:foldl(fun(Pollset, Acc) -> - lists:zipwith(fun(A, B) -> - add_pollset_infos(A,B) - end, - Pollset, Acc) - end, - hd(Rest), tl(Rest))). + lists:foldl( + fun(Pollset, Acc) -> + lists:zipwith(fun(A, B) -> + add_pollset_infos(A,B) + end, + Pollset, Acc) + end, + hd(OnlyPollThreads), tl(OnlyPollThreads))). + +is_scheduler_pollset(Pollset) -> + proplists:get_value(poll_threads, Pollset) == 0. add_pollset_infos({Tag, A}=TA , {Tag, B}=TB) -> case tag_type(Tag) of diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index a2f3489943..ca5f90621f 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -1175,6 +1175,15 @@ maps(Config) when is_list(Config) -> M2 = maps_from_list_nif(maps:to_list(M2)), M3 = maps_from_list_nif(maps:to_list(M3)), + %% Test different map sizes (OTP-15567) + repeat_while(fun({35,_}) -> false; + ({K,Map}) -> + Map = maps_from_list_nif(maps:to_list(Map)), + Map = maps:filter(fun(K,V) -> V =:= K*100 end, Map), + {K+1, maps:put(K,K*100,Map)} + end, + {1,#{}}), + has_duplicate_keys = maps_from_list_nif([{1,1},{1,1}]), verify_tmpmem(TmpMem), @@ -2471,6 +2480,13 @@ repeat(0, _, Arg) -> repeat(N, Fun, Arg0) -> repeat(N-1, Fun, Fun(Arg0)). +repeat_while(Fun, Acc0) -> + case Fun(Acc0) of + false -> ok; + Acc1 -> + repeat_while(Fun, Acc1) + end. + check(Exp,Got,Line) -> case Got of Exp -> Exp; diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl index f15217814a..6b834705cf 100644 --- a/erts/emulator/test/num_bif_SUITE.erl +++ b/erts/emulator/test/num_bif_SUITE.erl @@ -504,6 +504,10 @@ t_integer_to_string(Config) when is_list(Config) -> test_its("A", 10, 16), test_its("D4BE", 54462, 16), test_its("-D4BE", -54462, 16), + test_its("FFFFFFFFFF", 1099511627775, 16), + test_its("123456789ABCDEF123456789ABCDEF123456789ABCDEF", + 108977460683796539709587792812439445667270661579197935, + 16), lists:foreach(fun(Value) -> {'EXIT', {badarg, _}} = @@ -515,12 +519,14 @@ t_integer_to_string(Config) when is_list(Config) -> ok. test_its(List,Int) -> - Int = list_to_integer(List), - Int = binary_to_integer(list_to_binary(List)). + List = integer_to_list(Int), + Binary = list_to_binary(List), + Binary = integer_to_binary(Int). test_its(List,Int,Base) -> - Int = list_to_integer(List, Base), - Int = binary_to_integer(list_to_binary(List), Base). + List = integer_to_list(Int, Base), + Binary = list_to_binary(List), + Binary = integer_to_binary(Int, Base). %% Tests binary_to_integer/1. diff --git a/erts/emulator/test/persistent_term_SUITE.erl b/erts/emulator/test/persistent_term_SUITE.erl index 58cd3276b0..93eb026ced 100644 --- a/erts/emulator/test/persistent_term_SUITE.erl +++ b/erts/emulator/test/persistent_term_SUITE.erl @@ -6,7 +6,7 @@ %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at -%5 +%% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software @@ -21,7 +21,7 @@ -module(persistent_term_SUITE). -include_lib("common_test/include/ct.hrl"). --export([all/0,suite/0, +-export([all/0,suite/0,init_per_suite/1,end_per_suite/1, basic/1,purging/1,sharing/1,get_trapping/1, info/1,info_trapping/1,killed_while_trapping/1, off_heap_values/1,keys/1,collisions/1, @@ -39,39 +39,50 @@ all() -> killed_while_trapping,off_heap_values,keys,collisions, init_restart]. +init_per_suite(Config) -> + %% Put a term in the dict so that we know that the testcases handle + %% stray terms left by stdlib or other test suites. + persistent_term:put(init_per_suite, {?MODULE}), + Config. + +end_per_suite(Config) -> + persistent_term:erase(init_per_suite), + Config. + basic(_Config) -> Chk = chk(), N = 777, Seq = lists:seq(1, N), - par(2, N, Seq), - seq(3, Seq), - seq(3, Seq), %Same values. + par(2, N, Seq, Chk), + seq(3, Seq, Chk), + seq(3, Seq, Chk), %Same values. _ = [begin Key = {?MODULE,{key,I}}, true = persistent_term:erase(Key), false = persistent_term:erase(Key), - {'EXIT',{badarg,_}} = (catch persistent_term:get(Key)) + {'EXIT',{badarg,_}} = (catch persistent_term:get(Key)), + {not_present,Key} = persistent_term:get(Key, {not_present,Key}) end || I <- Seq], - [] = [P || {{?MODULE,_},_}=P <- persistent_term:get()], + [] = [P || {{?MODULE,_},_}=P <- pget(Chk)], chk(Chk). -par(C, N, Seq) -> +par(C, N, Seq, Chk) -> _ = [spawn_link(fun() -> ok = persistent_term:put({?MODULE,{key,I}}, {value,C*I}) end) || I <- Seq], - Result = wait(N), + Result = wait(N, Chk), _ = [begin Double = C*I, {{?MODULE,{key,I}},{value,Double}} = Res end || {I,Res} <- lists:zip(Seq, Result)], ok. -seq(C, Seq) -> +seq(C, Seq, Chk) -> _ = [ok = persistent_term:put({?MODULE,{key,I}}, {value,C*I}) || I <- Seq], - All = persistent_term:get(), - All = [P || {{?MODULE,_},_}=P <- persistent_term:get()], + All = pget(Chk), + All = [P || {{?MODULE,_},_}=P <- All], All = [{Key,persistent_term:get(Key)} || {Key,_} <- All], Result = lists:sort(All), _ = [begin @@ -80,15 +91,15 @@ seq(C, Seq) -> end || {I,Res} <- lists:zip(Seq, Result)], ok. -wait(N) -> - All = [P || {{?MODULE,_},_}=P <- persistent_term:get()], +wait(N, Chk) -> + All = [P || {{?MODULE,_},_}=P <- pget(Chk)], case length(All) of N -> All = [{Key,persistent_term:get(Key)} || {Key,_} <- All], lists:sort(All); _ -> receive after 10 -> ok end, - wait(N) + wait(N, Chk) end. %% Make sure that terms that have been erased are copied into all @@ -200,23 +211,23 @@ get_trapping(_Config) -> _ -> 1000 end, spawn_link(fun() -> get_trapping_create(N) end), - All = do_get_trapping(N, []), + All = do_get_trapping(N, [], Chk), N = get_trapping_check_result(lists:sort(All), 1), erlang:garbage_collect(), get_trapping_erase(N), chk(Chk). -do_get_trapping(N, Prev) -> - case persistent_term:get() of +do_get_trapping(N, Prev, Chk) -> + case pget(Chk) of Prev when length(Prev) >= N -> All = [P || {{?MODULE,{get_trapping,_}},_}=P <- Prev], case length(All) of N -> All; - _ -> do_get_trapping(N, Prev) + _ -> do_get_trapping(N, Prev, Chk) end; New -> receive after 1 -> ok end, - do_get_trapping(N, New) + do_get_trapping(N, New, Chk) end. get_trapping_create(0) -> @@ -331,25 +342,25 @@ info_trapping(_Config) -> _ -> 1000 end, spawn_link(fun() -> info_trapping_create(N) end), - All = do_info_trapping(N, 0), + All = do_info_trapping(N, 0, Chk), N = info_trapping_check_result(lists:sort(All), 1), erlang:garbage_collect(), info_trapping_erase(N), chk(Chk). -do_info_trapping(N, PrevMem) -> +do_info_trapping(N, PrevMem, Chk) -> case info_info() of - {N,Mem} -> + {M,Mem} when M >= N -> true = Mem >= PrevMem, - All = [P || {{?MODULE,{info_trapping,_}},_}=P <- persistent_term:get()], + All = [P || {{?MODULE,{info_trapping,_}},_}=P <- pget(Chk)], case length(All) of N -> All; - _ -> do_info_trapping(N, PrevMem) + _ -> do_info_trapping(N, PrevMem, Chk) end; {_,Mem} -> true = Mem >= PrevMem, receive after 1 -> ok end, - do_info_trapping(N, Mem) + do_info_trapping(N, Mem, Chk) end. info_trapping_create(0) -> @@ -462,17 +473,17 @@ collisions(_Config) -> _ = [V = persistent_term:get(K) || {K,V} <- Kvs], %% Now delete the persistent terms in random order. - collisions_delete(lists:keysort(2, Kvs)), + collisions_delete(lists:keysort(2, Kvs), Chk), chk(Chk). -collisions_delete([{Key,Val}|Kvs]) -> +collisions_delete([{Key,Val}|Kvs], Chk) -> Val = persistent_term:get(Key), true = persistent_term:erase(Key), - true = lists:sort(persistent_term:get()) =:= lists:sort(Kvs), + true = lists:sort(pget(Chk)) =:= lists:sort(Kvs), _ = [V = persistent_term:get(K) || {K,V} <- Kvs], - collisions_delete(Kvs); -collisions_delete([]) -> + collisions_delete(Kvs, Chk); +collisions_delete([], _) -> ok. colliding_keys() -> @@ -589,15 +600,16 @@ do_test_init_restart_cmd(File) -> %% and after each test case. chk() -> - persistent_term:info(). + {persistent_term:info(), persistent_term:get()}. -chk(Chk) -> - Chk = persistent_term:info(), +chk({Info, _Initial} = Chk) -> + Info = persistent_term:info(), Key = {?MODULE,?FUNCTION_NAME}, - ok = persistent_term:put(Key, {term,Chk}), + ok = persistent_term:put(Key, {term,Info}), Term = persistent_term:get(Key), true = persistent_term:erase(Key), chk_not_stuck(Term), + [persistent_term:erase(K) || {K, _} <- pget(Chk)], ok. chk_not_stuck(Term) -> @@ -612,3 +624,6 @@ chk_not_stuck(Term) -> _ -> ok end. + +pget({_, Initial}) -> + persistent_term:get() -- Initial. diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index 57eb082d64..0cb0d6c1e2 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -44,6 +44,7 @@ process_info_garbage_collection/1, process_info_smoke_all/1, process_info_status_handled_signal/1, + process_info_reductions/1, bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1, otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1, process_info_messages/1, process_flag_badarg/1, process_flag_heap_size/1, @@ -84,6 +85,7 @@ all() -> process_info_garbage_collection, process_info_smoke_all, process_info_status_handled_signal, + process_info_reductions, bump_reductions, low_prio, yield, yield2, otp_4725, bad_register, garbage_collect, process_info_messages, process_flag_badarg, process_flag_heap_size, @@ -1084,6 +1086,46 @@ process_info_status_handled_signal(Config) when is_list(Config) -> false = erlang:is_process_alive(P), ok. +%% OTP-15709 +%% Provoke a bug where process_info(reductions) returned wrong result +%% because REDS_IN (def_arg_reg[5]) is read when the process in not running. +process_info_reductions(Config) when is_list(Config) -> + pi_reductions_tester(spawn_link(fun() -> pi_reductions_spinnloop() end)), + pi_reductions_tester(spawn_link(fun() -> pi_reductions_recvloop() end)), + ok. + +pi_reductions_tester(Pid) -> + {_, DiffList} = + lists:foldl(fun(_, {Prev, Acc}) -> + %% Add another item that force sending the request + %% as a signal, like 'current_function'. + PI = process_info(Pid, [reductions, current_function]), + [{reductions,Reds}, {current_function,_}] = PI, + Diff = Reds - Prev, + {Diff, true} = {Diff, (Diff >= 0)}, + {Diff, true} = {Diff, (Diff =< 1000*1000)}, + {Reds, [Diff | Acc]} + end, + {0, []}, + lists:seq(1,10)), + unlink(Pid), + exit(Pid,kill), + io:format("Reduction diffs: ~p\n", [DiffList]), + ok. + +pi_reductions_spinnloop() -> + %% 6 args to make use of def_arg_reg[5] which is also used as REDS_IN + pi_reductions_spinnloop(1, atom, "hej", self(), make_ref(), 3.14). + +pi_reductions_spinnloop(A,B,C,D,E,F) -> + pi_reductions_spinnloop(B,C,D,E,F,A). + +pi_reductions_recvloop() -> + receive + "a free lunch" -> false + end. + + %% Tests erlang:bump_reductions/1. bump_reductions(Config) when is_list(Config) -> erlang:garbage_collect(), @@ -2104,6 +2146,13 @@ spawn_opt_max_heap_size(_Config) -> error_logger:add_report_handler(?MODULE, self()), + %% flush any prior messages in error_logger + Pid = spawn(fun() -> ok = nok end), + receive + {error, _, {emulator, _, [Pid|_]}} -> + flush() + end, + %% Test that numerical limit works max_heap_size_test(1024, 1024, true, true), @@ -2208,6 +2257,13 @@ receive_unexpected() -> ok end. +flush() -> + receive + _M -> flush() + after 0 -> + ok + end. + %% error_logger report handler proxy init(Pid) -> {ok, Pid}. diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl index 2e0dfa42f3..f61949c75b 100644 --- a/erts/emulator/test/scheduler_SUITE.erl +++ b/erts/emulator/test/scheduler_SUITE.erl @@ -1450,28 +1450,26 @@ poll_threads(Config) when is_list(Config) -> {Conc, PollType, KP} = get_ioconfig(Config), {Sched, SchedOnln, _} = get_sstate(Config, ""), + [1, 1] = get_ionum(Config,"+IOt 2 +IOp 2"), + [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 5"), + [1, 1] = get_ionum(Config, "+S 2 +IOPt 100 +IOPp 100"), + if Conc -> - [1, 1, 1] = get_ionum(Config,"+IOt 2 +IOp 2"), - [1, 1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 5"), - [1, 1, 1] = get_ionum(Config, "+S 2 +IOPt 100 +IOPp 100"), - [5, 1] = get_ionum(Config,"+IOt 5 +IOp 1"), - [3, 2, 1] = get_ionum(Config,"+IOt 5 +IOp 2"), - [2, 2, 2, 2, 2, 1] = get_ionum(Config,"+IOt 10 +IOPp 50"), + [5] = get_ionum(Config,"+IOt 5 +IOp 1"), + [3, 2] = get_ionum(Config,"+IOt 5 +IOp 2"), + [2, 2, 2, 2, 2] = get_ionum(Config,"+IOt 10 +IOPp 50"), - [2, 1] = get_ionum(Config, "+S 2 +IOPt 100"), - [4, 1] = get_ionum(Config, "+S 4 +IOPt 100"), - [4, 1] = get_ionum(Config, "+S 4:2 +IOPt 100"), - [4, 4, 1] = get_ionum(Config, "+S 8 +IOPt 100 +IOPp 25"), + [2] = get_ionum(Config, "+S 2 +IOPt 100"), + [4] = get_ionum(Config, "+S 4 +IOPt 100"), + [4] = get_ionum(Config, "+S 4:2 +IOPt 100"), + [4, 4] = get_ionum(Config, "+S 8 +IOPt 100 +IOPp 25"), fail = get_ionum(Config, "+IOt 1 +IOp 2"), ok; not Conc -> - [1, 1] = get_ionum(Config,"+IOt 2 +IOp 2"), - [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 5"), - [1, 1] = get_ionum(Config, "+S 2 +IOPt 100 +IOPp 100"), [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 1"), [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 2"), @@ -1515,7 +1513,8 @@ get_iostate(Config, Cmd)-> erlang:system_info(check_io) end]), IO = [IOState || IOState <- IOStates, - proplists:get_value(fallback, IOState) == false], + proplists:get_value(fallback, IOState) == false, + proplists:get_value(poll_threads, IOState) /= 0], stop_node(Node), IO; {error,timeout} -> diff --git a/erts/emulator/test/system_info_SUITE.erl b/erts/emulator/test/system_info_SUITE.erl index 21ab6b378a..4e663fed7f 100644 --- a/erts/emulator/test/system_info_SUITE.erl +++ b/erts/emulator/test/system_info_SUITE.erl @@ -37,8 +37,9 @@ -export([process_count/1, system_version/1, misc_smoke_tests/1, heap_size/1, wordsize/1, memory/1, ets_limit/1, atom_limit/1, - ets_count/1, - atom_count/1]). + ets_count/1, atom_count/1, system_logger/1]). + +-export([init/1, handle_event/2, handle_call/2]). suite() -> [{ct_hooks,[ts_install_cth]}, @@ -46,8 +47,8 @@ suite() -> all() -> [process_count, system_version, misc_smoke_tests, - ets_count, - heap_size, wordsize, memory, ets_limit, atom_limit, atom_count]. + ets_count, heap_size, wordsize, memory, ets_limit, atom_limit, atom_count, + system_logger]. %%% %%% The test cases ------------------------------------------------------------- @@ -573,3 +574,78 @@ atom_count(Config) when is_list(Config) -> true = Limit >= Count2, true = Count2 > Count1, ok. + + +system_logger(Config) when is_list(Config) -> + + TC = self(), + + ok = error_logger:add_report_handler(?MODULE, [TC]), + + generate_log_event(), + + flush(1, report_handler), + + Initial = erlang:system_info(system_logger), + + {Logger,_} = spawn_monitor(fun F() -> receive M -> TC ! {system_logger,M}, F() end end), + + Initial = erlang:system_flag(system_logger, Logger), + Logger = erlang:system_info(system_logger), + + generate_log_event(), + flush(1, system_logger), + + Logger = erlang:system_flag(system_logger, Logger), + + generate_log_event(), + flush(1, system_logger), + + exit(Logger, die), + receive {'DOWN',_,_,_,_} -> ok end, + + generate_log_event(), + flush(1, report_handler), + + logger = erlang:system_info(system_logger), + + logger = erlang:system_flag(system_logger, undefined), + generate_log_event(), + flush(), + + undefined = erlang:system_flag(system_logger, Initial), + + ok. + +flush() -> + receive + M -> + ct:fail({unexpected_message, M}) + after 0 -> + ok + end. + +flush(0, _Pat) -> + flush(); +flush(Cnt, Pat) -> + receive + M when element(1,M) =:= Pat -> + ct:log("~p",[M]), + flush(Cnt-1, Pat) + after 500 -> + ct:fail({missing, Cnt, Pat}) + end. + +generate_log_event() -> + {_Pid, Ref} = spawn_monitor(fun() -> ok = nok end), + receive {'DOWN', Ref, _, _, _} -> ok end. + +init([To]) -> + {ok, To}. + +handle_call(Msg, State) -> + {ok, Msg, State}. + +handle_event(Event, State) -> + State ! {report_handler, Event}, + {ok, State}. diff --git a/erts/emulator/test/z_SUITE.erl b/erts/emulator/test/z_SUITE.erl index 1c52e1a934..6549108126 100644 --- a/erts/emulator/test/z_SUITE.erl +++ b/erts/emulator/test/z_SUITE.erl @@ -251,7 +251,7 @@ pollset_size(Config) when is_list(Config) -> end. check_io_debug(Config) when is_list(Config) -> - case lists:keysearch(name, 1, erlang:system_info(check_io)) of + case lists:keysearch(name, 1, hd(erlang:system_info(check_io))) of {value, {name, erts_poll}} -> check_io_debug_test(); _ -> {skipped, "Not implemented in this emulator"} end. diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c index 0cb01fd4ef..23bbb86333 100644 --- a/erts/etc/common/erlexec.c +++ b/erts/etc/common/erlexec.c @@ -174,6 +174,7 @@ static char *plusz_val_switches[] = { "dbbl", "dntgc", "ebwt", + "tma", NULL }; diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c index bd218ff725..bb843a616b 100644 --- a/erts/etc/common/heart.c +++ b/erts/etc/common/heart.c @@ -500,7 +500,7 @@ message_loop(erlin_fd, erlout_fd) #if defined(__WIN32__) static void -kill_old_erlang(void){ +kill_old_erlang(int reason){ HANDLE erlh; DWORD exit_code; char* envvar = NULL; @@ -536,7 +536,8 @@ kill_old_erlang(void){ } #else static void -kill_old_erlang(void){ +kill_old_erlang(int reason) +{ pid_t pid; int i, res; int sig = SIGKILL; @@ -546,14 +547,25 @@ kill_old_erlang(void){ if (envvar && strcmp(envvar, "TRUE") == 0) return; - envvar = get_env(HEART_KILL_SIGNAL); - if (envvar && strcmp(envvar, "SIGABRT") == 0) { - print_error("kill signal SIGABRT requested"); - sig = SIGABRT; - } - if(heart_beat_kill_pid != 0){ - pid = (pid_t) heart_beat_kill_pid; + pid = (pid_t) heart_beat_kill_pid; + if (reason == R_CLOSED) { + print_error("Wait 5 seconds for Erlang to terminate nicely"); + for (i=0; i < 5; ++i) { + res = kill(pid, 0); /* check if alive */ + if (res < 0 && errno == ESRCH) + return; + sleep(1); + } + print_error("Erlang still alive, kill it"); + } + + envvar = get_env(HEART_KILL_SIGNAL); + if (envvar && strcmp(envvar, "SIGABRT") == 0) { + print_error("kill signal SIGABRT requested"); + sig = SIGABRT; + } + res = kill(pid,sig); for(i=0; i < 5 && res == 0; ++i){ sleep(1); @@ -677,7 +689,7 @@ do_terminate(int erlin_fd, int reason) { if(!command) print_error("Would reboot. Terminating."); else { - kill_old_erlang(); + kill_old_erlang(reason); /* High prio combined with system() works badly indeed... */ SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); win_system(command); @@ -685,7 +697,7 @@ do_terminate(int erlin_fd, int reason) { } free_env_val(command); } else { - kill_old_erlang(); + kill_old_erlang(reason); /* High prio combined with system() works badly indeed... */ SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); win_system(&cmd[0]); @@ -697,13 +709,13 @@ do_terminate(int erlin_fd, int reason) { if(!command) print_error("Would reboot. Terminating."); else { - kill_old_erlang(); + kill_old_erlang(reason); ret = system(command); print_error("Executed \"%s\" -> %d. Terminating.",command, ret); } free_env_val(command); } else { - kill_old_erlang(); + kill_old_erlang(reason); ret = system((char*)&cmd[0]); print_error("Executed \"%s\" -> %d. Terminating.",cmd, ret); } diff --git a/erts/etc/unix/Makefile b/erts/etc/unix/Makefile index 83c64d35fd..21a725cb88 100644 --- a/erts/etc/unix/Makefile +++ b/erts/etc/unix/Makefile @@ -30,7 +30,8 @@ opt debug lcnt: etc etc: etp-commands etp-commands: etp-commands.in - $(gen_verbose)sed 's:@ERL_TOP@:${ERL_TOP}:g' etp-commands.in > etp-commands + $(gen_verbose)sed -e 's:@ERL_TOP@:${ERL_TOP}:g' \ + etp-commands.in > etp-commands .PHONY: docs docs: diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src index 2e034513b0..bcd64d242e 100644 --- a/erts/etc/unix/cerl.src +++ b/erts/etc/unix/cerl.src @@ -224,7 +224,13 @@ while [ $# -gt 0 ]; do shift cargs="$cargs -rr" run_rr=yes - skip_erlexec=yes + case "$1" in + "replay"|"ps") + ;; + *) + skip_erlexec=yes + ;; + esac ;; *) break @@ -307,7 +313,26 @@ if [ "x$GDB" = "x" ]; then exec $taskset1 valgrind $valgrind_xml $valgrind_log $valgrind_misc_flags $BINDIR/$EMU_NAME $sched_arg $emu_xargs "$@" elif [ $run_rr = yes ]; then - exec rr record --ignore-nested $BINDIR/$EMU_NAME $emu_xargs "$@" + if [ $1 = replay ]; then + shift + cmdfile="/tmp/.cerlgdb.$$" + echo "set \$etp_beam_executable = \"$BINDIR/$EMU_NAME\"" > $cmdfile + if [ "$1" = "-p" ]; then + echo 'set $etp_rr_run_until_beam = 1' >> $cmdfile + fi + cat $ROOTDIR/erts/etc/unix/etp-commands.in >> $cmdfile + exec rr replay -x $cmdfile $* + elif [ $1 = ps ]; then + shift + rr ps $* | head -1 + ChildSetup=`rr ps $* | grep 'erl_child_setup' | awk '{ print $2 }'` + for CS in $ChildSetup; do + rr ps $* | grep -E "^$CS" + done + exit 0 + else + exec rr record --ignore-nested $BINDIR/$EMU_NAME $emu_xargs "$@" + fi else exec $EXEC $xargs ${1+"$@"} fi diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in index b12a205ba7..bb7b1a73f5 100644 --- a/erts/etc/unix/etp-commands.in +++ b/erts/etc/unix/etp-commands.in @@ -149,7 +149,7 @@ define etp-1 else # (($arg0) & 0x3) == 0 if (($arg0) == etp_the_non_value) - printf "<the non-value>" + printf "<the-non-value>" else etp-cp-1 ($arg0) end @@ -1241,7 +1241,7 @@ define etp-sig-int if $etp_sig_tag != etp_the_non_value etp-1 $etp_sig_tag 0 else - print "!ENCODED-DIST-MSG" + printf "!ENCODED-DIST-MSG" end if ($arg0)->m[1] != $etp_nil printf " @token= " @@ -1251,7 +1251,7 @@ define etp-sig-int etp-1 ($arg0)->m[2] 0 else if ($etp_sig_tag & 0x3f) != 0x30 - print "!INVALID-SIGNAL" + printf "!INVALID-SIGNAL" else set $etp_sig_op = (($etp_sig_tag >> 6) & 0xff) set $etp_sig_type = (($etp_sig_tag >> 14) & 0xff) @@ -4326,6 +4326,20 @@ document etp-show %--------------------------------------------------------------------------- end +define etp-rr-run-until-beam + source @ERL_TOP@/erts/etc/unix/etp-rr-run-until-beam.py +end + +document etp-rr-run-until-beam +%--------------------------------------------------------------------------- +% etp-rr-run-until-beam +% +% Use this gdb macro to make cerl -rr replay -p PID walk until +% the correct execute has been made. You may have to change the +% file that is used to debug with. +%--------------------------------------------------------------------------- +end + ############################################################################ # Init # @@ -4363,7 +4377,13 @@ define hook-run set $_exitsignal = -1 end +handle SIGPIPE nostop + etp-init help etp-init -etp-show -etp-system-info +if $etp_rr_run_until_beam + help etp-rr-run-until-beam +else + etp-show + etp-system-info +end diff --git a/erts/etc/unix/etp-rr-run-until-beam.py b/erts/etc/unix/etp-rr-run-until-beam.py new file mode 100644 index 0000000000..078998b910 --- /dev/null +++ b/erts/etc/unix/etp-rr-run-until-beam.py @@ -0,0 +1,45 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2013-2016. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# %CopyrightEnd% +# + +has_exited = False + +def stop_handler (event): + global has_exited + if isinstance(event, gdb.SignalEvent): + print("exit code: %s" % (event.stop_signal)) + has_exited = True + +gdb.events.stop.connect (stop_handler) + +gdb.execute('continue') + +while not has_exited: + r = gdb.execute('when', to_string=True) + m = re.match("[^0-9]*([0-9]+)", r) + if m: + event = int(m.group(1)); + gdb.execute('start ' + str(event + 1)); + gdb.execute('continue') + +gdb.events.stop.disconnect (stop_handler) + +gdb.execute('file ' + str(gdb.parse_and_eval("$etp_beam_executable"))) +gdb.execute('break main') +gdb.execute('reverse-continue') diff --git a/erts/etc/unix/to_erl.c b/erts/etc/unix/to_erl.c index afff8f7e54..ed4fe12e8b 100644 --- a/erts/etc/unix/to_erl.c +++ b/erts/etc/unix/to_erl.c @@ -245,7 +245,6 @@ int main(int argc, char **argv) tty_smode.c_iflag = 1*BRKINT |/*Signal interrupt on break.*/ 1*IGNPAR |/*Ignore characters with parity errors.*/ - 1*ISTRIP |/*Strip character.*/ 0; #if 0 diff --git a/erts/lib_src/Makefile.in b/erts/lib_src/Makefile.in index 8e1f5b58c4..1da11c2d0a 100644 --- a/erts/lib_src/Makefile.in +++ b/erts/lib_src/Makefile.in @@ -29,7 +29,6 @@ CC=@CC@ LD=@LD@ AR=@AR@ RANLIB=@RANLIB@ -RM=@RM@ MKDIR=@MKDIR@ INSTALL=@INSTALL@ INSTALL_DIR=@INSTALL_DIR@ @@ -536,9 +535,9 @@ release_docs_spec: # .PHONY: clean clean: - $(RM) -rf ../lib/internal/$(TARGET)/* - $(RM) -rf ../lib/$(TARGET)/* - $(RM) -rf obj/$(TARGET)/* + $(RM) -r ../lib/internal/$(TARGET)/* + $(RM) -r ../lib/$(TARGET)/* + $(RM) -r obj/$(TARGET)/* # # Make dependencies diff --git a/erts/preloaded/ebin/atomics.beam b/erts/preloaded/ebin/atomics.beam Binary files differindex a5ac24f0b8..f8fb26b728 100644 --- a/erts/preloaded/ebin/atomics.beam +++ b/erts/preloaded/ebin/atomics.beam diff --git a/erts/preloaded/ebin/counters.beam b/erts/preloaded/ebin/counters.beam Binary files differindex a1aa34a415..54fe86eb18 100644 --- a/erts/preloaded/ebin/counters.beam +++ b/erts/preloaded/ebin/counters.beam diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam Binary files differindex 37903d24b6..6f5a75a2db 100644 --- a/erts/preloaded/ebin/erl_prim_loader.beam +++ b/erts/preloaded/ebin/erl_prim_loader.beam diff --git a/erts/preloaded/ebin/erl_tracer.beam b/erts/preloaded/ebin/erl_tracer.beam Binary files differindex 2509f238bf..ec4d6153d1 100644 --- a/erts/preloaded/ebin/erl_tracer.beam +++ b/erts/preloaded/ebin/erl_tracer.beam diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex 7563663807..ee96878ff7 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam Binary files differindex bc697d11d7..ce4a749d38 100644 --- a/erts/preloaded/ebin/erts_code_purger.beam +++ b/erts/preloaded/ebin/erts_code_purger.beam diff --git a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam Binary files differindex 5b788368af..c22aeb8949 100644 --- a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam +++ b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam Binary files differindex b8415a9833..bc53a2e431 100644 --- a/erts/preloaded/ebin/erts_internal.beam +++ b/erts/preloaded/ebin/erts_internal.beam diff --git a/erts/preloaded/ebin/erts_literal_area_collector.beam b/erts/preloaded/ebin/erts_literal_area_collector.beam Binary files differindex e2a8c65f38..0845a8405a 100644 --- a/erts/preloaded/ebin/erts_literal_area_collector.beam +++ b/erts/preloaded/ebin/erts_literal_area_collector.beam diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam Binary files differindex fee2da33a6..d8c3a26674 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 324e111ad1..57ad5c7fdd 100644 --- a/erts/preloaded/ebin/otp_ring0.beam +++ b/erts/preloaded/ebin/otp_ring0.beam diff --git a/erts/preloaded/ebin/persistent_term.beam b/erts/preloaded/ebin/persistent_term.beam Binary files differindex c73da80a98..c882e4fad4 100644 --- a/erts/preloaded/ebin/persistent_term.beam +++ b/erts/preloaded/ebin/persistent_term.beam diff --git a/erts/preloaded/ebin/prim_buffer.beam b/erts/preloaded/ebin/prim_buffer.beam Binary files differindex 75e5b7c9cb..ac5a232dd4 100644 --- a/erts/preloaded/ebin/prim_buffer.beam +++ b/erts/preloaded/ebin/prim_buffer.beam diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam Binary files differindex ddda4764e1..24911123f9 100644 --- a/erts/preloaded/ebin/prim_eval.beam +++ b/erts/preloaded/ebin/prim_eval.beam diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex 2d1ce7d631..d3d4a75a11 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 558968b58a..d3614d5f16 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 51721a27a8..45142bd5d2 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 4519b540c4..5465917179 100644 --- a/erts/preloaded/ebin/zlib.beam +++ b/erts/preloaded/ebin/zlib.beam diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index ae5f86e017..1605c20f2c 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -297,12 +297,13 @@ check_file_result(Func, Target, {error,Reason}) -> "Target: " ++ TargetStr ++ ". " ++ "Function: " ++ atom_to_list(Func) ++ ". " ++ Process end, - %% this is equal to calling error_logger:error_report/1 which - %% we don't want to do from code_server during system boot + %% This is equal to calling logger:error/2 which + %% we don't want to do from code_server during system boot. + %% We don't want to call logger:timestamp() either. logger ! {log,error,#{label=>{?MODULE,file_error},report=>Report}, #{pid=>self(), gl=>group_leader(), - time=>erlang:monotonic_time(microsecond), + time=>os:system_time(microsecond), error_logger=>#{tag=>error_report, type=>std_error}}}, error diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 1ed6b6b284..5730e999cb 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -2526,6 +2526,9 @@ subtract(_,_) -> OldSchedulersOnline when SchedulersOnline :: pos_integer(), OldSchedulersOnline :: pos_integer(); + (system_logger, Logger) -> PrevLogger when + Logger :: logger | undefined | pid(), + PrevLogger :: logger | undefined | pid(); (trace_control_word, TCW) -> OldTCW when TCW :: non_neg_integer(), OldTCW :: non_neg_integer(); @@ -2534,7 +2537,7 @@ subtract(_,_) -> %% These are deliberately not documented (internal_cpu_topology, term()) -> term(); (sequential_tracer, pid() | port() | {module(), term()} | false) -> pid() | port() | false; - (1,0) -> true. + (reset_seq_trace,true) -> true. system_flag(_Flag, _Value) -> erlang:nif_error(undefined). @@ -2731,8 +2734,9 @@ tuple_to_list(_Tuple) -> (schedulers | schedulers_online) -> pos_integer(); (smp_support) -> boolean(); (start_time) -> integer(); - (system_version) -> string(); (system_architecture) -> string(); + (system_logger) -> logger | undefined | pid(); + (system_version) -> string(); (threads) -> boolean(); (thread_pool_size) -> non_neg_integer(); (time_correction) -> true | false; @@ -3395,60 +3399,15 @@ get_cookie() -> -spec integer_to_list(Integer, Base) -> string() when Integer :: integer(), Base :: 2..36. -integer_to_list(I, 10) -> - erlang:integer_to_list(I); -integer_to_list(I, Base) - 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 -> - integer_to_list(I, Base, []) - end; -integer_to_list(I, Base) -> - erlang:error(badarg, [I, Base]). - -integer_to_list(I0, Base, R0) -> - D = I0 rem Base, - I1 = I0 div Base, - R1 = if D >= 10 -> - [D-10+$A|R0]; - true -> - [D+$0|R0] - end, - if I1 =:= 0 -> - R1; - true -> - integer_to_list(I1, Base, R1) - end. +integer_to_list(_I, _Base) -> + erlang:nif_error(undefined). -spec integer_to_binary(Integer, Base) -> binary() when Integer :: integer(), Base :: 2..36. -integer_to_binary(I, 10) -> - erlang:integer_to_binary(I); -integer_to_binary(I, Base) - when erlang:is_integer(I), erlang:is_integer(Base), - Base >= 2, Base =< 1+$Z-$A+10 -> - if I < 0 -> - <<$-,(integer_to_binary(-I, Base, <<>>))/binary>>; - true -> - integer_to_binary(I, Base, <<>>) - end; -integer_to_binary(I, Base) -> - erlang:error(badarg, [I, Base]). - -integer_to_binary(I0, Base, R0) -> - D = I0 rem Base, - I1 = I0 div Base, - R1 = if - D >= 10 -> <<(D-10+$A),R0/binary>>; - true -> <<(D+$0),R0/binary>> - end, - if - I1 =:= 0 -> R1; - true -> integer_to_binary(I1, Base, R1) - end. +integer_to_binary(_I, _Base) -> + erlang:nif_error(undefined). + -record(cpu, {node = -1, processor = -1, diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 8f29a569f2..305b524438 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -97,6 +97,8 @@ -export([counters_new/1, counters_get/2, counters_add/3, counters_put/3, counters_info/1]). +-export([spawn_system_process/3]). + %% %% Await result of send to port %% @@ -726,3 +728,10 @@ counters_put(_Ref, _Ix, _Value) -> -spec counters_info(reference()) -> #{}. counters_info(_Ref) -> erlang:nif_error(undef). + +-spec spawn_system_process(Mod, Func, Args) -> pid() when + Mod :: atom(), + Func :: atom(), + Args :: list(). +spawn_system_process(_Mod, _Func, _Args) -> + erlang:nif_error(undefined). diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index b4b8b3bf9b..86b4f35ae5 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -483,13 +483,16 @@ do_handle_msg(Msg,State) -> {From, {ensure_loaded, _}} -> From ! {init, not_allowed}; X -> + %% This is equal to calling logger:info/3 which we don't + %% want to do from the init process, at least not during + %% system boot. We don't want to call logger:timestamp() + %% either. case whereis(user) of undefined -> - Time = erlang:monotonic_time(microsecond), catch logger ! {log, info, "init got unexpected: ~p", [X], #{pid=>self(), gl=>self(), - time=>Time, + time=>os:system_time(microsecond), error_logger=>#{tag=>info_msg}}}; User -> User ! X, diff --git a/erts/preloaded/src/persistent_term.erl b/erts/preloaded/src/persistent_term.erl index 5d0c266127..ee7e49b6cb 100644 --- a/erts/preloaded/src/persistent_term.erl +++ b/erts/preloaded/src/persistent_term.erl @@ -19,7 +19,7 @@ %% -module(persistent_term). --export([erase/1,get/0,get/1,info/0,put/2]). +-export([erase/1,get/0,get/1,get/2,info/0,put/2]). -type key() :: term(). -type value() :: term(). @@ -41,6 +41,13 @@ get() -> get(_Key) -> erlang:nif_error(undef). +-spec get(Key, Default) -> Value when + Key :: key(), + Default :: value(), + Value :: value(). +get(_Key, _Default) -> + erlang:nif_error(undef). + -spec info() -> Info when Info :: #{'count':=Count,'memory':=Memory}, Count :: non_neg_integer(), diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 5fc22bc582..1aa5d85c64 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -46,7 +46,7 @@ -define(MIN_READLINE_SIZE, 256). -define(LARGEFILESIZE, (1 bsl 63)). --export([copy/3]). +-export([copy/3, start/0]). -include("file_int.hrl"). @@ -85,14 +85,21 @@ is_translatable(_) -> %% This is a janitor process used to close files whose controlling process has %% died. The emulator will be torn down if this is killed. -delayed_close_loop() -> +start() -> + helper_loop(). + +helper_loop() -> receive {close, FRef} when is_reference(FRef) -> delayed_close_nif(FRef); _ -> ok end, - delayed_close_loop(). + helper_loop(). -%% +on_load() -> + %% This is spawned as a system process to prevent init:restart/0 from + %% killing it. + Pid = erts_internal:spawn_system_process(?MODULE, start, []), + ok = erlang:load_nif(atom_to_list(?MODULE), Pid). %% Returns {error, Reason} | {ok, BytesCopied} copy(#file_descriptor{module = ?MODULE} = Source, @@ -103,14 +110,6 @@ copy(#file_descriptor{module = ?MODULE} = Source, %% XXX Should be moved down to the driver for optimization. file:copy_opened(Source, Dest, Length). -on_load() -> - Pid = spawn(fun() -> - process_flag(trap_exit, true), - delayed_close_loop() - end), - true = register(erts_prim_file, Pid), - ok = erlang:load_nif(atom_to_list(?MODULE), Pid). - open(Name, Modes) -> %% The try/catch pattern seen here is used throughout the file to adhere to %% the public file interface, which has leaked through for ages because of @@ -573,12 +572,13 @@ list_dir_convert([RawName | Rest], SkipInvalid, Result) -> {error, ignore} -> list_dir_convert(Rest, SkipInvalid, Result); {error, warning} -> - %% this is equal to calling error_logger:warning_msg/2 which - %% we don't want to do from code_server during system boot + %% This is equal to calling logger:warning/3 which + %% we don't want to do from code_server during system boot. + %% We don't want to call logger:timestamp() either. logger ! {log,warning,"Non-unicode filename ~p ignored\n", [RawName], #{pid=>self(), gl=>group_leader(), - time=>erlang:system_time(microsecond), + time=>os:system_time(microsecond), error_logger=>#{tag=>warning_msg}}}, list_dir_convert(Rest, SkipInvalid, Result); {error, _} -> diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index f1d938c9a4..2820a5bef4 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2018. All Rights Reserved. +%% Copyright Ericsson AB 2000-2019. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -172,8 +172,18 @@ close(S) when is_port(S) -> %% and is a contradiction in itself. %% We have hereby done our best... %% - Tref = erlang:start_timer(T * 1000, self(), close_port), - close_pend_loop(S, Tref, undefined); + case subscribe(S, [subs_empty_out_q]) of + {ok, [{subs_empty_out_q,0}]} -> + close_port(S); + {ok, [{subs_empty_out_q,N}]} when N > 0 -> + %% Wait for pending output to be sent + Tref = erlang:start_timer(T * 1000, self(), close_port), + close_pend_loop(S, Tref, N); + _ -> + %% Subscribe failed - wait full time + Tref = erlang:start_timer(T * 1000, self(), close_port), + close_pend_loop(S, Tref, undefined) + end; _ -> % Regard this as {ok,{false,_}} case subscribe(S, [subs_empty_out_q]) of {ok, [{subs_empty_out_q,N}]} when N > 0 -> @@ -2679,12 +2689,13 @@ get_ip6([X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13,X14,X15,X16 | T]) -> ?u16(X9,X10),?u16(X11,X12),?u16(X13,X14),?u16(X15,X16)}, T }. +-define(ERTS_INET_DRV_CONTROL_MAGIC_NUMBER, 16#03f1a300). %% Control command ctl_cmd(Port, Cmd, Args) -> ?DBG_FORMAT("prim_inet:ctl_cmd(~p, ~p, ~p)~n", [Port,Cmd,Args]), Result = - try erlang:port_control(Port, Cmd, Args) of + try erlang:port_control(Port, Cmd+?ERTS_INET_DRV_CONTROL_MAGIC_NUMBER, Args) of [?INET_REP_OK|Reply] -> {ok,Reply}; [?INET_REP] -> inet_reply; [?INET_REP_ERROR|Err] -> {error,list_to_atom(Err)} diff --git a/erts/vsn.mk b/erts/vsn.mk index 0adee946cc..bce5ce4167 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% # -VSN = 10.2 +VSN = 10.3.2 # Port number 4365 in 4.2 # Port number 4366 in 4.3 |