diff options
Diffstat (limited to 'erts')
165 files changed, 7975 insertions, 19128 deletions
diff --git a/erts/aclocal.m4 b/erts/aclocal.m4 index 11c311f2c0..eb7d0411a7 100644 --- a/erts/aclocal.m4 +++ b/erts/aclocal.m4 @@ -74,21 +74,6 @@ AC_ARG_VAR(erl_xcomp_clock_gettime_cpu_time, [clock_gettime() can be used for re AC_ARG_VAR(erl_xcomp_after_morecore_hook, [__after_morecore_hook can track malloc()s core memory usage: yes|no (only used when cross compiling)]) AC_ARG_VAR(erl_xcomp_dlsym_brk_wrappers, [dlsym(RTLD_NEXT, _) brk wrappers can track malloc()s core memory usage: yes|no (only used when cross compiling)]) -dnl Cross compilation variables for OSE -AC_ARG_VAR(erl_xcomp_ose_ldflags_pass1, [Linker flags for the OSE module (pass 1) (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_ldflags_pass2, [Linker flags for the OSE module (pass 2) (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_OSEROOT, [OSE installation root directory (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_STRIP, [Strip utility shipped with the OSE distribution(only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file]) -AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file]) - ]) AC_DEFUN(ERL_XCOMP_SYSROOT_INIT, @@ -503,8 +488,6 @@ AC_CACHE_VAL(ac_cv_sys_ipv6_support, #ifdef __WIN32__ #include <winsock2.h> #include <ws2tcpip.h> -#elif __OSE__ -#error "no ipv6" #else #include <netinet/in.h> #endif], @@ -517,8 +500,6 @@ else #ifdef __WIN32__ #include <winsock2.h> #include <ws2tcpip.h> -#elif __OSE__ -#error "no ipv6" #else #include <netinet/in.h> #endif], @@ -750,8 +731,8 @@ AC_DEFUN(ERL_MONOTONIC_CLOCK, prefer_resolution_clock_gettime_monotonic="$2" ;; *) - check_msg="" - prefer_resolution_clock_gettime_monotonic= + check_msg="custom " + prefer_resolution_clock_gettime_monotonic="$2" ;; esac @@ -940,16 +921,16 @@ AC_DEFUN(ERL_WALL_CLOCK, erl_wall_clock_low_resolution=no erl_wall_clock_id= - case $erl_cv_clock_gettime_wall_$1-$erl_cv_mach_clock_get_time_wall-$ac_cv_func_gettimeofday-$host_os in - *-*-*-win32) + case $1-$erl_cv_clock_gettime_wall_$1-$erl_cv_mach_clock_get_time_wall-$ac_cv_func_gettimeofday-$host_os in + *-*-*-*-win32) erl_wall_clock_func=WindowsAPI erl_wall_clock_low_resolution=yes ;; - no-yes-*-*) + high_resolution-no-yes-*-*) erl_wall_clock_func=mach_clock_get_time erl_wall_clock_id=CALENDAR_CLOCK ;; - CLOCK_*-*-*-*) + *-CLOCK_*-*-*-*) erl_wall_clock_func=clock_gettime erl_wall_clock_id=$erl_cv_clock_gettime_wall_$1 for low_res_id in $low_resolution_clock_gettime_wall; do @@ -959,7 +940,7 @@ AC_DEFUN(ERL_WALL_CLOCK, fi done ;; - no-no-yes-*) + *-no-*-yes-*) erl_wall_clock_func=gettimeofday ;; *) @@ -991,12 +972,6 @@ if test "X$host_os" = "Xwin32"; then THR_LIBS= THR_LIB_NAME=win32_threads THR_LIB_TYPE=win32_threads -elif test "X$host_os" = "Xose"; then - AC_MSG_RESULT(yes) - THR_DEFS="-DOSE_THREADS" - THR_LIBS= - THR_LIB_NAME=ose_threads - THR_LIB_TYPE=ose_threads else AC_MSG_RESULT(no) THR_DEFS= @@ -1472,7 +1447,7 @@ AC_ARG_WITH(with_sparc_memory_order, LM_CHECK_THR_LIB ERL_INTERNAL_LIBS -ERL_MONOTONIC_CLOCK(high_resolution, undefined, no) +ERL_MONOTONIC_CLOCK(try_find_pthread_compatible, CLOCK_HIGHRES CLOCK_MONOTONIC, no) case $erl_monotonic_clock_func in clock_gettime) @@ -1583,22 +1558,9 @@ case "$THR_LIB_NAME" in fi ;; - pthread|ose_threads) - case "$THR_LIB_NAME" in - pthread) - ETHR_THR_LIB_BASE_DIR=pthread - AC_DEFINE(ETHR_PTHREADS, 1, [Define if you have pthreads]) - ;; - ose_threads) - AC_DEFINE(ETHR_OSE_THREADS, 1, - [Define if you have OSE style threads]) - ETHR_THR_LIB_BASE_DIR=ose - AC_CHECK_HEADER(ose_spi/ose_spi.h, - AC_DEFINE(HAVE_OSE_SPI_H, 1, - [Define if you have the "ose_spi/ose_spi.h" header file.])) - ;; - esac - if test "x$THR_LIB_NAME" = "xpthread"; then + pthread) + ETHR_THR_LIB_BASE_DIR=pthread + AC_DEFINE(ETHR_PTHREADS, 1, [Define if you have pthreads]) case $host_os in openbsd*) # The default stack size is insufficient for our needs @@ -1657,7 +1619,6 @@ case "$THR_LIB_NAME" in *) ;; esac - fi dnl We sometimes need ETHR_DEFS in order to find certain headers dnl (at least for pthread.h on osf1). saved_cppflags="$CPPFLAGS" @@ -1702,7 +1663,6 @@ case "$THR_LIB_NAME" in dnl dnl Check for functions dnl - if test "x$THR_LIB_NAME" = "xpthread"; then AC_CHECK_FUNC(pthread_spin_lock, \ [ethr_have_native_spinlock=yes \ AC_DEFINE(ETHR_HAVE_PTHREAD_SPIN_LOCK, 1, \ @@ -1922,8 +1882,6 @@ case "$THR_LIB_NAME" in esac CFLAGS=$old_CFLAGS - fi ## test "x$THR_LIB_NAME" = "xpthread" - if test "X$disable_native_ethr_impls" = "Xyes"; then ethr_have_native_atomics=no else @@ -2219,10 +2177,10 @@ AS_HELP_STRING([--with-clock-gettime-monotonic-id=CLOCKID], [specify clock id to use with clock_gettime() for monotonic time)])) AC_ARG_ENABLE(prefer-elapsed-monotonic-time-during-suspend, - AS_HELP_STRING([--enable-prefer-elapsed-monotonic-time-during-suspend], - [Prefer an OS monotonic time source with elapsed time during suspend]) - AS_HELP_STRING([--disable-prefer-elapsed-monotonic-time-during-suspend], - [Do not prefer an OS monotonic time source with elapsed time during suspend]), +AS_HELP_STRING([--enable-prefer-elapsed-monotonic-time-during-suspend], + [Prefer an OS monotonic time source with elapsed time during suspend]) +AS_HELP_STRING([--disable-prefer-elapsed-monotonic-time-during-suspend], + [Do not prefer an OS monotonic time source with elapsed time during suspend]), [ case "$enableval" in yes) prefer_elapsed_monotonic_time_during_suspend=yes ;; *) prefer_elapsed_monotonic_time_during_suspend=no ;; @@ -2296,6 +2254,9 @@ case "$erl_wall_clock_func-$erl_wall_clock_id-$with_clock_gettime_realtime_id" i esac case $erl_wall_clock_func in + none) + AC_MSG_ERROR([No wall clock source found]) + ;; mach_clock_get_time) AC_DEFINE(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME, [1], [Define if you want to implement erts_os_system_time() using mach clock_get_time()]) ;; diff --git a/erts/configure.in b/erts/configure.in index 22ca7ec17d..96ad58f941 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -143,14 +143,6 @@ AS_HELP_STRING([--enable-dirty-schedulers], [enable dirty scheduler support]), *) enable_dirty_schedulers=yes ;; esac ], enable_dirty_schedulers=no) -AC_ARG_ENABLE(halfword-emulator, -AS_HELP_STRING([--enable-halfword-emulator], - [enable halfword emulator (only for 64bit builds). Note: Halfword emulator is marked as deprecated and scheduled for removal in future major release.]), -[ case "$enableval" in - no) enable_halfword_emualtor=no ;; - *) enable_halfword_emulator=yes ;; - esac ], enable_halfword_emulator=unknown) - AC_ARG_ENABLE(smp-support, AS_HELP_STRING([--enable-smp-support], [enable smp support]) AS_HELP_STRING([--disable-smp-support], [disable smp support]), @@ -342,6 +334,15 @@ AS_HELP_STRING([--enable-systemd], [enable systemd support in epmd]), [], [enable_systemd=no]) +AC_ARG_ENABLE(saved-compile-time, +AS_HELP_STRING([--disable-saved-compile-time], [disable saved compile time]), +[ case "$enableval" in + no) save_compile_time=0 ;; + *) save_compile_time=1 ;; + esac ], save_compile_time=1) + +AC_DEFINE_UNQUOTED(ERTS_SAVED_COMPILE_TIME, $save_compile_time, [Save compile time?]) + dnl Magic test for clearcase. OTP_RELEASE= if test "${ERLANG_COMMERCIAL_BUILD}" != ""; then @@ -787,36 +788,6 @@ esac AC_SUBST(LIBCARBON) -dnl Check if we should/can build a halfword emulator - -AC_MSG_CHECKING(if we are building a halfword emulator (32bit heap on 64bit machine)) -if test "$enable_halfword_emulator" = "yes"; then - if test "$ARCH" = "amd64"; then - AC_DEFINE(HALFWORD_HEAP_EMULATOR, [1], - [Define if building a halfword-heap 64bit emulator]) - ENABLE_ALLOC_TYPE_VARS="$ENABLE_ALLOC_TYPE_VARS halfword" - AC_MSG_RESULT([yes]) - - test -f "$ERL_TOP/erts/CONF_INFO" || - echo "" > "$ERL_TOP/erts/CONF_INFO" - cat >> $ERL_TOP/erts/CONF_INFO <<EOF - - The HALFWORD emulator has been enabled. - This is a DEPRECATED feature scheduled for removal - in a future major release. - -EOF - else - AC_MSG_ERROR(no; halfword emulator not supported on this architecture) - fi -else - AC_MSG_RESULT([no]) -fi - - - - - dnl some tests below will call this if we haven't already - and autoconf dnl can't handle those tests being done conditionally at runtime AC_PROG_CPP @@ -935,10 +906,7 @@ dnl what the user say. This might not be the right way to do it, but dnl for now that is the way we do it. USER_LD=$LD USER_LDFLAGS="$LDFLAGS" -case $host in - *ose) ;; - *) LD='$(CC)' ;; -esac +LD='$(CC)' AC_SUBST(LD) LDFLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH" @@ -953,8 +921,6 @@ dnl This is the os flavour, should be unix, ose, vxworks or win32 case $host in win32) ERLANG_OSTYPE=win32 ;; - *ose) - ERLANG_OSTYPE=ose ;; *) ERLANG_OSTYPE=unix ;; esac @@ -1263,7 +1229,7 @@ case "$enable_threads"-"$found_threads" in AC_MSG_RESULT(yes; enabled by user) ;; unknown-yes) case $host_os in - solaris*|linux*|darwin*|win32|ose) + solaris*|linux*|darwin*|win32) emu_threads=yes AC_MSG_RESULT(yes; default on this platform) ;; @@ -1345,7 +1311,7 @@ else enable_child_waiter_thread=no fi ;; - win32|ose) + win32) # Child waiter thread cannot be enabled disable_child_waiter_thread=yes enable_child_waiter_thread=no @@ -2109,7 +2075,7 @@ AC_CHECK_FUNCS([getipnodebyname getipnodebyaddr gethostbyname2]) AC_CHECK_FUNCS([ieee_handler fpsetmask finite isnan isinf res_gethostbyname dlopen \ pread pwrite memmove strerror strerror_r strncasecmp \ gethrtime localtime_r gmtime_r inet_pton \ - memcpy mallopt sbrk _sbrk __sbrk brk _brk __brk \ + mmap mremap memcpy mallopt sbrk _sbrk __sbrk brk _brk __brk \ flockfile fstat strlcpy strlcat setsid posix2time time2posix \ setlocale nl_langinfo poll mlockall ppoll]) @@ -2161,17 +2127,6 @@ case $host_os in AC_CHECK_FUNCS([writev]) ;; esac -case $host_os in - *ose) - AC_MSG_CHECKING([for mmap]) - AC_MSG_RESULT(not using for OSE) - AC_MSG_CHECKING([for mremap]) - AC_MSG_RESULT(not using for OSE) ;; - *) - AC_CHECK_FUNCS([mmap mremap]) ;; -esac - - AC_CHECK_DECLS([posix2time, time2posix],,,[#include <time.h>]) disable_vfork=false @@ -2825,12 +2780,6 @@ if test "$cross_compiling" != "yes" && test X${enable_hipe} != Xno; then if test -z "$M4"; then enable_hipe=no AC_MSG_NOTICE([HiPE disabled as no valid m4 is found in PATH]) - elif test "$enable_halfword_emulator" = "yes"; then - if test X${enable_hipe} = Xyes; then - AC_MSG_ERROR([HiPE can not be combined with halfword emulator (yet)]) - else - AC_MSG_NOTICE([HiPE auto-disabled on halfword emulator]) - fi else case "$ARCH-$OPSYS" in x86-linux|amd64-linux|x86-darwin*|amd64-darwin*|ppc-linux|ppc64-linux|ppc-darwin|arm-linux|amd64-freebsd|x86-freebsd|x86-sol2|amd64-sol2|ultrasparc-linux) @@ -4931,7 +4880,6 @@ AC_OUTPUT( Makefile:Makefile.in ../make/$host/otp.mk:../make/otp.mk.in ../make/$host/otp_ded.mk:../make/otp_ded.mk.in - ../make/$host/ose_lm.mk:../make/ose_lm.mk.in dnl dnl The ones below should be moved to their respective lib dnl diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 547d5e583d..49fe784d06 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -70,6 +70,10 @@ Rep(D) = <c><![CDATA[[Rep(F_1), ..., Rep(F_k)]]]></c>.</item> <item>If F is an attribute <c><![CDATA[-module(Mod)]]></c>, then Rep(F) = <c><![CDATA[{attribute,LINE,module,Mod}]]></c>.</item> + <item>If F is an attribute <c><![CDATA[-behavior(Behavior)]]></c>, then + Rep(F) = <c><![CDATA[{attribute,LINE,behavior,Behavior}]]></c>.</item> + <item>If F is an attribute <c><![CDATA[-behaviour(Behaviour)]]></c>, then + Rep(F) = <c><![CDATA[{attribute,LINE,behaviour,Behaviour}]]></c>.</item> <item>If F is an attribute <c><![CDATA[-export([Fun_1/A_1, ..., Fun_k/A_k])]]></c>, then Rep(F) = <c><![CDATA[{attribute,LINE,export,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}]]></c>.</item> <item>If F is an attribute <c><![CDATA[-import(Mod,[Fun_1/A_1, ..., Fun_k/A_k])]]></c>, then @@ -243,12 +247,6 @@ <item>If V is <c><![CDATA[A = E]]></c>, then Rep(V) = <c><![CDATA[{record_field,LINE,Rep(A),Rep(E)}]]></c>.</item> <item>If V is <c><![CDATA[A :: T]]></c>, where <c><![CDATA[A]]></c> is - an atom and <c><![CDATA[T]]></c> is a type and it does not contain - <c><![CDATA[undefined]]></c> syntactically, then Rep(V) = - <c><![CDATA[{typed_record_field,{record_field,LINE,Rep(A)},Rep(undefined | T)}]]></c>. - Note that if <![CDATA[T]]> is an annotated type, it will be wrapped in - parentheses.</item> - <item>If V is <c><![CDATA[A :: T]]></c>, where <c><![CDATA[A]]></c> is an atom and <c><![CDATA[T]]></c> is a type, then Rep(V) = <c><![CDATA[{typed_record_field,{record_field,LINE,Rep(A)},Rep(T)}]]></c>. </item> diff --git a/erts/doc/src/driver_entry.xml b/erts/doc/src/driver_entry.xml index 30772c68fe..c802693977 100644 --- a/erts/doc/src/driver_entry.xml +++ b/erts/doc/src/driver_entry.xml @@ -4,7 +4,7 @@ <cref> <header> <copyright> - <year>2001</year><year>2013</year> + <year>2001</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -126,7 +126,7 @@ <section> <title>DATA TYPES</title> <taglist> - <tag><b>ErlDrvEntry</b></tag> + <tag><em>ErlDrvEntry</em></tag> <item> <p/> <code type="none"> @@ -235,6 +235,7 @@ typedef struct erl_drv_entry { </item> <tag><marker id="ready_input"/>void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event)</tag> + <item/> <tag><marker id="ready_output"/>void (*ready_output)(ErlDrvData drv_data, ErlDrvEvent event)</tag> <item> <p>This is called when a driver event (given in the @@ -246,14 +247,10 @@ typedef struct erl_drv_entry { something that the <c>WaitForMultipleObjects</c> API function understands). (Some trickery in the emulator allows more than the built-in limit of 64 <c>Events</c> to be used.)</p> - <p>On Enea OSE the <c>event</c> is one or more signals that can - be retrieved using <seealso marker="ose:ose_erl_driver#erl_drv_ose_get_signal">erl_drv_ose_get_signal</seealso>.</p> <p>To use this with threads and asynchronous routines, create a - pipe on unix, an Event on Windows or a unique signal number on - Enea OSE. When the routine + pipe on unix and an Event on Windows. When the routine completes, write to the pipe (use <c>SetEvent</c> on - Windows or send a message to the emulator process on Enea OSE), - this will make the emulator call + Windows), this will make the emulator call <c>ready_input</c> or <c>ready_output</c>.</p> <p>Spurious events may happen. That is, calls to <c>ready_input</c> or <c>ready_output</c> even though no real events are signaled. In diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index b0322b7d43..63ab2532ab 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -4,7 +4,7 @@ <comref> <header> <copyright> - <year>1996</year><year>2013</year> + <year>1996</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -138,7 +138,7 @@ see <seealso marker="kernel:app">app(4)</seealso> and <seealso marker="kernel:application">application(3)</seealso>.</p> </item> - <tag><marker id="args_file"><c><![CDATA[-args_file FileName]]></c></marker></tag> + <tag><marker id="args_file"/><c><![CDATA[-args_file FileName]]></c></tag> <item> <p>Command line arguments are read from the file <c><![CDATA[FileName]]></c>. The arguments read from the file replace the @@ -203,7 +203,7 @@ <seealso marker="kernel:app">app(4)</seealso> and <seealso marker="kernel:application">application(3)</seealso>.</p> </item> - <tag><marker id="connect_all"><c><![CDATA[-connect_all false]]></c></marker></tag> + <tag><marker id="connect_all"/><c><![CDATA[-connect_all false]]></c></tag> <item> <p>If this flag is present, <c><![CDATA[global]]></c> will not maintain a fully connected network of distributed Erlang nodes, and then @@ -288,7 +288,7 @@ <p>Makes <c><![CDATA[init]]></c> write some debug information while interpreting the boot script.</p> </item> - <tag><marker id="instr"><c><![CDATA[-instr]]></c>(emulator flag)</marker></tag> + <tag><marker id="instr"/><c><![CDATA[-instr]]></c>(emulator flag)</tag> <item> <p>Selects an instrumented Erlang runtime system (virtual machine) to run, instead of the ordinary one. When running an @@ -436,7 +436,7 @@ flag and those running with the <c><![CDATA[-name]]></c> flag, as node names must be unique in distributed Erlang systems.</p> </item> - <tag><marker id="smp"><c><![CDATA[-smp [enable|auto|disable]]]></c></marker></tag> + <tag><marker id="smp"/><c><![CDATA[-smp [enable|auto|disable]]]></c></tag> <item> <p><c>-smp enable</c> and <c>-smp</c> starts the Erlang runtime system with SMP support enabled. This may fail if no runtime @@ -462,7 +462,7 @@ <p><c><![CDATA[erl]]></c> invokes the code for the Erlang emulator (virtual machine), which supports the following flags:</p> <taglist> - <tag><marker id="async_thread_stack_size"><c><![CDATA[+a size]]></c></marker></tag> + <tag><marker id="async_thread_stack_size"/><c><![CDATA[+a size]]></c></tag> <item> <p>Suggested stack size, in kilowords, for threads in the async-thread pool. Valid range is 16-8192 kilowords. The @@ -477,7 +477,7 @@ suggestion, and it might even be ignored on some platforms.</p> </item> - <tag><marker id="async_thread_pool_size"><c><![CDATA[+A size]]></c></marker></tag> + <tag><marker id="async_thread_pool_size"/><c><![CDATA[+A size]]></c></tag> <item> <p>Sets the number of threads in async thread pool, valid range is 0-1024. If thread support is available, the default is 10.</p> @@ -496,7 +496,7 @@ <c><![CDATA[werl]]></c>, not <c><![CDATA[erl]]></c> (<c><![CDATA[oldshell]]></c>). Note also that <c><![CDATA[Ctrl-Break]]></c> is used instead of <c><![CDATA[Ctrl-C]]></c> on Windows.</p> </item> - <tag><marker id="+c"><c><![CDATA[+c true | false]]></c></marker></tag> + <tag><marker id="+c"/><c><![CDATA[+c true | false]]></c></tag> <item> <p>Enable or disable <seealso marker="time_correction#Time_Correction">time correction</seealso>:</p> @@ -512,7 +512,7 @@ This is interpreted as <c>+c false</c>. </p> </item> - <tag><marker id="+C_"><c><![CDATA[+C no_time_warp | single_time_warp | multi_time_warp]]></c></marker></tag> + <tag><marker id="+C_"/><c><![CDATA[+C no_time_warp | single_time_warp | multi_time_warp]]></c></tag> <item> <p>Set <seealso marker="time_correction#Time_Warp_Modes">time warp mode</seealso>: @@ -540,7 +540,7 @@ produce a crash dump. On Unix systems, sending an emulator process a SIGUSR1 signal will also force a crash dump.</p> </item> - <tag><marker id="+e"><c><![CDATA[+e Number]]></c></marker></tag> + <tag><marker id="+e"/><c><![CDATA[+e Number]]></c></tag> <item> <p>Set max number of ETS tables.</p> </item> @@ -625,7 +625,7 @@ information about the file names and line numbers. </p> </item> - <tag><marker id="erts_alloc"><c><![CDATA[+MFlag Value]]></c></marker></tag> + <tag><marker id="erts_alloc"/><c><![CDATA[+MFlag Value]]></c></tag> <item> <p>Memory allocator specific flags, see <seealso marker="erts_alloc">erts_alloc(3)</seealso> for @@ -664,10 +664,10 @@ debugging.</item> </taglist> </item> - <tag><marker id="+pc"/><marker id="printable_character_range"><c><![CDATA[+pc Range]]></c></marker></tag> + <tag><marker id="+pc"/><marker id="printable_character_range"/><c><![CDATA[+pc Range]]></c></tag> <item> <p>Sets the range of characters that the system will consider printable in heuristic detection of strings. This typically affects the shell, debugger and io:format functions (when ~tp is used in the format string).</p> - <p>Currently two values for the <c>Range</c> are supported: + <p>Currently two values for the <c>Range</c> are supported:</p> <taglist> <tag><c>latin1</c></tag> <item>The default. Only characters in the ISO-latin-1 range can be considered printable, which means @@ -682,11 +682,10 @@ example your font does not cover all Unicode characters.</item> </taglist> - </p> <p>Se also <seealso marker="stdlib:io#printable_range/0"> io:printable_range/0</seealso>.</p> </item> - <tag><marker id="+P"/><marker id="max_processes"><c><![CDATA[+P Number|legacy]]></c></marker></tag> + <tag><marker id="+P"/><marker id="max_processes"/><c><![CDATA[+P Number|legacy]]></c></tag> <item> <p>Sets the maximum number of simultaneously existing processes for this system if a <c>Number</c> is passed as value. Valid range for @@ -706,7 +705,7 @@ circumstances be extremely expensive. The legacy algoritm is deprecated, and the <c>legacy</c> option is scheduled for removal in OTP-R18.</p> </item> - <tag><marker id="+Q"/><marker id="max_ports"><c><![CDATA[+Q Number|legacy]]></c></marker></tag> + <tag><marker id="+Q"/><marker id="max_ports"/><c><![CDATA[+Q Number|legacy]]></c></tag> <item> <p>Sets the maximum number of simultaneously existing ports for this system if a Number is passed as value. Valid range for <c>Number</c> @@ -737,7 +736,7 @@ circumstances be extremely expensive. The legacy algoritm is deprecated, and the <c>legacy</c> option is scheduled for removal in OTP-R18.</p> </item> - <tag><marker id="compat_rel"><c><![CDATA[+R ReleaseNumber]]></c></marker></tag> + <tag><marker id="compat_rel"/><c><![CDATA[+R ReleaseNumber]]></c></tag> <item> <p>Sets the compatibility mode.</p> <p>The distribution mechanism is not backwards compatible by @@ -757,7 +756,7 @@ <item> <p>Force ets memory block to be moved on realloc.</p> </item> - <tag><marker id="+rg"><c><![CDATA[+rg ReaderGroupsLimit]]></c></marker></tag> + <tag><marker id="+rg"/><c><![CDATA[+rg ReaderGroupsLimit]]></c></tag> <item> <p>Limits the amount of reader groups used by read/write locks optimized for read operations in the Erlang runtime system. By @@ -775,7 +774,7 @@ schedulers to logical processors</seealso>, since the reader groups are distributed better between schedulers.</p> </item> - <tag><marker id="+S"><c><![CDATA[+S Schedulers:SchedulerOnline]]></c></marker></tag> + <tag><marker id="+S"/><c><![CDATA[+S Schedulers:SchedulerOnline]]></c></tag> <item> <p>Sets the number of scheduler threads to create and scheduler threads to set online when SMP support has been enabled. The maximum for @@ -800,7 +799,7 @@ SMP support enabled (see the <seealso marker="#smp">-smp</seealso> flag).</p> </item> - <tag><marker id="+SP"><c><![CDATA[+SP SchedulersPercentage:SchedulersOnlinePercentage]]></c></marker></tag> + <tag><marker id="+SP"/><c><![CDATA[+SP SchedulersPercentage:SchedulersOnlinePercentage]]></c></tag> <item> <p>Similar to <seealso marker="#+S">+S</seealso> but uses percentages to set the number of scheduler threads to create, based on logical processors configured, @@ -821,7 +820,7 @@ SMP support enabled (see the <seealso marker="#smp">-smp</seealso> flag).</p> </item> - <tag><marker id="+SDcpu"><c><![CDATA[+SDcpu DirtyCPUSchedulers:DirtyCPUSchedulersOnline]]></c></marker></tag> + <tag><marker id="+SDcpu"/><c><![CDATA[+SDcpu DirtyCPUSchedulers:DirtyCPUSchedulersOnline]]></c></tag> <item> <p>Sets the number of dirty CPU scheduler threads to create and dirty CPU scheduler threads to set online when threading support has been @@ -845,7 +844,7 @@ enabled (it's disabled by default). </p> </item> - <tag><marker id="+SDPcpu"><c><![CDATA[+SDPcpu DirtyCPUSchedulersPercentage:DirtyCPUSchedulersOnlinePercentage]]></c></marker></tag> + <tag><marker id="+SDPcpu"/><c><![CDATA[+SDPcpu DirtyCPUSchedulersPercentage:DirtyCPUSchedulersOnlinePercentage]]></c></tag> <item> <p>Similar to <seealso marker="#+SDcpu">+SDcpu</seealso> but uses percentages to set the number of dirty CPU scheduler threads to create and number of dirty CPU scheduler threads @@ -868,7 +867,7 @@ enabled (it's disabled by default). </p> </item> - <tag><marker id="+SDio"><c><![CDATA[+SDio IOSchedulers]]></c></marker></tag> + <tag><marker id="+SDio"/><c><![CDATA[+SDio IOSchedulers]]></c></tag> <item> <p>Sets the number of dirty I/O scheduler threads to create when threading support has been enabled. The valid range is 0-1024. By default, the number @@ -886,7 +885,7 @@ <item> <p>Scheduling specific flags.</p> <taglist> - <tag><marker id="+sbt"><c>+sbt BindType</c></marker></tag> + <tag><marker id="+sbt"/><c>+sbt BindType</c></tag> <item> <p>Set scheduler bind type.</p> <p>Schedulers can also be bound using the @@ -1010,7 +1009,7 @@ <seealso marker="erlang#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. </p> </item> - <tag><marker id="+sbwt"><c>+sbwt none|very_short|short|medium|long|very_long</c></marker></tag> + <tag><marker id="+sbwt"/><c>+sbwt none|very_short|short|medium|long|very_long</c></tag> <item> <p>Set scheduler busy wait threshold. Default is <c>medium</c>. The threshold determines how long schedulers should busy @@ -1020,7 +1019,7 @@ without prior notice. </p> </item> - <tag><marker id="+scl"><c>+scl true|false</c></marker></tag> + <tag><marker id="+scl"/><c>+scl true|false</c></tag> <item> <p>Enable or disable scheduler compaction of load. By default scheduler compaction of load is enabled. When enabled, load @@ -1037,7 +1036,7 @@ between schedulers. </p> </item> - <tag><marker id="+sct"><c>+sct CpuTopology</c></marker></tag> + <tag><marker id="+sct"/><c>+sct CpuTopology</c></tag> <item> <list type="bulleted"> <item><c><![CDATA[<Id> = integer(); when 0 =< <Id> =< 65535]]></c></item> @@ -1159,7 +1158,7 @@ <p>For more information, see <seealso marker="erlang#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso>.</p> </item> - <tag><marker id="+secio"><c>+secio true|false</c></marker></tag> + <tag><marker id="+secio"/><c>+secio true|false</c></tag> <item> <p>Enable or disable eager check I/O scheduling. The default is currently <c>true</c>. The default was changed from <c>false</c> @@ -1176,7 +1175,7 @@ <p><seealso marker="erlang#system_info_eager_check_io"><c>erlang:system_info(eager_check_io)</c></seealso> returns the value of this parameter used when starting the VM.</p> </item> - <tag><marker id="+sfwi"><c>+sfwi Interval</c></marker></tag> + <tag><marker id="+sfwi"/><c>+sfwi Interval</c></tag> <item> <p>Set scheduler forced wakeup interval. All run queues will be scanned each <c>Interval</c> milliseconds. While there are @@ -1190,7 +1189,7 @@ the <c>+sfwi</c> flag will be removed. </p> </item> - <tag><marker id="+stbt"><c>+stbt BindType</c></marker></tag> + <tag><marker id="+stbt"/><c>+stbt BindType</c></tag> <item> <p>Try to set scheduler bind type. The same as the <seealso marker="#+sbt">+sbt</seealso> flag with the exception of @@ -1198,7 +1197,7 @@ documentation of the <seealso marker="#+sbt">+sbt</seealso> flag. </p> </item> - <tag><marker id="+sub"><c>+sub true|false</c></marker></tag> + <tag><marker id="+sub"/><c>+sub true|false</c></tag> <item> <p>Enable or disable <seealso marker="erts:erlang#statistics_scheduler_wall_time">scheduler @@ -1221,7 +1220,7 @@ utilization. </p> </item> - <tag><marker id="+swct"><c>+swct very_eager|eager|medium|lazy|very_lazy</c></marker></tag> + <tag><marker id="+swct"/><c>+swct very_eager|eager|medium|lazy|very_lazy</c></tag> <item> <p> Set scheduler wake cleanup threshold. Default is <c>medium</c>. @@ -1235,7 +1234,7 @@ <p><em>NOTE:</em> This flag may be removed or changed at any time without prior notice. </p> </item> - <tag><marker id="+sws"><c>+sws default|legacy</c></marker></tag> + <tag><marker id="+sws"/><c>+sws default|legacy</c></tag> <item> <p> Set scheduler wakeup strategy. Default strategy changed in erts-5.10/OTP-R16A. This strategy was previously known as <c>proposal</c> in OTP-R15. The <c>legacy</c> strategy was used as default from R13 up to and including R15. @@ -1243,7 +1242,7 @@ <p><em>NOTE:</em> This flag may be removed or changed at any time without prior notice. </p> </item> - <tag><marker id="+swt"><c>+swt very_low|low|medium|high|very_high</c></marker></tag> + <tag><marker id="+swt"/><c>+swt very_low|low|medium|high|very_high</c></tag> <item> <p>Set scheduler wakeup threshold. Default is <c>medium</c>. The threshold determines when to wake up sleeping schedulers @@ -1257,7 +1256,7 @@ without prior notice. </p> </item> - <tag><marker id="+spp"><c>+spp Bool</c></marker></tag> + <tag><marker id="+spp"/><c>+spp Bool</c></tag> <item> <p>Set default scheduler hint for port parallelism. If set to <c>true</c>, the VM will schedule port tasks when doing so will @@ -1273,7 +1272,7 @@ option to <seealso marker="erlang#open_port/2">open_port/2</seealso></p>. </item> - <tag><marker id="sched_thread_stack_size"><c><![CDATA[+sss size]]></c></marker></tag> + <tag><marker id="sched_thread_stack_size"/><c><![CDATA[+sss size]]></c></tag> <item> <p>Suggested stack size, in kilowords, for scheduler threads. Valid range is 4-8192 kilowords. The default stack size @@ -1281,11 +1280,11 @@ </item> </taglist> </item> - <tag><marker id="+t"><c><![CDATA[+t size]]></c></marker></tag> + <tag><marker id="+t"/><c><![CDATA[+t size]]></c></tag> <item> <p>Set the maximum number of atoms the VM can handle. Default is 1048576.</p> </item> - <tag><marker id="+T"><c><![CDATA[+T Level]]></c></marker></tag> + <tag><marker id="+T"/><c><![CDATA[+T Level]]></c></tag> <item> <p>Enables modified timing and sets the modified timing level. Currently valid range is 0-9. The timing of the runtime system @@ -1339,7 +1338,7 @@ <item> <p>Miscellaneous flags.</p> <taglist> - <tag><marker id="+zdbbl"><c>+zdbbl size</c></marker></tag> + <tag><marker id="+zdbbl"/><c>+zdbbl size</c></tag> <item> <p>Set the distribution buffer busy limit (<seealso marker="erlang#system_info_dist_buf_busy_limit">dist_buf_busy_limit</seealso>) @@ -1352,7 +1351,7 @@ give lower latency and higher throughput at the expense of higher memory usage.</p> </item> - <tag><marker id="+zdntgc"><c>+zdntgc time</c></marker></tag> + <tag><marker id="+zdntgc"/><c>+zdntgc time</c></tag> <item> <p>Set the delayed node table garbage collection time (<seealso marker="erlang#system_info_delayed_node_table_gc">delayed_node_table_gc</seealso>) @@ -1426,7 +1425,7 @@ </item> </taglist> </item> - <tag><marker id="ERL_AFLAGS"><c><![CDATA[ERL_AFLAGS]]></c></marker></tag> + <tag><marker id="ERL_AFLAGS"/><c><![CDATA[ERL_AFLAGS]]></c></tag> <item> <p>The content of this environment variable will be added to the beginning of the command line for <c><![CDATA[erl]]></c>.</p> @@ -1436,7 +1435,7 @@ the <c><![CDATA[-extra]]></c> section, i.e. the end of the command line following after an <c><![CDATA[-extra]]></c> flag.</p> </item> - <tag><marker id="ERL_ZFLAGS"><c><![CDATA[ERL_ZFLAGS]]></c></marker> and <marker id="ERL_FLAGS"><c><![CDATA[ERL_FLAGS]]></c></marker></tag> + <tag><marker id="ERL_ZFLAGS"/><c><![CDATA[ERL_ZFLAGS]]></c> and <marker id="ERL_FLAGS"/><c><![CDATA[ERL_FLAGS]]></c></tag> <item> <p>The content of these environment variables will be added to the end of the command line for <c><![CDATA[erl]]></c>.</p> diff --git a/erts/doc/src/erl_dist_protocol.xml b/erts/doc/src/erl_dist_protocol.xml index e1a58856f3..b435d5c9b4 100644 --- a/erts/doc/src/erl_dist_protocol.xml +++ b/erts/doc/src/erl_dist_protocol.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2007</year> - <year>2013</year> + <year>2015</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -549,10 +549,10 @@ If Result > 0, the packet only consists of [119, Result]. --> </section> - <marker id="distribution_handshake"/> <section> <title>Distribution Handshake</title> <p> + <marker id="distribution_handshake"/> This section describes the distribution handshake protocol introduced in the OTP-R6 release of Erlang/OTP. This description was previously located in diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml index 1f7fe0f961..f7b4187b80 100644 --- a/erts/doc/src/erl_driver.xml +++ b/erts/doc/src/erl_driver.xml @@ -4,7 +4,7 @@ <cref> <header> <copyright> - <year>2001</year><year>2014</year> + <year>2001</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -223,7 +223,7 @@ asynchronous function calls, using a thread pool provided by Erlang. There is also a select call, that can be used for asynchronous drivers.</item> - <tag><marker id="multi_threading">Multi-threading</marker></tag> + <tag><marker id="multi_threading"/>Multi-threading</tag> <item> <p>A POSIX thread like API for multi-threading is provided. The Erlang driver thread API only provide a subset of the functionality @@ -297,7 +297,7 @@ <item><p>A driver can add and later remove drivers.</p></item> <tag>Monitoring processes</tag> <item><p>A driver can monitor a process that does not own a port.</p></item> - <tag><marker id="version_management">Version management</marker></tag> + <tag><marker id="version_management"/>Version management</tag> <item> <p>Version management is enabled for drivers that have set the <seealso marker="driver_entry#extended_marker">extended_marker</seealso> @@ -384,12 +384,12 @@ <item> <p> Rewrite driver callback - <c><seealso marker="driver_entry#control">control</seealso></c> + <seealso marker="driver_entry#control"><c>control</c></seealso> to use return type <c>ErlDrvSSizeT</c> instead of <c>int</c>. </p> <p> Rewrite driver callback - <c><seealso marker="driver_entry#call">call</seealso></c> + <seealso marker="driver_entry#call"><c>call</c></seealso> to use return type <c>ErlDrvSSizeT</c> instead of <c>int</c>. </p> <note> @@ -407,19 +407,19 @@ <item> <p> Driver callback - <c><seealso marker="driver_entry#output">output</seealso></c> + <seealso marker="driver_entry#output"><c>output</c></seealso> now gets <c>ErlDrvSizeT</c> as 3rd argument instead of previously <c>int</c>. </p> <p> Driver callback - <c><seealso marker="driver_entry#control">control</seealso></c> + <seealso marker="driver_entry#control"><c>control</c></seealso> now gets <c>ErlDrvSizeT</c> as 4th and 6th arguments instead of previously <c>int</c>. </p> <p> Driver callback - <c><seealso marker="driver_entry#call">call</seealso></c> + <seealso marker="driver_entry#call"><c>call</c></seealso> now gets <c>ErlDrvSizeT</c> as 4th and 6th arguments instead of previously <c>int</c>. </p> @@ -1044,9 +1044,7 @@ typedef struct ErlIOVec { <c>select</c>/<c>poll</c> can use). On windows, the Win32 API function <c>WaitForMultipleObjects</c> is used. This places other restrictions on the event object. - Refer to the Win32 SDK documentation. - On Enea OSE, the receive function is used. See the <seealso - marker="ose:ose_erl_driver"></seealso> for more details.</p> + Refer to the Win32 SDK documentation.</p> <p>The <c>on</c> parameter should be <c>1</c> for setting events and <c>0</c> for clearing them.</p> <p>The <c>mode</c> argument is a bitwise-or combination of @@ -1058,7 +1056,7 @@ typedef struct ErlIOVec { <seealso marker="driver_entry#ready_output">ready_output</seealso>. </p> <note> - <p>Some OS (Windows and Enea OSE) do not differentiate between read and write events. + <p>Some OS (Windows) do not differentiate between read and write events. The call-back for a fired event then only depends on the value of <c>mode</c>.</p> </note> <p><c>ERL_DRV_USE</c> specifies if we are using the event object or if we want to close it. diff --git a/erts/doc/src/erl_ext_dist.xml b/erts/doc/src/erl_ext_dist.xml index caf1e812c4..2ac974f497 100644 --- a/erts/doc/src/erl_ext_dist.xml +++ b/erts/doc/src/erl_ext_dist.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2007</year> - <year>2014</year> + <year>2015</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -150,10 +150,10 @@ </note> </section> - <marker id="distribution_header"/> <section> <title>Distribution header</title> <p> + <marker id="distribution_header"/> As of erts version 5.7.2 the old atom cache protocol was dropped and a new one was introduced. This atom cache protocol introduced the distribution header. Nodes with erts versions diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 23c3d5fcee..dae14b8d08 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -4,7 +4,7 @@ <cref> <header> <copyright> - <year>2001</year><year>2013</year> + <year>2001</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -833,9 +833,10 @@ typedef enum { <fsummary>Determine if a term is an empty list</fsummary> <desc><p>Return true if <c>term</c> is an empty list.</p></desc> </func> - <marker id="enif_is_exception"/><func><name><ret>int</ret><nametext>enif_is_exception(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> + <func><name><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><p>Return true if <c>term</c> is an exception.</p></desc> + <desc><marker id="enif_is_exception"/> + <p>Return true if <c>term</c> is an exception.</p></desc> </func> <func><name><ret>int</ret><nametext>enif_is_map(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name> <fsummary>Determine if a term is a map</fsummary> diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 37f0aa289e..3927339b2b 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2013</year> + <year>1996</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -30,42 +30,43 @@ <file>erlang.xml</file> </header> <module>erlang</module> - <modulesummary>The Erlang BIFs</modulesummary> + <modulesummary>The Erlang BIFs.</modulesummary> <description> - <p>By convention, most built-in functions (BIFs) are seen as being - in the module <c>erlang</c>. A number of the BIFs are viewed more + <p>By convention, most Built-In Functions (BIFs) are seen as being + in this module. Some of the BIFs are viewed more or less as part of the Erlang programming language and are - <em>auto-imported</em>. Thus, it is not necessary to specify - the module name and both the calls <c>atom_to_list(Erlang)</c> and - <c>erlang:atom_to_list(Erlang)</c> are identical.</p> - <p>In the text, auto-imported BIFs are listed without module prefix. + <em>auto-imported</em>. Thus, it is not necessary to specify the + module name. For example, the calls <c>atom_to_list(Erlang)</c> + and <c>erlang:atom_to_list(Erlang)</c> are identical.</p> + <p>Auto-imported BIFs are listed without module prefix. BIFs listed with module prefix are not auto-imported.</p> - <p>BIFs may fail for a variety of reasons. All BIFs fail with + <p>BIFs can fail for various reasons. All BIFs fail with reason <c>badarg</c> if they are called with arguments of an - incorrect type. The other reasons that may make BIFs fail are - described in connection with the description of each individual - BIF.</p> - <p>Some BIFs may be used in guard tests, these are marked with + incorrect type. The other reasons are described in the + description of each individual BIF.</p> + <p>Some BIFs can be used in guard tests and are marked with "Allowed in guard tests".</p> </description> <datatypes> <datatype> - <name><marker id="type-ext_binary">ext_binary()</marker></name> + <name>ext_binary()</name> <desc> + <marker id="type-ext_binary"></marker> <p>A binary data object, structured according to the Erlang external term format.</p> </desc> </datatype> + <datatype> <name name="timestamp"></name> <desc><p>See <seealso marker="#timestamp/0">erlang:timestamp/0</seealso>.</p> </desc> </datatype> - <marker id="type_time_unit"/> <datatype> <name name="time_unit"></name> - <desc><p>Currently supported time unit representations:</p> + <desc><p><marker id="type_time_unit"/> + Supported time unit representations:</p> <taglist> <tag><c>PartsPerSecond :: integer() >= 1</c></tag> <item><p>Time unit expressed in parts per second. That is, @@ -92,11 +93,11 @@ used by the Erlang runtime system.</p> <p>The <c>native</c> time unit is determined at - runtime system start, and will remain the same until + runtime system start, and remains the same until the runtime system terminates. If a runtime system is stopped and then started again (even on the same machine), the <c>native</c> time unit of the new - runtime system instance may differ from the + runtime system instance can differ from the <c>native</c> time unit of the old runtime system instance.</p> @@ -105,8 +106,7 @@ seconds, native)</c>. The result equals the number of whole <c>native</c> time units per second. In case the number of <c>native</c> time units per second does - not add up to a whole number, the result will be - rounded downwards.</p> + not add up to a whole number, the result is rounded downwards.</p> <note> <p>The value of the <c>native</c> time unit gives @@ -120,7 +120,7 @@ but it gives absolutely no information at all about the <seealso marker="time_correction#Time_Accuracy">accuracy</seealso> of time values. The resolution of the <c>native</c> time - unit and the resolution of time values may differ + unit and the resolution of time values can differ significantly.</p> </note> </item> @@ -139,12 +139,15 @@ <func> <name name="abs" arity="1" clause_i="1"/> <name name="abs" arity="1" clause_i="2"/> - <type variable="Float" name_i="1"/> - <type variable="Int" name_i="2"/> - <fsummary>Arithmetical absolute value</fsummary> - <desc> - <p>Returns an integer or float which is the arithmetical - absolute value of <c><anno>Float</anno></c> or <c><anno>Int</anno></c>.</p> + <fsummary>Arithmetical absolute value.</fsummary> + <type> + <v>Float = float()</v> + <v>Int = integer()</v> + </type> + <desc> + <p>Returns an integer or float that is the arithmetical + absolute value of <c><anno>Float</anno></c> or + <c><anno>Int</anno></c>, for example:</p> <pre> > <input>abs(-3.33).</input> 3.33 @@ -153,206 +156,214 @@ <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="adler32" arity="1"/> - <fsummary>Compute adler32 checksum</fsummary> + <fsummary>Computes adler32 checksum.</fsummary> <desc> - <p>Computes and returns the adler32 checksum for <c><anno>Data</anno></c>.</p> + <p>Computes and returns the adler32 checksum for + <c><anno>Data</anno></c>.</p> </desc> </func> + <func> <name name="adler32" arity="2"/> - <fsummary>Compute adler32 checksum</fsummary> + <fsummary>Computes adler32 checksum.</fsummary> <desc> - <p>Continue computing the adler32 checksum by combining - the previous checksum, <c><anno>OldAdler</anno></c>, with the checksum of - <c><anno>Data</anno></c>.</p> - <p>The following code:</p> - <code> - X = erlang:adler32(Data1), - Y = erlang:adler32(X,Data2). - </code> - <p>- would assign the same value to <c>Y</c> as this would:</p> - <code> - Y = erlang:adler32([Data1,Data2]). - </code> + <p>Continues computing the adler32 checksum by combining + the previous checksum, <c><anno>OldAdler</anno></c>, with + the checksum of <c><anno>Data</anno></c>.</p> + <p>The following code:</p> + <code> + X = erlang:adler32(Data1), + Y = erlang:adler32(X,Data2).</code> + <p>assigns the same value to <c>Y</c> as this:</p> + <code> + Y = erlang:adler32([Data1,Data2]).</code> </desc> </func> + <func> <name name="adler32_combine" arity="3"/> - <fsummary>Combine two adler32 checksums</fsummary> - <desc> - <p>Combines two previously computed adler32 checksums. - This computation requires the size of the data object for - the second checksum to be known.</p> - <p>The following code:</p> - <code> - Y = erlang:adler32(Data1), - Z = erlang:adler32(Y,Data2). - </code> - <p>- would assign the same value to <c>Z</c> as this would:</p> - <code> - X = erlang:adler32(Data1), - Y = erlang:adler32(Data2), - Z = erlang:adler32_combine(X,Y,iolist_size(Data2)). - </code> + <fsummary>Combines two adler32 checksums.</fsummary> + <desc> + <p>Combines two previously computed adler32 checksums. + This computation requires the size of the data object for + the second checksum to be known.</p> + <p>The following code:</p> + <code> + Y = erlang:adler32(Data1), + Z = erlang:adler32(Y,Data2).</code> + <p>assigns the same value to <c>Z</c> as this:</p> + <code> + X = erlang:adler32(Data1), + Y = erlang:adler32(Data2), + Z = erlang:adler32_combine(X,Y,iolist_size(Data2)).</code> </desc> </func> + <func> <name name="append_element" arity="2"/> - <fsummary>Append an extra element to a tuple</fsummary> - <desc> - <p>Returns a new tuple which has one element more than - <c><anno>Tuple1</anno></c>, and contains the elements in <c><anno>Tuple1</anno></c> - followed by <c><anno>Term</anno></c> as the last element. Semantically - equivalent to - <c>list_to_tuple(tuple_to_list(<anno>Tuple1</anno>) ++ [<anno>Term</anno>])</c>, but much - faster.</p> + <fsummary>Appends an extra element to a tuple.</fsummary> + <desc> + <p>Returns a new tuple that has one element more than + <c><anno>Tuple1</anno></c>, and contains the elements in + <c><anno>Tuple1</anno></c> + followed by <c><anno>Term</anno></c> as the last element. + Semantically equivalent to + <c>list_to_tuple(tuple_to_list(<anno>Tuple1</anno>) ++ + [<anno>Term</anno>])</c>, but much faster.</p> + <p>Example:</p> <pre> > <input>erlang:append_element({one, two}, three).</input> {one,two,three}</pre> </desc> </func> + <func> <name name="apply" arity="2"/> - <fsummary>Apply a function to an argument list</fsummary> + <fsummary>Applies a function to an argument list.</fsummary> <desc> - <p>Call a fun, passing the elements in <c><anno>Args</anno></c> as - arguments.</p> - <p>Note: If the number of elements in the arguments are known at - compile-time, the call is better written as + <p>Calls a fun, passing the elements in <c><anno>Args</anno></c> + as arguments.</p> + <p>If the number of elements in the arguments are known at + compile time, the call is better written as <c><anno>Fun</anno>(Arg1, Arg2, ... ArgN)</c>.</p> <warning> <p>Earlier, <c><anno>Fun</anno></c> could also be given as <c>{Module, Function}</c>, equivalent to - <c>apply(Module, Function, Args)</c>. This usage is - deprecated and will stop working in a future release of - Erlang/OTP.</p> + <c>apply(Module, Function, Args)</c>. This use is + deprecated and will stop working in a future release.</p> </warning> </desc> </func> + <func> <name name="apply" arity="3"/> - <fsummary>Apply a function to an argument list</fsummary> + <fsummary>Applies a function to an argument list.</fsummary> <desc> <p>Returns the result of applying <c>Function</c> in - <c><anno>Module</anno></c> to <c><anno>Args</anno></c>. The applied function must + <c><anno>Module</anno></c> to <c><anno>Args</anno></c>. + The applied function must be exported from <c>Module</c>. The arity of the function is the length of <c>Args</c>.</p> + <p>Example:</p> <pre> > <input>apply(lists, reverse, [[a, b, c]]).</input> -[c,b,a]</pre> - <p><c>apply</c> can be used to evaluate BIFs by using - the module name <c>erlang</c>.</p> - <pre> +[c,b,a] > <input>apply(erlang, atom_to_list, ['Erlang']).</input> "Erlang"</pre> - <p>Note: If the number of arguments are known at compile-time, + <p>If the number of arguments are known at compile time, the call is better written as <c><anno>Module</anno>:<anno>Function</anno>(Arg1, Arg2, ..., ArgN)</c>.</p> <p>Failure: <c>error_handler:undefined_function/3</c> is called if the applied function is not exported. The error handler can be redefined (see <seealso marker="#process_flag/2">process_flag/2</seealso>). - If the <c>error_handler</c> is undefined, or if the user has + If <c>error_handler</c> is undefined, or if the user has redefined the default <c>error_handler</c> so the replacement module is undefined, an error with the reason <c>undef</c> is generated.</p> </desc> </func> + <func> <name name="atom_to_binary" arity="2"/> - <fsummary>Return the binary representation of an atom</fsummary> - <desc> - <p>Returns a binary which corresponds to the text - representation of <c><anno>Atom</anno></c>. If <c><anno>Encoding</anno></c> - is <c>latin1</c>, there will be one byte for each character - in the text representation. If <c><anno>Encoding</anno></c> is - <c>utf8</c> or - <c>unicode</c>, the characters will be encoded using UTF-8 - (meaning that characters from 16#80 up to 0xFF will be - encoded in two bytes).</p> - - <note><p>Currently, <c>atom_to_binary(<anno>Atom</anno>, latin1)</c> can - never fail because the text representation of an atom can only contain - characters from 0 to 16#FF. In a future release, the text representation - of atoms might be allowed to contain any Unicode character - and <c>atom_to_binary(<anno>Atom</anno>, latin1)</c> will fail if the - text representation for the <c><anno>Atom</anno></c> contains a Unicode - character greater than 16#FF.</p></note> - + <fsummary>Returns the binary representation of an atom.</fsummary> + <desc> + <p>Returns a binary corresponding to the text + representation of <c><anno>Atom</anno></c>. + If <c><anno>Encoding</anno></c> + is <c>latin1</c>, there is one byte for each character + in the text representation. If <c><anno>Encoding</anno></c> is + <c>utf8</c> or + <c>unicode</c>, the characters are encoded using UTF-8 + (that is, characters from 128 through 255 are + encoded in two bytes).</p> + <note><p><c>atom_to_binary(<anno>Atom</anno>, latin1)</c> never + fails because the text representation of an atom can only + contain characters from 0 through 255. In a future release, + the text representation + of atoms can be allowed to contain any Unicode character and + <c>atom_to_binary(<anno>Atom</anno>, latin1)</c> will then fail if the + text representation for <c><anno>Atom</anno></c> contains a Unicode + character greater than 255.</p></note> + <p>Example:</p> <pre> > <input>atom_to_binary('Erlang', latin1).</input> <<"Erlang">></pre> </desc> </func> + <func> <name name="atom_to_list" arity="1"/> - <fsummary>Text representation of an atom</fsummary> + <fsummary>Text representation of an atom.</fsummary> <desc> - <p>Returns a string which corresponds to the text - representation of <c><anno>Atom</anno></c>.</p> + <p>Returns a string corresponding to the text + representation of <c><anno>Atom</anno></c>, for example:</p> <pre> > <input>atom_to_list('Erlang').</input> "Erlang"</pre> </desc> </func> + <func> <name name="binary_part" arity="2"/> - <fsummary>Extracts a part of a binary</fsummary> + <fsummary>Extracts a part of a binary.</fsummary> <desc> - <p>Extracts the part of the binary described by <c><anno>PosLen</anno></c>.</p> - - <p>Negative length can be used to extract bytes at the end of a binary:</p> - + <p>Extracts the part of the binary described by + <c><anno>PosLen</anno></c>.</p> + <p>Negative length can be used to extract bytes at the end + of a binary, for example:</p> <code> 1> Bin = <<1,2,3,4,5,6,7,8,9,10>>. 2> binary_part(Bin,{byte_size(Bin), -5}). -<<6,7,8,9,10>> -</code> - - <p>If <c><anno>PosLen</anno></c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> - - <p><c><anno>Start</anno></c> is zero-based, i.e.:</p> +<<6,7,8,9,10>></code> + <p>Failure: <c>badarg</c> if <c><anno>PosLen</anno></c> in any way + references outside the binary.</p> + <p><c><anno>Start</anno></c> is zero-based, that is:</p> <code> 1> Bin = <<1,2,3>> 2> binary_part(Bin,{0,2}). -<<1,2>> -</code> - - <p>See the STDLIB module <c>binary</c> for details about the <c><anno>PosLen</anno></c> semantics.</p> - +<<1,2>></code> + <p>For details about the <c><anno>PosLen</anno></c> semantics, see the + <seealso marker="stdlib:binary">binary</seealso> + manual page in <c>STDLIB</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="binary_part" arity="3"/> - <fsummary>Extracts a part of a binary</fsummary> + <fsummary>Extracts a part of a binary.</fsummary> <desc> - <p>The same as <c>binary_part(<anno>Subject</anno>, {<anno>Start</anno>, <anno>Length</anno>})</c>.</p> - + <p>The same as <c>binary_part(<anno>Subject</anno>, + {<anno>Start</anno>, <anno>Length</anno>})</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="binary_to_atom" arity="2"/> - <fsummary>Convert from text representation to an atom</fsummary> + <fsummary>Converts from text representation to an atom.</fsummary> <desc> <p>Returns the atom whose text representation is - <c><anno>Binary</anno></c>. If <c><anno>Encoding</anno></c> is <c>latin1</c>, no - translation of bytes in the binary is done. If <c><anno>Encoding</anno></c> - is <c>utf8</c> or <c>unicode</c>, the binary must contain - valid UTF-8 sequences; furthermore, only Unicode characters up - to 0xFF are allowed.</p> - - <note><p><c>binary_to_atom(<anno>Binary</anno>, utf8)</c> will fail if - the binary contains Unicode characters greater than 16#FF. - In a future release, such Unicode characters might be allowed - and <c>binary_to_atom(<anno>Binary</anno>, utf8)</c> - will not fail in that case. For more information on Unicode support in atoms - see <seealso marker="erl_ext_dist#utf8_atoms">note on UTF-8 encoded atoms</seealso> - in the chapter about the external term format in the ERTS User's Guide.</p></note> - + <c><anno>Binary</anno></c>. + If <c><anno>Encoding</anno></c> is <c>latin1</c>, no + translation of bytes in the binary is done. + If <c><anno>Encoding</anno></c> + is <c>utf8</c> or <c>unicode</c>, the binary must contain + valid UTF-8 sequences. Only Unicode characters up + to 255 are allowed.</p> + <note><p><c>binary_to_atom(<anno>Binary</anno>, utf8)</c> fails if + the binary contains Unicode characters greater than 255. + In a future release, such Unicode characters can be allowed + and <c>binary_to_atom(<anno>Binary</anno>, utf8)</c> does then not fail. + For more information on Unicode support in atoms, see the + <seealso marker="erl_ext_dist#utf8_atoms">note on UTF-8 + encoded atoms</seealso> + in Section "External Term Format" in the User's Guide.</p></note> + <p>Examples:</p> <pre> > <input>binary_to_atom(<<"Erlang">>, latin1).</input> 'Erlang' @@ -362,20 +373,24 @@ called as binary_to_atom(<<208,128>>,utf8)</pre> </desc> </func> + <func> <name name="binary_to_existing_atom" arity="2"/> - <fsummary>Convert from text representation to an atom</fsummary> + <fsummary>Converts from text representation to an atom.</fsummary> <desc> - <p>Works like <seealso marker="#binary_to_atom/2">binary_to_atom/2</seealso>, - but the atom must already exist.</p> - <p>Failure: <c>badarg</c> if the atom does not already exist.</p> + <p>As + <seealso marker="#binary_to_atom/2">binary_to_atom/2</seealso>, + but the atom must exist.</p> + <p>Failure: <c>badarg</c> if the atom does not exist.</p> </desc> </func> + <func> <name name="binary_to_float" arity="1"/> - <fsummary>Convert from text representation to a float</fsummary> + <fsummary>Converts from text representation to a float.</fsummary> <desc> - <p>Returns the float whose text representation is <c><anno>Binary</anno></c>.</p> + <p>Returns the float whose text representation is + <c><anno>Binary</anno></c>, for example:</p> <pre> > <input>binary_to_float(<<"2.2017764e+0">>).</input> 2.2017764</pre> @@ -383,12 +398,13 @@ representation of a float.</p> </desc> </func> + <func> <name name="binary_to_integer" arity="1"/> - <fsummary>Convert from text representation to an integer</fsummary> + <fsummary>Converts from text representation to an integer.</fsummary> <desc> <p>Returns an integer whose text representation is - <c><anno>Binary</anno></c>.</p> + <c><anno>Binary</anno></c>, for example:</p> <pre> > <input>binary_to_integer(<<"123">>).</input> 123</pre> @@ -396,12 +412,13 @@ representation of an integer.</p> </desc> </func> + <func> <name name="binary_to_integer" arity="2"/> - <fsummary>Convert from text representation to an integer</fsummary> + <fsummary>Converts from text representation to an integer.</fsummary> <desc> <p>Returns an integer whose text representation in base - <c><anno>Base</anno></c> is <c><anno>Binary</anno></c>.</p> + <c><anno>Base</anno></c> is <c><anno>Binary</anno></c>, for example:</p> <pre> > <input>binary_to_integer(<<"3FF">>, 16).</input> 1023</pre> @@ -409,93 +426,101 @@ representation of an integer.</p> </desc> </func> + <func> <name name="binary_to_list" arity="1"/> - <fsummary>Convert a binary to a list</fsummary> + <fsummary>Converts a binary to a list.</fsummary> <desc> - <p>Returns a list of integers which correspond to the bytes of + <p>Returns a list of integers corresponding to the bytes of <c><anno>Binary</anno></c>.</p> </desc> </func> + <func> <name name="binary_to_list" arity="3"/> - <fsummary>Convert part of a binary to a list</fsummary> - <type_desc variable="Start">1..byte_size(<anno>Binary</anno>)</type_desc> + <fsummary>Converts part of a binary to a list.</fsummary> + <type_desc variable="Start">1..byte_size(<c><anno>Binary</anno></c>)</type_desc> <desc> <p>As <c>binary_to_list/1</c>, but returns a list of integers corresponding to the bytes from position <c><anno>Start</anno></c> to - position <c><anno>Stop</anno></c> in <c><anno>Binary</anno></c>. Positions in the + position <c><anno>Stop</anno></c> in <c><anno>Binary</anno></c>. + The positions in the binary are numbered starting from 1.</p> - - <note><p>This function's indexing style of using one-based indices for - binaries is deprecated. New code should use the functions in - the STDLIB module <c>binary</c> instead. They consequently - use the same (zero-based) style of indexing.</p></note> + <note><p>The one-based indexing for binaries used by + this function is deprecated. New code is to use + <seealso marker="stdlib:binary#bin_to_list/3">binary:bin_to_list/3</seealso> + in <c>STDLIB</c> instead. All functions in module + <c>binary</c> consistently use zero-based indexing.</p></note> </desc> </func> + <func> <name name="bitstring_to_list" arity="1"/> - <fsummary>Convert a bitstring to a list</fsummary> + <fsummary>Converts a bitstring to a list.</fsummary> <desc> - <p>Returns a list of integers which correspond to the bytes of - <c><anno>Bitstring</anno></c>. If the number of bits in the binary is not - divisible by 8, the last element of the list will be a bitstring - containing the remaining bits (1 up to 7 bits).</p> + <p>Returns a list of integers corresponding to the bytes of + <c><anno>Bitstring</anno></c>. If the number of bits in the binary + is not divisible by 8, the last element of the list is a bitstring + containing the remaining 1-7 bits.</p> </desc> </func> + <func> <name name="binary_to_term" arity="1"/> - <fsummary>Decode an Erlang external term format binary</fsummary> + <fsummary>Decodes an Erlang external term format binary.</fsummary> <desc> - <p>Returns an Erlang term which is the result of decoding - the binary object <c><anno>Binary</anno></c>, which must be encoded + <p>Returns an Erlang term that is the result of decoding + binary object <c><anno>Binary</anno></c>, which must be encoded according to the Erlang external term format.</p> - <warning> - <p>When decoding binaries from untrusted sources, consider using - <c>binary_to_term/2</c> to prevent denial of service attacks.</p> - </warning> - <p>See also - <seealso marker="#term_to_binary/1">term_to_binary/1</seealso> - and - <seealso marker="#binary_to_term/2">binary_to_term/2</seealso>.</p> + <warning><p>When decoding binaries from untrusted sources, + consider using <c>binary_to_term/2</c> to prevent Denial + of Service attacks.</p></warning> + <p>See also + <seealso marker="#term_to_binary/1">term_to_binary/1</seealso> + and + <seealso marker="#binary_to_term/2">binary_to_term/2</seealso>.</p> </desc> </func> + <func> <name name="binary_to_term" arity="2"/> - <fsummary>Decode an Erlang external term format binary</fsummary> + <fsummary>Decodes an Erlang external term format binary.</fsummary> <desc> <p>As <c>binary_to_term/1</c>, but takes options that affect decoding of the binary.</p> <taglist> <tag><c>safe</c></tag> <item> - <p>Use this option when receiving binaries from an untrusted + <p>Use this option when receiving binaries from an untrusted source.</p> - <p>When enabled, it prevents decoding data that may be used to - attack the Erlang system. In the event of receiving unsafe - data, decoding fails with a badarg error.</p> - <p>Currently, this prevents creation of new atoms directly, - creation of new atoms indirectly (as they are embedded in - certain structures like pids, refs, funs, etc.), and creation of - new external function references. None of those resources are - currently garbage collected, so unchecked creation of them can - exhaust available memory.</p> + <p>When enabled, it prevents decoding data that can be used to + attack the Erlang system. In the event of receiving unsafe + data, decoding fails with a <c>badarg</c> error.</p> + <p>This prevents creation of new atoms directly, + creation of new atoms indirectly (as they are embedded in + certain structures, such as process identifiers, + refs, and funs), and + creation of new external function references. + None of those resources are garbage collected, so unchecked + creation of them can exhaust available memory.</p> </item> </taglist> - <p>Failure: <c>badarg</c> if <c>safe</c> is specified and unsafe data - is decoded.</p> + <p>Failure: <c>badarg</c> if <c>safe</c> is specified and unsafe + data is decoded.</p> <p>See also <seealso marker="#term_to_binary/1">term_to_binary/1</seealso>, <seealso marker="#binary_to_term/1">binary_to_term/1</seealso>, - and <seealso marker="#list_to_existing_atom/1"> - list_to_existing_atom/1</seealso>.</p> + and + <seealso marker="#list_to_existing_atom/1">list_to_existing_atom/1</seealso>.</p> </desc> </func> + <func> <name name="bit_size" arity="1"/> - <fsummary>Return the size of a bitstring</fsummary> + <fsummary>Returns the size of a bitstring.</fsummary> <desc> - <p>Returns an integer which is the size in bits of <c><anno>Bitstring</anno></c>.</p> + <p>Returns an integer that is the size in bits of + <c><anno>Bitstring</anno></c>, for example:</p> <pre> > <input>bit_size(<<433:16,3:3>>).</input> 19 @@ -504,30 +529,34 @@ <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="bump_reductions" arity="1"/> - <fsummary>Increment the reduction counter</fsummary> + <fsummary>Increments the reduction counter.</fsummary> <desc> <p>This implementation-dependent function increments the reduction counter for the calling process. In the Beam emulator, the reduction counter is normally incremented by - one for each function and BIF call, and a context switch is - forced when the counter reaches the maximum number of reductions - for a process (2000 reductions in R12B).</p> + one for each function and BIF call. A context switch is + forced when the counter reaches the maximum number of + reductions for a process (2000 reductions in OTP R12B).</p> <warning> - <p>This BIF might be removed in a future version of the Beam + <p>This BIF can be removed in a future version of the Beam machine without prior warning. It is unlikely to be implemented in other Erlang implementations.</p> </warning> </desc> </func> + <func> <name name="byte_size" arity="1"/> - <fsummary>Return the size of a bitstring (or binary)</fsummary> + <fsummary>Returns the size of a bitstring (or binary).</fsummary> <desc> - <p>Returns an integer which is the number of bytes needed to contain - <c><anno>Bitstring</anno></c>. (That is, if the number of bits in <c><anno>Bitstring</anno></c> is not - divisible by 8, the resulting number of bytes will be rounded <em>up</em>.)</p> + <p>Returns an integer that is the number of bytes needed to + contain <c><anno>Bitstring</anno></c>. That is, if the number of bits + in <c><anno>Bitstring</anno></c> is not divisible by 8, the resulting + number of bytes is rounded <em>up</em>.</p> + <p>Examples:</p> <pre> > <input>byte_size(<<433:16,3:3>>).</input> 3 @@ -536,18 +565,19 @@ <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="cancel_timer" arity="2"/> - <fsummary>Cancel a timer</fsummary> + <fsummary>Cancels a timer.</fsummary> <desc> <p> - Cancels a timer that has been created by either + Cancels a timer that has been created by <seealso marker="#start_timer/4"><c>erlang:start_timer()</c></seealso>, or <seealso marker="#send_after/4"><c>erlang:send_after()</c></seealso>. <c><anno>TimerRef</anno></c> identifies the timer, and was returned by the BIF that created the timer. </p> - <p>Currently available <c><anno>Option</anno></c>s:</p> + <p>Available <c><anno>Option</anno></c>s:</p> <taglist> <tag><c>{async, Async}</c></tag> <item> @@ -556,7 +586,7 @@ defaults to <c>false</c> which will cause the cancellation to be performed synchronously. When <c>Async</c> is set to <c>true</c>, the cancel - operation will be performed asynchronously. That is, + operation is performed asynchronously. That is, <c>erlang:cancel_timer()</c> will send an asynchronous request for cancellation to the timer service that manages the timer, and then return <c>ok</c>. @@ -567,17 +597,17 @@ <p> Request information about the <c><anno>Result</anno></c> of the cancellation. <c>Info</c> defaults to <c>true</c> - which means that the <c><anno>Result</anno></c> will - be given. When <c>Info</c> is set to <c>false</c>, no + which means the <c><anno>Result</anno></c> is + given. When <c>Info</c> is set to <c>false</c>, no information about the result of the cancellation - will be given. When the operation is performed</p> + is given. When the operation is performed</p> <taglist> <tag>synchronously</tag> <item> <p> - If <c>Info</c> is <c>true</c>, the <c>Result</c> will + If <c>Info</c> is <c>true</c>, the <c>Result</c> is returned by <c>erlang:cancel_timer()</c>; otherwise, - <c>ok</c> will be returned. + <c>ok</c> is returned. </p> </item> <tag>asynchronously</tag> @@ -585,10 +615,10 @@ <p> If <c>Info</c> is <c>true</c>, a message on the form <c>{cancel_timer, <anno>TimerRef</anno>, - <anno>Result</anno>}</c> will be sent to the + <anno>Result</anno>}</c> is sent to the caller of <c>erlang:cancel_timer()</c> when the cancellation operation has been performed; otherwise, - no message will be sent. + no message is sent. </p> </item> </taglist> @@ -597,30 +627,30 @@ <p> More <c><anno>Option</anno></c>s may be added in the future. </p> + <p>If <c><anno>Result</anno></c> is an integer, it represents + the time in milli-seconds left until the canceled timer would + have expired.</p> <p> - When the <c><anno>Result</anno></c> equals <c>false</c>, a + If <c><anno>Result</anno></c> is <c>false</c>, a timer corresponding to <c><anno>TimerRef</anno></c> could not be found. This can be either because the timer had expired, already had been canceled, or because <c><anno>TimerRef</anno></c> - never has corresponded to a timer. If the timer has expired, - the timeout message has been sent, but it does not tell you - whether or not it has arrived at its destination yet. When the - <c><anno>Result</anno></c> is an integer, it represents the - time in milli-seconds left until the timer will expire. + never corresponded to a timer. Even if the timer had expired, + it does not tell you whether or not the timeout message has + arrived at its destination yet. </p> <note> <p> The timer service that manages the timer may be co-located with another scheduler than the scheduler that the calling process is executing on. If this is the case, communication - with the timer service will take much longer time than if it + with the timer service takes much longer time than if it is located locally. If the calling process is in critical path, and can do other things while waiting for the result of this operation, or is not interested in the result of - the operation, you want to use the <c>{async, true}</c> - option. If using the <c>{async, false}</c> option, the calling - process will be blocked until the operation has been - performed. + the operation, you want to use option <c>{async, true}</c>. + If using option <c>{async, false}</c>, the calling + process blocks until the operation has been performed. </p> </note> <p>See also @@ -632,7 +662,7 @@ </func> <func> <name name="cancel_timer" arity="1"/> - <fsummary>Cancel a timer</fsummary> + <fsummary>Cancels a timer.</fsummary> <desc> <p>Cancels a timer. The same as calling <seealso marker="#cancel_timer/2"><c>erlang:cancel_timer(TimerRef, @@ -641,103 +671,102 @@ </func> <func> <name name="check_old_code" arity="1"/> - <fsummary>Check if a module has old code</fsummary> + <fsummary>Checks if a module has old code.</fsummary> <desc> - <p>Returns <c>true</c> if the <c><anno>Module</anno></c> has old code, - and <c>false</c> otherwise.</p> + <p>Returns <c>true</c> if <c><anno>Module</anno></c> has old code, + otherwise <c>false</c>.</p> <p>See also <seealso marker="kernel:code">code(3)</seealso>.</p> </desc> </func> + <func> <name name="check_process_code" arity="2"/> - <fsummary>Check if a process is executing old code for a module</fsummary> + <fsummary>Checks if a process executes old code for a module.</fsummary> <desc> <p>The same as - <seealso marker="#check_process_code/3"><c>erlang:check_process_code(<anno>Pid</anno>, - <anno>Module</anno>, [])</c></seealso>.</p> + <seealso marker="#check_process_code/3"><c>erlang:check_process_code(<anno>Pid</anno>, <anno>Module</anno>, [])</c></seealso>.</p> </desc> </func> + <func> <name name="check_process_code" arity="3"/> - <fsummary>Check if a process is executing old code for a module</fsummary> + <fsummary>Checks if a process executes old code for a module.</fsummary> <desc> - <p>Check if the node local process identified by <c><anno>Pid</anno></c> - is executing old code for <c><anno>Module</anno></c>.</p> - <p>Currently available <c><anno>Option</anno>s</c>:</p> + <p>Checks if the node local process identified by <c><anno>Pid</anno></c> + executes old code for <c><anno>Module</anno></c>.</p> + <p>The available <c><anno>Option</anno></c>s are as follows:</p> <taglist> <tag><c>{allow_gc, boolean()}</c></tag> <item> - Determines if garbage collection is allowed when performing - the operation. If <c>{allow_gc, false}</c> is passed, and - a garbage collection is needed in order to determine the - result of the operation, the operation will be aborted - (see information on <c><anno>CheckResult</anno></c> below). - The default is to allow garbage collection, i.e., - <c>{allow_gc, true}</c>. + <p>Determines if garbage collection is allowed when performing + the operation. If <c>{allow_gc, false}</c> is passed, and + a garbage collection is needed to determine the + result of the operation, the operation is aborted (see + information on <c><anno>CheckResult</anno></c> in the following). + The default is to allow garbage collection, that is, + <c>{allow_gc, true}</c>.</p> </item> <tag><c>{async, RequestId}</c></tag> <item> - The <c>check_process_code/3</c> function will return - the value <c>async</c> immediately after the request - has been sent. When the request has been processed, the - process that called this function will be passed a - message on the form:<br/> - <c>{check_process_code, <anno>RequestId</anno>, <anno>CheckResult</anno>}</c>. + <p>The function <c>check_process_code/3</c> returns + the value <c>async</c> immediately after the request + has been sent. When the request has been processed, the + process that called this function is passed a + message on the form + <c>{check_process_code, <anno>RequestId</anno>, <anno>CheckResult</anno>}</c>.</p> </item> </taglist> - <p>If <c><anno>Pid</anno></c> equals <c>self()</c>, and - no <c>async</c> option has been passed, the operation will - be performed at once. In all other cases a request for - the operation will be sent to the process identified by - <c><anno>Pid</anno></c>, and will be handled when - appropriate. If no <c>async</c> option has been passed, - the caller will block until <c><anno>CheckResult</anno></c> - is available and can be returned.</p> - <p><c><anno>CheckResult</anno></c> informs about the result of - the request:</p> + <p>If <c><anno>Pid</anno></c> equals <c>self()</c>, and + no <c>async</c> option has been passed, the operation + is performed at once. Otherwise a request for + the operation is sent to the process identified by + <c><anno>Pid</anno></c>, and is handled when + appropriate. If no <c>async</c> option has been passed, + the caller blocks until <c><anno>CheckResult</anno></c> + is available and can be returned.</p> + <p><c><anno>CheckResult</anno></c> informs about the result of + the request as follows:</p> <taglist> <tag><c>true</c></tag> <item> - The process identified by <c><anno>Pid</anno></c> is - executing old code for <c><anno>Module</anno></c>. - That is, the current call of the process executes old - code for this module, or the process has references - to old code for this module, or the process contains - funs that references old code for this module. + <p>The process identified by <c><anno>Pid</anno></c> + executes old code for <c><anno>Module</anno></c>. + That is, the current call of the process executes old + code for this module, or the process has references + to old code for this module, or the process contains + funs that references old code for this module.</p> </item> <tag><c>false</c></tag> <item> - The process identified by <c><anno>Pid</anno></c> is - not executing old code for <c><anno>Module</anno></c>. + <p>The process identified by <c><anno>Pid</anno></c> does + not execute old code for <c><anno>Module</anno></c>.</p> </item> <tag><c>aborted</c></tag> <item> - The operation was aborted since the process needed to - be garbage collected in order to determine the result - of the operation, and the operation was requested - by passing the <c>{allow_gc, false}</c> option.</item> + <p>The operation was aborted, as the process needed to + be garbage collected to determine the operation result, + and the operation was requested + by passing option <c>{allow_gc, false}</c>.</p></item> </taglist> <p>See also <seealso marker="kernel:code">code(3)</seealso>.</p> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> - <item> - If <c><anno>Pid</anno></c> is not a node local process identifier. + <item>If <c><anno>Pid</anno></c> is not a node local process identifier. </item> <tag><c>badarg</c></tag> - <item> - If <c><anno>Module</anno></c> is not an atom. + <item>If <c><anno>Module</anno></c> is not an atom. </item> <tag><c>badarg</c></tag> - <item> - If <c><anno>OptionList</anno></c> is not a valid list of options. + <item>If <c><anno>OptionList</anno></c> is an invalid list of options. </item> </taglist> </desc> </func> + <func> <name name="convert_time_unit" arity="3"/> - <fsummary>Convert time unit of a time value</fsummary> + <fsummary>Converts time unit of a time value.</fsummary> <desc> <p>Converts the <c><anno>Time</anno></c> value of time unit <c><anno>FromUnit</anno></c> to the corresponding @@ -753,100 +782,102 @@ </func> <func> <name name="crc32" arity="1"/> - <fsummary>Compute crc32 (IEEE 802.3) checksum</fsummary> + <fsummary>Computes crc32 (IEEE 802.3) checksum.</fsummary> <desc> - <p>Computes and returns the crc32 (IEEE 802.3 style) checksum for <c><anno>Data</anno></c>.</p> + <p>Computes and returns the crc32 (IEEE 802.3 style) checksum + for <c><anno>Data</anno></c>.</p> </desc> </func> + <func> <name name="crc32" arity="2"/> - <fsummary>Compute crc32 (IEEE 802.3) checksum</fsummary> + <fsummary>Computes crc32 (IEEE 802.3) checksum.</fsummary> <desc> - <p>Continue computing the crc32 checksum by combining - the previous checksum, <c><anno>OldCrc</anno></c>, with the checksum of - <c><anno>Data</anno></c>.</p> - <p>The following code:</p> - <code> - X = erlang:crc32(Data1), - Y = erlang:crc32(X,Data2). - </code> - <p>- would assign the same value to <c>Y</c> as this would:</p> - <code> - Y = erlang:crc32([Data1,Data2]). - </code> + <p>Continues computing the crc32 checksum by combining + the previous checksum, <c><anno>OldCrc</anno></c>, with the checksum of + <c><anno>Data</anno></c>.</p> + <p>The following code:</p> + <code> + X = erlang:crc32(Data1), + Y = erlang:crc32(X,Data2).</code> + <p>assigns the same value to <c>Y</c> as this:</p> + <code> + Y = erlang:crc32([Data1,Data2]).</code> </desc> </func> + <func> <name name="crc32_combine" arity="3"/> - <fsummary>Combine two crc32 (IEEE 802.3) checksums</fsummary> - <desc> - <p>Combines two previously computed crc32 checksums. - This computation requires the size of the data object for - the second checksum to be known.</p> - <p>The following code:</p> + <fsummary>Combines two crc32 (IEEE 802.3) checksums.</fsummary> + <desc> + <p>Combines two previously computed crc32 checksums. + This computation requires the size of the data object for + the second checksum to be known.</p> + <p>The following code:</p> + <code> + Y = erlang:crc32(Data1), + Z = erlang:crc32(Y,Data2).</code> + <p>assigns the same value to <c>Z</c> as this:</p> <code> - Y = erlang:crc32(Data1), - Z = erlang:crc32(Y,Data2). - </code> - <p>- would assign the same value to <c>Z</c> as this would:</p> - <code> - X = erlang:crc32(Data1), - Y = erlang:crc32(Data2), - Z = erlang:crc32_combine(X,Y,iolist_size(Data2)). - </code> + X = erlang:crc32(Data1), + Y = erlang:crc32(Data2), + Z = erlang:crc32_combine(X,Y,iolist_size(Data2)).</code> </desc> </func> + <func> <name name="date" arity="0"/> - <fsummary>Current date</fsummary> + <fsummary>Current date.</fsummary> <desc> <p>Returns the current date as <c>{Year, Month, Day}</c>.</p> - <p>The time zone and daylight saving time correction depend on + <p>The time zone and Daylight Saving Time correction depend on the underlying OS.</p> + <p>Example:</p> <pre> > <input>date().</input> {1995,2,19}</pre> </desc> </func> + <func> <name name="decode_packet" arity="3"/> - <fsummary>Extracts a protocol packet from a binary</fsummary> + <fsummary>Extracts a protocol packet from a binary.</fsummary> <desc> - <p>Decodes the binary <c><anno>Bin</anno></c> according to the packet - protocol specified by <c><anno>Type</anno></c>. Very similar to the packet - handling done by sockets with the option {packet,<anno>Type</anno>}.</p> - <p>If an entire packet is contained in <c><anno>Bin</anno></c> it is + protocol specified by <c><anno>Type</anno></c>. Similar to the packet + handling done by sockets with option {packet,<anno>Type</anno>}.</p> + <p>If an entire packet is contained in <c><anno>Bin</anno></c>, it is returned together with the remainder of the binary as <c>{ok,<anno>Packet</anno>,<anno>Rest</anno>}</c>.</p> <p>If <c><anno>Bin</anno></c> does not contain the entire packet, - <c>{more,<anno>Length</anno>}</c> is returned. <c><anno>Length</anno></c> is either the - expected <em>total size</em> of the packet or <c>undefined</c> - if the expected packet size is not known. <c>decode_packet</c> + <c>{more,<anno>Length</anno>}</c> is returned. + <c><anno>Length</anno></c> is either the + expected <em>total size</em> of the packet, or <c>undefined</c> + if the expected packet size is unknown. <c>decode_packet</c> can then be called again with more data added.</p> - <p>If the packet does not conform to the protocol format + <p>If the packet does not conform to the protocol format, <c>{error,<anno>Reason</anno>}</c> is returned.</p> - <p>The following values of <c><anno>Type</anno></c> are valid:</p> + <p>The following <c>Type</c>s are valid:</p> <taglist> <tag><c>raw | 0</c></tag> <item> - <p>No packet handling is done. Entire binary is + <p>No packet handling is done. The entire binary is returned unless it is empty.</p> </item> <tag><c>1 | 2 | 4</c></tag> <item> <p>Packets consist of a header specifying the number of bytes in the packet, followed by that number of bytes. - The length of header can be one, two, or four bytes; + The length of the header can be one, two, or four bytes; the order of the bytes is big-endian. The header - will be stripped off when the packet is returned.</p> + is stripped off when the packet is returned.</p> </item> <tag><c>line</c></tag> <item> - <p>A packet is a line terminated with newline. The - newline character is included in the returned packet - unless the line was truncated according to the option - <c>line_length</c>.</p> + <p>A packet is a line terminated by a delimiter byte, + default is the latin1 newline character. The delimiter + byte is included in the returned packet unless the line + was truncated according to option <c>line_length</c>.</p> </item> <tag><c>asn1 | cdr | sunrm | fcgi | tpkt</c></tag> <item> @@ -864,41 +895,50 @@ <item> <p>The Hypertext Transfer Protocol. The packets are returned with the format according to - <c><anno>HttpPacket</anno></c> described above. A packet is either a - request, a response, a header or an end of header - mark. Invalid lines are returned as <c><anno>HttpError</anno></c>.</p> - <p>Recognized request methods and header fields are returned as atoms. - Others are returned as strings. Strings of unrecognized header fields - are formatted with only capital letters first and after hyphen characters - (like <c>"Sec-Websocket-Key"</c>).</p> - <p>The protocol type <c>http</c> should only be used for - the first line when a <c><anno>HttpRequest</anno></c> or a - <c><anno>HttpResponse</anno></c> is expected. The following calls - should use <c>httph</c> to get <c><anno>HttpHeader</anno></c>'s until - <c>http_eoh</c> is returned that marks the end of the + <c><anno>HttpPacket</anno></c> described earlier. + A packet is either a + request, a response, a header, or an end of header + mark. Invalid lines are returned as + <c><anno>HttpError</anno></c>.</p> + <p>Recognized request methods and header fields are returned + as atoms. Others are returned as strings. Strings of + unrecognized header fields are formatted with only + capital letters first and after hyphen characters, for + example, <c>"Sec-Websocket-Key"</c>.</p> + <p>The protocol type <c>http</c> is only to be used for + the first line when an <c><anno>HttpRequest</anno></c> or an + <c><anno>HttpResponse</anno></c> is expected. + The following calls are to use <c>httph</c> to get + <c><anno>HttpHeader</anno></c>s until + <c>http_eoh</c> is returned, which marks the end of the headers and the beginning of any following message body.</p> - <p>The variants <c>http_bin</c> and <c>httph_bin</c> will return + <p>The variants <c>http_bin</c> and <c>httph_bin</c> return strings (<c>HttpString</c>) as binaries instead of lists.</p> </item> </taglist> <p>The following options are available:</p> <taglist> <tag><c>{packet_size, integer() >= 0}</c></tag> - <item><p>Sets the max allowed size of the packet body. If - the packet header indicates that the length of the - packet is longer than the max allowed length, the packet - is considered invalid. Default is 0 which means no - size limit.</p> + <item><p>Sets the maximum allowed size of the packet body. + If the packet header indicates that the length of the + packet is longer than the maximum allowed length, the + packet is considered invalid. Default is 0, which means + no size limit.</p> </item> <tag><c>{line_length, integer() >= 0}</c></tag> - <item><p>For packet type <c>line</c>, truncate lines longer - than the indicated length.</p> - <p>Option <c>line_length</c> also applies to <c>http*</c> - packet types as an alias for option <c>packet_size</c> in the - case when <c>packet_size</c> itself is not set. This usage is - only intended for backward compatibility.</p> + <item><p>For packet type <c>line</c>, lines longer than + the indicated length are truncated.</p> + <p>Option <c>line_length</c> also applies to <c>http*</c> + packet types as an alias for option <c>packet_size</c> + if <c>packet_size</c> itself is not set. This use is + only intended for backward compatibility.</p> + </item> + <tag><c>{line_delimiter, 0 =< byte() =< 255}</c></tag> + <item><p>For packet type <c>line</c>, sets the delimiting byte. + Default is the latin1 character <c>$\n</c>.</p> </item> </taglist> + <p>Examples:</p> <pre> > <input>erlang:decode_packet(1,<<3,"abcd">>,[]).</input> {ok,<<"abc">>,<<"d">>} @@ -909,13 +949,11 @@ <func> <name name="delete_element" arity="2"/> - <fsummary>Delete element at index in a tuple</fsummary> + <fsummary>Deletes element at index in a tuple.</fsummary> <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno>)</type_desc> <desc> - <p> - Returns a new tuple with element at <c><anno>Index</anno></c> removed from - tuple <c><anno>Tuple1</anno></c>. - </p> + <p>Returns a new tuple with element at <c><anno>Index</anno></c> + removed from tuple <c><anno>Tuple1</anno></c>, for example:</p> <pre> > <input>erlang:delete_element(2, {one, two, three}).</input> {one,three}</pre> @@ -924,78 +962,82 @@ <func> <name name="delete_module" arity="1"/> - <fsummary>Make the current code for a module old</fsummary> + <fsummary>Makes the current code for a module old.</fsummary> <desc> - <p>Makes the current code for <c><anno>Module</anno></c> become old code, and - deletes all references for this module from the export table. + <p>Makes the current code for <c><anno>Module</anno></c> become old code, + and deletes all references for this module from the export table. Returns <c>undefined</c> if the module does not exist, otherwise <c>true</c>.</p> <warning> <p>This BIF is intended for the code server (see - <seealso marker="kernel:code">code(3)</seealso>) and should not be - used elsewhere.</p> + <seealso marker="kernel:code">code(3)</seealso>) and is not + to be used elsewhere.</p> </warning> - <p>Failure: <c>badarg</c> if there is already an old version of + <p>Failure: <c>badarg</c> if there already is an old version of <c>Module</c>.</p> </desc> </func> + <func> <name name="demonitor" arity="1"/> - <fsummary>Stop monitoring</fsummary> + <fsummary>Stops monitoring.</fsummary> <desc> - <p>If <c><anno>MonitorRef</anno></c> is a reference which the calling process - obtained by calling + <p>If <c><anno>MonitorRef</anno></c> is a reference that the + calling process obtained by calling <seealso marker="#monitor/2">monitor/2</seealso>, this monitoring is turned off. If the monitoring is already turned off, nothing happens.</p> - <p>Once <c>demonitor(<anno>MonitorRef</anno>)</c> has returned it is - guaranteed that no <c>{'DOWN', <anno>MonitorRef</anno>, _, _, _}</c> message - due to the monitor will be placed in the caller's message queue - in the future. A <c>{'DOWN', <anno>MonitorRef</anno>, _, _, _}</c> message - might have been placed in the caller's message queue prior to - the call, though. Therefore, in most cases, it is advisable + <p>Once <c>demonitor(<anno>MonitorRef</anno>)</c> has returned, it is + guaranteed that no <c>{'DOWN', + <anno>MonitorRef</anno>, _, _, _}</c> message, + because of the monitor, will be placed in the caller message queue + in the future. A <c>{'DOWN', + <anno>MonitorRef</anno>, _, _, _}</c> message + can have been placed in the caller message queue before + the call, though. It is therefore usually advisable to remove such a <c>'DOWN'</c> message from the message queue - after monitoring has been stopped. - <seealso marker="#demonitor/2">demonitor(<anno>MonitorRef</anno>, [flush])</seealso> can be used instead of + after monitoring has been stopped. + <seealso marker="#demonitor/2"><c>demonitor(<anno>MonitorRef</anno>, [flush])</c></seealso> + can be used instead of <c>demonitor(<anno>MonitorRef</anno>)</c> if this cleanup is wanted.</p> <note> - <p>Prior to OTP release R11B (erts version 5.5) <c>demonitor/1</c> - behaved completely asynchronous, i.e., the monitor was active - until the "demonitor signal" reached the monitored entity. This - had one undesirable effect, though. You could never know when - you were guaranteed <em>not</em> to receive a <c>DOWN</c> message - due to the monitor.</p> - <p>Current behavior can be viewed as two combined operations: - asynchronously send a "demonitor signal" to the monitored entity - and ignore any future results of the monitor. </p> + <p>Before OTP R11B (<c>ERTS</c> 5.5), <c>demonitor/1</c> + behaved asynchronous, that is, the monitor was active + until the "demonitor signal" reached the monitored entity. + This had an undesirable effect, as you could never know when + you were guaranteed <em>not</em> to receive a <c>DOWN</c> + message because of the monitor.</p> + <p>The current behavior can be viewed as two combined operations: + asynchronously send a "demonitor signal" to the monitored + entity and ignore any future results of the monitor.</p> </note> <p>Failure: It is an error if <c><anno>MonitorRef</anno></c> refers to a monitoring started by another process. Not all such cases are - cheap to check; if checking is cheap, the call fails with - <c>badarg</c> (for example if <c><anno>MonitorRef</anno></c> is a remote - reference).</p> + cheap to check. If checking is cheap, the call fails with + <c>badarg</c> for example, if <c><anno>MonitorRef</anno></c> is a + remote reference.</p> </desc> </func> + <func> <name name="demonitor" arity="2"/> - <fsummary>Stop monitoring</fsummary> + <fsummary>Stops monitoring.</fsummary> <desc> <p>The returned value is <c>true</c> unless <c>info</c> is part - of <c><anno>OptionList</anno></c>. - </p> + of <c><anno>OptionList</anno></c>.</p> <p><c>demonitor(<anno>MonitorRef</anno>, [])</c> is equivalent to - <seealso marker="#demonitor/1">demonitor(<anno>MonitorRef</anno>)</seealso>.</p> - <p>Currently the following <c><anno>Option</anno></c>s are valid:</p> + <seealso marker="#demonitor/1"><c>demonitor(<anno>MonitorRef</anno>)</c></seealso>.</p> + <p>The available <c><anno>Option</anno></c>s are as follows:</p> <taglist> <tag><c>flush</c></tag> <item> - <p>Remove (one) <c>{_, <anno>MonitorRef</anno>, _, _, _}</c> message, - if there is one, from the caller's message queue after + <p>Removes (one) <c>{_, + <anno>MonitorRef</anno>, _, _, _}</c> message, + if there is one, from the caller message queue after monitoring has been stopped.</p> <p>Calling <c>demonitor(<anno>MonitorRef</anno>, [flush])</c> is equivalent to the following, but more efficient:</p> <code type="none"> - demonitor(MonitorRef), receive {_, MonitorRef, _, _, _} -> @@ -1006,78 +1048,90 @@ </item> <tag><c>info</c></tag> <item> - <p>The returned value is one of the following:</p> - <taglist> - <tag><c>true</c></tag> - <item><p>The monitor was found and removed. In this case - no <c>'DOWN'</c> message due to this monitor have - been nor will be placed in the message queue - of the caller. - </p> - </item> - <tag><c>false</c></tag> - <item><p>The monitor was not found and could not be removed. - This probably because someone already has placed a - <c>'DOWN'</c> message corresponding to this monitor - in the caller's message queue. - </p> - </item> - </taglist> - <p>If the <c>info</c> option is combined with the <c>flush</c> - option, <c>false</c> will be returned if a flush was needed; - otherwise, <c>true</c>. - </p> + <p>The returned value is one of the following:</p> + <taglist> + <tag><c>true</c></tag> + <item>The monitor was found and removed. In this case, + no <c>'DOWN'</c> message corresponding to this + monitor has been delivered and will not be delivered. + </item> + <tag><c>false</c></tag> + <item>The monitor was not found and could not be removed. + This probably because someone already has placed a + <c>'DOWN'</c> message corresponding to this monitor + in the caller message queue. + </item> + </taglist> + <p>If option <c>info</c> is combined with option <c>flush</c>, + <c>false</c> is returned if a flush was needed, + otherwise <c>true</c>.</p> </item> </taglist> <note> - <p>More options may be added in the future.</p> + <p>More options can be added in a future release.</p> </note> - <p>Failure: <c>badarg</c> if <c><anno>OptionList</anno></c> is not a list, or - if <c><anno>Option</anno></c> is not a valid option, or the same failure as for - <seealso marker="#demonitor/1">demonitor/1</seealso></p> + <p>Failures:</p> + <taglist> + <tag><c>badarg</c></tag> + <item>If <c><anno>OptionList</anno></c> is not a list. + </item> + <tag><c>badarg</c></tag> + <item>If <c><anno>Option</anno></c> is an invalid option. + </item> + <tag><c>badarg</c></tag> + <item>The same failure as for + <seealso marker="#demonitor/1">demonitor/1</seealso>. + </item> + </taglist> </desc> </func> + <func> <name name="disconnect_node" arity="1"/> - <fsummary>Force the disconnection of a node</fsummary> + <fsummary>Forces the disconnection of a node.</fsummary> <desc> - <p>Forces the disconnection of a node. This will appear to - the node <c><anno>Node</anno></c> as if the local node has crashed. This - BIF is mainly used in the Erlang network authentication - protocols. Returns <c>true</c> if disconnection succeeds, + <p>Forces the disconnection of a node. This appears to + the node <c><anno>Node</anno></c> as if the local node has crashed. + This BIF is mainly used in the Erlang network authentication + protocols.</p> + <p>Returns <c>true</c> if disconnection succeeds, otherwise <c>false</c>. If the local node is not alive, - the function returns <c>ignored</c>.</p> + <c>ignored</c> is returned.</p> </desc> </func> + <func> <name name="display" arity="1"/> - <fsummary>Print a term on standard output</fsummary> + <fsummary>Prints a term on standard output.</fsummary> <desc> - <p>Prints a text representation of <c><anno>Term</anno></c> on the standard - output. On OSE the term is printed to the ramlog.</p> + <p>Prints a text representation of <c><anno>Term</anno></c> on the + standard output.</p> <warning> <p>This BIF is intended for debugging only.</p> </warning> </desc> </func> + <func> <name name="element" arity="2"/> + <fsummary>Returns the Nth element of a tuple.</fsummary> <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc> - <fsummary>Get Nth element of a tuple</fsummary> <desc> <p>Returns the <c><anno>N</anno></c>th element (numbering from 1) of - <c><anno>Tuple</anno></c>.</p> + <c><anno>Tuple</anno></c>, for example:</p> <pre> > <input>element(2, {a, b, c}).</input> b</pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="erase" arity="0"/> - <fsummary>Return and delete the process dictionary</fsummary> + <fsummary>Returns and deletes the process dictionary.</fsummary> <desc> - <p>Returns the process dictionary and deletes it.</p> + <p>Returns the process dictionary and deletes it, for + example:</p> <pre> > <input>put(key1, {1, 2, 3}),</input> <input>put(key2, [a, b, c]),</input> @@ -1085,13 +1139,16 @@ b</pre> [{key1,{1,2,3}},{key2,[a,b,c]}]</pre> </desc> </func> + <func> <name name="erase" arity="1"/> - <fsummary>Return and delete a value from the process dictionary</fsummary> + <fsummary>Returns and deletes a value from the process dictionary.</fsummary> <desc> - <p>Returns the value <c><anno>Val</anno></c> associated with <c><anno>Key</anno></c> and - deletes it from the process dictionary. Returns - <c>undefined</c> if no value is associated with <c><anno>Key</anno></c>.</p> + <p>Returns the value <c><anno>Val</anno></c> associated with + <c><anno>Key</anno></c> and deletes it from the process dictionary. + Returns <c>undefined</c> if no value is associated with + <c><anno>Key</anno></c>.</p> + <p>Example:</p> <pre> > <input>put(key1, {merry, lambs, are, playing}),</input> <input>X = erase(key1),</input> @@ -1099,16 +1156,19 @@ b</pre> {{merry,lambs,are,playing},undefined}</pre> </desc> </func> + <func> <name name="error" arity="1"/> - <fsummary>Stop execution with a given reason</fsummary> + <fsummary>Stops execution with a given reason.</fsummary> <desc> <p>Stops the execution of the calling process with the reason - <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> is any term. The actual - exit reason will be <c>{<anno>Reason</anno>, Where}</c>, where <c>Where</c> + <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> + is any term. The exit reason is + <c>{<anno>Reason</anno>, Where}</c>, where <c>Where</c> is a list of the functions most recently called (the current function first). Since evaluating this function causes the process to terminate, it has no return value.</p> + <p>Example:</p> <pre> > <input>catch error(foobar).</input> {'EXIT',{foobar,[{erl_eval,do_apply,5}, @@ -1118,29 +1178,34 @@ b</pre> {shell,eval_loop,3}]}}</pre> </desc> </func> + <func> <name name="error" arity="2"/> - <fsummary>Stop execution with a given reason</fsummary> + <fsummary>Stops execution with a given reason.</fsummary> <desc> <p>Stops the execution of the calling process with the reason - <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> is any term. The actual - exit reason will be <c>{<anno>Reason</anno>, Where}</c>, where <c>Where</c> + <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> + is any term. The exit reason is + <c>{<anno>Reason</anno>, Where}</c>, where <c>Where</c> is a list of the functions most recently called (the current - function first). <c><anno>Args</anno></c> is expected to be the list of - arguments for the current function; in Beam it will be used - to provide the actual arguments for the current function in - the <c>Where</c> term. Since evaluating this function causes + function first). <c><anno>Args</anno></c> is expected to be the + list of arguments for the current function; in Beam it is used + to provide the arguments for the current function in + the term <c>Where</c>. Since evaluating this function causes the process to terminate, it has no return value.</p> </desc> </func> + <func> <name name="exit" arity="1"/> - <fsummary>Stop execution with a given reason</fsummary> + <fsummary>Stops execution with a given reason.</fsummary> <desc> - <p>Stops the execution of the calling process with the exit - reason <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> is any term. Since + <p>Stops the execution of the calling process with exit reason + <c><anno>Reason</anno></c>, where <c><anno>Reason</anno></c> + is any term. Since evaluating this function causes the process to terminate, it has no return value.</p> + <p>Example:</p> <pre> > <input>exit(foobar).</input> ** exception exit: foobar @@ -1148,110 +1213,117 @@ b</pre> {'EXIT',foobar}</pre> </desc> </func> + <func> <name name="exit" arity="2"/> - <fsummary>Send an exit signal to a process or a port</fsummary> + <fsummary>Sends 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 the process or port identified by <c><anno>Pid</anno></c>.</p> - <p>The following behavior apply if <c><anno>Reason</anno></c> is any term - except <c>normal</c> or <c>kill</c>:</p> - <p>If <c><anno>Pid</anno></c> is not trapping exits, <c><anno>Pid</anno></c> itself will - exit with exit reason <c><anno>Reason</anno></c>. If <c><anno>Pid</anno></c> is trapping - exits, the exit signal is transformed into a message - <c>{'EXIT', From, <anno>Reason</anno>}</c> and delivered to the message - queue of <c><anno>Pid</anno></c>. <c>From</c> is the pid of the process - which sent the exit signal. See also - <seealso marker="#process_flag/2">process_flag/2</seealso>.</p> - <p>If <c><anno>Reason</anno></c> is the atom <c>normal</c>, <c><anno>Pid</anno></c> will - not exit. If it is trapping exits, the exit signal is - transformed into a message <c>{'EXIT', From, normal}</c> - and delivered to its message queue.</p> - <p>If <c><anno>Reason</anno></c> is the atom <c>kill</c>, that is if - <c>exit(<anno>Pid</anno>, kill)</c> is called, an untrappable exit signal - is sent to <c><anno>Pid</anno></c> which will unconditionally exit with - exit reason <c>killed</c>.</p> + <p>The following behavior applies if <c><anno>Reason</anno></c> + is any term, except <c>normal</c> or <c>kill</c>:</p> + <list type="bulleted"> + <item>If <c><anno>Pid</anno></c> is not trapping exits, + <c><anno>Pid</anno></c> + itself exits with exit reason <c><anno>Reason</anno></c>. + </item> + <item>If <c><anno>Pid</anno></c> is trapping exits, the exit + signal is transformed into a message + <c>{'EXIT', From, <anno>Reason</anno>}</c> + and delivered to the message queue of <c><anno>Pid</anno></c>. + </item> + <item><c>From</c> is the process identifier of the process + that sent the exit signal. See also + <seealso marker="#process_flag/2">process_flag/2</seealso>. + </item> + </list> + <p>If <c><anno>Reason</anno></c> is the atom <c>normal</c>, + <c><anno>Pid</anno></c> + does not exit. If it is trapping exits, the exit signal is + transformed into a message <c>{'EXIT', From, normal}</c> + and delivered to its message queue.</p> + <p>If <c><anno>Reason</anno></c> is the atom <c>kill</c>, + that is, if <c>exit(<anno>Pid</anno>, kill)</c> is called, + an untrappable exit signal is sent to <c><anno>Pid</anno></c>, + which unconditionally exits with exit reason <c>killed</c>. + </p> </desc> </func> + <func> <name name="external_size" arity="1"/> - <fsummary>Calculate the maximum size for a term encoded in the Erlang - external term format</fsummary> + <fsummary>Calculates the maximum size for a term encoded in the Erlang external term format.</fsummary> <desc> <p>Calculates, without doing the encoding, the maximum byte size for a term encoded in the Erlang external term format. The following condition applies always:</p> - <p> <pre> > <input>Size1 = byte_size(term_to_binary(<anno>Term</anno>)),</input> > <input>Size2 = erlang:external_size(<anno>Term</anno>),</input> > <input>true = Size1 =< Size2.</input> -true - </pre> - </p> - <p>This is equivalent to a call to: <code>erlang:external_size(<anno>Term</anno>, []) - </code></p> +true</pre> + <p>This is equivalent to a call to:</p> +<code>erlang:external_size(<anno>Term</anno>, [])</code> </desc> </func> + <func> <name name="external_size" arity="2"/> - <fsummary>Calculate the maximum size for a term encoded in the Erlang - external term format</fsummary> + <fsummary>Calculates the maximum size for a term encoded in the Erlang external term format.</fsummary> <desc> <p>Calculates, without doing the encoding, the maximum byte size for a term encoded in the Erlang external term format. The following condition applies always:</p> - <p> <pre> > <input>Size1 = byte_size(term_to_binary(<anno>Term</anno>, <anno>Options</anno>)),</input> > <input>Size2 = erlang:external_size(<anno>Term</anno>, <anno>Options</anno>),</input> > <input>true = Size1 =< Size2.</input> -true - </pre> - </p> - <p>The option <c>{minor_version, <anno>Version</anno>}</c> specifies how floats - are encoded. See - <seealso marker="#term_to_binary/2">term_to_binary/2</seealso> for - a more detailed description. - </p> +true</pre> + <p>Option <c>{minor_version, <anno>Version</anno>}</c> specifies how + floats are encoded. For a detailed description, see + <seealso marker="#term_to_binary/2">term_to_binary/2</seealso>.</p> </desc> </func> + <func> <name name="float" arity="1"/> - <fsummary>Convert a number to a float</fsummary> + <fsummary>Converts a number to a float.</fsummary> <desc> - <p>Returns a float by converting <c><anno>Number</anno></c> to a float.</p> + <p>Returns a float by converting <c><anno>Number</anno></c> to a float, + for example:</p> <pre> > <input>float(55).</input> 55.0</pre> <p>Allowed in guard tests.</p> <note> - <p>Note that if used on the top-level in a guard, it will - test whether the argument is a floating point number; for - clarity, use + <p>If used on the top level in a guard, it tests whether the + argument is a floating point number; for clarity, use <seealso marker="#is_float/1">is_float/1</seealso> instead.</p> <p>When <c>float/1</c> is used in an expression in a guard, such as '<c>float(A) == 4.0</c>', it converts a number as - described above.</p> + described earlier.</p> </note> </desc> </func> + <func> <name name="float_to_binary" arity="1"/> - <fsummary>Text representation of a float</fsummary> + <fsummary>Text representation of a float.</fsummary> <desc> - <p>The same as <c>float_to_binary(<anno>Float</anno>,[{scientific,20}])</c>.</p> + <p>The same as + <c>float_to_binary(<anno>Float</anno>,[{scientific,20}])</c>.</p> </desc> </func> + <func> <name name="float_to_binary" arity="2"/> - <fsummary>Text representation of a float formatted using given options</fsummary> + <fsummary>Text representation of a float formatted using given options.</fsummary> <desc> - <p>Returns a binary which corresponds to the text + <p>Returns a binary corresponding to the text representation of <c><anno>Float</anno></c> using fixed decimal - point formatting. The <c><anno>Options</anno></c> behave in the same - way as <seealso marker="#float_to_list/2">float_to_list/2</seealso>. - </p> + point formatting. <c><anno>Options</anno></c> behaves in the same + way as <seealso marker="#float_to_list/2">float_to_list/2</seealso>.</p> + <p>Examples:</p> <pre> > <input>float_to_binary(7.12, [{decimals, 4}]).</input> <<"7.1200">> @@ -1259,31 +1331,42 @@ true <<"7.12">></pre> </desc> </func> + <func> <name name="float_to_list" arity="1"/> - <fsummary>Text representation of a float</fsummary> + <fsummary>Text representation of a float.</fsummary> <desc> - <p>The same as <c>float_to_list(<anno>Float</anno>,[{scientific,20}])</c>.</p> + <p>The same as + <c>float_to_list(<anno>Float</anno>,[{scientific,20}])</c>.</p> </desc> </func> + <func> <name name="float_to_list" arity="2"/> - <fsummary>Text representation of a float formatted using given options</fsummary> - <desc> - <p>Returns a string which corresponds to the text - representation of <c>Float</c> using fixed decimal point formatting. - When <c>decimals</c> option is specified - the returned value will contain at most <c>Decimals</c> number of - digits past the decimal point. If the number doesn't fit in the - internal static buffer of 256 bytes, the function throws <c>badarg</c>. - When <c>compact</c> option is provided - the trailing zeros at the end of the list are truncated (this option is - only meaningful together with the <c>decimals</c> option). When - <c>scientific</c> option is provided, the float will be formatted using - scientific notation with <c>Decimals</c> digits of precision. If - <c>Options</c> is <c>[]</c> the function behaves like - <c><seealso marker="#float_to_list/1">float_to_list/1</seealso></c>. - </p> + <fsummary>Text representation of a float formatted using given options.</fsummary> + <desc> + <p>Returns a string corresponding to the text representation + of <c>Float</c> using fixed decimal point formatting. The + options are as follows:</p> + <list type="bulleted"> + <item>If option <c>decimals</c> is specified, the returned value + contains at most <c>Decimals</c> number of digits past the + decimal point. If the number does not fit in the internal + static buffer of 256 bytes, the function throws <c>badarg</c>. + </item> + <item>If option <c>compact</c> is provided, the trailing zeros + at the end of the list are truncated. This option is only + meaningful together with option <c>decimals</c>. + </item> + <item>If option <c>scientific</c> is provided, the float is + formatted using scientific notation with <c>Decimals</c> + digits of precision. + </item> + <item>If <c>Options</c> is <c>[]</c>, the function behaves as + <seealso marker="#float_to_list/1">float_to_list/1</seealso>. + </item> + </list> + <p>Examples:</p> <pre> > <input>float_to_list(7.12, [{decimals, 4}]).</input> "7.1200" @@ -1291,36 +1374,40 @@ true "7.12"</pre> </desc> </func> + <func> <name name="fun_info" arity="1"/> - <fsummary>Information about a fun</fsummary> + <fsummary>Information about a fun.</fsummary> <desc> - <p>Returns a list containing information about the fun - <c><anno>Fun</anno></c>. Each element of the list is a tuple. The order of - the tuples is not defined, and more tuples may be added in a + <p>Returns a list with information about the fun + <c><anno>Fun</anno></c>. Each list element is a tuple. The order + of the tuples is undefined, and more tuples can be added in a future release.</p> <warning> <p>This BIF is mainly intended for debugging, but it can - occasionally be useful in library functions that might need - to verify, for instance, the arity of a fun.</p> + sometimes be useful in library functions that need + to verify, for example, the arity of a fun.</p> </warning> - <p>There are two types of funs with slightly different - semantics:</p> - <p>A fun created by <c>fun M:F/A</c> is called an - <em>external</em> fun. Calling it will always call the - function <c>F</c> with arity <c>A</c> in the latest code for - module <c>M</c>. Note that module <c>M</c> does not even need - to be loaded when the fun <c>fun M:F/A</c> is created.</p> - <p>All other funs are called <em>local</em>. When a local fun - is called, the same version of the code that created the fun - will be called (even if newer version of the module has been - loaded).</p> - <p>The following elements will always be present in the list + <p>Two types of funs have slightly different semantics:</p> + <list type="bulleted"> + <item>A fun created by <c>fun M:F/A</c> is called an + <em>external</em> fun. Calling it will always call the + function <c>F</c> with arity <c>A</c> in the latest code for + module <c>M</c>. Notice that module <c>M</c> does not even + need to be loaded when the fun <c>fun M:F/A</c> is created. + </item> + <item>All other funs are called <em>local</em>. When a local fun + is called, the same version of the code that created the fun + is called (even if a newer version of the module has been + loaded). + </item> + </list> + <p>The following elements are always present in the list for both local and external funs:</p> <taglist> <tag><c>{type, Type}</c></tag> <item> - <p><c>Type</c> is either <c>local</c> or <c>external</c>.</p> + <p><c>Type</c> is <c>local</c> or <c>external</c>.</p> </item> <tag><c>{module, Module}</c></tag> <item> @@ -1335,148 +1422,154 @@ true <p><c>Name</c> (an atom) is a function name.</p> <p>If <c>Fun</c> is a local fun, <c>Name</c> is the name of the local function that implements the fun. - (This name was generated by the compiler, and is generally + (This name was generated by the compiler, and is only of informational use. As it is a local function, it - is not possible to call it directly.) + cannot be called directly.) If no code is currently loaded for the fun, <c>[]</c> - will be returned instead of an atom.</p> + is returned instead of an atom.</p> <p>If <c>Fun</c> is an external fun, <c>Name</c> is the name of the exported function that the fun refers to.</p> </item> <tag><c>{arity, Arity}</c></tag> <item> <p><c>Arity</c> is the number of arguments that the fun - should be called with.</p> + is to be called with.</p> </item> <tag><c>{env, Env}</c></tag> <item> <p><c>Env</c> (a list) is the environment or free variables - for the fun. (For external funs, the returned list is - always empty.)</p> + for the fun. For external funs, the returned list is + always empty.</p> </item> </taglist> - <p>The following elements will only be present in the list if + <p>The following elements are only present in the list if <c>Fun</c> is local:</p> <taglist> <tag><c>{pid, Pid}</c></tag> <item> - <p><c>Pid</c> is the pid of the process that originally - created the fun.</p> + <p><c>Pid</c> is the process identifier of the process + that originally created the fun.</p> </item> <tag><c>{index, Index}</c></tag> <item> - <p><c>Index</c> (an integer) is an index into the module's + <p><c>Index</c> (an integer) is an index into the module fun table.</p> </item> <tag><c>{new_index, Index}</c></tag> <item> - <p><c>Index</c> (an integer) is an index into the module's + <p><c>Index</c> (an integer) is an index into the module fun table.</p> </item> <tag><c>{new_uniq, Uniq}</c></tag> <item> - <p><c>Uniq</c> (a binary) is a unique value for this fun. - It is calculated from the compiled code for the entire module.</p> + <p><c>Uniq</c> (a binary) is a unique value for this fun. It + is calculated from the compiled code for the entire module.</p> </item> <tag><c>{uniq, Uniq}</c></tag> <item> <p><c>Uniq</c> (an integer) is a unique value for this fun. - Starting in the R15 release, this integer is calculated from - the compiled code for the entire module. Before R15, this - integer was based on only the body of the fun. - </p> + As from OTP R15, this integer is calculated from the + compiled code for the entire module. Before OTP R15, this + integer was based on only the body of the fun.</p> </item> </taglist> </desc> </func> + <func> <name name="fun_info" arity="2"/> + <fsummary>Information about a fun.</fsummary> <type name="fun_info_item"/> - <fsummary>Information about a fun</fsummary> <desc> <p>Returns information about <c><anno>Fun</anno></c> as specified by - <c><anno>Item</anno></c>, in the form <c>{<anno>Item</anno>,<anno>Info</anno>}</c>.</p> + <c><anno>Item</anno></c>, in the form + <c>{<anno>Item</anno>,<anno>Info</anno>}</c>.</p> <p>For any fun, <c><anno>Item</anno></c> can be any of the atoms - <c>module</c>, <c>name</c>, <c>arity</c>, <c>env</c>, or <c>type</c>.</p> - <p>For a local fun, <c><anno>Item</anno></c> can also be any of the atoms - <c>index</c>, <c>new_index</c>, <c>new_uniq</c>, + <c>module</c>, <c>name</c>, <c>arity</c>, <c>env</c>, or + <c>type</c>.</p> + <p>For a local fun, <c><anno>Item</anno></c> can also be any of the + atoms <c>index</c>, <c>new_index</c>, <c>new_uniq</c>, <c>uniq</c>, and <c>pid</c>. For an external fun, the value of any of these items is always the atom <c>undefined</c>.</p> <p>See <seealso marker="#fun_info/1">erlang:fun_info/1</seealso>.</p> </desc> </func> + <func> <name name="fun_to_list" arity="1"/> - <fsummary>Text representation of a fun</fsummary> + <fsummary>Text representation of a fun.</fsummary> <desc> - <p>Returns a string which corresponds to the text + <p>Returns a string corresponding to the text representation of <c><anno>Fun</anno></c>.</p> </desc> </func> + <func> <name name="function_exported" arity="3"/> - <fsummary>Check if a function is exported and loaded</fsummary> + <fsummary>Checks if a function is exported and loaded.</fsummary> <desc> <p>Returns <c>true</c> if the module <c><anno>Module</anno></c> is loaded and contains an exported function <c><anno>Function</anno>/<anno>Arity</anno></c>, or if there is a BIF (a built-in function implemented in C) - with the given name; otherwise returns <c>false</c>.</p> + with the given name, otherwise returns <c>false</c>.</p> <note><p>This function used to return false for built-in functions before the 18.0 release.</p></note> </desc> </func> + <func> <name name="garbage_collect" arity="0"/> - <fsummary>Force an immediate garbage collection of the calling process</fsummary> + <fsummary>Forces an immediate garbage collection of the calling process.</fsummary> <desc> - <p>Forces an immediate garbage collection of the currently - executing process. The function should not be used, unless - it has been noticed -- or there are good reasons to suspect -- + <p>Forces an immediate garbage collection of the + executing process. The function is not to be used unless + it has been noticed (or there are good reasons to suspect) that the spontaneous garbage collection will occur too late - or not at all. Improper use may seriously degrade system - performance.</p> + or not at all.</p> + <warning> + <p>Improper use can seriously degrade system performance.</p> + </warning> </desc> </func> + <func> <name name="garbage_collect" arity="1"/> - <fsummary>Garbage collect a process</fsummary> + <fsummary>Garbage collects a process.</fsummary> <desc> <p>The same as <seealso marker="#garbage_collect/2"><c>garbage_collect(<anno>Pid</anno>, [])</c></seealso>.</p> </desc> </func> + <func> <name name="garbage_collect" arity="2"/> - <fsummary>Garbage collect a process</fsummary> + <fsummary>Garbage collects a process.</fsummary> <desc> - <p>Garbage collect the node local process identified by - <c><anno>Pid</anno></c>.</p> - <p>Currently available <c><anno>Option</anno></c>s:</p> + <p>Garbage collects the node local process identified by + <c><anno>Pid</anno></c>.</p> + <p>The available <c><anno>Option</anno></c>s are as follows:</p> <taglist> <tag><c>{async, RequestId}</c></tag> - <item> - The <c>garbage_collect/2</c> function will return + <item>The function <c>garbage_collect/2</c> returns the value <c>async</c> immediately after the request has been sent. When the request has been processed, the - process that called this function will be passed a - message on the form:<br/> - <c>{garbage_collect, <anno>RequestId</anno>, <anno>GCResult</anno>}</c>. - </item> + process that called this function is passed a message on + the form <c>{garbage_collect, + <anno>RequestId</anno>, <anno>GCResult</anno>}</c>. + </item> </taglist> <p>If <c><anno>Pid</anno></c> equals <c>self()</c>, and no <c>async</c> option has been passed, the garbage - collection will be performed at once, i.e. the same as - calling + collection is performed at once, that is, the same as calling <seealso marker="#garbage_collect/0">garbage_collect/0</seealso>. - In all other cases a request for garbage collection will - be sent to the process identified by <c><anno>Pid</anno></c>, + Otherwise a request for garbage collection + is sent to the process identified by <c><anno>Pid</anno></c>, and will be handled when appropriate. If no <c>async</c> - option has been passed, the caller will block until - <c><anno>GCResult</anno></c> is available and can be - returned.</p> + option has been passed, the caller blocks until + <c><anno>GCResult</anno></c> is available and can be returned.</p> <p><c><anno>GCResult</anno></c> informs about the result of - the garbage collection request:</p> + the garbage collection request as follows:</p> <taglist> <tag><c>true</c></tag> <item> @@ -1485,14 +1578,13 @@ true </item> <tag><c>false</c></tag> <item> - No garbage collection was performed. This since the + No garbage collection was performed, as the process identified by <c><anno>Pid</anno></c> terminated before the request could be satisfied. </item> </taglist> - <p>Note that the same caveats as for - <seealso marker="#garbage_collect/0">garbage_collect/0</seealso> - apply.</p> + <p>Notice that the same caveats apply as for + <seealso marker="#garbage_collect/0">garbage_collect/0</seealso>.</p> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> @@ -1501,17 +1593,18 @@ true </item> <tag><c>badarg</c></tag> <item> - If <c><anno>OptionList</anno></c> is not a valid list of options. + If <c><anno>OptionList</anno></c> is an invalid list of options. </item> </taglist> </desc> </func> + <func> <name name="get" arity="0"/> - <fsummary>Return the process dictionary</fsummary> + <fsummary>Returns the process dictionary.</fsummary> <desc> <p>Returns the process dictionary as a list of - <c>{<anno>Key</anno>, <anno>Val</anno>}</c> tuples.</p> + <c>{<anno>Key</anno>, <anno>Val</anno>}</c> tuples, for example:</p> <pre> > <input>put(key1, merry),</input> <input>put(key2, lambs),</input> @@ -1520,13 +1613,15 @@ true [{key1,merry},{key2,lambs},{key3,{are,playing}}]</pre> </desc> </func> + <func> <name name="get" arity="1"/> - <fsummary>Return a value from the process dictionary</fsummary> + <fsummary>Returns a value from the process dictionary.</fsummary> <desc> <p>Returns the value <c><anno>Val</anno></c> associated with <c><anno>Key</anno></c> in the process dictionary, or <c>undefined</c> if <c><anno>Key</anno></c> does not exist.</p> + <p>Example:</p> <pre> > <input>put(key1, merry),</input> <input>put(key2, lambs),</input> @@ -1535,14 +1630,16 @@ true {are,playing}</pre> </desc> </func> + <func> <name name="get_cookie" arity="0"/> - <fsummary>Get the magic cookie of the local node</fsummary> + <fsummary>Gets the magic cookie of the local node.</fsummary> <desc> - <p>Returns the magic cookie of the local node, if the node is - alive; otherwise the atom <c>nocookie</c>.</p> + <p>Returns the magic cookie of the local node if the node is + alive, otherwise the atom <c>nocookie</c>.</p> </desc> </func> + <func> <name name="get_keys" arity="0"/> <fsummary>Return a list of all keys from the process dictionary</fsummary> @@ -1558,10 +1655,10 @@ true </func> <func> <name name="get_keys" arity="1"/> - <fsummary>Return a list of keys from the process dictionary</fsummary> + <fsummary>Returns a list of keys from the process dictionary.</fsummary> <desc> - <p>Returns a list of keys which are associated with the value - <c><anno>Val</anno></c> in the process dictionary.</p> + <p>Returns a list of keys that are associated with the value + <c><anno>Val</anno></c> in the process dictionary, for example:</p> <pre> > <input>put(mary, {1, 2}),</input> <input>put(had, {1, 2}),</input> @@ -1573,40 +1670,40 @@ true [mary,had,a,little,lamb]</pre> </desc> </func> + <func> <name name="get_stacktrace" arity="0"/> - <fsummary>Get the call stack back-trace of the last exception</fsummary> + <fsummary>Gets the call stack back-trace of the last exception.</fsummary> <type name="stack_item"/> <desc> - <p>Get the call stack back-trace (<em>stacktrace</em>) of the last - exception in the calling process as a list of + <p>Gets the call stack back-trace (<em>stacktrace</em>) of the + last exception in the calling process as a list of <c>{<anno>Module</anno>,<anno>Function</anno>,<anno>Arity</anno>,<anno>Location</anno>}</c> tuples. - The <c><anno>Arity</anno></c> field in the first tuple may be the argument - list of that function call instead of an arity integer, + Field <c><anno>Arity</anno></c> in the first tuple can be the + argument list of that function call instead of an arity integer, depending on the exception.</p> <p>If there has not been any exceptions in a process, the stacktrace is <c>[]</c>. After a code change for the process, - the stacktrace may also be reset to [].</p> + the stacktrace can also be reset to <c>[]</c>.</p> <p>The stacktrace is the same data as the <c>catch</c> operator returns, for example:</p> <p><c>{'EXIT',{badarg,Stacktrace}} = catch abs(x)</c></p> - <p><c><anno>Location</anno></c> is a (possibly empty) list of two-tuples that - may indicate the location in the source code of the function. - The first element is an atom that describes the type of - information in the second element. Currently the following - items may occur:</p> + <p><c><anno>Location</anno></c> is a (possibly empty) list + of two-tuples that + can indicate the location in the source code of the function. + The first element is an atom describing the type of + information in the second element. The following + items can occur:</p> <taglist> <tag><c>file</c></tag> - <item> - <p>The second element of the tuple is a string (list of - characters) representing the filename of the source file - of the function.</p> + <item>The second element of the tuple is a string (list of + characters) representing the file name of the source file + of the function. </item> <tag><c>line</c></tag> - <item> - <p>The second element of the tuple is the line number + <item>The second element of the tuple is the line number (an integer greater than zero) in the source file - where the exception occurred or the function was called.</p> + where the exception occurred or the function was called. </item> </taglist> <p>See also @@ -1614,49 +1711,56 @@ true <seealso marker="#error/2">erlang:error/2</seealso>.</p> </desc> </func> + <func> <name name="group_leader" arity="0"/> - <fsummary>Get the group leader for the calling process</fsummary> + <fsummary>Gets the group leader for the calling process.</fsummary> <desc> - <p>Returns the pid of the group leader for the process which - evaluates the function.</p> + <p>Returns the process identifier of the group leader for the + process evaluating the function.</p> <p>Every process is a member of some process group and all - groups have a <em>group leader</em>. All IO from the group + groups have a <em>group leader</em>. All I/O from the group is channeled to the group leader. When a new process is spawned, it gets the same group leader as the spawning process. Initially, at system start-up, <c>init</c> is both its own group leader and the group leader of all processes.</p> </desc> </func> + <func> <name name="group_leader" arity="2"/> - <fsummary>Set the group leader for a process</fsummary> + <fsummary>Sets the group leader for a process.</fsummary> <desc> - <p>Sets the group leader of <c><anno>Pid</anno></c> to <c><anno>GroupLeader</anno></c>. - Typically, this is used when a processes started from a - certain shell should have another group leader than + <p>Sets the group leader of <c><anno>Pid</anno></c> + to <c><anno>GroupLeader</anno></c>. + Typically, this is used when a process started from a + certain shell is to have another group leader than <c>init</c>.</p> <p>See also <seealso marker="#group_leader/0">group_leader/0</seealso>.</p> </desc> </func> + <func> <name name="halt" arity="0"/> - <fsummary>Halt the Erlang runtime system and indicate normal exit to the calling environment</fsummary> + <fsummary>Halts the Erlang runtime system and indicates normal exit to the calling environment.</fsummary> <desc> <p>The same as <seealso marker="#halt/2"><c>halt(0, [])</c></seealso>.</p> + <p>Example:</p> <pre> > <input>halt().</input> os_prompt% </pre> </desc> </func> + <func> <name name="halt" arity="1"/> - <fsummary>Halt the Erlang runtime system</fsummary> + <fsummary>Halts the Erlang runtime system.</fsummary> <desc> <p>The same as <seealso marker="#halt/2"><c>halt(<anno>Status</anno>, [])</c></seealso>.</p> + <p>Example:</p> <pre> > <input>halt(17).</input> os_prompt% <input>echo $?</input> @@ -1664,178 +1768,188 @@ os_prompt% <input>echo $?</input> os_prompt% </pre> </desc> </func> + <func> <name name="halt" arity="2"/> - <fsummary>Halt the Erlang runtime system</fsummary> + <fsummary>Halts the Erlang runtime system.</fsummary> <desc> <p><c><anno>Status</anno></c> must be a non-negative integer, a string, or the atom <c>abort</c>. Halts the Erlang runtime system. Has no return value. - Depending on <c><anno>Status</anno></c>: - </p> + Depending on <c><anno>Status</anno></c>, the following occurs:</p> <taglist> <tag>integer()</tag> - <item>The runtime system exits with the integer value <c><anno>Status</anno></c> - as status code to the calling environment (operating system). + <item>The runtime system exits with integer value + <c><anno>Status</anno></c> + as status code to the calling environment (OS). </item> <tag>string()</tag> - <item>An erlang crash dump is produced with <c><anno>Status</anno></c> as slogan, - and then the runtime system exits with status code <c>1</c>. + <item>An Erlang crash dump is produced with <c><anno>Status</anno></c> + as slogan. Then the runtime system exits with status code <c>1</c>. </item> <tag><c>abort</c></tag> <item> The runtime system aborts producing a core dump, if that is - enabled in the operating system. + enabled in the OS. </item> </taglist> - <p>Note that on many platforms, only the status codes 0-255 are - supported by the operating system. - </p> - <p>For integer <c><anno>Status</anno></c> the Erlang runtime system closes all ports - and allows async threads to finish their operations before exiting. - To exit without such flushing use - <c><anno>Option</anno></c> as <c>{flush,false}</c>. - </p> - <p>For statuses <c>string()</c> and <c>abort</c> the <c>flush</c> - option is ignored and flushing is <em>not</em> done. - </p> + <note><p>On many platforms, the OS supports only status + codes 0-255.</p></note> + <p>For integer <c><anno>Status</anno></c>, the Erlang runtime system + closes all ports and allows async threads to finish their + operations before exiting. To exit without such flushing, use + <c><anno>Option</anno></c> as <c>{flush,false}</c>.</p> + <p>For statuses <c>string()</c> and <c>abort</c>, option + <c>flush</c> is ignored and flushing is <em>not</em> done.</p> </desc> </func> + <func> <name name="hash" arity="2"/> - <fsummary>Hash function (deprecated)</fsummary> + <fsummary>Hash function (deprecated).</fsummary> <desc> <p>Returns a hash value for <c><anno>Term</anno></c> within the range - <c>1..<anno>Range</anno></c>. The allowed range is 1..2^27-1.</p> + <c>1..<anno>Range</anno></c>. The maximum range is 1..2^27-1.</p> <warning> - <p>This BIF is deprecated as the hash value may differ on - different architectures. Also the hash values for integer - terms larger than 2^27 as well as large binaries are very + <p>This BIF is deprecated, as the hash value can differ on + different architectures. The hash values for integer + terms higher than 2^27 and large binaries are poor. The BIF is retained for backward compatibility - reasons (it may have been used to hash records into a file), - but all new code should use one of the BIFs + reasons (it can have been used to hash records into a file), + but all new code is to use one of the BIFs <c>erlang:phash/2</c> or <c>erlang:phash2/1,2</c> instead.</p> </warning> </desc> </func> + <func> <name name="hd" arity="1"/> - <fsummary>Head of a list</fsummary> + <fsummary>Head of a list.</fsummary> <desc> - <p>Returns the head of <c><anno>List</anno></c>, that is, the first element.</p> + <p>Returns the head of <c><anno>List</anno></c>, that is, + the first element, for example:</p> <pre> > <input>hd([1,2,3,4,5]).</input> 1</pre> <p>Allowed in guard tests.</p> - <p>Failure: <c>badarg</c> if <c><anno>List</anno></c> is the empty list [].</p> + <p>Failure: <c>badarg</c> if <c><anno>List</anno></c> is the empty + list <c>[]</c>.</p> </desc> </func> + <func> <name name="hibernate" arity="3"/> - <fsummary>Hibernate a process until a message is sent to it</fsummary> + <fsummary>Hibernates a process until a message is sent to it.</fsummary> <desc> <p>Puts the calling process into a wait state where its memory - allocation has been reduced as much as possible, which is + allocation has been reduced as much as possible. This is useful if the process does not expect to receive any messages - in the near future.</p> - <p>The process will be awaken when a message is sent to it, and - control will resume in <c><anno>Module</anno>:<anno>Function</anno></c> with - the arguments given by <c><anno>Args</anno></c> with the call stack - emptied, meaning that the process will terminate when that - function returns. Thus <c>erlang:hibernate/3</c> will never - return to its caller.</p> + soon.</p> + <p>The process is awaken when a message is sent to it, and control + resumes in <c><anno>Module</anno>:<anno>Function</anno></c> with + the arguments given by <c><anno>Args</anno></c> with the call + stack emptied, meaning that the process terminates when that + function returns. Thus <c>erlang:hibernate/3</c> never + returns to its caller.</p> <p>If the process has any message in its message queue, - the process will be awaken immediately in the same way as - described above.</p> + the process is awakened immediately in the same way as + described earlier.</p> <p>In more technical terms, what <c>erlang:hibernate/3</c> does - is the following. It discards the call stack for the process. - Then it garbage collects the process. After the garbage - collection, all live data is in one continuous heap. The heap + is the following. It discards the call stack for the process, + and then garbage collects the process. After this, + all live data is in one continuous heap. The heap is then shrunken to the exact same size as the live data - which it holds (even if that size is less than the minimum + that it holds (even if that size is less than the minimum heap size for the process).</p> <p>If the size of the live data in the process is less than the minimum heap size, the first garbage collection occurring - after the process has been awaken will ensure that the heap + after the process is awakened ensures that the heap size is changed to a size not smaller than the minimum heap size.</p> - <p>Note that emptying the call stack means that any surrounding - <c>catch</c> is removed and has to be re-inserted after + <p>Notice that emptying the call stack means that any surrounding + <c>catch</c> is removed and must be reinserted after hibernation. One effect of this is that processes started using <c>proc_lib</c> (also indirectly, such as - <c>gen_server</c> processes), should use + <c>gen_server</c> processes), are to use <seealso marker="stdlib:proc_lib#hibernate/3">proc_lib:hibernate/3</seealso> - instead to ensure that the exception handler continues to work + instead, to ensure that the exception handler continues to work when the process wakes up.</p> </desc> </func> <func> <name name="insert_element" arity="3"/> - <fsummary>Insert an element at index in a tuple</fsummary> + <fsummary>Inserts an element at index in a tuple.</fsummary> <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno>) + 1</type_desc> <desc> - <p> - Returns a new tuple with element <c><anno>Term</anno></c> insert at position - <c><anno>Index</anno></c> in tuple <c><anno>Tuple1</anno></c>. - All elements from position <c><anno>Index</anno></c> and upwards are subsequently - pushed one step higher in the new tuple <c><anno>Tuple2</anno></c>. - </p> + <p>Returns a new tuple with element <c><anno>Term</anno></c> + inserted at position + <c><anno>Index</anno></c> in tuple <c><anno>Tuple1</anno></c>. + All elements from position <c><anno>Index</anno></c> and upwards are + pushed one step higher in the new tuple <c><anno>Tuple2</anno></c>.</p> + <p>Example:</p> <pre> > <input>erlang:insert_element(2, {one, two, three}, new).</input> {one,new,two,three}</pre> </desc> </func> + <func> <name name="integer_to_binary" arity="1"/> - <fsummary>Text representation of an integer</fsummary> + <fsummary>Text representation of an integer.</fsummary> <desc> - <p>Returns a binary which corresponds to the text - representation of <c><anno>Integer</anno></c>.</p> + <p>Returns a binary corresponding to the text + representation of <c><anno>Integer</anno></c>, for example:</p> <pre> > <input>integer_to_binary(77).</input> <<"77">></pre> </desc> </func> + <func> <name name="integer_to_binary" arity="2"/> - <fsummary>Text representation of an integer</fsummary> + <fsummary>Text representation of an integer.</fsummary> <desc> - <p>Returns a binary which corresponds to the text - representation of <c><anno>Integer</anno></c> in base <c><anno>Base</anno></c>.</p> + <p>Returns a binary corresponding to the text + representation of <c><anno>Integer</anno></c> in base + <c><anno>Base</anno></c>, for example:</p> <pre> > <input>integer_to_binary(1023, 16).</input> <<"3FF">></pre> </desc> </func> + <func> <name name="integer_to_list" arity="1"/> - <fsummary>Text representation of an integer</fsummary> + <fsummary>Text representation of an integer.</fsummary> <desc> - <p>Returns a string which corresponds to the text - representation of <c><anno>Integer</anno></c>.</p> + <p>Returns a string corresponding to the text + representation of <c><anno>Integer</anno></c>, for example:</p> <pre> > <input>integer_to_list(77).</input> "77"</pre> </desc> </func> + <func> <name name="integer_to_list" arity="2"/> - <fsummary>Text representation of an integer</fsummary> + <fsummary>Text representation of an integer.</fsummary> <desc> - <p>Returns a string which corresponds to the text - representation of <c><anno>Integer</anno></c> in base <c><anno>Base</anno></c>.</p> + <p>Returns a string corresponding to the text + representation of <c><anno>Integer</anno></c> in base + <c><anno>Base</anno></c>, for example:</p> <pre> > <input>integer_to_list(1023, 16).</input> "3FF"</pre> </desc> </func> + <func> <name name="iolist_to_binary" arity="1"/> - <fsummary>Convert an iolist to a binary</fsummary> + <fsummary>Converts an iolist to a binary.</fsummary> <desc> - <p>Returns a binary which is made from the integers and - binaries in <c><anno>IoListOrBinary</anno></c>.</p> + <p>Returns a binary that is made from the integers and + binaries in <c><anno>IoListOrBinary</anno></c>, for example:</p> <pre> > <input>Bin1 = <<1,2,3>>.</input> <<1,2,3>> @@ -1847,278 +1961,311 @@ os_prompt% </pre> <<1,2,3,1,2,3,4,5,4,6>></pre> </desc> </func> + <func> <name name="iolist_size" arity="1"/> - <fsummary>Size of an iolist</fsummary> + <fsummary>Size of an iolist.</fsummary> <desc> - <p>Returns an integer which is the size in bytes - of the binary that would be the result of - <c>iolist_to_binary(<anno>Item</anno>)</c>.</p> + <p>Returns an integer that is the size in bytes + of the binary that would be the result of + <c>iolist_to_binary(<anno>Item</anno>)</c>, for example:</p> <pre> > <input>iolist_size([1,2|<<3,4>>]).</input> 4</pre> </desc> </func> + <func> <name name="is_alive" arity="0"/> - <fsummary>Check whether the local node is alive</fsummary> + <fsummary>Checks whether the local node is alive.</fsummary> <desc> - <p>Returns <c>true</c> if the local node is alive; that is, if - the node can be part of a distributed system. Otherwise, it - returns <c>false</c>.</p> + <p>Returns <c>true</c> if the local node is alive (that is, if + the node can be part of a distributed system), otherwise + <c>false</c>.</p> </desc> </func> + <func> <name name="is_atom" arity="1"/> - <fsummary>Check whether a term is an atom</fsummary> + <fsummary>Checks whether a term is an atom.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an atom; - otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an atom, + otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_binary" arity="1"/> - <fsummary>Check whether a term is a binary</fsummary> + <fsummary>Checks whether a term is a binary.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a binary; - otherwise returns <c>false</c>.</p> - + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a binary, + otherwise <c>false</c>.</p> <p>A binary always contains a complete number of bytes.</p> - <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_bitstring" arity="1"/> - <fsummary>Check whether a term is a bitstring</fsummary> + <fsummary>Checks whether a term is a bitstring.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a bitstring (including a binary); - otherwise returns <c>false</c>.</p> - + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a + bitstring (including a binary), otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_boolean" arity="1"/> - <fsummary>Check whether a term is a boolean</fsummary> + <fsummary>Checks whether a term is a boolean.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is - either the atom <c>true</c> or the atom <c>false</c> - (i.e. a boolean); otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is the + atom <c>true</c> or the atom <c>false</c> (that is, a boolean). + Otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_builtin" arity="3"/> - <fsummary>Check if a function is a BIF implemented in C</fsummary> + <fsummary>Checks if a function is a BIF implemented in C.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Module</anno>:<anno>Function</anno>/<anno>Arity</anno></c> is - a BIF implemented in C; otherwise returns <c>false</c>. - This BIF is useful for builders of cross reference tools.</p> + <p>This BIF is useful for builders of cross-reference tools.</p> + <p>Returns <c>true</c> if + <c><anno>Module</anno>:<anno>Function</anno>/<anno>Arity</anno></c> + is a BIF implemented in C, otherwise <c>false</c>.</p> </desc> </func> + <func> <name name="is_float" arity="1"/> - <fsummary>Check whether a term is a float</fsummary> + <fsummary>Checks whether a term is a float.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a floating point - number; otherwise returns <c>false</c>.</p> + number, otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_function" arity="1"/> - <fsummary>Check whether a term is a fun</fsummary> + <fsummary>Checks whether a term is a fun.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a fun; otherwise - returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a fun, otherwise + <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_function" arity="2"/> - <fsummary>Check whether a term is a fun with a given arity</fsummary> + <fsummary>Checks whether a term is a fun with a given arity.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a fun that can be - applied with <c><anno>Arity</anno></c> number of arguments; otherwise - returns <c>false</c>.</p> + applied with <c><anno>Arity</anno></c> number of arguments, otherwise + <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_integer" arity="1"/> - <fsummary>Check whether a term is an integer</fsummary> + <fsummary>Checks whether a term is an integer.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an integer; - otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an integer, + otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_list" arity="1"/> - <fsummary>Check whether a term is a list</fsummary> + <fsummary>Checks whether a term is a list.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a list with - zero or more elements; otherwise returns <c>false</c>.</p> + zero or more elements, otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_map" arity="1"/> - <fsummary>Check whether a term is a map</fsummary> + <fsummary>Checks whether a term is a map.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a map; - otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a map, + otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_number" arity="1"/> - <fsummary>Check whether a term is a number</fsummary> + <fsummary>Checks whether a term is a number.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is either an integer or a - floating point number; otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is an integer or a + floating point number. Otherwise returns <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_pid" arity="1"/> - <fsummary>Check whether a term is a pid</fsummary> + <fsummary>Checks whether a term is a process identifier.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a pid (process - identifier); otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a process + identifier, otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_port" arity="1"/> - <fsummary>Check whether a term is a port</fsummary> + <fsummary>Checks whether a term is a port.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a port identifier; - otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a port identifier, + otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_process_alive" arity="1"/> - <fsummary>Check whether a process is alive</fsummary> + <fsummary>Checks whether a process is alive.</fsummary> <desc> - <p> - <c><anno>Pid</anno></c> must refer to a process at the local node. - Returns <c>true</c> if the process exists and is alive, that - is, is not exiting and has not exited. Otherwise, returns + <p><c><anno>Pid</anno></c> must refer to a process at the local node.</p> + <p>Returns <c>true</c> if the process exists and is alive, that + is, is not exiting and has not exited. Otherwise returns <c>false</c>. </p> </desc> </func> + <func> <name name="is_record" arity="2"/> - <fsummary>Check whether a term appears to be a record</fsummary> + <fsummary>Checks 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 first - element is <c><anno>RecordTag</anno></c>. Otherwise, returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a tuple and its + first element is <c><anno>RecordTag</anno></c>. + Otherwise returns <c>false</c>.</p> <note> <p>Normally the compiler treats calls to <c>is_record/2</c> - specially. It emits code to verify that <c><anno>Term</anno></c> is a - tuple, that its first element is <c><anno>RecordTag</anno></c>, and that - the size is correct. However, if the <c><anno>RecordTag</anno></c> is - not a literal atom, the <c>is_record/2</c> BIF will be - called instead and the size of the tuple will not be - verified.</p> + specially. It emits code to verify that <c><anno>Term</anno></c> + is a tuple, that its first element is + <c><anno>RecordTag</anno></c>, and that the + size is correct. However, if <c><anno>RecordTag</anno></c> is + not a literal atom, the BIF <c>is_record/2</c> is called + instead and the size of the tuple is not verified.</p> </note> - <p>Allowed in guard tests, if <c><anno>RecordTag</anno></c> is a literal - atom.</p> + <p>Allowed in guard tests, if <c><anno>RecordTag</anno></c> is + a literal atom.</p> </desc> </func> + <func> <name name="is_record" arity="3"/> - <fsummary>Check whether a term appears to be a record</fsummary> - <desc> - <p><c><anno>RecordTag</anno></c> must be an atom. Returns <c>true</c> if - <c><anno>Term</anno></c> is a tuple, its first element is <c><anno>RecordTag</anno></c>, - and its size is <c><anno>Size</anno></c>. Otherwise, returns <c>false</c>.</p> - <p>Allowed in guard tests, provided that <c><anno>RecordTag</anno></c> is + <fsummary>Checks whether a term appears to be a record.</fsummary> + <desc> + <p><c><anno>RecordTag</anno></c> must be an atom.</p> + <p>Returns <c>true</c> if + <c><anno>Term</anno></c> is a tuple, + its first element is <c><anno>RecordTag</anno></c>, + and its size is <c><anno>Size</anno></c>. + Otherwise returns <c>false</c>.</p> + <p>Allowed in guard tests if <c><anno>RecordTag</anno></c> is a literal atom and <c>Size</c> is a literal integer.</p> <note> - <p>This BIF is documented for completeness. In most cases - <c>is_record/2</c> should be used.</p> + <p>This BIF is documented for completeness. Usually + <c>is_record/2</c> is to be used.</p> </note> </desc> </func> + <func> <name name="is_reference" arity="1"/> - <fsummary>Check whether a term is a reference</fsummary> + <fsummary>Checks whether a term is a reference.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a reference; - otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a reference, + otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="is_tuple" arity="1"/> - <fsummary>Check whether a term is a tuple</fsummary> + <fsummary>Checks whether a term is a tuple.</fsummary> <desc> - <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a tuple; - otherwise returns <c>false</c>.</p> + <p>Returns <c>true</c> if <c><anno>Term</anno></c> is a tuple, + otherwise <c>false</c>.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="length" arity="1"/> - <fsummary>Length of a list</fsummary> + <fsummary>Length of a list.</fsummary> <desc> - <p>Returns the length of <c><anno>List</anno></c>.</p> + <p>Returns the length of <c><anno>List</anno></c>, for example:</p> <pre> > <input>length([1,2,3,4,5,6,7,8,9]).</input> 9</pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="link" arity="1"/> - <fsummary>Create a link to another process (or port)</fsummary> + <fsummary>Creates a link to another process (or port).</fsummary> <desc> <p>Creates a link between the calling process and another - process (or port) <c><anno>PidOrPort</anno></c>, if there is not such a link + process (or port) <c><anno>PidOrPort</anno></c>, if there is + not such a link already. If a process attempts to create a link to itself, nothing is done. Returns <c>true</c>.</p> - <p>If <c><anno>PidOrPort</anno></c> does not exist, the behavior of the BIF depends - on if the calling process is trapping exits or not (see + <p>If <c><anno>PidOrPort</anno></c> does not exist, the behavior + of the BIF + depends on if the calling process is trapping exits or not (see <seealso marker="#process_flag/2">process_flag/2</seealso>):</p> <list type="bulleted"> <item>If the calling process is not trapping exits, and - checking <c><anno>PidOrPort</anno></c> is cheap -- that is, if <c><anno>PidOrPort</anno></c> is - local -- <c>link/1</c> fails with reason <c>noproc</c>.</item> + checking <c><anno>PidOrPort</anno></c> is cheap + (that is, if <c><anno>PidOrPort</anno></c> + is local), <c>link/1</c> fails with reason <c>noproc</c>.</item> <item>Otherwise, if the calling process is trapping exits, - and/or <c><anno>PidOrPort</anno></c> is remote, <c>link/1</c> returns - <c>true</c>, but an exit signal with reason <c>noproc</c> + and/or <c><anno>PidOrPort</anno></c> is remote, <c>link/1</c> + returns <c>true</c>, but an exit signal with reason <c>noproc</c> is sent to the calling process.</item> </list> </desc> </func> + <func> <name name="list_to_atom" arity="1"/> - <fsummary>Convert from text representation to an atom</fsummary> - <desc> - <p>Returns the atom whose text representation is <c><anno>String</anno></c>.</p> - <p><c><anno>String</anno></c> may only contain ISO-latin-1 - characters (i.e. numbers below 256) as the current - implementation does not allow unicode characters >= 256 in - atoms. For more information on Unicode support in atoms - see <seealso marker="erl_ext_dist#utf8_atoms">note on UTF-8 encoded atoms</seealso> - in the chapter about the external term format in the ERTS User's Guide.</p> + <fsummary>Converts from text representation to an atom.</fsummary> + <desc> + <p>Returns the atom whose text representation is + <c><anno>String</anno></c>.</p> + <p><c><anno>String</anno></c> can only contain ISO-latin-1 + characters (that is, + numbers less than 256) as the implementation does not + allow unicode characters equal to or above 256 in atoms. + For more information on Unicode support in atoms, see + <seealso marker="erl_ext_dist#utf8_atoms">note on UTF-8 + encoded atoms</seealso> + in Section "External Term Format" in the User's Guide.</p> + <p>Example:</p> <pre> > <input>list_to_atom("Erlang").</input> 'Erlang'</pre> </desc> </func> + <func> <name name="list_to_binary" arity="1"/> - <fsummary>Convert a list to a binary</fsummary> + <fsummary>Converts a list to a binary.</fsummary> <desc> - <p>Returns a binary which is made from the integers and - binaries in <c><anno>IoList</anno></c>.</p> + <p>Returns a binary that is made from the integers and + binaries in <c><anno>IoList</anno></c>, for example:</p> <pre> > <input>Bin1 = <<1,2,3>>.</input> <<1,2,3>> @@ -2130,40 +2277,46 @@ os_prompt% </pre> <<1,2,3,1,2,3,4,5,4,6>></pre> </desc> </func> + <func> <name name="list_to_bitstring" arity="1"/> + <fsummary>Converts a list to a bitstring.</fsummary> <type name="bitstring_list"/> - <fsummary>Convert a list to a bitstring</fsummary> <desc> - <p>Returns a bitstring which is made from the integers and - bitstrings in <c><anno>BitstringList</anno></c>. (The last tail in <c><anno>BitstringList</anno></c> - is allowed to be a bitstring.)</p> + <p>Returns a bitstring that is made from the integers and + bitstrings in <c><anno>BitstringList</anno></c>. (The last tail in + <c><anno>BitstringList</anno></c> is allowed to be a bitstring.)</p> + <p>Example:</p> <pre> > <input>Bin1 = <<1,2,3>>.</input> <<1,2,3>> > <input>Bin2 = <<4,5>>.</input> <<4,5>> -> <input>Bin3 = <<6,7:4,>>.</input> -<<6>> +> <input>Bin3 = <<6,7:4>>.</input> +<<6,7:4>> > <input>list_to_bitstring([Bin1,1,[2,3,Bin2],4|Bin3]).</input> -<<1,2,3,1,2,3,4,5,4,6,7:46>></pre> +<<1,2,3,1,2,3,4,5,4,6,7:4>></pre> </desc> </func> + <func> <name name="list_to_existing_atom" arity="1"/> - <fsummary>Convert from text representation to an atom</fsummary> + <fsummary>Converts from text representation to an atom.</fsummary> <desc> - <p>Returns the atom whose text representation is <c><anno>String</anno></c>, + <p>Returns the atom whose text representation is + <c><anno>String</anno></c>, but only if there already exists such atom.</p> <p>Failure: <c>badarg</c> if there does not already exist an atom whose text representation is <c><anno>String</anno></c>.</p> </desc> </func> + <func> <name name="list_to_float" arity="1"/> - <fsummary>Convert from text representation to a float</fsummary> + <fsummary>Converts from text representation to a float.</fsummary> <desc> - <p>Returns the float whose text representation is <c><anno>String</anno></c>.</p> + <p>Returns the float whose text representation is + <c><anno>String</anno></c>, for example:</p> <pre> > <input>list_to_float("2.2017764e+0").</input> 2.2017764</pre> @@ -2171,12 +2324,13 @@ os_prompt% </pre> representation of a float.</p> </desc> </func> + <func> <name name="list_to_integer" arity="1"/> - <fsummary>Convert from text representation to an integer</fsummary> + <fsummary>Converts from text representation to an integer.</fsummary> <desc> <p>Returns an integer whose text representation is - <c><anno>String</anno></c>.</p> + <c><anno>String</anno></c>, for example:</p> <pre> > <input>list_to_integer("123").</input> 123</pre> @@ -2184,12 +2338,14 @@ os_prompt% </pre> representation of an integer.</p> </desc> </func> + <func> <name name="list_to_integer" arity="2"/> - <fsummary>Convert from text representation to an integer</fsummary> + <fsummary>Converts from text representation to an integer.</fsummary> <desc> <p>Returns an integer whose text representation in base - <c><anno>Base</anno></c> is <c><anno>String</anno></c>.</p> + <c><anno>Base</anno></c> is <c><anno>String</anno></c>, + for example:</p> <pre> > <input>list_to_integer("3FF", 16).</input> 1023</pre> @@ -2197,47 +2353,52 @@ os_prompt% </pre> representation of an integer.</p> </desc> </func> + <func> <name name="list_to_pid" arity="1"/> - <fsummary>Convert from text representation to a pid</fsummary> + <fsummary>Converts from text representation to a pid.</fsummary> <desc> - <p>Returns a pid whose text representation is <c><anno>String</anno></c>.</p> - <warning> - <p>This BIF is intended for debugging and for use in - the Erlang operating system. It should not be used in - application programs.</p> - </warning> + <p>Returns a process identifier whose text representation is a + <c><anno>String</anno></c>, for example:</p> <pre> > <input>list_to_pid("<0.4.1>").</input> <0.4.1></pre> <p>Failure: <c>badarg</c> if <c><anno>String</anno></c> contains a bad - representation of a pid.</p> + representation of a process identifier.</p> + <warning> + <p>This BIF is intended for debugging and is not to be used + in application programs.</p> + </warning> </desc> </func> + <func> <name name="list_to_tuple" arity="1"/> - <fsummary>Convert a list to a tuple</fsummary> + <fsummary>Converts a list to a tuple.</fsummary> <desc> - <p>Returns a tuple which corresponds to <c><anno>List</anno></c>. <c><anno>List</anno></c> - can contain any Erlang terms.</p> + <p>Returns a tuple corresponding to <c><anno>List</anno></c>, + for example</p> <pre> > <input>list_to_tuple([share, ['Ericsson_B', 163]]).</input> {share, ['Ericsson_B', 163]}</pre> + <p><c><anno>List</anno></c> can contain any Erlang terms.</p> </desc> </func> + <func> <name name="load_module" arity="2"/> - <fsummary>Load object code for a module</fsummary> + <fsummary>Loads object code for a module.</fsummary> <desc> - <p>If <c><anno>Binary</anno></c> contains the object code for the module - <c><anno>Module</anno></c>, this BIF loads that object code. Also, if - the code for the module <c><anno>Module</anno></c> already exists, all + <p>If <c><anno>Binary</anno></c> contains the object code for module + <c><anno>Module</anno></c>, this BIF loads that object code. If + the code for module <c><anno>Module</anno></c> already exists, all export references are replaced so they point to the newly loaded code. The previously loaded code is kept in the system - as old code, as there may still be processes which are - executing that code. It returns either - <c>{module, <anno>Module</anno>}</c>, or <c>{error, <anno>Reason</anno>}</c> if loading - fails. <c><anno>Reason</anno></c> is one of the following:</p> + as old code, as there can still be processes executing + that code.</p> + <p>Returns either <c>{module, <anno>Module</anno>}</c>, or + <c>{error, <anno>Reason</anno>}</c> if loading fails. + <c><anno>Reason</anno></c> is any of the following:</p> <taglist> <tag><c>badfile</c></tag> <item> @@ -2247,118 +2408,122 @@ os_prompt% </pre> </item> <tag><c>not_purged</c></tag> <item> - <p><c><anno>Binary</anno></c> contains a module which cannot be loaded - because old code for this module already exists.</p> + <p><c><anno>Binary</anno></c> contains a module that cannot be + loaded because old code for this module already exists.</p> </item> </taglist> <warning> <p>This BIF is intended for the code server (see - <seealso marker="kernel:code">code(3)</seealso>) and should not be - used elsewhere.</p> + <seealso marker="kernel:code">code(3)</seealso>) + and is not to be used elsewhere.</p> </warning> </desc> </func> + <func> <name name="load_nif" arity="2"/> - <fsummary>Load NIF library</fsummary> + <fsummary>Loads NIF library.</fsummary> <desc> <note> - <p>In releases older than OTP R14B, NIFs were an - experimental feature. Versions of OTP older than R14B might + <p>Before OTP R14B, NIFs were an + experimental feature. Versions before OTP R14B can have different and possibly incompatible NIF semantics and - interfaces. For example, in R13B03 the return value on - failure was - <c>{error,Reason,Text}</c>.</p> + interfaces. For example, in OTP R13B03 the return value on + failure was <c>{error,Reason,Text}</c>.</p> </note> <p>Loads and links a dynamic library containing native - implemented functions (NIFs) for a module. <c><anno>Path</anno></c> is a - file path to the sharable object/dynamic library file minus - the OS-dependent file extension (.so for Unix and .dll for - Windows). See <seealso marker="erl_nif">erl_nif</seealso> - on how to implement a NIF library.</p> - <p><c><anno>LoadInfo</anno></c> can be any term. It will be passed on to + implemented functions (NIFs) for a module. <c><anno>Path</anno></c> + is a file path to the shareable object/dynamic library file minus + the OS-dependent file extension (<c>.so</c> for Unix and + <c>.dll</c> for Windows. For information on how to + implement a NIF library, see + <seealso marker="erl_nif">erl_nif</seealso>.</p> + <p><c><anno>LoadInfo</anno></c> can be any term. It is passed on to the library as part of the initialization. A good practice is to include a module version number to support future code upgrade scenarios.</p> <p>The call to <c>load_nif/2</c> must be made <em>directly</em> from the Erlang code of the module that the - NIF library belongs to.</p> - <p>It returns either <c>ok</c>, or <c>{error,{<anno>Reason</anno>,Text}}</c> - if loading fails. <c><anno>Reason</anno></c> is one of the atoms below, - while <c><anno>Text</anno></c> is a human readable string that may give - some more information about the failure.</p> + NIF library belongs to. It returns either <c>ok</c>, or + <c>{error,{<anno>Reason</anno>,Text}}</c> if loading fails. + <c><anno>Reason</anno></c> is one of the following atoms + while <c><anno>Text</anno></c> is a human readable string that + can give more information about the failure:</p> <taglist> <tag><c>load_failed</c></tag> - <item> - <p>The OS failed to load the NIF library.</p> + <item>The OS failed to load the NIF library. </item> <tag><c>bad_lib</c></tag> - <item> - <p>The library did not fulfil the requirements as a NIF - library of the calling module.</p> + <item>The library did not fulfill the requirements as a NIF + library of the calling module. </item> <tag><c>load | reload | upgrade</c></tag> - <item> - <p>The corresponding library callback was not successful.</p> + <item>The corresponding library callback was unsuccessful. </item> <tag><c>old_code</c></tag> - <item> - <p>The call to <c>load_nif/2</c> was made from the old - code of a module that has been upgraded. This is not - allowed.</p> + <item>The call to <c>load_nif/2</c> was made from the old + code of a module that has been upgraded; this is not + allowed. </item> </taglist> </desc> </func> + <func> <name name="loaded" arity="0"/> - <fsummary>List of all loaded modules</fsummary> + <fsummary>Lists all loaded modules.</fsummary> <desc> - <p>Returns a list of all loaded Erlang modules (current and/or + <p>Returns a list of all loaded Erlang modules (current and old code), including preloaded modules.</p> <p>See also <seealso marker="kernel:code">code(3)</seealso>.</p> </desc> </func> + <func> <name name="localtime" arity="0"/> - <fsummary>Current local date and time</fsummary> + <fsummary>Current local date and time.</fsummary> <desc> - <p>Returns the current local date and time - <c>{{Year, Month, Day}, {Hour, Minute, Second}}</c>.</p> - <p>The time zone and daylight saving time correction depend - on the underlying OS.</p> + <p>Returns the current local date and time, + <c>{{Year, Month, Day}, {Hour, Minute, Second}}</c>, + for example:</p> <pre> > <input>erlang:localtime().</input> {{1996,11,6},{14,45,17}}</pre> + <p>The time zone and Daylight Saving Time correction depend + on the underlying OS.</p> </desc> </func> + <func> <name name="localtime_to_universaltime" arity="1"/> - <fsummary>Convert from local to Universal Time Coordinated (UTC) date and time</fsummary> + <fsummary>Converts from local to Universal Time Coordinated (UTC) date and time.</fsummary> <desc> <p>Converts local date and time to Universal Time Coordinated - (UTC), if this is supported by the underlying OS. Otherwise, - no conversion is done and <c><anno>Localtime</anno></c> is returned.</p> + (UTC), if supported by the underlying OS. Otherwise + no conversion is done and <c><anno>Localtime</anno></c> + is returned.</p> + <p>Example:</p> <pre> > <input>erlang:localtime_to_universaltime({{1996,11,6},{14,45,17}}).</input> {{1996,11,6},{13,45,17}}</pre> - <p>Failure: <c>badarg</c> if <c><anno>Localtime</anno></c> does not denote - a valid date and time.</p> + <p>Failure: <c>badarg</c> if <c><anno>Localtime</anno></c> denotes an + invalid date and time.</p> </desc> </func> + <func> <name name="localtime_to_universaltime" arity="2"/> - <fsummary>Convert from local to Universal Time Coordinated (UTC) date and time</fsummary> + <fsummary>Converts from local to Universal Time Coordinated (UTC) date and time.</fsummary> <desc> <p>Converts local date and time to Universal Time Coordinated - (UTC) just like <c>erlang:localtime_to_universaltime/1</c>, - but the caller decides if daylight saving time is active or - not.</p> - <p>If <c><anno>IsDst</anno> == true</c> the <c><anno>Localtime</anno></c> is during - daylight saving time, if <c><anno>IsDst</anno> == false</c> it is not, - and if <c><anno>IsDst</anno> == undefined</c> the underlying OS may + (UTC) as <c>erlang:localtime_to_universaltime/1</c>, + but the caller decides if Daylight Saving Time is active.</p> + <p>If <c><anno>IsDst</anno> == true</c>, <c><anno>Localtime</anno></c> is + during Daylight Saving Time, if <c><anno>IsDst</anno> == false</c> it is + not. If <c><anno>IsDst</anno> == undefined</c>, the underlying OS can guess, which is the same as calling <c>erlang:localtime_to_universaltime(<anno>Localtime</anno>)</c>.</p> + <p>Examples:</p> <pre> > <input>erlang:localtime_to_universaltime({{1996,11,6},{14,45,17}}, true).</input> {{1996,11,6},{12,45,17}} @@ -2366,15 +2531,16 @@ os_prompt% </pre> {{1996,11,6},{13,45,17}} > <input>erlang:localtime_to_universaltime({{1996,11,6},{14,45,17}}, undefined).</input> {{1996,11,6},{13,45,17}}</pre> - <p>Failure: <c>badarg</c> if <c><anno>Localtime</anno></c> does not denote - a valid date and time.</p> + <p>Failure: <c>badarg</c> if <c><anno>Localtime</anno></c> denotes an + invalid date and time.</p> </desc> </func> + <func> <name name="make_ref" arity="0"/> - <fsummary>Return a unique reference</fsummary> + <fsummary>Returns a unique reference.</fsummary> <desc> - <p>Return a <seealso marker="doc/efficiency_guide:advanced#unique_references">unique + <p>Returns a <seealso marker="doc/efficiency_guide:advanced#unique_references">unique reference</seealso>. The reference is unique among connected nodes.</p> <warning><p>Known issue: When a node is restarted multiple @@ -2383,200 +2549,209 @@ os_prompt% </pre> created on an older node with the same node name.</p></warning> </desc> </func> + <func> <name name="make_tuple" arity="2"/> - <fsummary>Create a new tuple of a given arity</fsummary> + <fsummary>Creates a new tuple of a given arity.</fsummary> <desc> - <p>Returns a new tuple of the given <c><anno>Arity</anno></c>, where all - elements are <c><anno>InitialValue</anno></c>.</p> + <p>Creates a new tuple of the given <c><anno>Arity</anno></c>, where all + elements are <c><anno>InitialValue</anno></c>, for example:</p> <pre> > <input>erlang:make_tuple(4, []).</input> {[],[],[],[]}</pre> </desc> </func> + <func> <name name="make_tuple" arity="3"/> - <fsummary>Create a new tuple with given arity and contents</fsummary> - <desc> - <p><c>erlang:make_tuple</c> first creates a tuple of size <c><anno>Arity</anno></c> - where each element has the value <c><anno>DefaultValue</anno></c>. It then fills - in values from <c><anno>InitList</anno></c>. Each list element in <c><anno>InitList</anno></c> - must be a two-tuple where the first element is a position in the - newly created tuple and the second element is any term. If a position - occurs more than once in the list, the term corresponding to - last occurrence will be used.</p> + <fsummary>Creates a new tuple with given arity and contents.</fsummary> + <desc> + <p>Creates a tuple of size <c><anno>Arity</anno></c>, where each element + has value <c><anno>DefaultValue</anno></c>, and then fills in + values from <c><anno>InitList</anno></c>. + Each list element in <c><anno>InitList</anno></c> + must be a two-tuple, where the first element is a position in the + newly created tuple and the second element is any term. If a + position occurs more than once in the list, the term corresponding + to the last occurrence is used.</p> + <p>Example:</p> <pre> > <input>erlang:make_tuple(5, [], [{2,ignored},{5,zz},{2,aa}]).</input> {{[],aa,[],[],zz}</pre> </desc> </func> + <func> <name name="map_size" arity="1"/> - <fsummary>Return the size of a map</fsummary> + <fsummary>Returns the size of a map.</fsummary> <desc> - <p>Returns an integer which is the number of key-value pairs in <c><anno>Map</anno></c>.</p> + <p>Returns an integer, which is the number of key-value pairs + in <c><anno>Map</anno></c>, for example:</p> <pre> > <input>map_size(#{a=>1, b=>2, c=>3}).</input> 3</pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="max" arity="2"/> - <fsummary>Return the largest of two term</fsummary> + <fsummary>Returns the largest of two terms.</fsummary> <desc> - <p>Return the largest of <c><anno>Term1</anno></c> and <c><anno>Term2</anno></c>; - if the terms compare equal, <c><anno>Term1</anno></c> will be returned.</p> + <p>Returns the largest of <c><anno>Term1</anno></c> and + <c><anno>Term2</anno></c>. + If the terms are equal, <c><anno>Term1</anno></c> is returned.</p> </desc> </func> + <func> <name name="md5" arity="1"/> - <fsummary>Compute an MD5 message digest</fsummary> + <fsummary>Computes an MD5 message digest.</fsummary> <desc> - <p>Computes an <c>MD5</c> message digest from <c><anno>Data</anno></c>, where - the length of the digest is 128 bits (16 bytes). <c><anno>Data</anno></c> + <p>Computes an MD5 message digest from <c><anno>Data</anno></c>, where + the length of the digest is 128 bits (16 bytes). + <c><anno>Data</anno></c> is a binary or a list of small integers and binaries.</p> - <p>See The MD5 Message Digest Algorithm (RFC 1321) for more - information about MD5.</p> - <warning><p>The MD5 Message Digest Algorithm is <em>not</em> considered - safe for code-signing or software integrity purposes.</p></warning> + <p>For more information about MD5, see RFC 1321 - The + MD5 Message-Digest Algorithm.</p> + <warning><p>The MD5 Message-Digest Algorithm is <em>not</em> considered + safe for code-signing or software-integrity purposes.</p></warning> </desc> </func> + <func> <name name="md5_final" arity="1"/> - <fsummary>Finish the update of an MD5 context and return the computed MD5 message digest</fsummary> + <fsummary>Finishes the update of an MD5 context and returns the computed MD5 message digest.</fsummary> <desc> <p>Finishes the update of an MD5 <c><anno>Context</anno></c> and returns the computed <c>MD5</c> message digest.</p> </desc> </func> + <func> <name name="md5_init" arity="0"/> - <fsummary>Create an MD5 context</fsummary> + <fsummary>Creates an MD5 context.</fsummary> <desc> <p>Creates an MD5 context, to be used in subsequent calls to <c>md5_update/2</c>.</p> </desc> </func> + <func> <name name="md5_update" arity="2"/> - <fsummary>Update an MD5 context with data, and return a new context</fsummary> + <fsummary>Updates an MD5 context with data and returns a new context.</fsummary> <desc> - <p>Updates an MD5 <c><anno>Context</anno></c> with <c><anno>Data</anno></c>, and returns - a <c><anno>NewContext</anno></c>.</p> + <p>Updates an MD5 <c><anno>Context</anno></c> with + <c><anno>Data</anno></c> and returns a + <c><anno>NewContext</anno></c>.</p> </desc> </func> + <func> <name name="memory" arity="0"/> + <fsummary>Information about dynamically allocated memory.</fsummary> <type name="memory_type"/> - <fsummary>Information about dynamically allocated memory</fsummary> - <desc> - <p>Returns a list containing information about memory - dynamically allocated by the Erlang emulator. Each element of - the list is a tuple <c>{Type, Size}</c>. The first element - <c><anno>Type</anno></c>is an atom describing memory type. The second - element <c><anno>Size</anno></c>is memory size in bytes. A description of - each memory type follows:</p> + <desc> + <p>Returns a list with information about memory + dynamically allocated by the Erlang emulator. Each list + element is a tuple <c>{Type, Size}</c>. The first element + <c><anno>Type</anno></c> is an atom describing memory type. The second + element <c><anno>Size</anno></c> is the memory size in bytes.</p> + <p>The memory types are as follows:</p> <taglist> <tag><c>total</c></tag> <item> - <p>The total amount of memory currently allocated, which is - the same as the sum of memory size for <c>processes</c> + <p>The total amount of memory currently allocated. This is + the same as the sum of the memory size for <c>processes</c> and <c>system</c>.</p> </item> <tag><c>processes</c></tag> <item> - <p>The total amount of memory currently allocated by + <p>The total amount of memory currently allocated for the Erlang processes.</p> </item> <tag><c>processes_used</c></tag> <item> <p>The total amount of memory currently used by the Erlang - processes.</p> - <p>This memory is part of the memory presented as + processes. This is part of the memory presented as <c>processes</c> memory.</p> </item> <tag><c>system</c></tag> <item> - <p>The total amount of memory currently allocated by + <p>The total amount of memory currently allocated for the emulator that is not directly related to any Erlang - process.</p> - <p>Memory presented as <c>processes</c> is not included in - this memory.</p> + process. Memory presented as <c>processes</c> is not + included in this memory.</p> </item> <tag><c>atom</c></tag> <item> - <p>The total amount of memory currently allocated for atoms.</p> - <p>This memory is part of the memory presented as + <p>The total amount of memory currently allocated for atoms. + This memory is part of the memory presented as <c>system</c> memory.</p> </item> <tag><c>atom_used</c></tag> <item> - <p>The total amount of memory currently used for atoms.</p> - <p>This memory is part of the memory presented as + <p>The total amount of memory currently used for atoms. + This memory is part of the memory presented as <c>atom</c> memory.</p> </item> <tag><c>binary</c></tag> <item> <p>The total amount of memory currently allocated for - binaries.</p> - <p>This memory is part of the memory presented as - <c>system</c> memory.</p> + binaries. This memory is part of the memory presented + as <c>system</c> memory.</p> </item> <tag><c>code</c></tag> <item> <p>The total amount of memory currently allocated for - Erlang code.</p> - <p>This memory is part of the memory presented as - <c>system</c> memory.</p> + Erlang code. This memory is part of the memory presented + as <c>system</c> memory.</p> </item> <tag><c>ets</c></tag> <item> <p>The total amount of memory currently allocated for ets - tables.</p> - <p>This memory is part of the memory presented as + tables. This memory is part of the memory presented as <c>system</c> memory.</p> </item> <tag><c>low</c></tag> <item> - <p>Only on 64-bit halfword emulator.</p> - <p>The total amount of memory allocated in low memory areas - that are restricted to less than 4 Gb even though - the system may have more physical memory.</p> - <p>May be removed in future releases of halfword emulator.</p> + <p>Only on 64-bit halfword emulator. + The total amount of memory allocated in low memory areas + that are restricted to less than 4 GB, although + the system can have more memory.</p> + <p>Can be removed in a future release of the halfword + emulator.</p> </item> <tag><c>maximum</c></tag> <item> <p>The maximum total amount of memory allocated since - the emulator was started.</p> - <p>This tuple is only present when the emulator is run with - instrumentation.</p> + the emulator was started. This tuple is only present + when the emulator is run with instrumentation.</p> <p>For information on how to run the emulator with - instrumentation see + instrumentation, see <seealso marker="tools:instrument">instrument(3)</seealso> and/or <seealso marker="erts:erl">erl(1)</seealso>.</p> </item> </taglist> <note> <p>The <c>system</c> value is not complete. Some allocated - memory that should be part of the <c>system</c> value are - not.</p> + memory that is to be part of this value is not.</p> <p>When the emulator is run with instrumentation, the <c>system</c> value is more accurate, but memory - directly allocated by <c>malloc</c> (and friends) are still + directly allocated for <c>malloc</c> (and friends) is still not part of the <c>system</c> value. Direct calls to - <c>malloc</c> are only done from OS specific runtime - libraries and perhaps from user implemented Erlang drivers + <c>malloc</c> are only done from OS-specific runtime + libraries and perhaps from user-implemented Erlang drivers that do not use the memory allocation functions in the driver interface.</p> - <p>Since the <c>total</c> value is the sum of <c>processes</c> - and <c>system</c> the error in <c>system</c> will propagate + <p>As the <c>total</c> value is the sum of <c>processes</c> + and <c>system</c>, the error in <c>system</c> propagates to the <c>total</c> value.</p> <p>The different amounts of memory that are summed are - <em>not</em> gathered atomically which also introduce + <em>not</em> gathered atomically, which introduces an error in the result.</p> </note> - <p>The different values has the following relation to each + <p>The different values have the following relation to each other. Values beginning with an uppercase letter is not part of the result.</p> <code type="none"> @@ -2584,69 +2759,62 @@ os_prompt% </pre> processes = processes_used + ProcessesNotUsed system = atom + binary + code + ets + OtherSystem atom = atom_used + AtomNotUsed - RealTotal = processes + RealSystem RealSystem = system + MissedSystem</code> - <p>More tuples in the returned list may be added in the future.</p> + <p>More tuples in the returned list can be added in a + future release.</p> <note> <p>The <c>total</c> value is supposed to be the total amount of memory dynamically allocated by the emulator. Shared libraries, the code of the emulator itself, and - the emulator stack(s) are not supposed to be included. That + the emulator stacks are not supposed to be included. That is, the <c>total</c> value is <em>not</em> supposed to be - equal to the total size of all pages mapped to the emulator. - Furthermore, due to fragmentation and pre-reservation of - memory areas, the size of the memory segments which contain - the dynamically allocated memory blocks can be substantially + equal to the total size of all pages mapped to the emulator.</p> + <p>Furthermore, because of fragmentation and prereservation of + memory areas, the size of the memory segments containing + the dynamically allocated memory blocks can be much larger than the total size of the dynamically allocated memory blocks.</p> </note> <note> - <p> - Since erts version 5.6.4 <c>erlang:memory/0</c> requires that + <p>As from <c>ERTS</c> 5.6.4, <c>erlang:memory/0</c> requires that all <seealso marker="erts:erts_alloc">erts_alloc(3)</seealso> - allocators are enabled (default behaviour). - </p> + allocators are enabled (default behavior).</p> </note> - <p>Failure:</p> - <taglist> - <tag><c>notsup</c></tag> - <item> - If an <seealso marker="erts:erts_alloc">erts_alloc(3)</seealso> - allocator has been disabled. - </item> - </taglist> + <p>Failure: <c>notsup</c> if an + <seealso marker="erts:erts_alloc">erts_alloc(3)</seealso> + allocator has been disabled.</p> </desc> </func> + <func> <name name="memory" arity="1" clause_i="1"/> <name name="memory" arity="1" clause_i="2"/> + <fsummary>Information about dynamically allocated memory.</fsummary> <type name="memory_type"/> - <fsummary>Information about dynamically allocated memory</fsummary> <desc> <p>Returns the memory size in bytes allocated for memory of type <c><anno>Type</anno></c>. The argument can also be given as a list of <c>memory_type()</c> atoms, in which case a corresponding list of <c>{memory_type(), Size :: integer >= 0}</c> tuples is returned.</p> <note> - <p> - Since erts version 5.6.4 <c>erlang:memory/1</c> requires that + <p>As from <c>ERTS</c> version 5.6.4, + <c>erlang:memory/1</c> requires that all <seealso marker="erts:erts_alloc">erts_alloc(3)</seealso> - allocators are enabled (default behaviour). - </p> + allocators are enabled (default behavior).</p> </note> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> <item> - If <c><anno>Type</anno></c> is not one of the memory types listed in the - documentation of + If <c><anno>Type</anno></c> is not one of the memory types + listed in the description of <seealso marker="#memory/0">erlang:memory/0</seealso>. </item> <tag><c>badarg</c></tag> <item> - If <c>maximum</c> is passed as <c><anno>Type</anno></c> and the emulator - is not run in instrumented mode. + If <c>maximum</c> is passed as <c><anno>Type</anno></c> and + the emulator is not run in instrumented mode. </item> <tag><c>notsup</c></tag> <item> @@ -2658,35 +2826,39 @@ os_prompt% </pre> <seealso marker="#memory/0">erlang:memory/0</seealso>.</p> </desc> </func> + <func> <name name="min" arity="2"/> - <fsummary>Return the smallest of two term</fsummary> + <fsummary>Returns the smallest of two terms.</fsummary> <desc> - <p>Return the smallest of <c><anno>Term1</anno></c> and <c><anno>Term2</anno></c>; - if the terms compare equal, <c><anno>Term1</anno></c> will be returned.</p> + <p>Returns the smallest of <c><anno>Term1</anno></c> and + <c><anno>Term2</anno></c>. + If the terms are equal, <c><anno>Term1</anno></c> is returned.</p> </desc> </func> + <func> <name name="module_loaded" arity="1"/> - <fsummary>Check if a module is loaded</fsummary> + <fsummary>Checks if a module is loaded.</fsummary> <desc> - <p>Returns <c>true</c> if the module <c><anno>Module</anno></c> is loaded, - otherwise returns <c>false</c>. It does not attempt to load + <p>Returns <c>true</c> if the module <c><anno>Module</anno></c> + is loaded, otherwise <c>false</c>. It does not attempt to load the module.</p> <warning> <p>This BIF is intended for the code server (see - <seealso marker="kernel:code">code(3)</seealso>) and should not be + <seealso marker="kernel:code">code(3)</seealso>) and is not to be used elsewhere.</p> </warning> </desc> </func> + <func> <name name="monitor" arity="2" clause_i="1"/> <name name="monitor" arity="2" clause_i="2"/> + <fsummary>Starts monitoring.</fsummary> <type name="registered_name"/> <type name="registered_process_identifier"/> <type name="monitor_process_identifier"/> - <fsummary>Start monitoring</fsummary> <desc> <p>Send a monitor request of type <c><anno>Type</anno></c> to the entity identified by <c><anno>Item</anno></c>. The caller of @@ -2694,15 +2866,15 @@ os_prompt% </pre> following format if the monitored state is changed:</p> <code type="none">{Tag, <anno>MonitorRef</anno>, <anno>Type</anno>, Object, Info}</code> <note><p>The monitor request is an asynchronous signal. That is, it - takes time before the signal reach its destination.</p></note> - <p>Currently valid <c><anno>Type</anno></c>s:</p> + takes time before the signal reaches its destination.</p></note> + <p>Valid <c><anno>Type</anno></c>s:</p> <taglist> <tag><marker id="monitor_process"/><c>process</c></tag> <item> <p>Monitor the existence of the process identified by - <c><anno>Item</anno></c>. Currently valid + <c><anno>Item</anno></c>. Valid <c><anno>Item</anno></c>s in combination with the - <c>process <anno>Type</anno></c>:</p> + <c>process <anno>Type</anno></c> can be any of the following:</p> <taglist> <tag><c>pid()</c></tag> <item> @@ -2721,10 +2893,10 @@ os_prompt% </pre> will become monitored.</p> </item> </taglist> - <note><p>When a process is monitored by registered name, the - process that has the registered name at the time when the + <note><p>When a registered name is used, the + process that has the registered name when the monitor request reach its destination will be monitored. - The monitor will not be effected, if the registered name is + The monitor is not effected if the registered name is unregistered, or unregistered and later registered on another process.</p></note> <p>The monitor is triggered either when the monitored process @@ -2732,22 +2904,22 @@ os_prompt% </pre> lost. In the case the connection to it is lost, we do not know if it still exist or not. After this type of monitor has been triggered, the monitor is automatically removed.</p> - <p>When the monitor is triggered a <c>'DOWN'</c> message will - be sent to the monitoring process. A <c>'DOWN'</c> message has + <p>When the monitor is triggered a <c>'DOWN'</c> message is + sent to the monitoring process. A <c>'DOWN'</c> message has the following pattern:</p> <code type="none">{'DOWN', MonitorRef, Type, Object, Info}</code> - <p>where <c>MonitorRef</c> and <c>Type</c> are the same as - described above, and:</p> + <p>Here <c>MonitorRef</c> and <c>Type</c> are the same as + described earlier, and:</p> <taglist> <tag><c>Object</c></tag> <item> <p>equals:</p> <taglist> <tag><c><anno>Item</anno></c></tag> - <item>If <c><anno>Item</anno></c> was specified by a - pid.</item> + <item>If <c><anno>Item</anno></c> is specified by a + process identifier.</item> <tag><c>{RegisteredName, Node}</c></tag> - <item>If <c><anno>Item</anno></c> was specified as + <item>If <c><anno>Item</anno></c> is specified as <c>RegisteredName</c>, or <c>{RegisteredName, Node}</c> where <c>Node</c> corresponds to the node that the monitored process resides on.</item> @@ -2760,26 +2932,26 @@ os_prompt% </pre> connection to the node where the monitored process resides).</p></item> </taglist> - <p>The monitoring is turned off either when the <c>'DOWN'</c> - message is sent, or when + <p>The monitoring is turned off when the <c>'DOWN'</c> + message is sent or when <seealso marker="#demonitor/1">demonitor/1</seealso> is called.</p> <p>If an attempt is made to monitor a process on an older node - (where remote process monitoring is not implemented or one + (where remote process monitoring is not implemented or where remote process monitoring by registered name is not implemented), the call fails with <c>badarg</c>.</p> <note> - <p>The format of the <c>'DOWN'</c> message changed in the 5.2 - version of the emulator (OTP release R9B) for monitor - <em>by registered name</em>. The <c>Object</c> element of + <p>The format of the <c>'DOWN'</c> message changed in ERTS + version 5.2 (OTP R9B) for monitoring + <em>by registered name</em>. Element <c>Object</c> of the <c>'DOWN'</c> message could in earlier versions - sometimes be the pid of the monitored process and sometimes - be the registered name. Now the <c>Object</c> element is + sometimes be the process identifier of the monitored process and sometimes + be the registered name. Now element <c>Object</c> is always a tuple consisting of the registered name and - the node name. Processes on new nodes (emulator version 5.2 - or greater) will always get <c>'DOWN'</c> messages on + the node name. Processes on new nodes (ERTS version 5.2 + or higher) always get <c>'DOWN'</c> messages on the new format even if they are monitoring processes on old - nodes. Processes on old nodes will always get <c>'DOWN'</c> + nodes. Processes on old nodes always get <c>'DOWN'</c> messages on the old format.</p> </note> </item> @@ -2807,8 +2979,8 @@ os_prompt% </pre> <seealso marker="time_correction#Single_Time_Warp_Mode">single time warp mode</seealso> is used. When a change from preliminary to final time offset is made, the monitor will be triggered once - regardless of whether the time offset value was changed due to - the finalization or not.</p> + regardless of whether the time offset value was actually changed + or not.</p> <p>If the runtime system is in <seealso marker="time_correction#Multi_Time_Warp_Mode">multi @@ -2836,7 +3008,7 @@ os_prompt% </pre> <p>When the <c>'CHANGE'</c> message has been received you are guaranteed not to retrieve the old time offset when calling <seealso marker="#time_offset/0"><c>erlang:time_offset()</c></seealso>. - Note that you may observe the change of the time offset + Note that you can observe the change of the time offset when calling <c>erlang:time_offset()</c> before you get the <c>'CHANGE'</c> message.</p> @@ -2844,67 +3016,71 @@ os_prompt% </pre> </taglist> <p>Making several calls to <c>monitor/2</c> for the same <c><anno>Item</anno></c> and/or <c><anno>Type</anno></c> is not - an error; it results in many, completely independent, - monitorings.</p> + an error; it results in as many independent monitoring instances.</p> <p>The monitor functionality is expected to be extended. That is, other <c><anno>Type</anno></c>s and <c><anno>Item</anno></c>s - are expected to be supported in the future.</p> + are expected to be supported in a future release.</p> <note> - <p>If/when <c>monitor/2</c> is extended, other - possible values for <c>Tag</c>, <c>Object</c>, and + <p>If or when <c>monitor/2</c> is extended, other + possible values for <c>Tag</c>, <c>Object</c> and <c>Info</c> in the monitor message will be introduced.</p> </note> </desc> </func> + <func> <name name="monitor_node" arity="2"/> - <fsummary>Monitor the status of a node</fsummary> + <fsummary>Monitors the status of a node.</fsummary> <desc> - <p>Monitors the status of the node <c><anno>Node</anno></c>. If <c><anno>Flag</anno></c> - is <c>true</c>, monitoring is turned on; if <c><anno>Flag</anno></c> is - <c>false</c>, monitoring is turned off.</p> + <p>Monitors the status of the node <c><anno>Node</anno></c>. + If <c><anno>Flag</anno></c> + is <c>true</c>, monitoring is turned on. If <c><anno>Flag</anno></c> + is <c>false</c>, monitoring is turned off.</p> <p>Making several calls to <c>monitor_node(Node, true)</c> for - the same <c><anno>Node</anno></c> is not an error; it results in as many, - completely independent, monitorings.</p> + the same <c><anno>Node</anno></c> is not an error; it results + in as many independent monitoring instances.</p> <p>If <c><anno>Node</anno></c> fails or does not exist, the message <c>{nodedown, Node}</c> is delivered to the process. If a process has made two calls to <c>monitor_node(Node, true)</c> - and <c><anno>Node</anno></c> terminates, two <c>nodedown</c> messages are - delivered to the process. If there is no connection to - <c><anno>Node</anno></c>, there will be an attempt to create one. If this - fails, a <c>nodedown</c> message is delivered.</p> + and <c><anno>Node</anno></c> terminates, two <c>nodedown</c> messages + are delivered to the process. If there is no connection to + <c><anno>Node</anno></c>, an attempt is made to create one. + If this fails, a <c>nodedown</c> message is delivered.</p> <p>Nodes connected through hidden connections can be monitored - as any other node.</p> + as any other nodes.</p> <p>Failure: <c>badarg</c> if the local node is not alive.</p> </desc> </func> + <func> <name name="monitor_node" arity="3"/> - <fsummary>Monitor the status of a node</fsummary> + <fsummary>Monitors the status of a node.</fsummary> <desc> - <p>Behaves as <c>monitor_node/2</c> except that it allows an + <p>Behaves as + <seealso marker="#monitor_node/2">monitor_node/2</seealso> + except that it allows an extra option to be given, namely <c>allow_passive_connect</c>. - The option allows the BIF to wait the normal net connection - timeout for the <em>monitored node</em> to connect itself, + This option allows the BIF to wait the normal network connection + time-out for the <em>monitored node</em> to connect itself, even if it cannot be actively connected from this node - (i.e. it is blocked). The state where this might be useful can - only be achieved by using the kernel option - <c>dist_auto_connect once</c>. If that kernel option is not - used, the <c>allow_passive_connect</c> option has no - effect.</p> + (that is, it is blocked). The state where this can be useful + can only be achieved by using the <c>Kernel</c> option + <c>dist_auto_connect once</c>. If that option is not + used, option <c>allow_passive_connect</c> has no effect.</p> <note> - <p>The <c>allow_passive_connect</c> option is used + <p>Option <c>allow_passive_connect</c> is used internally and is seldom needed in applications where the - network topology and the kernel options in effect is known in - advance.</p> + network topology and the <c>Kernel</c> options in effect + are known in advance.</p> </note> <p>Failure: <c>badarg</c> if the local node is not alive or the option list is malformed.</p> </desc> </func> + <func> <name name="monotonic_time" arity="0"/> - <fsummary>Current Erlang monotonic time</fsummary> + <fsummary>Current Erlang monotonic time.</fsummary> <desc> <p>Returns the current <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang @@ -2917,7 +3093,7 @@ os_prompt% </pre> <seealso marker="time_correction#Monotonically_Increasing">monotonically increasing</seealso> time, but <em>not</em> a <seealso marker="time_correction#Strictly_Monotonically_Increasing">strictly monotonically increasing</seealso> time. That is, consecutive calls to - <c>erlang:monotonic_time/0</c> may produce the same result.</p> + <c>erlang:monotonic_time/0</c> can produce the same result.</p> <p>Different runtime system instances will use different unspecified points in time as base for their Erlang monotonic clocks. @@ -2925,9 +3101,9 @@ os_prompt% </pre> different runtime system instances. Different runtime system instances may also place this unspecified point in time different relative runtime system start. It may be placed in the future (time at start - will be a negative value), the past (time at start will be a - positive value), or the runtime system start (time at start will - be zero). The monotonic time as of runtime system start can be + is a negative value), the past (time at start is a + positive value), or the runtime system start (time at start is + zero). The monotonic time at runtime system start can be retrieved by calling <seealso marker="#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso>.</p></note> </desc> @@ -2949,61 +3125,68 @@ os_prompt% </pre> </func> <func> <name name="nif_error" arity="1"/> - <fsummary>Stop execution with a given reason</fsummary> + <fsummary>Stops execution with a given reason.</fsummary> <desc> <p>Works exactly like - <seealso marker="#error/1">erlang:error/1</seealso>, - but Dialyzer thinks that this BIF will return an arbitrary term. - When used in a stub function for a NIF to generate an - exception when the NIF library is not loaded, Dialyzer - will not generate false warnings.</p> + <seealso marker="#error/1">erlang:error/1</seealso>, but + <c>Dialyzer</c> thinks that this BIF will return an arbitrary + term. When used in a stub function for a NIF to generate an + exception when the NIF library is not loaded, <c>Dialyzer</c> + does not generate false warnings.</p> </desc> </func> + <func> <name name="nif_error" arity="2"/> - <fsummary>Stop execution with a given reason</fsummary> + <fsummary>Stops execution with a given reason.</fsummary> <desc> <p>Works exactly like - <seealso marker="#error/2">erlang:error/2</seealso>, - but Dialyzer thinks that this BIF will return an arbitrary term. - When used in a stub function for a NIF to generate an - exception when the NIF library is not loaded, Dialyzer - will not generate false warnings.</p> + <seealso marker="#error/2">erlang:error/2</seealso>, but + <c>Dialyzer</c> thinks that this BIF will return an arbitrary + term. When used in a stub function for a NIF to generate an + exception when the NIF library is not loaded, <c>Dialyzer</c> + does not generate false warnings.</p> </desc> </func> + <func> <name name="node" arity="0"/> - <fsummary>Name of the local node</fsummary> + <fsummary>Name of the local node.</fsummary> <desc> <p>Returns the name of the local node. If the node is not alive, <c>nonode@nohost</c> is returned instead.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="node" arity="1"/> - <fsummary>At which node is a pid, port or reference located</fsummary> + <fsummary>At which node a pid, port, or reference originates.</fsummary> <desc> - <p>Returns the node where <c><anno>Arg</anno></c> is located. <c><anno>Arg</anno></c> can - be a pid, a reference, or a port. If the local node is not + <p>Returns the node where <c><anno>Arg</anno></c> originates. + <c><anno>Arg</anno></c> can + be a process identifier, a reference, or a port. + If the local node is not alive, <c>nonode@nohost</c> is returned.</p> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="nodes" arity="0"/> - <fsummary>All visible nodes in the system</fsummary> + <fsummary>All visible nodes in the system.</fsummary> <desc> - <p>Returns a list of all visible nodes in the system, excluding + <p>Returns a list of all visible nodes in the system, except the local node. Same as <c>nodes(visible)</c>.</p> </desc> </func> + <func> <name name="nodes" arity="1"/> - <fsummary>All nodes of a certain type in the system</fsummary> + <fsummary>All nodes of a certain type in the system.</fsummary> <desc> - <p>Returns a list of nodes according to argument given. - The result returned when the argument is a list, is the list + <p>Returns a list of nodes according to the argument given. + The returned result when the argument is a list, is the list of nodes satisfying the disjunction(s) of the list elements.</p> <p><c><anno>NodeType</anno></c> can be any of the following:</p> <taglist> @@ -3025,22 +3208,26 @@ os_prompt% </pre> </item> <tag><c>known</c></tag> <item> - <p>Nodes which are known to this node, i.e., connected, - previously connected, etc.</p> + <p>Nodes that are known to this node. That is, connected + nodes and nodes referred to by process identifiers, port + identifiers and references located on this node. + The set of known nodes is garbage collected. Notice that + this garbage collection can be delayed. For more + information, see + <seealso marker="erlang#system_info_delayed_node_table_gc">delayed_node_table_gc</seealso>. + </p> </item> </taglist> <p>Some equalities: <c>[node()] = nodes(this)</c>, <c>nodes(connected) = nodes([visible, hidden])</c>, and <c>nodes() = nodes(visible)</c>.</p> - <p>If the local node is not alive, - <c>nodes(this) == nodes(known) == [nonode@nohost]</c>, for - any other <c><anno>Arg</anno></c> the empty list [] is returned.</p> </desc> </func> + <func> <name name="now" arity="0"/> + <fsummary>Elapsed time since 00:00 GMT.</fsummary> <type name="timestamp"/> - <fsummary>Elapsed time since 00:00 GMT</fsummary> <desc> <warning><p><em>This function is deprecated! Do not use it!</em> See the users guide chapter @@ -3050,107 +3237,101 @@ os_prompt% </pre> section for information on what to use instead of <c>erlang:now/0</c>. </p></warning> <p>Returns the tuple <c>{MegaSecs, Secs, MicroSecs}</c> which is - the elapsed time since 00:00 GMT, January 1, 1970 (zero hour) + the elapsed time since 00:00 GMT, January 1, 1970 (zero hour), on the assumption that the underlying OS supports this. - Otherwise, some other point in time is chosen. It is also - guaranteed that subsequent calls to this BIF returns + Otherwise some other point in time is chosen. It is also + guaranteed that subsequent calls to this BIF return continuously increasing values. Hence, the return value from - <c>now()</c> can be used to generate unique time-stamps, - and if it is called in a tight loop on a fast machine + <c>now()</c> can be used to generate unique time-stamps. + If it is called in a tight loop on a fast machine, the time of the node can become skewed.</p> - <p>It can only be used to check the local time of day if - the time-zone info of the underlying operating system is + <p>Can only be used to check the local time of day if + the time-zone information of the underlying OS is properly configured.</p> </desc> </func> + <func> <name name="open_port" arity="2"/> - <fsummary>Open a port</fsummary> + <fsummary>Opens a port.</fsummary> <desc> <p>Returns a port identifier as the result of opening a new Erlang port. A port can be seen as an external Erlang - process. - </p> + process.</p> <p>The name of the executable as well as the arguments - given in <c>cd</c>, <c>env</c>, <c>args</c> and <c>arg0</c> is subject to - Unicode file name translation if the system is running + given in <c>cd</c>, <c>env</c>, <c>args</c>, and <c>arg0</c> are + subject to Unicode file name translation if the system is running in Unicode file name mode. To avoid - translation or force i.e. UTF-8, supply the executable + translation or to force, for example UTF-8, supply the executable and/or arguments as a binary in the correct - encoding. See the <seealso - marker="kernel:file">file</seealso> module, the - <seealso marker="kernel:file#native_name_encoding/0"> - file:native_name_encoding/0</seealso> function and the - <seealso marker="stdlib:unicode_usage">stdlib users guide - </seealso> for details.</p> - - <note><p>The characters in the name (if given as a list) - can only be > 255 if the Erlang VM is started in - Unicode file name translation mode, otherwise the name + encoding. For details, see the module + <seealso marker="kernel:file">file</seealso>, the function + <seealso marker="kernel:file#native_name_encoding/0">file:native_name_encoding/0</seealso>, and the + <seealso marker="stdlib:unicode_usage">STDLIB </seealso> + User's Guide.</p> + <note><p>The characters in the name (if given as a list) can + only be higher than 255 if the Erlang Virtual Machine is started + in Unicode file name translation mode. Otherwise the name of the executable is limited to the ISO-latin-1 character set.</p></note> - - <p><c><anno>PortName</anno></c> is one of the following:</p> + <p><c><anno>PortName</anno></c> can be any of the following:</p> <taglist> <tag><c>{spawn, <anno>Command</anno>}</c></tag> <item> - <p>Starts an external program. <c><anno>Command</anno></c> is the name - of the external program which will be run. <c><anno>Command</anno></c> + <p>Starts an external program. <c><anno>Command</anno></c> + is the name of the external program to be run. + <c><anno>Command</anno></c> runs outside the Erlang work space unless an Erlang - driver with the name <c><anno>Command</anno></c> is found. If found, - that driver will be started. A driver runs in the Erlang - workspace, which means that it is linked with the Erlang + driver with the name <c><anno>Command</anno></c> is found. + If found, that driver is started. A driver runs in the Erlang + work space, which means that it is linked with the Erlang runtime system.</p> <p>When starting external programs on Solaris, the system call <c>vfork</c> is used in preference to <c>fork</c> for performance reasons, although it has a history of - being less robust. If there are problems with using - <c>vfork</c>, setting the environment variable - <c>ERL_NO_VFORK</c> to any value will cause <c>fork</c> + being less robust. If there are problems using + <c>vfork</c>, setting environment variable + <c>ERL_NO_VFORK</c> to any value causes <c>fork</c> to be used instead.</p> - - <p>For external programs, the <c>PATH</c> is searched + <p>For external programs, <c>PATH</c> is searched (or an equivalent method is used to find programs, - depending on operating system). This is done by invoking - the shell on certain platforms. The first space - separated token of the command will be considered as the + depending on OS). This is done by invoking + the shell on certain platforms. The first space-separated + token of the command is considered as the name of the executable (or driver). This (among other things) makes this option unsuitable for running - programs having spaces in file or directory names. Use - {spawn_executable, <anno>Command</anno>} instead if spaces in executable - file names is desired.</p> + programs having spaces in file names or directory names. + If spaces in executable file names are desired, use + <c>{spawn_executable, <anno>Command</anno>}</c> instead.</p> </item> <tag><c>{spawn_driver, <anno>Command</anno>}</c></tag> <item> <p>Works like <c>{spawn, <anno>Command</anno>}</c>, but demands the - first (space separated) token of the command to be the name of a + first (space-separated) token of the command to be the name of a loaded driver. If no driver with that name is loaded, a <c>badarg</c> error is raised.</p> </item> <tag><c>{spawn_executable, <anno>FileName</anno>}</c></tag> <item> - <p>Works like <c>{spawn, <anno>FileName</anno>}</c>, but only runs - external executables. The <c><anno>FileName</anno></c> in its whole - is used as the name of the executable, including any - spaces. If arguments are to be passed, the - <c>args</c> and <c>arg0</c> <c><anno>PortSettings</anno></c> can be used.</p> - - <p>The shell is not usually invoked to start the - program, it's executed directly. Neither is the - <c>PATH</c> (or equivalent) searched. To find a program - in the PATH to execute, use <seealso - marker="kernel:os#find_executable/1">os:find_executable/1</seealso>.</p> + external executables. <c><anno>FileName</anno></c> in its whole + is used as the name of the executable, including any spaces. + If arguments are to be passed, the <c><anno>PortSettings</anno></c> + <c>args</c> and <c>arg0</c> can be used.</p> + <p>The shell is usually not invoked to start the + program, it is executed directly. <c>PATH</c> (or + equivalent) is not searched. To find a program + in <c>PATH</c> to execute, use + <seealso marker="kernel:os#find_executable/1">os:find_executable/1</seealso>.</p> <p>Only if a shell script or <c>.bat</c> file is - executed, the appropriate command interpreter will - implicitly be invoked, but there will still be no - command argument expansion or implicit PATH search.</p> - - <p>If the <c><anno>FileName</anno></c> cannot be run, an error - exception, with the posix error code as the reason, is - raised. The error reason may differ between operating - systems. Typically the error <c>enoent</c> is raised - when one tries to run a program that is not found and + executed, the appropriate command interpreter is + invoked implicitly, but there is still no + command argument expansion or implicit <c>PATH</c> search.</p> + <p>If <c><anno>FileName</anno></c> cannot be run, an error + exception is raised, with the POSIX error code as the reason. + The error reason can differ between OSs. + Typically the error <c>enoent</c> is raised when an + attempt is made to run a program that is not found and <c>eacces</c> is raised when the given file is not executable.</p> </item> @@ -3160,19 +3341,18 @@ os_prompt% </pre> file descriptors used by Erlang. The file descriptor <c><anno>In</anno></c> can be used for standard input, and the file descriptor <c><anno>Out</anno></c> for standard output. It is only - used for various servers in the Erlang operating system - (<c>shell</c> and <c>user</c>). Hence, its use is very - limited.</p> + used for various servers in the Erlang OS (<c>shell</c> + and <c>user</c>). Hence, its use is limited.</p> </item> </taglist> <p><c><anno>PortSettings</anno></c> is a list of settings for the port. - Valid settings are:</p> + The valid settings are as follows:</p> <taglist> <tag><c>{packet, <anno>N</anno>}</c></tag> <item> <p>Messages are preceded by their length, sent in <c><anno>N</anno></c> - bytes, with the most significant byte first. Valid values - for <c>N</c> are 1, 2, or 4.</p> + bytes, with the most significant byte first. The valid values + for <c>N</c> are 1, 2, and 4.</p> </item> <tag><c>stream</c></tag> <item> @@ -3183,116 +3363,108 @@ os_prompt% </pre> <tag><c>{line, <anno>L</anno>}</c></tag> <item> <p>Messages are delivered on a per line basis. Each line - (delimited by the OS-dependent newline sequence) is - delivered in one single message. The message data format - is <c>{Flag, Line}</c>, where <c>Flag</c> is either - <c>eol</c> or <c>noeol</c> and <c>Line</c> is the actual - data delivered (without the newline sequence).</p> + (delimited by the OS-dependent new line sequence) is + delivered in a single message. The message data format + is <c>{Flag, Line}</c>, where <c>Flag</c> is + <c>eol</c> or <c>noeol</c>, and <c>Line</c> is the + data delivered (without the new line sequence).</p> <p><c><anno>L</anno></c> specifies the maximum line length in bytes. - Lines longer than this will be delivered in more than one - message, with the <c>Flag</c> set to <c>noeol</c> for all + Lines longer than this are delivered in more than one + message, with <c>Flag</c> set to <c>noeol</c> for all but the last message. If end of file is encountered - anywhere else than immediately following a newline - sequence, the last line will also be delivered with - the <c>Flag</c> set to <c>noeol</c>. In all other cases, + anywhere else than immediately following a new line + sequence, the last line is also delivered with + <c>Flag</c> set to <c>noeol</c>. Otherwise lines are delivered with <c>Flag</c> set to <c>eol</c>.</p> - <p>The <c>{packet, <anno>N</anno>}</c> and <c>{line, <anno>L</anno>}</c> settings are - mutually exclusive.</p> + <p>The <c>{packet, <anno>N</anno>}</c> and <c>{line, + <anno>L</anno>}</c> settings are mutually exclusive.</p> </item> <tag><c>{cd, <anno>Dir</anno>}</c></tag> <item> - <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> and - <c>{spawn_executable, <anno>FileName</anno>}</c>. + <p>Only valid for <c>{spawn, <anno>Command</anno>}</c> and + <c>{spawn_executable, <anno>FileName</anno>}</c>. The external program starts using <c><anno>Dir</anno></c> as its - working directory. <c><anno>Dir</anno></c> must be a string. - </p> + working directory. <c><anno>Dir</anno></c> must be a string.</p> </item> <tag><c>{env, <anno>Env</anno>}</c></tag> <item> - <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> and + <p>Only valid for <c>{spawn, <anno>Command</anno>}</c> and <c>{spawn_executable, <anno>FileName</anno>}</c>. The environment of the started process is extended using the environment specifications in <c><anno>Env</anno></c>.</p> - <p><c><anno>Env</anno></c> should be a list of tuples <c>{<anno>Name</anno>, <anno>Val</anno>}</c>, - where <c><anno>Name</anno></c> is the name of an environment variable, - and <c><anno>Val</anno></c> is the value it is to have in the spawned - port process. Both <c><anno>Name</anno></c> and <c><anno>Val</anno></c> must be - strings. The one exception is <c><anno>Val</anno></c> being the atom + <p><c><anno>Env</anno></c> is to be a list of tuples + <c>{<anno>Name</anno>, <anno>Val</anno>}</c>, + where <c><anno>Name</anno></c> is the name of an + environment variable, and <c><anno>Val</anno></c> is the + value it is to have in the spawned + port process. Both <c><anno>Name</anno></c> and + <c><anno>Val</anno></c> must be strings. The one + exception is <c><anno>Val</anno></c> being the atom <c>false</c> (in analogy with <c>os:getenv/1</c>), which - removes the environment variable. - </p> + removes the environment variable.</p> </item> <tag><c>{args, [ string() | binary() ]}</c></tag> <item> - - <p>This option is only valid for <c>{spawn_executable, <anno>FileName</anno>}</c> + <p>Only valid for <c>{spawn_executable, <anno>FileName</anno>}</c> and specifies arguments to the executable. Each argument is given as a separate string and (on Unix) eventually ends up as one element each in the argument vector. On - other platforms, similar behavior is mimicked.</p> - - <p>The arguments are not expanded by the shell prior to - being supplied to the executable, most notably this - means that file wildcard expansion will not happen. Use - <seealso - marker="stdlib:filelib#wildcard/1">filelib:wildcard/1</seealso> - to expand wildcards for the arguments. Note that even if + other platforms, a similar behavior is mimicked.</p> + <p>The arguments are not expanded by the shell before + being supplied to the executable. Most notably this + means that file wild card expansion does not happen. + To expand wild cards for the arguments, use + <seealso marker="stdlib:filelib#wildcard/1">filelib:wildcard/1</seealso>. + Notice that even if the program is a Unix shell script, meaning that the - shell will ultimately be invoked, wildcard expansion - will not happen and the script will be provided with the - untouched arguments. On Windows®, wildcard expansion - is always up to the program itself, why this isn't an - issue.</p> - - <p>Note also that the actual executable name (a.k.a. <c>argv[0]</c>) - should not be given in this list. The proper executable name will - automatically be used as argv[0] where applicable.</p> - - <p>If one, for any reason, wants to explicitly set the - program name in the argument vector, the <c>arg0</c> - option can be used.</p> - + shell ultimately is invoked, wild card expansion + does not happen, and the script is provided with the + untouched arguments. On Windows, wild card expansion + is always up to the program itself, therefore this is + not an issue issue.</p> + <p>The executable name (also known as <c>argv[0]</c>) + is not to be given in this list. The proper executable name + is automatically used as argv[0], where applicable.</p> + <p>If you explicitly want to set the + program name in the argument vector, option <c>arg0</c> + can be used.</p> </item> <tag><c>{arg0, string() | binary()}</c></tag> <item> - - <p>This option is only valid for <c>{spawn_executable, <anno>FileName</anno>}</c> + <p>Only valid for <c>{spawn_executable, <anno>FileName</anno>}</c> and explicitly specifies the program name argument when - running an executable. This might in some circumstances, - on some operating systems, be desirable. How the program - responds to this is highly system dependent and no specific + running an executable. This can in some circumstances, + on some OSs, be desirable. How the program + responds to this is highly system-dependent and no specific effect is guaranteed.</p> - </item> - <tag><c>exit_status</c></tag> <item> - <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> where - <c><anno>Command</anno></c> refers to an external program, and for - <c>{spawn_executable, <anno>FileName</anno>}</c>.</p> + <p>Only valid for <c>{spawn, <anno>Command</anno>}</c>, where + <c><anno>Command</anno></c> refers to an external program, and + for <c>{spawn_executable, <anno>FileName</anno>}</c>.</p> <p>When the external process connected to the port exits, a message of the form <c>{Port,{exit_status,Status}}</c> is sent to the connected process, where <c>Status</c> is the exit status of the external process. If the program - aborts, on Unix the same convention is used as the shells - do (i.e., 128+signal).</p> - <p>If the <c>eof</c> option has been given as well, - the <c>eof</c> message and the <c>exit_status</c> message - appear in an unspecified order.</p> - <p>If the port program closes its stdout without exiting, - the <c>exit_status</c> option will not work.</p> + aborts on Unix, the same convention is used as the shells + do (that is, 128+signal).</p> + <p>If option <c>eof</c> is also given, the messages <c>eof</c> + and <c>exit_status</c> appear in an unspecified order.</p> + <p>If the port program closes its <c>stdout</c> without exiting, + option <c>exit_status</c> does not work.</p> </item> <tag><c>use_stdio</c></tag> <item> - <p>This is only valid for <c>{spawn, <anno>Command</anno>}</c> and + <p>Only valid for <c>{spawn, <anno>Command</anno>}</c> and <c>{spawn_executable, <anno>FileName</anno>}</c>. It allows the standard input and output (file descriptors 0 - and 1) of the spawned (UNIX) process for communication + and 1) of the spawned (Unix) process for communication with Erlang.</p> </item> <tag><c>nouse_stdio</c></tag> <item> - <p>The opposite of <c>use_stdio</c>. Uses file descriptors + <p>The opposite of <c>use_stdio</c>. It uses file descriptors 3 and 4 for communication with Erlang.</p> </item> <tag><c>stderr_to_stdout</c></tag> @@ -3304,14 +3476,15 @@ os_prompt% </pre> </item> <tag><c>overlapped_io</c></tag> <item> - <p>Affects ports to external programs on Windows® only. - The standard input and standard output handles of the port program - will, if this option is supplied, be opened with the flag - FILE_FLAG_OVERLAPPED, so that the port program can (and has to) do + <p>Affects ports to external programs on Windows only. The + standard input and standard output handles of the port program + are, if this option is supplied, opened with flag + <c>FILE_FLAG_OVERLAPPED</c>, so that the port program can + (and must) do overlapped I/O on its standard handles. This is not normally the case for simple port programs, but an option of value for the - experienced Windows programmer. <em>On all other platforms, this - option is silently discarded</em>.</p> + experienced Windows programmer. <em>On all other platforms, this + option is silently discarded.</em></p> </item> <tag><c>in</c></tag> <item> @@ -3323,345 +3496,354 @@ os_prompt% </pre> </item> <tag><c>binary</c></tag> <item> - <p>All IO from the port are binary data objects as opposed + <p>All I/O from the port is binary data objects as opposed to lists of bytes.</p> </item> <tag><c>eof</c></tag> <item> - <p>The port will not be closed at the end of the file and - produce an exit signal. Instead, it will remain open and - a <c>{Port, eof}</c> message will be sent to the process + <p>The port is not closed at the end of the file and does not + produce an exit signal. Instead, it remains open and + a <c>{Port, eof}</c> message is sent to the process holding the port.</p> </item> <tag><c>hide</c></tag> <item> - <p>When running on Windows, suppress creation of a new + <p>When running on Windows, suppresses creation of a new console window when spawning the port program. (This option has no effect on other platforms.)</p> </item> - <tag><marker id="open_port_parallelism"><c>{parallelism, Boolean}</c></marker></tag> + <tag><c>{parallelism, Boolean}</c></tag> <item> - <p>Set scheduler hint for port parallelism. If set to <c>true</c>, - the VM will schedule port tasks when doing so will improve - parallelism in the system. If set to <c>false</c>, the VM will - try to perform port tasks immediately, improving latency at the - expense of parallelism. The default can be set on system startup - by passing the - <seealso marker="erl#+spp">+spp</seealso> command line argument - to <seealso marker="erl">erl(1)</seealso>. - </p> + <marker id="open_port_parallelism"></marker> + <p>Sets scheduler hint for port parallelism. If set to + <c>true</c>, the Virtual Machine schedules port tasks; + when doing so, it improves parallelism in the system. If set + to <c>false</c>, the Virtual Machine tries to + perform port tasks immediately, improving latency at the + expense of parallelism. The default can be set at system startup + by passing command-line argument + <seealso marker="erl#+spp">+spp</seealso> to <c>erl(1)</c>.</p> </item> </taglist> - <p>The default is <c>stream</c> for all types of port and + <p>Default is <c>stream</c> for all port types and <c>use_stdio</c> for spawned ports.</p> <p>Failure: If the port cannot be opened, the exit reason is - <c>badarg</c>, <c>system_limit</c>, or the Posix error code which - most closely describes the error, or <c>einval</c> if no Posix code - is appropriate:</p> + <c>badarg</c>, <c>system_limit</c>, or the POSIX error code that + most closely describes the error, or <c>einval</c> if no POSIX + code is appropriate:</p> <taglist> <tag><c>badarg</c></tag> - <item> - <p>Bad input arguments to <c>open_port</c>.</p> + <item>Bad input arguments to <c>open_port</c>. </item> <tag><c>system_limit</c></tag> - <item> - <p>All available ports in the Erlang emulator are in use.</p> + <item>All available ports in the Erlang emulator are in use. </item> <tag><c>enomem</c></tag> - <item> - <p>There was not enough memory to create the port.</p> + <item>Not enough memory to create the port. </item> <tag><c>eagain</c></tag> - <item> - <p>There are no more available operating system processes.</p> + <item>No more available OS processes. </item> <tag><c>enametoolong</c></tag> - <item> - <p>The external command given was too long.</p> + <item>Too long external command. </item> <tag><c>emfile</c></tag> - <item> - <p>There are no more available file descriptors (for the operating system process - that the Erlang emulator runs in).</p> + <item>No more available file descriptors (for the + OS process that the Erlang emulator runs in). </item> <tag><c>enfile</c></tag> - <item> - <p>The file table is full (for the entire operating system).</p> + <item>Full file table (for the entire OS). </item> <tag><c>eacces</c></tag> - <item> - <p>The <c>Command</c> given in <c>{spawn_executable, Command}</c> does not point out an executable file.</p> + <item><c>Command</c> given in <c>{spawn_executable, Command}</c> + does not point out an executable file. </item> <tag><c>enoent</c></tag> - <item> - <p>The <c><anno>FileName</anno></c> given in <c>{spawn_executable, <anno>FileName</anno>}</c> does not point out an existing file.</p> + <item><c><anno>FileName</anno></c> given in + <c>{spawn_executable, <anno>FileName</anno>}</c> + does not point out an existing file. </item> </taglist> <p>During use of a port opened using <c>{spawn, Name}</c>, - <c>{spawn_driver, Name}</c> or <c>{spawn_executable, Name}</c>, + <c>{spawn_driver, Name}</c>, or <c>{spawn_executable, Name}</c>, errors arising when sending messages to it are reported to the owning process using signals of the form - <c>{'EXIT', Port, PosixCode}</c>. See <c>file(3)</c> for - possible values of <c>PosixCode</c>.</p> + <c>{'EXIT', Port, PosixCode}</c>. For the possible values of + <c>PosixCode</c>, see the + <seealso marker="kernel:file">file(3)</seealso> + manual page in <c>Kernel</c>.</p> <p>The maximum number of ports that can be open at the same - time can be configured by passing the - <seealso marker="erl#max_ports"><c>+Q</c></seealso> - command line flag to - <seealso marker="erl"><c>erl(1)</c></seealso>.</p> + time can be configured by passing command-line flag + <seealso marker="erl#max_ports"><c>+Q</c></seealso> to + <c>erl(1)</c>.</p> </desc> </func> + <func> <name name="phash" arity="2"/> + <fsummary>Portable hash function.</fsummary> <type_desc variable="Range">Range = 1..2^32, Hash = 1..Range</type_desc> - <fsummary>Portable hash function</fsummary> <desc> - <p>Portable hash function that will give the same hash for + <p>Portable hash function that gives the same hash for the same Erlang term regardless of machine architecture and - ERTS version (the BIF was introduced in ERTS 4.9.1.1). Range - can be between 1 and 2^32, the function returns a hash value - for <c><anno>Term</anno></c> within the range <c>1..<anno>Range</anno></c>.</p> - <p>This BIF could be used instead of the old deprecated - <c>erlang:hash/2</c> BIF, as it calculates better hashes for - all data-types, but consider using <c>phash2/1,2</c> instead.</p> + <c>ERTS</c> version (the BIF was introduced in <c>ERTS</c> 4.9.1.1). + The function returns a hash value for + <c><anno>Term</anno></c> within the range + <c>1..<anno>Range</anno></c>. The maximum value for + <c><anno>Range</anno></c> is 2^32.</p> + <p>This BIF can be used instead of the old deprecated BIF + <c>erlang:hash/2</c>, as it calculates better hashes for + all data types, but consider using <c>phash2/1,2</c> instead.</p> </desc> </func> + <func> <name name="phash2" arity="1"/> <name name="phash2" arity="2"/> + <fsummary>Portable hash function.</fsummary> <type_desc variable="Range">1..2^32</type_desc> <type_desc variable="Hash">0..Range-1</type_desc> - <fsummary>Portable hash function</fsummary> <desc> - <p>Portable hash function that will give the same hash for + <p>Portable hash function that gives the same hash for the same Erlang term regardless of machine architecture and - ERTS version (the BIF was introduced in ERTS 5.2). Range can - be between 1 and 2^32, the function returns a hash value for - <c><anno>Term</anno></c> within the range <c>0..<anno>Range</anno>-1</c>. When called - without the <c><anno>Range</anno></c> argument, a value in the range - <c>0..2^27-1</c> is returned.</p> - <p>This BIF should always be used for hashing terms. It + <c>ERTS</c> version (the BIF was introduced in <c>ERTS</c> 5.2). + The function returns a hash value for + <c><anno>Term</anno></c> within the range + <c>0..<anno>Range</anno>-1</c>. The maximum value for + <c><anno>Range</anno></c> is 2^32. When without argument + <c><anno>Range</anno></c>, a value in the range + 0..2^27-1 is returned.</p> + <p>This BIF is always to be used for hashing terms. It distributes small integers better than <c>phash/2</c>, and it is faster for bignums and binaries.</p> - <p>Note that the range <c>0..<anno>Range</anno>-1</c> is different from - the range of <c>phash/2</c> (<c>1..<anno>Range</anno></c>).</p> + <p>Notice that the range <c>0..<anno>Range</anno>-1</c> is + different from the range of <c>phash/2</c>, which is + <c>1..<anno>Range</anno></c>.</p> </desc> </func> + <func> <name name="pid_to_list" arity="1"/> - <fsummary>Text representation of a pid</fsummary> + <fsummary>Text representation of a pid.</fsummary> <desc> - <p>Returns a string which corresponds to the text + <p>Returns a string corresponding to the text representation of <c><anno>Pid</anno></c>.</p> <warning> - <p>This BIF is intended for debugging and for use in - the Erlang operating system. It should not be used in - application programs.</p> + <p>This BIF is intended for debugging and is not to be used + in application programs.</p> </warning> </desc> </func> + <func> <name name="port_close" arity="1"/> - <fsummary>Close an open port</fsummary> + <fsummary>Closes an open port.</fsummary> <desc> <p>Closes an open port. Roughly the same as - <c><anno>Port</anno> ! {self(), close}</c> except for the error behaviour - (see below), being synchronous, and that the port does - <em>not</em> reply with <c>{Port, closed}</c>. Any process may + <c><anno>Port</anno> ! {self(), close}</c> except for the error behavior + (see the following), being synchronous, and that the port does + <em>not</em> reply with <c>{Port, closed}</c>. Any process can close a port with <c>port_close/1</c>, not only the port owner (the connected process). If the calling process is linked to - port identified by <c><anno>Port</anno></c>, an exit signal due - to that link will be received by the process prior to the return - from <c>port_close/1</c>.</p> - <p>For comparison: <c><anno>Port</anno> ! {self(), close}</c> fails with - <c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to (i.e., - <c><anno>Port</anno></c> refers neither to a port nor to a process). If - <c><anno>Port</anno></c> is a closed port nothing happens. If <c><anno>Port</anno></c> + the port identified by <c><anno>Port</anno></c>, the exit + signal from the port is guaranteed to be delivered before + <c>port_close/1</c> returns.</p> + <p>For comparison: <c><anno>Port</anno> ! {self(), close}</c> + only fails with <c>badarg</c> if <c><anno>Port</anno></c> does + not refer to a port or a process. If <c><anno>Port</anno></c> + is a closed port, nothing happens. If <c><anno>Port</anno></c> is an open port and the calling process is the port owner, - the port replies with <c>{Port, closed}</c> when all buffers - have been flushed and the port really closes, but if - the calling process is not the port owner the <em>port owner</em> fails with <c>badsig</c>.</p> - - <p>Note that any process can close a port using - <c><anno>Port</anno> ! {PortOwner, close}</c> just as if it itself was + the port replies with <c>{Port, closed}</c> when all buffers + have been flushed and the port really closes. If the calling + process is not the port owner, the <em>port owner</em> fails + with <c>badsig</c>.</p> + <p>Notice that any process can close a port using + <c><anno>Port</anno> ! {PortOwner, close}</c> as if it itself was the port owner, but the reply always goes to the port owner.</p> - <p>As of OTP-R16 <c><anno>Port</anno> ! {PortOwner, close}</c> is truly - asynchronous. Note that this operation has always been + <p>As from OTP R16, <c><anno>Port</anno> ! {PortOwner, close}</c> is truly + asynchronous. Notice that this operation has always been documented as an asynchronous operation, while the underlying implementation has been synchronous. <c>port_close/1</c> is - however still fully synchronous. This due to its error + however still fully synchronous. This because of its error behavior.</p> - <p>Failure:</p> - <taglist> - <tag><c>badarg</c></tag> - <item> - If <c><anno>Port</anno></c> is not an identifier of an open - port, or the registered name of an open port. If the calling - process was linked to the previously open port identified by - <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to this exception. - </item> - </taglist> + <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an identifier + of an open port, or the registered name of an open port. + If the calling process was previously linked to the closed + port, identified by <c><anno>Port</anno></c>, the exit + signal from the port is guaranteed to be delivered before + this <c>badarg</c> exception occurs.</p> </desc> </func> + <func> <name name="port_command" arity="2"/> - <fsummary>Send data to a port</fsummary> + <fsummary>Sends data to a port.</fsummary> <desc> <p>Sends data to a port. Same as - <c><anno>Port</anno> ! {PortOwner, {command, Data}}</c> except for the error - behaviour and being synchronous (see below). Any process may - send data to a port with <c>port_command/2</c>, not only the + <c><anno>Port</anno> ! {PortOwner, {command, Data}}</c> except + for the error + behavior and being synchronous (see the following). Any process + can send data to a port with <c>port_command/2</c>, not only the port owner (the connected process).</p> <p>For comparison: <c><anno>Port</anno> ! {PortOwner, {command, Data}}</c> - fails with <c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to - (i.e., <c><anno>Port</anno></c> refers neither to a port nor to a process). - If <c><anno>Port</anno></c> is a closed port the data message disappears + only fails with <c>badarg</c> if <c><anno>Port</anno></c> + does not refer to a port or a process. If + <c><anno>Port</anno></c> is a closed port, the data message + disappears without a sound. If <c><anno>Port</anno></c> is open and the calling process is not the port owner, the <em>port owner</em> fails with <c>badsig</c>. The port owner fails with <c>badsig</c> - also if <c><anno>Data</anno></c> is not a valid IO list.</p> - <p>Note that any process can send to a port using - <c><anno>Port</anno> ! {PortOwner, {command, <anno>Data</anno>}}</c> just as if it - itself was the port owner.</p> - <p>If the port is busy, the calling process will be suspended - until the port is not busy anymore.</p> - <p>As of OTP-R16 <c><anno>Port</anno> ! {PortOwner, {command, Data}}</c> is - truly asynchronous. Note that this operation has always been + also if <c><anno>Data</anno></c> is an invalid I/O list.</p> + <p>Notice that any process can send to a port using + <c><anno>Port</anno> ! {PortOwner, {command, <anno>Data</anno>}}</c> + as if it itself was the port owner.</p> + <p>If the port is busy, the calling process is suspended + until the port is not busy any more.</p> + <p>As from OTP-R16, <c><anno>Port</anno> ! {PortOwner, {command, Data}}</c> + is truly asynchronous. Notice that this operation has always been documented as an asynchronous operation, while the underlying implementation has been synchronous. <c>port_command/2</c> is - however still fully synchronous. This due to its error + however still fully synchronous. This because of its error behavior.</p> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> <item> If <c><anno>Port</anno></c> is not an identifier of an open - port, or the registered name of an open port. If the calling - process was linked to the previously open port identified by - <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to this exception. + port, or the registered name of an open port. If the + calling process was previously linked to the closed port, + identified by <c><anno>Port</anno></c>, the exit signal + from the port is guaranteed to be delivered before this + <c>badarg</c> exception occurs. </item> <tag><c>badarg</c></tag> <item> - If <c><anno>Data</anno></c> is not a valid io list. + If <c><anno>Data</anno></c> is an invalid I/O list. </item> </taglist> </desc> </func> + <func> <name name="port_command" arity="3"/> - <fsummary>Send data to a port</fsummary> + <fsummary>Sends data to a port.</fsummary> <desc> <p>Sends data to a port. <c>port_command(Port, Data, [])</c> equals <c>port_command(Port, Data)</c>.</p> - <p>If the port command is aborted <c>false</c> is returned; - otherwise, <c>true</c> is returned.</p> - <p>If the port is busy, the calling process will be suspended - until the port is not busy anymore.</p> - <p>Currently the following <c><anno>Option</anno></c>s are valid:</p> + <p>If the port command is aborted, <c>false</c> is returned, + otherwise <c>true</c>.</p> + <p>If the port is busy, the calling process is suspended + until the port is not busy any more.</p> + <p>The following <c><anno>Option</anno></c>s are valid:</p> <taglist> <tag><c>force</c></tag> - <item>The calling process will not be suspended if the port is - busy; instead, the port command is forced through. The - call will fail with a <c>notsup</c> exception if the + <item>The calling process is not suspended if the port is + busy, instead the port command is forced through. The + call fails with a <c>notsup</c> exception if the driver of the port does not support this. For more - information see the - <seealso marker="driver_entry#driver_flags"><![CDATA[ERL_DRV_FLAG_SOFT_BUSY]]></seealso> - driver flag. + information, see driver flag + <seealso marker="driver_entry#driver_flags"><![CDATA[ERL_DRV_FLAG_SOFT_BUSY]]></seealso>. </item> <tag><c>nosuspend</c></tag> - <item>The calling process will not be suspended if the port is - busy; instead, the port command is aborted and + <item>The calling process is not suspended if the port is + busy, instead the port command is aborted and <c>false</c> is returned. </item> </taglist> <note> - <p>More options may be added in the future.</p> + <p>More options can be added in a future release.</p> </note> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> <item> If <c><anno>Port</anno></c> is not an identifier of an open - port, or the registered name of an open port. If the calling - process was linked to the previously open port identified by - <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to this exception. + port, or the registered name of an open port. If the + calling process was previously linked to the closed port, + identified by <c><anno>Port</anno></c>, the exit signal + from the port is guaranteed to be delivered before this + <c>badarg</c> exception occurs. </item> <tag><c>badarg</c></tag> <item> - If <c><anno>Data</anno></c> is not a valid io list. + If <c><anno>Data</anno></c> is an invalid I/O list. </item> <tag><c>badarg</c></tag> <item> - If <c><anno>OptionList</anno></c> is not a valid option list. + If <c><anno>OptionList</anno></c> is an invalid option list. </item> <tag><c>notsup</c></tag> <item> - If the <c>force</c> option has been passed, but the + If option <c>force</c> has been passed, but the driver of the port does not allow forcing through a busy port. </item> </taglist> </desc> </func> + <func> <name name="port_connect" arity="2"/> - <fsummary>Set the owner of a port</fsummary> + <fsummary>Sets the owner of a port.</fsummary> <desc> <p>Sets the port owner (the connected port) to <c><anno>Pid</anno></c>. - Roughly the same as <c><anno>Port</anno> ! {Owner, {connect, <anno>Pid</anno>}}</c> + Roughly the same as + <c><anno>Port</anno> ! {Owner, {connect, <anno>Pid</anno>}}</c> except for the following:</p> <list type="bulleted"> <item> - <p>The error behavior differs, see below.</p> + <p>The error behavior differs, see the following.</p> </item> <item> <p>The port does <em>not</em> reply with <c>{Port,connected}</c>.</p> </item> <item> - <p><c>port_connect/1</c> is synchronous, see below.</p> + <p><c>port_connect/1</c> is synchronous, see the following.</p> </item> <item> <p>The new port owner gets linked to the port.</p> </item> </list> - <p>The old port owner stays linked to the port and have to call - <c>unlink(Port)</c> if this is not desired. Any process may + <p>The old port owner stays linked to the port and must call + <c>unlink(Port)</c> if this is not desired. Any process can set the port owner to be any process with <c>port_connect/2</c>.</p> - <p>For comparison: <c><anno>Port</anno> ! {self(), {connect, <anno>Pid</anno>}}</c> fails - with <c>badarg</c> if <c><anno>Port</anno></c> cannot be sent to (i.e., - <c><anno>Port</anno></c> refers neither to a port nor to a process). If - <c><anno>Port</anno></c> is a closed port nothing happens. If <c><anno>Port</anno></c> + <p>For comparison: + <c><anno>Port</anno> ! {self(), {connect, <anno>Pid</anno>}}</c> + only fails with <c>badarg</c> if <c><anno>Port</anno></c> + does not refer to a port or a process. If + <c><anno>Port</anno></c> is a closed port, nothing happens. + If <c><anno>Port</anno></c> is an open port and the calling process is the port owner, the port replies with <c>{Port, connected}</c> to the old - port owner. Note that the old port owner is still linked to - the port, and that the new is not. If <c><anno>Port</anno></c> is an open + port owner. Notice that the old port owner is still linked to + the port, while the new is not. If <c><anno>Port</anno></c> is an open port and the calling process is not the port owner, the <em>port owner</em> fails with <c>badsig</c>. The port owner fails with <c>badsig</c> also if <c><anno>Pid</anno></c> is not an - existing local pid.</p> - <p>Note that any process can set the port owner using - <c><anno>Port</anno> ! {PortOwner, {connect, <anno>Pid</anno>}}</c> just as if it - itself was the port owner, but the reply always goes to + existing local process identifier.</p> + <p>Notice that any process can set the port owner using + <c><anno>Port</anno> ! {PortOwner, {connect, <anno>Pid</anno>}}</c> + as if it itself was the port owner, but the reply always goes to the port owner.</p> - <p>As of OTP-R16 <c><anno>Port</anno> ! {PortOwner, {connect, <anno>Pid</anno>}}</c> is - truly asynchronous. Note that this operation has always been + <p>As from OTP-R16, + <c><anno>Port</anno> ! {PortOwner, {connect, <anno>Pid</anno>}}</c> is + truly asynchronous. Notice that this operation has always been documented as an asynchronous operation, while the underlying implementation has been synchronous. <c>port_connect/2</c> is - however still fully synchronous. This due to its error + however still fully synchronous. This because of its error behavior.</p> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> <item> - If <c><anno>Port</anno></c> is not an identifier of an open - port, or the registered name of an open port. If the calling - process was linked to the previously open port identified by - <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to this exception. + If <c><anno>Port</anno></c> is not an identifier of an open port, or + the registered name of an open port. If the calling + process was previously linked to the closed port, + identified by <c><anno>Port</anno></c>, the exit signal + from the port is guaranteed to be delivered before this + <c>badarg</c> exception occurs. </item> <tag><c>badarg</c></tag> <item>If process identified by <c>Pid</c> is not an existing @@ -3669,53 +3851,75 @@ os_prompt% </pre> </taglist> </desc> </func> + <func> <name name="port_control" arity="3"/> - <fsummary>Perform a synchronous control operation on a port</fsummary> + <fsummary>Performs a synchronous control operation on a port.</fsummary> <desc> <p>Performs a synchronous control operation on a port. - The meaning of <c><anno>Operation</anno></c> and <c><anno>Data</anno></c> depends on - the port, i.e., on the port driver. Not all port drivers + The meaning of <c><anno>Operation</anno></c> and + <c><anno>Data</anno></c> depends on + the port, that is, on the port driver. Not all port drivers support this control feature.</p> - <p>Returns: a list of integers in the range 0 through 255, or a + <p>Returns a list of integers in the range 0..255, or a binary, depending on the port driver. The meaning of the returned data also depends on the port driver.</p> - <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not an open port or - the registered name of an open port, if <c><anno>Operation</anno></c> - cannot fit in a 32-bit integer, if the port driver does not - support synchronous control operations, or if the port driver - so decides for any reason (probably something wrong with - <c><anno>Operation</anno></c> or <c><anno>Data</anno></c>).</p> + <p>Failures:</p> + <taglist> + <tag><c>badarg</c></tag> + <item> + If <c><anno>Port</anno></c> is not an open port or the registered + name of an open port. + </item> + <tag><c>badarg</c></tag> + <item> + If <c><anno>Operation</anno></c> cannot fit in a 32-bit integer. + </item> + <tag><c>badarg</c></tag> + <item> + If the port driver does not support synchronous control + operations. + </item> + <tag><c>badarg</c></tag> + <item> + If the port driver so decides for any reason (probably + something wrong with <c><anno>Operation</anno></c> or + <c><anno>Data</anno></c>). + </item> + </taglist> </desc> </func> + <func> <name name="port_call" arity="3"/> - <fsummary>Synchronous call to a port with term data</fsummary> + <fsummary>Performs a synchronous call to a port with term data.</fsummary> <desc> <p>Performs a synchronous call to a port. The meaning of - <c><anno>Operation</anno></c> and <c><anno>Data</anno></c> depends on the port, i.e., + <c><anno>Operation</anno></c> and <c><anno>Data</anno></c> + depends on the port, that is, on the port driver. Not all port drivers support this feature.</p> - <p><c><anno>Port</anno></c> is a port identifier, referring to a driver.</p> + <p><c><anno>Port</anno></c> is a port identifier, + referring to a driver.</p> <p><c><anno>Operation</anno></c> is an integer, which is passed on to the driver.</p> - <p><c><anno>Data</anno></c> is any Erlang term. This data is converted to - binary term format and sent to the port.</p> - <p>Returns: a term from the driver. The meaning of the returned + <p><c><anno>Data</anno></c> is any Erlang term. This data is converted + to binary term format and sent to the port.</p> + <p>Returns a term from the driver. The meaning of the returned data also depends on the port driver.</p> <p>Failures:</p> <taglist> <tag><c>badarg</c></tag> <item> - If <c><anno>Port</anno></c> is not an identifier of an open - port, or the registered name of an open port. If the calling - process was linked to the previously open port identified by - <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to this exception. + If <c><anno>Port</anno></c> is not an identifier of an open port, + or the registered name of an open port. If the calling + process was previously linked to the closed port, + identified by <c><anno>Port</anno></c>, the exit signal + from the port is guaranteed to be delivered before this + <c>badarg</c> exception occurs. </item> <tag><c>badarg</c></tag> <item> - If <c><anno>Operation</anno></c> does not fit in a - 32-bit integer. + If <c><anno>Operation</anno></c> does not fit in a 32-bit integer. </item> <tag><c>badarg</c></tag> <item> @@ -3725,171 +3929,183 @@ os_prompt% </pre> <tag><c>badarg</c></tag> <item> If the port driver so decides for any reason (probably - something wrong with <c><anno>Operation</anno></c>, or - <c><anno>Data</anno></c>). + something wrong with <c><anno>Operation</anno></c> + or <c><anno>Data</anno></c>). </item> </taglist> </desc> </func> + <func> <name name="port_info" arity="1"/> - <fsummary>Information about a port</fsummary> + <fsummary>Information about a port.</fsummary> <desc> <p>Returns a list containing tuples with information about - the <c><anno>Port</anno></c>, or <c>undefined</c> if the port is not open. - The order of the tuples is not defined, nor are all the - tuples mandatory. - If <c>undefined</c> is returned and the calling process - was linked to a previously open port identified by - <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/1</c>.</p> - <p>Currently the result will containt information about the - following <c>Item</c>s: <c>registered_name</c> (if the port has - a registered name), <c>id</c>, <c>connected</c>, <c>links</c>, - <c>name</c>, <c>input</c>, and <c>output</c>. For more information - about the different <c>Item</c>s, see + <c><anno>Port</anno></c>, or <c>undefined</c> if the port is not open. + The order of the tuples is undefined, and all the + tuples are not mandatory. + If the port is closed and the calling process + was previously linked to the port, the exit signal from the + port is guaranteed to be delivered before <c>port_info/1</c> + returns <c>undefined</c>.</p> + <p>The result contains information about the following + <c>Item</c>s:</p> + <list type="bulleted"> + <item><c>registered_name</c> (if the port has a registered + name)</item> + <item><c>id</c></item> + <item><c>connected</c></item> + <item><c>links</c></item> + <item><c>name</c></item> + <item><c>input</c></item> + <item><c>output</c></item> + </list> + <p>For more information about the different <c>Item</c>s, see <seealso marker="#port_info/2">port_info/2</seealso>.</p> <p>Failure: <c>badarg</c> if <c>Port</c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="1"/> - <fsummary>Information about the connected process of a port</fsummary> + <fsummary>Information about the connected process of a port.</fsummary> <desc> <p><c><anno>Pid</anno></c> is the process identifier of the process connected to the port.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="2"/> - <fsummary>Information about the internal index of a port</fsummary> + <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 - index may be used to separate ports.</p> + index can be used to separate ports.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="3"/> - <fsummary>Information about the input of a port</fsummary> + <fsummary>Information about the input of a port.</fsummary> <desc> <p><c><anno>Bytes</anno></c> is the total number of bytes read from the port.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="4"/> - <fsummary>Information about the links of a port</fsummary> + <fsummary>Information about the links of a port.</fsummary> <desc> <p><c><anno>Pids</anno></c> is a list of the process identifiers of the processes that the port is linked to.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="5"/> - <fsummary>Information about the locking of a port</fsummary> + <fsummary>Information about the locking of a port.</fsummary> <desc> - <p><c><anno>Locking</anno></c> is currently either <c>false</c> - (emulator without SMP support), <c>port_level</c> (port specific - locking), or <c>driver_level</c> (driver specific locking). Note - that these results are highly implementation specific and might - change in the future.</p> + <p><c><anno>Locking</anno></c> is one of the following:</p> + <list type="bulleted"> + <item><c>false</c> (emulator without SMP support)</item> + <item><c>port_level</c> (port-specific locking)</item> + <item><c>driver_level</c> (driver-specific locking)</item> + </list> + <p>Notice that these results are highly implementation-specific + and can change in a future release.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="6"/> - <fsummary>Information about the memory size of a port</fsummary> + <fsummary>Information about the memory size of a port.</fsummary> <desc> - <p><c><anno>Bytes</anno></c> is the total amount of memory, - in bytes, allocated for this port by the runtime system. Note - that the port itself might have allocated memory which is not + <p><c><anno>Bytes</anno></c> is the total number of + bytes allocated for this port by the runtime system. The + port itself can have allocated memory that is not included in <c><anno>Bytes</anno></c>.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="7"/> - <fsummary>Information about the monitors of a port</fsummary> + <fsummary>Information about the monitors of a port.</fsummary> <desc> <p><c><anno>Monitors</anno></c> represent processes that this port - is monitoring.</p> + monitors.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="8"/> - <fsummary>Information about the name of a port</fsummary> + <fsummary>Information about the name of a port.</fsummary> <desc> <p><c><anno>Name</anno></c> is the command name set by <seealso marker="#open_port/2">open_port/2</seealso>.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="9"/> - <fsummary>Information about the OS pid of a port</fsummary> + <fsummary>Information about the OS pid of a port.</fsummary> <desc> <p><c><anno>OsPid</anno></c> is the process identifier (or equivalent) of an OS process created with @@ -3897,432 +4113,464 @@ os_prompt% </pre> Command}, Options)</seealso>. If the port is not the result of spawning an OS process, the value is <c>undefined</c>.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="10"/> - <fsummary>Information about the output of a port</fsummary> + <fsummary>Information about the output of a port.</fsummary> <desc> <p><c><anno>Bytes</anno></c> is the total number of bytes written - to the port from Erlang processes using either + to the port from Erlang processes using <seealso marker="#port_command/2">port_command/2</seealso>, <seealso marker="#port_command/3">port_command/3</seealso>, - or <c><anno>Port</anno> ! {Owner, {command, Data}</c>. - </p> + or <c><anno>Port</anno> ! {Owner, {command, Data}</c>.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="11"/> - <fsummary>Information about the parallelism hint of a port</fsummary> + <fsummary>Information about the parallelism hint of a port.</fsummary> <desc> <p><c><anno>Boolean</anno></c> corresponds to the port parallelism - hint being used by this port. For more information see - the <seealso marker="#open_port_parallelism">parallelism</seealso> - option of <seealso marker="#open_port/2">open_port/2</seealso>.</p> + hint being used by this port. For more information, see option + <seealso marker="#open_port_parallelism">parallelism</seealso> + of <seealso marker="#open_port/2">open_port/2</seealso>.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="12"/> - <fsummary>Information about the queue size of a port</fsummary> + <fsummary>Information about the queue size of a port.</fsummary> <desc> - <p><c><anno>Bytes</anno></c> is the total amount of data, - in bytes, queued by the port using the ERTS driver queue + <p><c><anno>Bytes</anno></c> is the total number + of bytes queued by the port using the <c>ERTS</c> driver queue implementation.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_info" arity="2" clause_i="13"/> - <fsummary>Information about the registered name of a port</fsummary> + <fsummary>Information about the registered name of a port.</fsummary> <desc> <p><c><anno>RegisteredName</anno></c> is the registered name of the port. If the port has no registered name, <c>[]</c> is returned.</p> <p>If the port identified by <c><anno>Port</anno></c> is not open, - <c>undefined</c> is returned. If <c>undefined</c> is returned and - the calling process was linked to a previously open port identified - by <c><anno>Port</anno></c>, an exit signal due to this link - was received by the process prior to the return from - <c>port_info/2</c>.</p> + <c>undefined</c> is returned. If the port is closed and the + calling process was previously linked to the port, the exit + signal from the port is guaranteed to be delivered before + <c>port_info/2</c> returns <c>undefined</c>.</p> <p>Failure: <c>badarg</c> if <c><anno>Port</anno></c> is not a local port identifier, or an atom.</p> </desc> </func> + <func> <name name="port_to_list" arity="1"/> - <fsummary>Text representation of a port identifier</fsummary> + <fsummary>Text representation of a port identifier.</fsummary> <desc> - <p>Returns a string which corresponds to the text + <p>Returns a string corresponding to the text representation of the port identifier <c><anno>Port</anno></c>.</p> <warning> - <p>This BIF is intended for debugging and for use in - the Erlang operating system. It should not be used in - application programs.</p> + <p>This BIF is intended for debugging. It is not to be used + in application programs.</p> </warning> </desc> </func> + <func> <name name="ports" arity="0"/> - <fsummary>All open ports</fsummary> + <fsummary>Lists all existing ports.</fsummary> <desc> <p>Returns a list of port identifiers corresponding to all the - ports currently existing on the local node.</p> - - <p>Note that a port that is exiting, exists but is not open.</p> + ports existing on the local node.</p> + <p>Notice that an exiting port exists, but is not open.</p> </desc> </func> + <func> <name name="pre_loaded" arity="0"/> - <fsummary>List of all pre-loaded modules</fsummary> + <fsummary>Lists all pre-loaded modules.</fsummary> <desc> - <p>Returns a list of Erlang modules which are pre-loaded in + <p>Returns a list of Erlang modules that are preloaded in the system. As all loading of code is done through the file system, the file system must have been loaded previously. - Hence, at least the module <c>init</c> must be pre-loaded.</p> + Hence, at least the module <c>init</c> must be preloaded.</p> </desc> </func> + <func> <name name="process_display" arity="2"/> - <fsummary>Write information about a local process on standard error</fsummary> + <fsummary>Writes information about a local process on standard error.</fsummary> <desc> <p>Writes information about the local process <c><anno>Pid</anno></c> on - standard error. The currently allowed value for the atom + standard error. The only allowed value for the atom <c><anno>Type</anno></c> is <c>backtrace</c>, which shows the contents of the call stack, including information about the call chain, with the current function printed first. The format of the output is not further defined.</p> </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="1"/> - <fsummary>Set process flag trap_exit for the calling process</fsummary> + <fsummary>Sets process flag <c>trap_exit</c> for the calling process.</fsummary> <desc> <p>When <c>trap_exit</c> is set to <c>true</c>, exit signals - arriving to a process are converted to <c>{'EXIT', From, Reason}</c> messages, which can be received as ordinary + arriving to a process are converted to <c>{'EXIT', From, Reason}</c> + messages, which can be received as ordinary messages. If <c>trap_exit</c> is set to <c>false</c>, the process exits if it receives an exit signal other than <c>normal</c> and the exit signal is propagated to its - linked processes. Application processes should normally - not trap exits.</p> + linked processes. Application processes are normally + not to trap exits.</p> <p>Returns the old value of the flag.</p> <p>See also <seealso marker="#exit/2">exit/2</seealso>.</p> </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="2"/> - <fsummary>Set process flag error_handler for the calling process</fsummary> + <fsummary>Sets process flag <c>error_handler</c> for the calling process.</fsummary> <desc> - <p>This is used by a process to redefine the error handler + <p>Used by a process to redefine the error handler for undefined function calls and undefined registered - processes. Inexperienced users should not use this flag - since code auto-loading is dependent on the correct + processes. Inexperienced users are not to use this flag, + as code auto-loading depends on the correct operation of the error handling module.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="3"/> - <fsummary>Set process flag min_heap_size for the calling process</fsummary> + <fsummary>Sets process flag <c>min_heap_size</c> for the calling process.</fsummary> <desc> - <p>This changes the minimum heap size for the calling - process.</p> + <p>Changes the minimum heap size for the calling process.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="4"/> - <fsummary>Set process flag min_bin_vheap_size for the calling process</fsummary> + <fsummary>Sets process flag <c>min_bin_vheap_size</c> for the calling process.</fsummary> <desc> - <p>This changes the minimum binary virtual heap size for the calling + <p>Changes the minimum binary virtual heap size for the calling process.</p> - <p>Returns the old value of the flag.</p> </desc> + <p>Returns the old value of the flag.</p> + </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="5"/> + <fsummary>Sets process flag <c>priority</c> for the calling process.</fsummary> <type name="priority_level"/> - <fsummary>Set process flag priority for the calling process</fsummary> <desc> <p><marker id="process_flag_priority"></marker> - This sets the process priority. <c><anno>Level</anno></c> is an atom. - There are currently four priority levels: <c>low</c>, - <c>normal</c>, <c>high</c>, and <c>max</c>. The default - priority level is <c>normal</c>. <em>NOTE</em>: The - <c>max</c> priority level is reserved for internal use in - the Erlang runtime system, and should <em>not</em> be used - by others. - </p> - <p>Internally in each priority level processes are scheduled - in a round robin fashion. - </p> + Sets the process priority. <c><anno>Level</anno></c> is an atom. + There are four priority levels: <c>low</c>, + <c>normal</c>, <c>high</c>, and <c>max</c>. Default + is <c>normal</c>.</p> + <note> + <p>Priority level <c>max</c> is reserved for internal use in + the Erlang runtime system, and is <em>not</em> to be used + by others.</p> + </note> + <p>Internally in each priority level, processes are scheduled + in a round robin fashion.</p> <p>Execution of processes on priority <c>normal</c> and - priority <c>low</c> will be interleaved. Processes on - priority <c>low</c> will be selected for execution less - frequently than processes on priority <c>normal</c>. - </p> - <p>When there are runnable processes on priority <c>high</c> - no processes on priority <c>low</c>, or <c>normal</c> will - be selected for execution. Note, however, that this does - <em>not</em> mean that no processes on priority <c>low</c>, - or <c>normal</c> will be able to run when there are - processes on priority <c>high</c> running. On the runtime - system with SMP support there might be more processes running - in parallel than processes on priority <c>high</c>, i.e., - a <c>low</c>, and a <c>high</c> priority process might - execute at the same time. - </p> - <p>When there are runnable processes on priority <c>max</c> + <c>low</c> are interleaved. Processes on priority + <c>low</c> are selected for execution less + frequently than processes on priority <c>normal</c>.</p> + <p>When there are runnable processes on priority <c>high</c>, + no processes on priority <c>low</c> or <c>normal</c> are + selected for execution. Notice however, that this does + <em>not</em> mean that no processes on priority <c>low</c> + or <c>normal</c> can run when there are processes + running on priority <c>high</c>. On the runtime + system with SMP support, more processes can be running + in parallel than processes on priority <c>high</c>, that is, + a <c>low</c> and a <c>high</c> priority process can + execute at the same time.</p> + <p>When there are runnable processes on priority <c>max</c>, no processes on priority <c>low</c>, <c>normal</c>, or - <c>high</c> will be selected for execution. As with the - <c>high</c> priority, processes on lower priorities might - execute in parallel with processes on priority <c>max</c>. - </p> + <c>high</c> are selected for execution. As with priority + <c>high</c>, processes on lower priorities can + execute in parallel with processes on priority <c>max</c>.</p> <p>Scheduling is preemptive. Regardless of priority, a process - is preempted when it has consumed more than a certain amount + is preempted when it has consumed more than a certain number of reductions since the last time it was selected for - execution. - </p> - <p><em>NOTE</em>: You should not depend on the scheduling + execution.</p> + <note> + <p>Do not depend on the scheduling to remain exactly as it is today. Scheduling, at least on - the runtime system with SMP support, is very likely to be - modified in the future in order to better utilize available - processor cores. - </p> - <p>There is currently <em>no</em> automatic mechanism for - avoiding priority inversion, such as priority inheritance, - or priority ceilings. When using priorities you have - to take this into account and handle such scenarios by - yourself. - </p> + the runtime system with SMP support, is likely to be + changed in a future release to use available + processor cores better.</p> + </note> + <p>There is <em>no</em> automatic mechanism for + avoiding priority inversion, such as priority inheritance + or priority ceilings. When using priorities, + take this into account and handle such scenarios by + yourself.</p> <p>Making calls from a <c>high</c> priority process into code - that you don't have control over may cause the <c>high</c> - priority process to wait for a processes with lower - priority, i.e., effectively decreasing the priority of the + that you have no control over can cause the <c>high</c> + priority process to wait for a process with lower + priority. That is, effectively decreasing the priority of the <c>high</c> priority process during the call. Even if this - isn't the case with one version of the code that you don't - have under your control, it might be the case in a future - version of it. This might, for example, happen if a - <c>high</c> priority process triggers code loading, since - the code server runs on priority <c>normal</c>. - </p> + is not the case with one version of the code that you have no + control over, it can be the case in a future + version of it. This can, for example, occur if a + <c>high</c> priority process triggers code loading, as + the code server runs on priority <c>normal</c>.</p> <p>Other priorities than <c>normal</c> are normally not needed. - When other priorities are used, they need to be used - with care, especially the <c>high</c> priority <em>must</em> - be used with care. A process on <c>high</c> priority should - only perform work for short periods of time. Busy looping for - long periods of time in a <c>high</c> priority process will - most likely cause problems, since there are important servers - in OTP running on priority <c>normal</c>. - </p> + When other priorities are used, use them with care, + <em>especially</em> priority <c>high</c>. A + process on priority <c>high</c> is only + to perform work for short periods. Busy looping for + long periods in a <c>high</c> priority process does + most likely cause problems, as important OTP servers + run on priority <c>normal</c>.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="6"/> - <fsummary>Set process flag save_calls for the calling process</fsummary> + <fsummary>Sets process flag <c>save_calls</c> for the calling process.</fsummary> <desc> <p><c><anno>N</anno></c> must be an integer in the interval 0..10000. - If <c><anno>N</anno></c> > 0, call saving is made active for the - process, which means that information about the <c><anno>N</anno></c> - most recent global function calls, BIF calls, sends and + If <c><anno>N</anno></c> is greater than 0, call saving is made + active for the + process. This means that information about the <c><anno>N</anno></c> + most recent global function calls, BIF calls, sends, and receives made by the process are saved in a list, which can be retrieved with <c>process_info(Pid, last_calls)</c>. A global function call is one in which the module of the function is explicitly mentioned. Only a fixed amount of information - is saved: a tuple <c>{Module, Function, Arity}</c> for - function calls, and the mere atoms <c>send</c>, - <c>'receive'</c> and <c>timeout</c> for sends and receives - (<c>'receive'</c> when a message is received and - <c>timeout</c> when a receive times out). If <c>N</c> = 0, + is saved, as follows:</p> + <list type="bulleted"> + <item>A tuple <c>{Module, Function, Arity}</c> for + function calls</item> + <item> The atoms <c>send</c>, <c>'receive'</c>, and + <c>timeout</c> for sends and receives (<c>'receive'</c> + when a message is received and <c>timeout</c> when a + receive times out)</item> + </list> + <p>If <c>N</c> = 0, call saving is disabled for the process, which is the default. Whenever the size of the call saving list is set, its contents are reset.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="process_flag" arity="2" clause_i="7"/> - <fsummary>Set process flag sensitive for the calling process</fsummary> + <fsummary>Sets process flag <c>sensitive</c> for the calling process.</fsummary> <desc> - <p>Set or clear the <c>sensitive</c> flag for the current process. + <p>Sets or clears flag <c>sensitive</c> for the current process. When a process has been marked as sensitive by calling - <c>process_flag(sensitive, true)</c>, features in the run-time - system that can be used for examining the data and/or inner working + <c>process_flag(sensitive, true)</c>, features in the runtime + system that can be used for examining the data or inner working of the process are silently disabled.</p> <p>Features that are disabled include (but are not limited to) the following:</p> - <p>Tracing: Trace flags can still be set for the process, but no - trace messages of any kind will be generated. - (If the <c>sensitive</c> flag is turned off, trace messages will - again be generated if there are any trace flags set.)</p> - <p>Sequential tracing: The sequential trace token will be propagated - as usual, but no sequential trace messages will be generated.</p> - <p><c>process_info/1,2</c> cannot be used to read out the message - queue or the process dictionary (both will be returned as empty lists).</p> + <list type="bulleted"> + <item>Tracing: Trace flags can still be set for the process, + but no trace messages of any kind are generated. (If flag + <c>sensitive</c> is turned off, trace messages are again + generated if any trace flags are set.)</item> + <item>Sequential tracing: The sequential trace token is + propagated as usual, but no sequential trace messages are + generated.</item> + </list> + <p><c>process_info/1,2</c> cannot be used to read out the + message queue or the process dictionary (both are returned + as empty lists).</p> <p>Stack back-traces cannot be displayed for the process.</p> <p>In crash dumps, the stack, messages, and the process dictionary - will be omitted.</p> + are omitted.</p> <p>If <c>{save_calls,N}</c> has been set for the process, no - function calls will be saved to the call saving list. - (The call saving list will not be cleared; furthermore, send, receive, - and timeout events will still be added to the list.)</p> + function calls are saved to the call saving list. + (The call saving list is not cleared. Furthermore, send, receive, + and timeout events are still added to the list.)</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="process_flag" arity="3"/> - <fsummary>Set process flags for a process</fsummary> + <fsummary>Sets process flags for a process.</fsummary> <desc> - <p>Sets certain flags for the process <c><anno>Pid</anno></c>, in the same - manner as + <p>Sets certain flags for the process <c><anno>Pid</anno></c>, + in the same manner as <seealso marker="#process_flag/2">process_flag/2</seealso>. - Returns the old value of the flag. The allowed values for + Returns the old value of the flag. The valid values for <c><anno>Flag</anno></c> are only a subset of those allowed in - <c>process_flag/2</c>, namely: <c>save_calls</c>.</p> - <p>Failure: <c>badarg</c> if <c><anno>Pid</anno></c> is not a local process.</p> + <c>process_flag/2</c>, namely <c>save_calls</c>.</p> + <p>Failure: <c>badarg</c> if <c><anno>Pid</anno></c> + is not a local process.</p> </desc> </func> + <func> <name name="process_info" arity="1"/> + <fsummary>Information about a process.</fsummary> <type name="process_info_result_item"/> <type name="priority_level"/> <type name="stack_item"/> - <fsummary>Information about a process</fsummary> <desc> <p>Returns a list containing <c><anno>InfoTuple</anno></c>s with miscellaneous information about the process identified by - <c>Pid</c>, or <c>undefined</c> if the process is not alive. - </p> - <p> - The order of the <c><anno>InfoTuple</anno></c>s is not defined, nor - are all the <c><anno>InfoTuple</anno></c>s mandatory. The <c><anno>InfoTuple</anno></c>s - part of the result may be changed without prior notice. - Currently <c><anno>InfoTuple</anno></c>s with the following items - are part of the result: - <c>current_function</c>, <c>initial_call</c>, <c>status</c>, - <c>message_queue_len</c>, <c>messages</c>, <c>links</c>, - <c>dictionary</c>, <c>trap_exit</c>, <c>error_handler</c>, - <c>priority</c>, <c>group_leader</c>, <c>total_heap_size</c>, - <c>heap_size</c>, <c>stack_size</c>, <c>reductions</c>, and - <c>garbage_collection</c>. - If the process identified by <c><anno>Pid</anno></c> has a registered name - also an <c><anno>InfoTuple</anno></c> with the item <c>registered_name</c> - will appear. - </p> - <p>See <seealso marker="#process_info/2">process_info/2</seealso> - for information about specific <c><anno>InfoTuple</anno></c>s.</p> + <c>Pid</c>, or <c>undefined</c> if the process is not alive.</p> + <p>The order of the <c><anno>InfoTuple</anno></c>s is undefined and + all <c><anno>InfoTuple</anno></c>s are not mandatory. + The <c><anno>InfoTuple</anno></c>s + part of the result can be changed without prior notice.</p> + <p>The <c><anno>InfoTuple</anno></c>s with the following items + are part of the result:</p> + <list type="bulleted"> + <item><c>current_function</c></item> + <item><c>initial_call</c></item> + <item><c>status</c></item> + <item><c>message_queue_len</c></item> + <item><c>messages</c></item> + <item><c>links</c></item> + <item><c>dictionary</c></item> + <item><c>trap_exit</c></item> + <item><c>error_handler</c></item> + <item><c>priority</c></item> + <item><c>group_leader</c></item> + <item><c>total_heap_size</c></item> + <item><c>heap_size</c></item> + <item><c>stack_size</c></item> + <item><c>reductions</c></item> + <item><c>garbage_collection</c></item> + </list> + <p>If the process identified by <c><anno>Pid</anno></c> has a + registered name, + also an <c><anno>InfoTuple</anno></c> with item <c>registered_name</c> + appears.</p> + <p>For information about specific <c><anno>InfoTuple</anno></c>s, see + <seealso marker="#process_info/2">process_info/2</seealso>.</p> <warning> - <p>This BIF is intended for <em>debugging only</em>, use - <seealso marker="#process_info/2">process_info/2</seealso> - for all other purposes. - </p> + <p>This BIF is intended for <em>debugging only</em>. For + all other purposes, use + <seealso marker="#process_info/2">process_info/2</seealso>.</p> </warning> - <p>Failure: <c>badarg</c> if <c>Pid</c> is not a local process.</p> + <p>Failure: <c>badarg</c> if <c><anno>Pid</anno></c> is not a + local process.</p> </desc> </func> + <func> <name name="process_info" arity="2" clause_i="1"/> <name name="process_info" arity="2" clause_i="2"/> + <fsummary>Information about a process.</fsummary> <type name="process_info_item"/> <type name="process_info_result_item"/> <type name="stack_item"/> <type name="priority_level"/> - <fsummary>Information about a process</fsummary> <desc> - <p>Returns information about the process identified by <c><anno>Pid</anno></c> - as specified by the <c><anno>Item</anno></c> or the <c><anno>ItemList</anno></c>, or <c>undefined</c> if the - process is not alive. - </p> - <p>If the process is alive and a single <c><anno>Item</anno></c> is given, - the returned value is the corresponding - <c><anno>InfoTuple</anno></c> unless <c>Item =:= registered_name</c> - and the process has no registered name. In this case - <c>[]</c> is returned. This strange behavior is due to - historical reasons, and is kept for backward compatibility. - </p> - <p>If an <c>ItemList</c> is given, the result is an - <c><anno>InfoTupleList</anno></c>. The <c><anno>InfoTuple</anno></c>s in the - <c><anno>InfoTupleList</anno></c> will appear with the corresponding - <c><anno>Item</anno></c>s in the same order as the <c><anno>Item</anno></c>s appeared - in the <c><anno>ItemList</anno></c>. Valid <c><anno>Item</anno></c>s may appear multiple - times in the <c><anno>ItemList</anno></c>. - </p> - <note><p>If <c>registered_name</c> is part of an <c><anno>ItemList</anno></c> + <p>Returns information about the process identified by + <c><anno>Pid</anno></c>, as specified by + <c><anno>Item</anno></c> or <c><anno>ItemList</anno></c>. + Returns <c>undefined</c> if the process is not alive.</p> + <p>If the process is alive and a single <c><anno>Item</anno></c> + is given, the returned value is the corresponding + <c><anno>InfoTuple</anno></c>, unless <c>Item =:= registered_name</c> + and the process has no registered name. In this case, + <c>[]</c> is returned. This strange behavior is because of + historical reasons, and is kept for backward compatibility.</p> + <p>If <c><anno>ItemList</anno></c> is given, the result is + <c><anno>InfoTupleList</anno></c>. + The <c><anno>InfoTuple</anno></c>s in + <c><anno>InfoTupleList</anno></c> appear with the corresponding + <c><anno>Item</anno></c>s in the same order as the + <c><anno>Item</anno></c>s appeared + in <c><anno>ItemList</anno></c>. Valid <c><anno>Item</anno></c>s can + appear multiple times in <c><anno>ItemList</anno></c>.</p> + <note><p>If <c>registered_name</c> is part of <c><anno>ItemList</anno></c> and the process has no name registered a - <c>{registered_name, []}</c> <c><anno>InfoTuple</anno></c> <em>will</em> - appear in the resulting <c><anno>InfoTupleList</anno></c>. This - behavior is different than when a single - <c>Item =:= registered_name</c> is given, and than when - <c>process_info/1</c> is used. - </p></note> - <p>Currently the following <c><anno>InfoTuple</anno></c>s with corresponding + <c>{registered_name, []}</c>, <c><anno>InfoTuple</anno></c> + <em>will</em> appear in the resulting + <c><anno>InfoTupleList</anno></c>. This + behavior is different when a single + <c>Item =:= registered_name</c> is given, and when + <c>process_info/1</c> is used.</p> + </note> + <p>The following <c><anno>InfoTuple</anno></c>s with corresponding <c><anno>Item</anno></c>s are valid:</p> <taglist> <tag><c>{backtrace, <anno>Bin</anno>}</c></tag> <item> - <p>The binary <c><anno>Bin</anno></c> contains the same information as - the output from + <p>Binary <c><anno>Bin</anno></c> contains the same information + as the output from <c>erlang:process_display(<anno>Pid</anno>, backtrace)</c>. Use <c>binary_to_list/1</c> to obtain the string of characters from the binary.</p> </item> <tag><c>{binary, <anno>BinInfo</anno>}</c></tag> <item> - <p><c><anno>BinInfo</anno></c> is a list containing miscellaneous information - about binaries currently being referred to by this process. - This <c><anno>InfoTuple</anno></c> may be changed or removed without prior - notice.</p> + <p><c><anno>BinInfo</anno></c> is a list containing miscellaneous + information about binaries currently being referred to by this + process. This <c><anno>InfoTuple</anno></c> can be changed or + removed without prior notice.</p> </item> <tag><c>{catchlevel, <anno>CatchLevel</anno>}</c></tag> <item> <p><c><anno>CatchLevel</anno></c> is the number of currently active - catches in this process. This <c><anno>InfoTuple</anno></c> may be + catches in this process. This <c><anno>InfoTuple</anno></c> can be changed or removed without prior notice.</p> </item> - <tag><c>{current_function, {<anno>Module</anno>, <anno>Function</anno>, <anno>Arity</anno>}}</c></tag> + <tag><c>{current_function, {<anno>Module</anno>, + <anno>Function</anno>, Arity}}</c></tag> <item> - <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, <c><anno>Arity</anno></c> is + <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, + <c><anno>Arity</anno></c> is the current function call of the process.</p> </item> - <tag><c>{current_location, {<anno>Module</anno>, <anno>Function</anno>, <anno>Arity</anno>, <anno>Location</anno>}}</c></tag> + <tag><c>{current_location, {<anno>Module</anno>, + <anno>Function</anno>, <anno>Arity</anno>, + <anno>Location</anno>}}</c></tag> <item> - <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, <c><anno>Arity</anno></c> is + <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, + <c><anno>Arity</anno></c> is the current function call of the process. - <c><anno>Location</anno></c> is a list of two-tuples that describes the - location in the source code. - </p> + <c><anno>Location</anno></c> is a list of two-tuples describing the + location in the source code.</p> </item> <tag><c>{current_stacktrace, <anno>Stack</anno>}</c></tag> <item> - <p>Return the current call stack back-trace (<em>stacktrace</em>) + <p>Returns the current call stack back-trace (<em>stacktrace</em>) of the process. The stack has the same format as returned by - <seealso marker="#get_stacktrace/0">erlang:get_stacktrace/0</seealso>. - </p> + <seealso marker="#get_stacktrace/0">erlang:get_stacktrace/0</seealso>.</p> </item> <tag><c>{dictionary, <anno>Dictionary</anno>}</c></tag> <item> - <p><c><anno>Dictionary</anno></c> is the dictionary of the process.</p> + <p><c><anno>Dictionary</anno></c> is the process dictionary.</p> </item> <tag><c>{error_handler, <anno>Module</anno>}</c></tag> <item> @@ -4331,34 +4579,36 @@ os_prompt% </pre> </item> <tag><c>{garbage_collection, <anno>GCInfo</anno>}</c></tag> <item> - <p><c><anno>GCInfo</anno></c> is a list which contains miscellaneous + <p><c><anno>GCInfo</anno></c> is a list containing miscellaneous information about garbage collection for this process. - The content of <c><anno>GCInfo</anno></c> may be changed without + The content of <c><anno>GCInfo</anno></c> can be changed without prior notice.</p> </item> <tag><c>{group_leader, <anno>GroupLeader</anno>}</c></tag> <item> - <p><c><anno>GroupLeader</anno></c> is group leader for the IO of + <p><c><anno>GroupLeader</anno></c> is group leader for the I/O of the process.</p> </item> <tag><c>{heap_size, <anno>Size</anno>}</c></tag> <item> - <p><c><anno>Size</anno></c> is the size in words of youngest heap generation - of the process. This generation currently include the stack - of the process. This information is highly implementation - dependent, and may change if the implementation change. - </p> + <p><c><anno>Size</anno></c> is the size in words of the youngest heap + generation of the process. This generation includes + the process stack. This information is highly + implementation-dependent, and can change if the + implementation changes.</p> </item> - <tag><c>{initial_call, {Module, Function, Arity}}</c></tag> + <tag><c>{initial_call, {<anno>Module</anno>, <anno>Function</anno>, + <anno>Arity</anno>}}</c></tag> <item> - <p><c>Module</c>, <c>Function</c>, <c>Arity</c> is + <p><c><anno>Module</anno></c>, <c><anno>Function</anno></c>, + <c><anno>Arity</anno></c> is the initial function call with which the process was spawned.</p> </item> <tag><c>{links, <anno>PidsAndPorts</anno>}</c></tag> <item> - <p><c><anno>PidsAndPorts</anno></c> is a list of pids and - port identifiers, with processes or ports to which the process + <p><c><anno>PidsAndPorts</anno></c> is a list of process identifiers + and port identifiers, with processes or ports to which the process has a link.</p> </item> <tag><c>{last_calls, false|Calls}</c></tag> @@ -4372,14 +4622,14 @@ os_prompt% </pre> <tag><c>{memory, <anno>Size</anno>}</c></tag> <item> <p><c><anno>Size</anno></c> is the size in bytes of the process. This - includes call stack, heap and internal structures.</p> + includes call stack, heap, and internal structures.</p> </item> <tag><c>{message_queue_len, <anno>MessageQueueLen</anno>}</c></tag> <item> <p><c><anno>MessageQueueLen</anno></c> is the number of messages currently in the message queue of the process. This is the length of the list <c><anno>MessageQueue</anno></c> returned as - the info item <c>messages</c> (see below).</p> + the information item <c>messages</c> (see the following).</p> </item> <tag><c>{messages, <anno>MessageQueue</anno>}</c></tag> <item> @@ -4388,31 +4638,35 @@ os_prompt% </pre> </item> <tag><c>{min_heap_size, <anno>MinHeapSize</anno>}</c></tag> <item> - <p><c><anno>MinHeapSize</anno></c> is the minimum heap size for the process.</p> + <p><c><anno>MinHeapSize</anno></c> is the minimum heap size + for the process.</p> </item> <tag><c>{min_bin_vheap_size, <anno>MinBinVHeapSize</anno>}</c></tag> <item> - <p><c><anno>MinBinVHeapSize</anno></c> is the minimum binary virtual heap size for the process.</p> + <p><c><anno>MinBinVHeapSize</anno></c> is the minimum binary virtual + heap size for the process.</p> </item> <tag><c>{monitored_by, <anno>Pids</anno>}</c></tag> <item> - <p>A list of pids that are monitoring the process (with + <p>A list of process identifiers monitoring the process (with <c>monitor/2</c>).</p> </item> <tag><c>{monitors, <anno>Monitors</anno>}</c></tag> <item> <p>A list of monitors (started by <c>monitor/2</c>) that are active for the process. For a local process - monitor or a remote process monitor by pid, the list item - is <c>{process, <anno>Pid</anno>}</c>, and for a remote process + monitor or a remote process monitor by a process + identifier, the list item is <c>{process, <anno>Pid</anno>}</c>. + For a remote process monitor by name, the list item is <c>{process, {<anno>RegName</anno>, <anno>Node</anno>}}</c>.</p> </item> - <tag><c>{priority, Level}</c></tag> + <tag><c>{priority, <anno>Level</anno>}</c></tag> <item> <p><c><anno>Level</anno></c> is the current priority level for - the process. For more information on priorities see - <seealso marker="#process_flag_priority">process_flag(priority, Level)</seealso>.</p> + the process. For more information on priorities, see + <seealso marker="#process_flag_priority">process_flag(priority, + Level)</seealso>.</p> </item> <tag><c>{reductions, <anno>Number</anno>}</c></tag> <item> @@ -4427,166 +4681,201 @@ os_prompt% </pre> </item> <tag><c>{sequential_trace_token, [] | <anno>SequentialTraceToken</anno>}</c></tag> <item> - <p><c><anno>SequentialTraceToken</anno></c> the sequential trace token for - the process. This <c><anno>InfoTuple</anno></c> may be changed or removed - without prior notice.</p> + <p><c><anno>SequentialTraceToken</anno></c> is the sequential trace + token for the process. This <c><anno>InfoTuple</anno></c> can be + changed or removed without prior notice.</p> </item> <tag><c>{stack_size, <anno>Size</anno>}</c></tag> <item> - <p><c><anno>Size</anno></c> is the stack size of the process in words.</p> + <p><c><anno>Size</anno></c> is the stack size, in words, + of the process.</p> </item> <tag><c>{status, <anno>Status</anno>}</c></tag> <item> - <p><c><anno>Status</anno></c> is the status of the process. <c><anno>Status</anno></c> - is <c>exiting</c>, <c>garbage_collecting</c>, - <c>waiting</c> (for a message), <c>running</c>, - <c>runnable</c> (ready to run, but another process is - running), or <c>suspended</c> (suspended on a "busy" port - or by the <c>erlang:suspend_process/[1,2]</c> BIF).</p> + <p><c><anno>Status</anno></c> is the status of the process and is one + of the following:</p> + <list type="bulleted"> + <item><c>exiting</c></item> + <item><c>garbage_collecting</c></item> + <item><c>waiting</c> (for a message)</item> + <item><c>running</c></item> + <item><c>runnable</c> (ready to run, but another process is + running)</item> + <item><c>suspended</c> (suspended on a "busy" port + or by the BIF <c>erlang:suspend_process/[1,2]</c>)</item> + </list> </item> <tag><c>{suspending, <anno>SuspendeeList</anno>}</c></tag> <item> - <p><c><anno>SuspendeeList</anno></c> is a list of <c>{<anno>Suspendee</anno>, - <anno>ActiveSuspendCount</anno>, <anno>OutstandingSuspendCount</anno>}</c> tuples. - <c><anno>Suspendee</anno></c> is the pid of a process that have been or is to - be suspended by the process identified by <c><anno>Pid</anno></c> via the - <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso> - BIF, or the - <seealso marker="#suspend_process/1">erlang:suspend_process/1</seealso> - BIF. <c><anno>ActiveSuspendCount</anno></c> is the number of times the - <c><anno>Suspendee</anno></c> has been suspended by <c><anno>Pid</anno></c>. + <p><c><anno>SuspendeeList</anno></c> is a list of + <c>{<anno>Suspendee</anno>, <anno>ActiveSuspendCount</anno>, + <anno>OutstandingSuspendCount</anno>}</c> tuples. + <c><anno>Suspendee</anno></c> is the process identifier of a + process that has been, or is to be, + suspended by the process identified by <c><anno>Pid</anno></c> + through one of the following BIFs:</p> + <list type="bulleted"> + <item> + <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso> + </item> + <item> + <seealso marker="#suspend_process/1">erlang:suspend_process/1</seealso> + </item> + </list> + <p><c><anno>ActiveSuspendCount</anno></c> is the number of + times <c><anno>Suspendee</anno></c> has been suspended by + <c><anno>Pid</anno></c>. <c><anno>OutstandingSuspendCount</anno></c> is the number of not yet - completed suspend requests sent by <c><anno>Pid</anno></c>. That is, - if <c><anno>ActiveSuspendCount</anno> =/= 0</c>, <c><anno>Suspendee</anno></c> is - currently in the suspended state, and if - <c><anno>OutstandingSuspendCount</anno> =/= 0</c> the <c>asynchronous</c> - option of <c>erlang:suspend_process/2</c> has been used and - the suspendee has not yet been suspended by <c><anno>Pid</anno></c>. - Note that the <c><anno>ActiveSuspendCount</anno></c> and - <c><anno>OutstandingSuspendCount</anno></c> are not the total suspend count - on <c><anno>Suspendee</anno></c>, only the parts contributed by <c>Pid</c>. - </p> + completed suspend requests sent by <c><anno>Pid</anno></c>, that is:</p> + <list type="bulleted"> + <item>If <c><anno>ActiveSuspendCount</anno> =/= 0</c>, + <c><anno>Suspendee</anno></c> is + currently in the suspended state. + </item> + <item>If <c><anno>OutstandingSuspendCount</anno> =/= 0</c>, option + <c>asynchronous</c> of <c>erlang:suspend_process/2</c> + has been used and the suspendee has not yet been + suspended by <c><anno>Pid</anno></c>. + </item> + </list> + <p>Notice that <c><anno>ActiveSuspendCount</anno></c> and + <c><anno>OutstandingSuspendCount</anno></c> are not the + total suspend count on <c><anno>Suspendee</anno></c>, + only the parts contributed by <c><anno>Pid</anno></c>.</p> </item> <tag><c>{total_heap_size, <anno>Size</anno>}</c></tag> <item> - <p><c><anno>Size</anno></c> is the total size in words of all heap - fragments of the process. This currently include the stack - of the process. - </p> + <p><c><anno>Size</anno></c> is the total size, in words, of all heap + fragments of the process. This includes the process stack.</p> </item> <tag><c>{trace, <anno>InternalTraceFlags</anno>}</c></tag> <item> - <p><c><anno>InternalTraceFlags</anno></c> is an integer representing - internal trace flag for this process. This <c><anno>InfoTuple</anno></c> - may be changed or removed without prior notice.</p> + <p><c><anno>InternalTraceFlags</anno></c> is an integer + representing the internal trace flag for this process. + This <c><anno>InfoTuple</anno></c> + can be changed or removed without prior notice.</p> </item> <tag><c>{trap_exit, <anno>Boolean</anno>}</c></tag> <item> - <p><c><anno>Boolean</anno></c> is <c>true</c> if the process is trapping - exits, otherwise it is <c>false</c>.</p> + <p><c><anno>Boolean</anno></c> is <c>true</c> if the process + is trapping exits, otherwise <c>false</c>.</p> </item> </taglist> - <p>Note however, that not all implementations support every one - of the above <c><anno>Item</anno></c>s.</p> - <p>Failure: <c>badarg</c> if <c><anno>Pid</anno></c> is not a local process, - or if <c><anno>Item</anno></c> is not a valid <c><anno>Item</anno></c>.</p> + <p>Notice that not all implementations support all + these <c><anno>Item</anno></c>s.</p> + <p>Failures:</p> + <taglist> + <tag><c>badarg</c></tag> + <item>If <c><anno>Pid</anno></c> is not a local process.</item> + <tag><c>badarg</c></tag> + <item>If <c><anno>Item</anno></c> is an invalid item.</item> + </taglist> </desc> </func> + <func> <name name="processes" arity="0"/> - <fsummary>All processes</fsummary> + <fsummary>All processes.</fsummary> <desc> <p>Returns a list of process identifiers corresponding to - all the processes currently existing on the local node. - </p> - <p>Note that a process that is exiting, exists but is not alive, i.e., - <c>is_process_alive/1</c> will return <c>false</c> for a process - that is exiting, but its process identifier will be part - of the result returned from <c>processes/0</c>. - </p> + all the processes currently existing on the local node.</p> + <p>Notice that an exiting process exists, but is not alive. + That is, <c>is_process_alive/1</c> returns <c>false</c> + for an exiting process, but its process identifier is part + of the result returned from <c>processes/0</c>.</p> + <p>Example:</p> <pre> > <input>processes().</input> [<0.0.0>,<0.2.0>,<0.4.0>,<0.5.0>,<0.7.0>,<0.8.0>]</pre> </desc> </func> + <func> <name name="purge_module" arity="1"/> - <fsummary>Remove old code for a module</fsummary> + <fsummary>Removes old code for a module.</fsummary> <desc> - <p>Removes old code for <c><anno>Module</anno></c>. Before this BIF is used, - <c>erlang:check_process_code/2</c> should be called to check - that no processes are executing old code in the module.</p> + <p>Removes old code for <c><anno>Module</anno></c>. + Before this BIF is used, + <c>erlang:check_process_code/2</c> is to be called to check + that no processes execute old code in the module.</p> <warning> <p>This BIF is intended for the code server (see - <seealso marker="kernel:code">code(3)</seealso>) and should not be - used elsewhere.</p> + <seealso marker="kernel:code">code(3)</seealso>) + and is not to be used elsewhere.</p> </warning> <p>Failure: <c>badarg</c> if there is no old code for <c><anno>Module</anno></c>.</p> </desc> </func> + <func> <name name="put" arity="2"/> - <fsummary>Add a new value to the process dictionary</fsummary> - <desc> - <p>Adds a new <c><anno>Key</anno></c> to the process dictionary, associated - with the value <c><anno>Val</anno></c>, and returns <c>undefined</c>. If - <c><anno>Key</anno></c> already exists, the old value is deleted and - replaced by <c><anno>Val</anno></c> and the function returns the old value.</p> - <note> - <p>The values stored when <c>put</c> is evaluated within - the scope of a <c>catch</c> will not be retracted if a - <c>throw</c> is evaluated, or if an error occurs.</p> - </note> + <fsummary>Adds a new value to the process dictionary.</fsummary> + <desc> + <p>Adds a new <c><anno>Key</anno></c> to the process dictionary, + associated with the value <c><anno>Val</anno></c>, and returns + <c>undefined</c>. If <c><anno>Key</anno></c> exists, the old + value is deleted and replaced by <c><anno>Val</anno></c>, and + the function returns the old value.</p> + <p>Example:</p> <pre> > <input>X = put(name, walrus), Y = put(name, carpenter),</input> <input>Z = get(name),</input> <input>{X, Y, Z}.</input> {undefined,walrus,carpenter}</pre> + <note> + <p>The values stored when <c>put</c> is evaluated within + the scope of a <c>catch</c> are not retracted if a + <c>throw</c> is evaluated, or if an error occurs.</p> + </note> </desc> </func> + <func> <name name="raise" arity="3"/> + <fsummary>Stops execution with an exception of given class, reason, and call stack backtrace.</fsummary> <type name="raise_stacktrace"/> - <fsummary>Stop execution with an exception of given class, reason and call stack backtrace</fsummary> <desc> <p>Stops the execution of the calling process with an - exception of given class, reason and call stack backtrace + exception of given class, reason, and call stack backtrace (<em>stacktrace</em>).</p> <warning> - <p>This BIF is intended for debugging and for use in - the Erlang operating system. In general, it should - be avoided in applications, unless you know - very well what you are doing.</p> + <p>This BIF is intended for debugging. Avoid to use it in applications, + unless you really know what you are doing.</p> </warning> - <p><c><anno>Class</anno></c> is one of <c>error</c>, <c>exit</c> or - <c>throw</c>, so if it were not for the stacktrace - <c>erlang:raise(<anno>Class</anno>, <anno>Reason</anno>, <anno>Stacktrace</anno>)</c> is - equivalent to <c>erlang:<anno>Class</anno>(<anno>Reason</anno>)</c>. - <c><anno>Reason</anno></c> is any term and <c><anno>Stacktrace</anno></c> is a list as - returned from <c>get_stacktrace()</c>, that is a list of - 4-tuples <c>{Module, Function, Arity | Args, - Location}</c> where <c>Module</c> and <c>Function</c> - are atoms and the third element is an integer arity or an - argument list. The stacktrace may also contain <c>{Fun, - Args, Location}</c> tuples where - <c>Fun</c> is a local fun and <c>Args</c> is an argument list.</p> - <p>The <c>Location</c> element at the end is optional. + <p><c><anno>Class</anno></c> is <c>error</c>, <c>exit</c>, or + <c>throw</c>. So, if it were not for the stacktrace, + <c>erlang:raise(<anno>Class</anno>, <anno>Reason</anno>, + <anno>Stacktrace</anno>)</c> is + equivalent to <c>erlang:<anno>Class</anno>(<anno>Reason</anno>)</c>.</p> + <p><c><anno>Reason</anno></c> is any term. + <c><anno>Stacktrace</anno></c> is a list as + returned from <c>get_stacktrace()</c>, that is, a list of + four-tuples <c>{Module, Function, Arity | Args, + Location}</c>, where <c>Module</c> and <c>Function</c> + are atoms, and the third element is an integer arity or an + argument list. The stacktrace can also contain <c>{Fun, + Args, Location}</c> tuples, where <c>Fun</c> is a local + fun and <c>Args</c> is an argument list.</p> + <p>Element <c>Location</c> at the end is optional. Omitting it is equivalent to specifying an empty list.</p> <p>The stacktrace is used as the exception stacktrace for the - calling process; it will be truncated to the current + calling process; it is truncated to the current maximum stacktrace depth.</p> - <p>Because evaluating this function causes the process to - terminate, it has no return value - unless the arguments are - invalid, in which case the function <em>returns the error reason</em>, that is <c>badarg</c>. If you want to be - really sure not to return you can call - <c>error(erlang:raise(<anno>Class</anno>, <anno>Reason</anno>, <anno>Stacktrace</anno>))</c> + <p>Since evaluating this function causes the process to + terminate, it has no return value unless the arguments are + invalid, in which case the function <em>returns the error + reason</em> <c>badarg</c>. If you want to be + sure not to return, you can call + <c>error(erlang:raise(<anno>Class</anno>, <anno>Reason</anno>, + <anno>Stacktrace</anno>))</c> and hope to distinguish exceptions later.</p> </desc> </func> + <func> <name name="read_timer" arity="2"/> - <fsummary>Read the state of a timer</fsummary> + <fsummary>Reads the state of a timer.</fsummary> <desc> <p> Read the state of a timer that has been created by either @@ -4595,7 +4884,7 @@ os_prompt% </pre> <c><anno>TimerRef</anno></c> identifies the timer, and was returned by the BIF that created the timer. </p> - <p>Currently available <c><anno>Option</anno>s</c>:</p> + <p>Available <c><anno>Option</anno>s</c>:</p> <taglist> <tag><c>{async, Async}</c></tag> <item> @@ -4603,12 +4892,12 @@ os_prompt% </pre> Asynchronous request for state information. <c>Async</c> defaults to <c>false</c> which will cause the operation to be performed synchronously. In this case, the <c>Result</c> - will be returned by <c>erlang:read_timer()</c>. When - <c>Async</c> is set to <c>true</c>, <c>erlang:read_timer()</c> - will send an asynchronous request for the state information - to the timer service that manages the timer, and then return + is returned by <c>erlang:read_timer()</c>. When + <c>Async</c> is <c>true</c>, <c>erlang:read_timer()</c> + sends an asynchronous request for the state information + to the timer service that manages the timer, and then returns <c>ok</c>. A message on the format <c>{read_timer, - <anno>TimerRef</anno>, <anno>Result</anno>}</c> will be + <anno>TimerRef</anno>, <anno>Result</anno>}</c> is sent to the caller of <c>erlang:read_timer()</c> when the operation has been processed. </p> @@ -4618,26 +4907,27 @@ os_prompt% </pre> More <c><anno>Option</anno></c>s may be added in the future. </p> <p> - When the <c><anno>Result</anno></c> equals <c>false</c>, a + If <c><anno>Result</anno></c> is an integer, it represents the + time in milli-seconds left until the timer expires.</p> + <p> + If <c><anno>Result</anno></c> is <c>false</c>, a timer corresponding to <c><anno>TimerRef</anno></c> could not - be found. This can be either because the timer had expired, - had been canceled, or because <c><anno>TimerRef</anno></c> - never has corresponded to a timer. If the timer has expired, - the timeout message has been sent, but it does not tell you - whether or not it has arrived at its destination yet. When the - <c><anno>Result</anno></c> is an integer, it represents the - time in milli-seconds left until the timer will expire. + be found. This can be because the timer had expired, + it had been canceled, or because <c><anno>TimerRef</anno></c> + never has corresponded to a timer. Even if the timer has expired, + it does not tell you whether or not the timeout message has + arrived at its destination yet. </p> <note> <p> The timer service that manages the timer may be co-located with another scheduler than the scheduler that the calling process is executing on. If this is the case, communication - with the timer service will take much longer time than if it + with the timer service takes much longer time than if it is located locally. If the calling process is in critical path, and can do other things while waiting for the result - of this operation you want to use the <c>{async, true}</c> - option. If using the <c>{async, false}</c> option, the calling + of this operation, you want to use option <c>{async, true}</c>. + If using option <c>{async, false}</c>, the calling process will be blocked until the operation has been performed. </p> @@ -4651,70 +4941,86 @@ os_prompt% </pre> </func> <func> <name name="read_timer" arity="1"/> - <fsummary>Read the state of a timer</fsummary> + <fsummary>Reads the state of a timer.</fsummary> <desc> <p>Read the state of a timer. The same as calling <seealso marker="#read_timer/2"><c>erlang:read_timer(TimerRef, [])</c></seealso>.</p> </desc> </func> + <func> <name name="ref_to_list" arity="1"/> - <fsummary>Text representation of a reference</fsummary> + <fsummary>Text representation of a reference.</fsummary> <desc> - <p>Returns a string which corresponds to the text + <p>Returns a string corresponding to the text representation of <c><anno>Ref</anno></c>.</p> <warning> - <p>This BIF is intended for debugging and for use in - the Erlang operating system. It should not be used in - application programs.</p> + <p>This BIF is intended for debugging and is not to be used + in application programs.</p> </warning> </desc> </func> + <func> <name name="register" arity="2"/> - <fsummary>Register a name for a pid (or port)</fsummary> + <fsummary>Registers a name for a pid (or port).</fsummary> <desc> - <p>Associates the name <c><anno>RegName</anno></c> with a pid or a port - identifier. <c><anno>RegName</anno></c>, which must be an atom, can be used - instead of the pid / port identifier in the send operator + <p>Associates the name <c><anno>RegName</anno></c> with a process + identifier (pid) or a port identifier. + <c><anno>RegName</anno></c>, which must be an atom, can be used + instead of the pid or port identifier in send operator (<c><anno>RegName</anno> ! Message</c>).</p> + <p>Example:</p> <pre> > <input>register(db, Pid).</input> true</pre> - <p>Failure: <c>badarg</c> if <c><anno>PidOrPort</anno></c> is not an existing, - local process or port, if <c><anno>RegName</anno></c> is already in use, - if the process or port is already registered (already has a - name), or if <c><anno>RegName</anno></c> is the atom <c>undefined</c>.</p> + <p>Failures:</p> + <taglist> + <tag><c>badarg</c></tag> + <item>If <c><anno>PidOrPort</anno></c> is not an existing local + process or port.</item> + <tag><c>badarg</c></tag> + <item>If <c><anno>RegName</anno></c> is already in use.</item> + <tag><c>badarg</c></tag> + <item>If the process or port is already registered + (already has a name).</item> + <tag><c>badarg</c></tag> + <item>If <c><anno>RegName</anno></c> is the atom + <c>undefined</c>.</item> + </taglist> </desc> </func> + <func> <name name="registered" arity="0"/> - <fsummary>All registered names</fsummary> + <fsummary>All registered names.</fsummary> <desc> - <p>Returns a list of names which have been registered using - <seealso marker="#register/2">register/2</seealso>.</p> + <p>Returns a list of names that have been registered using + <seealso marker="#register/2">register/2</seealso>, for + example:</p> <pre> > <input>registered().</input> [code_server, file_server, init, user, my_db]</pre> </desc> </func> + <func> <name name="resume_process" arity="1"/> - <fsummary>Resume a suspended process</fsummary> + <fsummary>Resumes a suspended process.</fsummary> <desc> <p>Decreases the suspend count on the process identified by - <c><anno>Suspendee</anno></c>. <c><anno>Suspendee</anno></c> should previously have been - suspended via - <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso>, + <c><anno>Suspendee</anno></c>. <c><anno>Suspendee</anno></c> + is previously to have been suspended through + <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso> or <seealso marker="#suspend_process/1">erlang:suspend_process/1</seealso> - by the process calling <c>erlang:resume_process(<anno>Suspendee</anno>)</c>. When - the suspend count on <c><anno>Suspendee</anno></c> reach zero, <c><anno>Suspendee</anno></c> - will be resumed, i.e., the state of the <c>Suspendee</c> is changed - from suspended into the state <c><anno>Suspendee</anno></c> was in before it was - suspended. - </p> + by the process calling + <c>erlang:resume_process(<anno>Suspendee</anno>)</c>. When the + suspend count on <c><anno>Suspendee</anno></c> reaches zero, + <c><anno>Suspendee</anno></c> is resumed, that is, its state + is changed from suspended into the state it had before it was + suspended.</p> <warning> <p>This BIF is intended for debugging only.</p> </warning> @@ -4722,7 +5028,7 @@ true</pre> <taglist> <tag><c>badarg</c></tag> <item> - If <c><anno>Suspendee</anno></c> isn't a process identifier. + If <c><anno>Suspendee</anno></c> is not a process identifier. </item> <tag><c>badarg</c></tag> <item> @@ -4732,58 +5038,65 @@ true</pre> </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c><anno>Suspendee</anno></c> is not alive. + If the process identified by <c><anno>Suspendee</anno></c> + is not alive. </item> </taglist> </desc> </func> + <func> <name name="round" arity="1"/> - <fsummary>Return an integer by rounding a number</fsummary> + <fsummary>Returns an integer by rounding a number.</fsummary> <desc> - <p>Returns an integer by rounding <c><anno>Number</anno></c>.</p> + <p>Returns an integer by rounding <c><anno>Number</anno></c>, + for example:</p> <pre> -> <input>round(5.5).</input> +<input>round(5.5).</input> 6</pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="self" arity="0"/> - <fsummary>Pid of the calling process</fsummary> + <fsummary>Returns pid of the calling process.</fsummary> <desc> - <p>Returns the pid (process identifier) of the calling process.</p> + <p>Returns the process identifier of the calling process, for + example:</p> <pre> > <input>self().</input> <0.26.0></pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="send" arity="2"/> - <fsummary>Send a message</fsummary> + <fsummary>Sends a message.</fsummary> <type name="dst"/> <desc> - <p>Sends a message and returns <c><anno>Msg</anno></c>. This is the same as - <c><anno>Dest</anno> ! <anno>Msg</anno></c>.</p> - <p><c><anno>Dest</anno></c> may be a remote or local pid, a (local) port, a - locally registered name, or a tuple <c>{<anno>RegName</anno>, <anno>Node</anno>}</c> + <p>Sends a message and returns <c><anno>Msg</anno></c>. This + is the same as <c><anno>Dest</anno> ! <anno>Msg</anno></c>.</p> + <p><c><anno>Dest</anno></c> can be a remote or local process identifier, + a (local) port, a locally registered name, or a tuple + <c>{<anno>RegName</anno>, <anno>Node</anno>}</c> for a registered name at another node.</p> </desc> </func> + <func> <name name="send" arity="3"/> + <fsummary>Sends a message conditionally.</fsummary> <type name="dst"/> - <fsummary>Send a message conditionally</fsummary> - <desc> - <p>Sends a message and returns <c>ok</c>, or does not send - the message but returns something else (see below). Otherwise - the same as - <seealso marker="#send/2">erlang:send/2</seealso>. See - also - <seealso marker="#send_nosuspend/2">erlang:send_nosuspend/2,3</seealso>. - for more detailed explanation and warnings.</p> - <p>The possible options are:</p> + <desc> + <p>Either sends a message and returns <c>ok</c>, or does not send + the message but returns something else (see the following). + Otherwise the same as + <seealso marker="#send/2">erlang:send/2</seealso>. + For more detailed explanation and warnings, see + <seealso marker="#send_nosuspend/2">erlang:send_nosuspend/2,3</seealso>.</p> + <p>The options are as follows:</p> <taglist> <tag><c>nosuspend</c></tag> <item> @@ -4793,314 +5106,366 @@ true</pre> <tag><c>noconnect</c></tag> <item> <p>If the destination node would have to be auto-connected - before doing the send, <c>noconnect</c> is returned + to do the send, <c>noconnect</c> is returned instead.</p> </item> </taglist> <warning> - <p>As with <c>erlang:send_nosuspend/2,3</c>: Use with extreme - care!</p> + <p>As with <c>erlang:send_nosuspend/2,3</c>: use with extreme + care.</p> </warning> </desc> </func> + <func> <name name="send_after" arity="4"/> <fsummary>Start a timer</fsummary> <desc> <p> Starts a timer. When the timer expires, the message - <c><anno>Msg</anno></c> will be sent to the process - identified by <c><anno>Dest</anno></c>. Appart from - the format of the message sent to - <c><anno>Dest</anno></c> when the timer expires + <c><anno>Msg</anno></c> is sent to the process + identified by <c><anno>Dest</anno></c>. Apart from + the format of the timeout message, <c>erlang:send_after/4</c> works exactly as <seealso marker="#start_timer/4"><c>erlang:start_timer/4</c></seealso>.</p> </desc> </func> <func> <name name="send_after" arity="3"/> - <fsummary>Start a timer</fsummary> + <fsummary>Starts a timer.</fsummary> <desc> <p>Starts a timer. The same as calling <seealso marker="#send_after/4"><c>erlang:send_after(<anno>Time</anno>, <anno>Dest</anno>, <anno>Msg</anno>, [])</c></seealso>.</p> </desc> </func> + <func> <name name="send_nosuspend" arity="2"/> - <fsummary>Try to send a message without ever blocking</fsummary> + <fsummary>Tries to send a message without ever blocking.</fsummary> <type name="dst"/> <desc> <p>The same as - <seealso marker="#send/3">erlang:send(<anno>Dest</anno>, <anno>Msg</anno>, [nosuspend])</seealso>, but returns <c>true</c> if + <seealso marker="#send/3">erlang:send(<anno>Dest</anno>, + <anno>Msg</anno>, [nosuspend])</seealso>, + but returns <c>true</c> if the message was sent and <c>false</c> if the message was not sent because the sender would have had to be suspended.</p> - <p>This function is intended for send operations towards an + <p>This function is intended for send operations to an unreliable remote node without ever blocking the sending (Erlang) process. If the connection to the remote node (usually not a real Erlang node, but a node written in C or - Java) is overloaded, this function <em>will not send the message</em> but return <c>false</c> instead.</p> - <p>The same happens, if <c><anno>Dest</anno></c> refers to a local port that - is busy. For all other destinations (allowed for the ordinary - send operator <c>'!'</c>) this function sends the message and + Java) is overloaded, this function <em>does not send the message</em> + and returns <c>false</c>.</p> + <p>The same occurs if <c><anno>Dest</anno></c> refers to a local port + that is busy. For all other destinations (allowed for the ordinary + send operator <c>'!'</c>), this function sends the message and returns <c>true</c>.</p> - <p>This function is only to be used in very rare circumstances + <p>This function is only to be used in rare circumstances where a process communicates with Erlang nodes that can - disappear without any trace causing the TCP buffers and - the drivers queue to be over-full before the node will actually - be shut down (due to tick timeouts) by <c>net_kernel</c>. The - normal reaction to take when this happens is some kind of + disappear without any trace, causing the TCP buffers and + the drivers queue to be over-full before the node is + shut down (because of tick time-outs) by <c>net_kernel</c>. + The normal reaction to take when this occurs is some kind of premature shutdown of the other node.</p> - <p>Note that ignoring the return value from this function would - result in <em>unreliable</em> message passing, which is + <p>Notice that ignoring the return value from this function would + result in an <em>unreliable</em> message passing, which is contradictory to the Erlang programming model. The message is <em>not</em> sent if this function returns <c>false</c>.</p> - <p>Note also that in many systems, transient states of + <p>In many systems, transient states of overloaded queues are normal. The fact that this function - returns <c>false</c> does not in any way mean that the other + returns <c>false</c> does not mean that the other node is guaranteed to be non-responsive, it could be a - temporary overload. Also a return value of <c>true</c> does - only mean that the message could be sent on the (TCP) channel - without blocking, the message is not guaranteed to have - arrived at the remote node. Also in the case of a disconnected + temporary overload. Also, a return value of <c>true</c> does + only mean that the message can be sent on the (TCP) channel + without blocking, the message is not guaranteed to + arrive at the remote node. For a disconnected non-responsive node, the return value is <c>true</c> (mimics - the behaviour of the <c>!</c> operator). The expected - behaviour as well as the actions to take when the function - returns <c>false</c> are application and hardware specific.</p> + the behavior of operator <c>!</c>). The expected + behavior and the actions to take when the function + returns <c>false</c> are application- and hardware-specific.</p> <warning> - <p>Use with extreme care!</p> + <p>Use with extreme care.</p> </warning> </desc> </func> + <func> <name name="send_nosuspend" arity="3"/> - <fsummary>Try to send a message without ever blocking</fsummary> + <fsummary>Tries to send a message without ever blocking.</fsummary> <type name="dst"/> <desc> <p>The same as - <seealso marker="#send/3">erlang:send(<anno>Dest</anno>, <anno>Msg</anno>, [nosuspend | <anno>Options</anno>])</seealso>, - but with boolean return value.</p> + <seealso marker="#send/3">erlang:send(<anno>Dest</anno>, + <anno>Msg</anno>, [nosuspend | <anno>Options</anno>])</seealso>, + but with a Boolean return value.</p> <p>This function behaves like - <seealso marker="#send_nosuspend/2">erlang:send_nosuspend/2)</seealso>, - but takes a third parameter, a list of options. The only - currently implemented option is <c>noconnect</c>. The option - <c>noconnect</c> makes the function return <c>false</c> if + <seealso marker="#send_nosuspend/2">erlang:send_nosuspend/2</seealso>, + but takes a third parameter, a list of options. + The only option is <c>noconnect</c>, which + makes the function return <c>false</c> if the remote node is not currently reachable by the local - node. The normal behaviour is to try to connect to the node, - which may stall the process for a shorter period. The use of - the <c>noconnect</c> option makes it possible to be - absolutely sure not to get even the slightest delay when + node. The normal behavior is to try to connect to the node, + which can stall the process during a short period. The use of + option <c>noconnect</c> makes it possible to be + sure not to get the slightest delay when sending to a remote process. This is especially useful when - communicating with nodes who expect to always be - the connecting part (i.e. nodes written in C or Java).</p> + communicating with nodes that expect to always be + the connecting part (that is, nodes written in C or Java).</p> <p>Whenever the function returns <c>false</c> (either when a suspend would occur or when <c>noconnect</c> was specified and the node was not already connected), the message is guaranteed <em>not</em> to have been sent.</p> <warning> - <p>Use with extreme care!</p> + <p>Use with extreme care.</p> </warning> </desc> </func> + <func> <name name="set_cookie" arity="2"/> - <fsummary>Set the magic cookie of a node</fsummary> + <fsummary>Sets the magic cookie of a node.</fsummary> <desc> <p>Sets the magic cookie of <c><anno>Node</anno></c> to the atom - <c><anno>Cookie</anno></c>. If <c><anno>Node</anno></c> is the local node, the function + <c><anno>Cookie</anno></c>. If <c><anno>Node</anno></c> is the + local node, the function also sets the cookie of all other unknown nodes to - <c><anno>Cookie</anno></c> (see - <seealso marker="doc/reference_manual:distributed">Distributed Erlang</seealso> in the Erlang Reference Manual).</p> + <c><anno>Cookie</anno></c> (see Section + <seealso marker="doc/reference_manual:distributed">Distributed Erlang</seealso> + in the Erlang Reference Manual in System Documentation).</p> <p>Failure: <c>function_clause</c> if the local node is not alive.</p> </desc> </func> + <func> <name name="setelement" arity="3"/> - <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno>)</type_desc> - <fsummary>Set Nth element of a tuple</fsummary> + <fsummary>Sets the Nth element of a tuple.</fsummary> + <type_desc variable="Index">1..tuple_size(<anno>Tuple1</anno></type_desc> <desc> - <p>Returns a tuple which is a copy of the argument <c><anno>Tuple1</anno></c> - with the element given by the integer argument <c><anno>Index</anno></c> + <p>Returns a tuple that is a copy of argument + <c><anno>Tuple1</anno></c> + with the element given by integer argument + <c><anno>Index</anno></c> (the first element is the element with index 1) replaced by - the argument <c><anno>Value</anno></c>.</p> + argument <c><anno>Value</anno></c>, for example:</p> <pre> > <input>setelement(2, {10, green, bottles}, red).</input> {10,red,bottles}</pre> </desc> </func> + <func> <name name="size" arity="1"/> - <fsummary>Size of a tuple or binary</fsummary> + <fsummary>Size of a tuple or binary.</fsummary> <desc> - <p>Returns an integer which is the size of the argument - <c><anno>Item</anno></c>, which must be either a tuple or a binary.</p> + <p>Returns the number of elements in a tuple or the number of + bytes in a binary or bitstring, for example:</p> <pre> > <input>size({morni, mulle, bwange}).</input> -3</pre> +3 +> <input>size(<<11, 22, 33>>).</input> +3 +</pre> + <p>For bitstrings the number of whole bytes is returned. That is, if the number of bits + in the bitstring is not divisible by 8, the resulting + number of bytes is rounded <em>down</em>.</p> <p>Allowed in guard tests.</p> + <p>See also + <seealso marker="#tuple_size/1"><c>tuple_size/1</c></seealso>, + <seealso marker="#byte_size/1"><c>byte_size/1</c></seealso> + and + <seealso marker="#bit_size/1"><c>bit_size/1</c></seealso>.</p> </desc> </func> + <func> <name name="spawn" arity="1"/> - <fsummary>Create a new process with a fun as entry point</fsummary> + <fsummary>Creates a new process with a fun as entry point.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list <c>[]</c>. Otherwise works - like <seealso marker="#spawn/3">spawn/3</seealso>.</p> + <p>Returns the process identifier of a new process started by the + application of <c><anno>Fun</anno></c> to the empty list + <c>[]</c>. Otherwise + works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn" arity="2"/> - <fsummary>Create a new process with a fun as entry point on a given node</fsummary> + <fsummary>Creates a new process with a fun as entry point on a given node.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list <c>[]</c> on <c><anno>Node</anno></c>. If - <c><anno>Node</anno></c> does not exist, a useless pid is returned. - Otherwise works like + <p>Returns the process identifier of a new process started + by the application of <c><anno>Fun</anno></c> to the + empty list <c>[]</c> on <c><anno>Node</anno></c>. If + <c><anno>Node</anno></c> does not exist, a useless pid is + returned. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn" arity="3"/> - <fsummary>Create a new process with a function as entry point</fsummary> - <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c>. The new process - created will be placed in the system scheduler queue and be - run some time later.</p> - <p><c>error_handler:undefined_function(<anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c> is evaluated by the new process if - <c><anno>Module</anno>:<anno>Function</anno>/Arity</c> does not exist (where - <c>Arity</c> is the length of <c><anno>Args</anno></c>). The error handler + <fsummary>Creates a new process with a function as entry point.</fsummary> + <desc> + <p>Returns the process identifier of a new process started by + the application of <c><anno>Module</anno>:<anno>Function</anno></c> + to <c><anno>Args</anno></c>.</p> + <p><c>error_handler:undefined_function(<anno>Module</anno>, + <anno>Function</anno>, <anno>Args</anno>)</c> + is evaluated by the new process if + <c><anno>Module</anno>:<anno>Function</anno>/Arity</c> + does not exist (where <c>Arity</c> is the length of + <c><anno>Args</anno></c>). The error handler can be redefined (see <seealso marker="#process_flag/2">process_flag/2</seealso>). If <c>error_handler</c> is undefined, or the user has - redefined the default <c>error_handler</c> its replacement is - undefined, a failure with the reason <c>undef</c> will occur.</p> + redefined the default <c>error_handler</c> and its replacement is + undefined, a failure with reason <c>undef</c> occurs.</p> + <p>Example:</p> <pre> > <input>spawn(speed, regulator, [high_speed, thin_cut]).</input> <0.13.1></pre> </desc> </func> + <func> <name name="spawn" arity="4"/> - <fsummary>Create a new process with a function as entry point on a given node</fsummary> + <fsummary>Creates a new process with a function as entry point on a given node.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c> on <c>Node</c>. If - <c><anno>Node</anno></c> does not exists, a useless pid is returned. + <p>Returns the process identifier (pid) of a new process started + by the application + of <c><anno>Module</anno>:<anno>Function</anno></c> + to <c><anno>Args</anno></c> on <c><anno>Node</anno></c>. If + <c><anno>Node</anno></c> does not exist, a useless pid is returned. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_link" arity="1"/> - <fsummary>Create and link to a new process with a fun as entry point</fsummary> + <fsummary>Creates and links to a new process with a fun as entry point.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list []. A link is created between + <p>Returns the process identifier of a new process started by + the application of <c><anno>Fun</anno></c> to the empty list + <c>[]</c>. A link is created between the calling process and the new process, atomically. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_link" arity="2"/> - <fsummary>Create and link to a new process with a fun as entry point on a specified node</fsummary> + <fsummary>Creates and links to a new process with a fun as entry point on a specified node.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list [] on <c><anno>Node</anno></c>. A link is + <p>Returns the process identifier (pid) of a new process started + by the application of <c><anno>Fun</anno></c> to the empty + list <c>[]</c> on <c><anno>Node</anno></c>. A link is created between the calling process and the new process, - atomically. If <c><anno>Node</anno></c> does not exist, a useless pid is - returned (and due to the link, an exit signal with exit - reason <c>noconnection</c> will be received). Otherwise works - like <seealso marker="#spawn/3">spawn/3</seealso>.</p> + atomically. If <c><anno>Node</anno></c> does not exist, + a useless pid is returned and an exit signal with + reason <c>noconnection</c> is sent to the calling + process. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_link" arity="3"/> - <fsummary>Create and link to a new process with a function as entry point</fsummary> + <fsummary>Creates and links to a new process with a function as entry point.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c>. A link is created + <p>Returns the process identifier of a new process started by + the application of <c><anno>Module</anno>:<anno>Function</anno></c> + to <c><anno>Args</anno></c>. A link is created between the calling process and the new process, atomically. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_link" arity="4"/> - <fsummary>Create and link to a new process with a function as entry point on a given node</fsummary> + <fsummary>Creates and links to a new process with a function as entry point on a given node.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c> on <c>Node</c>. A + <p>Returns the process identifier (pid) of a new process + started by the application + of <c><anno>Module</anno>:<anno>Function</anno></c> + to <c><anno>Args</anno></c> on <c><anno>Node</anno></c>. A link is created between the calling process and the new - process, atomically. If <c><anno>Node</anno></c> does not exist, a useless - pid is returned (and due to the link, an exit signal with exit - reason <c>noconnection</c> will be received). Otherwise works - like <seealso marker="#spawn/3">spawn/3</seealso>.</p> + process, atomically. If <c><anno>Node</anno></c> does + not exist, a useless pid is returned and an exit signal with + reason <c>noconnection</c> is sent to the calling + process. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_monitor" arity="1"/> - <fsummary>Create and monitor a new process with a fun as entry point</fsummary> + <fsummary>Creates and monitors a new process with a fun as entry point.</fsummary> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list [] and reference for a monitor - created to the new process. + <p>Returns the process identifier of a new process, started by + the application of <c><anno>Fun</anno></c> to the empty list + <c>[]</c>, + and a reference for a monitor created to the new process. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_monitor" arity="3"/> - <fsummary>Create and monitor a new process with a function as entry point</fsummary> + <fsummary>Creates and monitors a new process with a function as entry point.</fsummary> <desc> <p>A new process is started by the application - of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c>, and the process is - monitored at the same time. Returns the pid and a reference - for the monitor. - Otherwise works like + of <c><anno>Module</anno>:<anno>Function</anno></c> + to <c><anno>Args</anno></c>. The process is + monitored at the same time. Returns the process identifier + and a reference for the monitor. Otherwise works like <seealso marker="#spawn/3">spawn/3</seealso>.</p> </desc> </func> + <func> <name name="spawn_opt" arity="2"/> - <type name="priority_level" /> - <fsummary>Create a new process with a fun as entry point</fsummary> + <fsummary>Creates a new process with a fun as entry point.</fsummary> + <type name="priority_level"/> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list <c>[]</c>. Otherwise - works like + <p>Returns the process identifier (pid) of a new process + started by the application of <c><anno>Fun</anno></c> + to the empty list <c>[]</c>. Otherwise works like <seealso marker="#spawn_opt/4">spawn_opt/4</seealso>.</p> - <p>If the option <c>monitor</c> is given, the newly created - process will be monitored and both the pid and reference for - the monitor will be returned.</p> + <p>If option <c>monitor</c> is given, the newly created + process is monitored, and both the pid and reference for + the monitor is returned.</p> </desc> </func> + <func> <name name="spawn_opt" arity="3"/> - <type name="priority_level" /> - <fsummary>Create a new process with a fun as entry point on a given node</fsummary> + <fsummary>Creates a new process with a fun as entry point on a given node.</fsummary> + <type name="priority_level"/> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Fun</anno></c> to the empty list <c>[]</c> on <c><anno>Node</anno></c>. If - <c><anno>Node</anno></c> does not exist, a useless pid is returned. - Otherwise works like + <p>Returns the process identifier (pid) of a new process started + by the application of <c><anno>Fun</anno></c> to the + empty list <c>[]</c> on <c><anno>Node</anno></c>. If + <c><anno>Node</anno></c> does not exist, a useless pid is + returned. Otherwise works like <seealso marker="#spawn_opt/4">spawn_opt/4</seealso>.</p> </desc> </func> + <func> <name name="spawn_opt" arity="4"/> - <type name="priority_level" /> - <fsummary>Create a new process with a function as entry point</fsummary> + <fsummary>Creates a new process with a function as entry point.</fsummary> + <type name="priority_level"/> <desc> - <p>Works exactly like + <p>Works as <seealso marker="#spawn/3">spawn/3</seealso>, except that an extra option list is given when creating the process.</p> - <p>If the option <c>monitor</c> is given, the newly created - process will be monitored and both the pid and reference for - the monitor will be returned.</p> + <p>If option <c>monitor</c> is given, the newly created + process is monitored, and both the pid and reference for + the monitor is returned.</p> + <p>The options are as follows:</p> <taglist> <tag><c>link</c></tag> <item> @@ -5109,112 +5474,123 @@ true</pre> </item> <tag><c>monitor</c></tag> <item> - <p>Monitor the new process (just like + <p>Monitors the new process (like <seealso marker="#monitor/2">monitor/2</seealso> does).</p> </item> - <tag><c>{priority, <anno>Level</anno>}</c></tag> + <tag><c>{priority, <anno>Level</anno></c></tag> <item> <p>Sets the priority of the new process. Equivalent to executing - <seealso marker="#process_flag_priority">process_flag(priority, <anno>Level</anno>)</seealso> in the start function of the new process, - except that the priority will be set before the process is - selected for execution for the first time. For more information - on priorities see - <seealso marker="#process_flag_priority">process_flag(priority, Level)</seealso>.</p> + <seealso marker="#process_flag_priority">process_flag(priority, + <anno>Level</anno>)</seealso> + in the start function of the new process, + except that the priority is set before the process is + selected for execution for the first time. For more + information on priorities, see + <seealso marker="#process_flag_priority">process_flag(priority, + <anno>Level</anno>)</seealso>.</p> </item> <tag><c>{fullsweep_after, <anno>Number</anno>}</c></tag> <item> - <p>This option is only useful for performance tuning. - In general, you should not use this option unless you - know that there is problem with execution times and/or - memory consumption, and you should measure to make sure - that the option improved matters. - </p> + <p>Useful only for performance tuning. Do not use this + option unless you + know that there is problem with execution times or + memory consumption, and ensure + that the option improves matters.</p> <p>The Erlang runtime system uses a generational garbage collection scheme, using an "old heap" for data that has survived at least one garbage collection. When there is no more room on the old heap, a fullsweep garbage - collection will be done.</p> - <p>The <c>fullsweep_after</c> option makes it possible to + collection is done.</p> + <p>Option <c>fullsweep_after</c> makes it possible to specify the maximum number of generational collections - before forcing a fullsweep even if there is still room on - the old heap. Setting the number to zero effectively - disables the general collection algorithm, meaning that + before forcing a fullsweep, even if there is room on + the old heap. Setting the number to zero + disables the general collection algorithm, that is, all live data is copied at every garbage collection.</p> - <p>Here are a few cases when it could be useful to change - <c>fullsweep_after</c>. Firstly, if binaries that are no - longer used should be thrown away as soon as possible. - (Set <c><anno>Number</anno></c> to zero.) Secondly, a process that - mostly have short-lived data will be fullsweeped seldom - or never, meaning that the old heap will contain mostly - garbage. To ensure a fullsweep once in a while, set - <c><anno>Number</anno></c> to a suitable value such as 10 or 20. - Thirdly, in embedded systems with limited amount of RAM - and no virtual memory, one might want to preserve memory - by setting <c><anno>Number</anno></c> to zero. (The value may be set - globally, see - <seealso marker="#system_flag/2">erlang:system_flag/2</seealso>.)</p> + <p>A few cases when it can be useful to change + <c>fullsweep_after</c>:</p> + <list type="bulleted"> + <item>If binaries that are no longer used are to be + thrown away as soon as possible. (Set + <c><anno>Number</anno></c> to zero.) + </item> + <item>A process that mostly have short-lived data is + fullsweeped seldom or never, that is, the old heap + contains mostly garbage. To ensure a fullsweep + occasionally, set <c><anno>Number</anno></c> to a + suitable value, such as 10 or 20. + </item> + <item>In embedded systems with a limited amount of RAM + and no virtual memory, you might want to preserve memory + by setting <c><anno>Number</anno></c> to zero. + (The value can be set globally, see + <seealso marker="#system_flag/2">erlang:system_flag/2</seealso>.) + </item> + </list> </item> <tag><c>{min_heap_size, <anno>Size</anno>}</c></tag> <item> - <p>This option is only useful for performance tuning. - In general, you should not use this option unless you - know that there is problem with execution times and/or - memory consumption, and you should measure to make sure - that the option improved matters. - </p> - <p>Gives a minimum heap size in words. Setting this value - higher than the system default might speed up some + <p>Useful only for performance tuning. Do not use this + option unless you know that there is problem with + execution times or memory consumption, and + ensure that the option improves matters.</p> + <p>Gives a minimum heap size, in words. Setting this value + higher than the system default can speed up some processes because less garbage collection is done. - Setting too high value, however, might waste memory and - slow down the system due to worse data locality. - Therefore, it is recommended to use this option only for + However, setting a too high value can waste memory and + slow down the system because of worse data locality. + Therefore, use this option only for fine-tuning an application and to measure the execution time with various <c><anno>Size</anno></c> values.</p> </item> <tag><c>{min_bin_vheap_size, <anno>VSize</anno>}</c></tag> <item> - <p>This option is only useful for performance tuning. - In general, you should not use this option unless you - know that there is problem with execution times and/or - memory consumption, and you should measure to make sure - that the option improved matters. - </p> - <p>Gives a minimum binary virtual heap size in words. Setting this value - higher than the system default might speed up some + <p>Useful only for performance tuning. Do not use this + option unless you know that there is problem with + execution times or memory consumption, and + ensure that the option improves matters.</p> + <p>Gives a minimum binary virtual heap size, in words. + Setting this value + higher than the system default can speed up some processes because less garbage collection is done. - Setting too high value, however, might waste memory. - Therefore, it is recommended to use this option only for + However, setting a too high value can waste memory. + Therefore, use this option only for fine-tuning an application and to measure the execution time with various <c><anno>VSize</anno></c> values.</p> </item> - </taglist> </desc> </func> + <func> <name name="spawn_opt" arity="5"/> - <type name="priority_level" /> - <fsummary>Create a new process with a function as entry point on a given node</fsummary> + <fsummary>Creates a new process with a function as entry point on a given node.</fsummary> + <type name="priority_level"/> <desc> - <p>Returns the pid of a new process started by the application - of <c><anno>Module</anno>:<anno>Function</anno></c> to <c><anno>Args</anno></c> on <c>Node</c>. If + <p>Returns the process identifier (pid) of a new process started + by the application + of <c><anno>Module</anno>:<anno>Function</anno></c> to + <c><anno>Args</anno></c> on <c><anno>Node</anno></c>. If <c><anno>Node</anno></c> does not exist, a useless pid is returned. Otherwise works like <seealso marker="#spawn_opt/4">spawn_opt/4</seealso>.</p> - <note><p>The <c>monitor</c> option is currently not supported by + <note><p>Option <c>monitor</c> is not supported by <c>spawn_opt/5</c>.</p></note> </desc> </func> + <func> <name name="split_binary" arity="2"/> + <fsummary>Splits a binary into two.</fsummary> <type_desc variable="Pos">0..byte_size(Bin)</type_desc> - <fsummary>Split a binary into two</fsummary> <desc> - <p>Returns a tuple containing the binaries which are the result - of splitting <c><anno>Bin</anno></c> into two parts at position <c><anno>Pos</anno></c>. + <p>Returns a tuple containing the binaries that are the result + of splitting <c><anno>Bin</anno></c> into two parts at + position <c><anno>Pos</anno></c>. This is not a destructive operation. After the operation, - there will be three binaries altogether.</p> + there are three binaries altogether.</p> + <p>Example:</p> <pre> > <input>B = list_to_binary("0123456789").</input> <<"0123456789">> @@ -5228,31 +5604,35 @@ true</pre> 7</pre> </desc> </func> + <func> <name name="start_timer" arity="4"/> - <fsummary>Start a timer</fsummary> + <fsummary>Starts a timer.</fsummary> <desc> <p> Starts a timer. When the timer expires, the message <c>{timeout, <anno>TimerRef</anno>, <anno>Msg</anno>}</c> - will be sent to the process identified by + is sent to the process identified by <c><anno>Dest</anno></c>. </p> - <p>Currently available <c><anno>Option</anno></c>s:</p> + <p>Available <c><anno>Option</anno></c>s:</p> <taglist> - <tag><c>{abs, Abs}</c></tag> + <tag><c>{abs, false}</c></tag> <item> <p> - Absolute <c><anno>Time</anno></c> value. <c>Abs</c> - defaults to <c>false</c> which means that the - <c><anno>Time</anno></c> value will be interpreted - as a time in milli-seconds relative current + This is the default. It means the + <c><anno>Time</anno></c> value is interpreted + as a time in milli-seconds <em>relative</em> current <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang - monotonic time</seealso>. When <c>Abs</c> is set to - <c>true</c>, the <c><anno>Time</anno></c> value will - be interpreted as an absolute Erlang monotonic time of - milli-seconds - <seealso marker="#type_time_unit">time unit</seealso>. + monotonic time</seealso>. + </p> + </item> + <tag><c>{abs, true}</c></tag> + <item> + <p> + Absolute <c><anno>Time</anno></c> value. The + <c><anno>Time</anno></c> value is interpreted as an + absolute Erlang monotonic time in milli-seconds. </p> </item> </taglist> @@ -5260,7 +5640,7 @@ true</pre> More <c><anno>Option</anno></c>s may be added in the future. </p> <p> - The absolute point in time that the timer is set to expire on + The absolute point in time, the timer is set to expire on, has to be in the interval <c>[</c><seealso marker="#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso><c>, </c><seealso marker="#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso><c>]</c>. @@ -5268,21 +5648,21 @@ true</pre> is not allowed to be negative. </p> <p> - If <c><anno>Dest</anno></c> is a <c>pid()</c>, it has to + If <c><anno>Dest</anno></c> is a <c>pid()</c>, it must be a <c>pid()</c> of a process created on the current runtime system instance. This process may or may not have terminated. If <c><anno>Dest</anno></c> is an - <c>atom()</c>, it will be interpreted as the name of a + <c>atom()</c>, it is interpreted as the name of a locally registered process. The process referred to by the name is looked up at the time of timer expiration. No error is given if the name does not refer to a process. </p> <p> - If <c><anno>Dest</anno></c> is a <c>pid()</c>, the timer will - be automatically canceled if the process referred to by the - <c>pid()</c> is not alive, or when the process exits. This - feature was introduced in erts version 5.4.11. Note that - timers will not be automatically canceled when + If <c><anno>Dest</anno></c> is a <c>pid()</c>, the timer is + automatically canceled if the process referred to by the + <c>pid()</c> is not alive, or if the process exits. This + feature was introduced in ERTS version 5.4.11. Notice that + timers are not automatically canceled when <c><anno>Dest</anno></c> is an <c>atom()</c>. </p> <p>See also @@ -5290,13 +5670,14 @@ true</pre> <seealso marker="#cancel_timer/2"><c>erlang:cancel_timer/2</c></seealso>, and <seealso marker="#read_timer/2"><c>erlang:read_timer/2</c></seealso>.</p> - <p>Failure: <c>badarg</c> if the arguments does not satisfy - the requirements specified above.</p> + <p>Failure: <c>badarg</c> if the arguments do not satisfy + the requirements specified here.</p> </desc> </func> + <func> <name name="start_timer" arity="3"/> - <fsummary>Start a timer</fsummary> + <fsummary>Starts a timer.</fsummary> <desc> <p>Starts a timer. The same as calling <seealso marker="#start_timer/4"><c>erlang:start_timer(<anno>Time</anno>, @@ -5305,126 +5686,137 @@ true</pre> </func> <func> <name name="statistics" arity="1" clause_i="1"/> - <fsummary>Information about context switches</fsummary> + <fsummary>Information about context switches.</fsummary> <desc> - <p><c><anno>ContextSwitches</anno></c> is the total number of context - switches since the system started.</p> + <p>Returns the total number of context switches since the + system started.</p> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="2"/> - <fsummary>Information about exact reductions</fsummary> + <fsummary>Information about exact reductions.</fsummary> <desc> <marker id="statistics_exact_reductions"></marker> - <note><p><c>statistics(exact_reductions)</c> is - a more expensive operation than - <seealso marker="#statistics_reductions">statistics(reductions)</seealso> - especially on an Erlang machine with SMP support.</p> - </note> + <p>Returns the number of exact reductions.</p> + <note><p><c>statistics(exact_reductions)</c> is + a more expensive operation than + <seealso marker="#statistics_reductions">statistics(reductions)</seealso>, + especially on an Erlang machine with SMP support.</p> + </note> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="3"/> - <fsummary>Information about garbage collection</fsummary> + <fsummary>Information about garbage collection.</fsummary> <desc> - <p>This information may not be valid for all implementations.</p> + <p>Returns information about garbage collection, for example:</p> <pre> > <input>statistics(garbage_collection).</input> -{85,23961,0} -</pre> +{85,23961,0}</pre> + <p>This information can be invalid for some implementations.</p> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="4"/> - <fsummary>Information about io</fsummary> + <fsummary>Information about I/O.</fsummary> <desc> - <p><c><anno>Input</anno></c> is the total number of bytes received - through ports, and <c><anno>Output</anno></c> is the total number of - bytes output to ports.</p> + <p>Returns <c><anno>Input</anno></c>, + which is the total number of bytes + received through ports, and <c><anno>Output</anno></c>, + which is the total number of bytes output to ports.</p> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="5"/> - <fsummary>Information about reductions</fsummary> + <fsummary>Information about reductions.</fsummary> <desc> <marker id="statistics_reductions"></marker> - <note> - <p>Since erts-5.5 (OTP release R11B) - this value does not include reductions performed in current - time slices of currently scheduled processes. If an - exact value is wanted, use - <seealso marker="#statistics_exact_reductions">statistics(exact_reductions)</seealso>.</p> - </note> + <p>Returns information about reductions, for example:</p> <pre> > <input>statistics(reductions).</input> -{2046,11} -</pre> +{2046,11}</pre> + <note><p>As from <c>ERTS</c> 5.5 (OTP R11B), + this value does not include reductions performed in current + time slices of currently scheduled processes. If an + exact value is wanted, use + <seealso marker="#statistics_exact_reductions">statistics(exact_reductions)</seealso>.</p> + </note> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="6"/> - <fsummary>Information about the run-queue</fsummary> + <fsummary>Information about the run-queue.</fsummary> <desc> - <p>Returns the total length of the run queues, that is, the number - of processes that are ready to run on all available run queues.</p> + <p>Returns the total length of run-queues, that is, the number + of processes that are ready to run on all available run-queues.</p> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="7"/> - <fsummary>Information about run-time</fsummary> + <fsummary>Information about runtime.</fsummary> <desc> - <p>Note that the run-time is the sum of the run-time for all - threads in the Erlang run-time system and may therefore be greater - than the wall-clock time. The time is returned in milliseconds.</p> + <p>Returns information about runtime, in milliseconds.</p> + <p>This is the sum of the runtime for all threads + in the Erlang runtime system and can therefore be greater + than the wall clock time.</p> + <p>Example:</p> <pre> > <input>statistics(runtime).</input> -{1690,1620} -</pre> +{1690,1620}</pre> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="8"/> - <fsummary>Information about each schedulers work time</fsummary> - <desc> - <marker id="statistics_scheduler_wall_time"></marker> - <p> - Returns a list of tuples with <c>{<anno>SchedulerId</anno>, - <anno>ActiveTime</anno>, <anno>TotalTime</anno>}</c>, where - <c>SchedulerId</c> is an integer id of the scheduler, <c>ActiveTime</c> is - the duration the scheduler has been busy, <c>TotalTime</c> is the total time duration since - <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> - activation. The time unit is not defined and may be subject to change - between releases, operating systems and system restarts. - <c>scheduler_wall_time</c> should only be used to calculate relative - values for scheduler-utilization. <c>ActiveTime</c> can never exceed <c>TotalTime</c>. - </p> - - <p>The definition of a busy scheduler is when it is not idle or not - scheduling (selecting) a process or port, meaning; executing process - code, executing linked-in-driver or NIF code, executing - built-in-functions or any other runtime handling, garbage collecting - or handling any other memory management. Note, a scheduler may also be - busy even if the operating system has scheduled out the scheduler - thread. - </p> - - <p> - Returns <c>undefined</c> if the system flag - <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> - is turned off. - </p> - - <p>The list of scheduler information is unsorted and may appear in different order - between calls. - </p> - <p>Using <c>scheduler_wall_time</c> to calculate scheduler utilization.</p> + <fsummary>Information about each schedulers work time.</fsummary> + <desc> + <marker id="statistics_scheduler_wall_time"></marker> + <p>Returns a list of tuples with + <c>{<anno>SchedulerId</anno>, <anno>ActiveTime</anno>, + <anno>TotalTime</anno>}</c>, where + <c><anno>SchedulerId</anno></c> is an integer ID of the scheduler, + <c><anno>ActiveTime</anno></c> is + the duration the scheduler has been busy, and + <c><anno>TotalTime</anno></c> is the total time duration since + <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> + activation. The time unit is undefined and can be subject + to change between releases, OSs, and system restarts. + <c>scheduler_wall_time</c> is only to be used to + calculate relative values for scheduler-utilization. + <c><anno>ActiveTime</anno></c> can never exceed + <c><anno>TotalTime</anno></c>.</p> + <p>The definition of a busy scheduler is when it is not idle + and is not scheduling (selecting) a process or port, + that is:</p> + <list type="bulleted"> + <item>Executing process code</item> + <item>Executing linked-in-driver or NIF code</item> + <item>Executing built-in-functions, or any other runtime + handling</item> + <item>Garbage collecting</item> + <item>Handling any other memory management</item> + </list> + <p>Notice that a scheduler can also be busy even if the + OS has scheduled out the scheduler thread.</p> + <p>Returns <c>undefined</c> if system flag + <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> + is turned off.</p> + <p>The list of scheduler information is unsorted and can + appear in different order between calls.</p> + <p>Using <c>scheduler_wall_time</c> to calculate scheduler-utilization:</p> <pre> > <input>erlang:system_flag(scheduler_wall_time, true).</input> false > <input>Ts0 = lists:sort(erlang:statistics(scheduler_wall_time)), ok.</input> -ok -</pre> - <p>Some time later we will take another snapshot and calculate scheduler-utilization per scheduler.</p> +ok</pre> + <p>Some time later the user takes another snapshot and calculates + scheduler-utilization per scheduler, for example:</p> <pre> > <input>Ts1 = lists:sort(erlang:statistics(scheduler_wall_time)), ok.</input> ok @@ -5437,86 +5829,90 @@ ok {5,0.9717956667018103}, {6,0.9739235846420741}, {7,0.973237033077876}, - {8,0.9741297293248656}] -</pre> - <p>Using the same snapshots to calculate a total scheduler-utilization.</p> + {8,0.9741297293248656}]</pre> + <p>Using the same snapshots to calculate a total scheduler-utilization:</p> <pre> > <input>{A, T} = lists:foldl(fun({{_, A0, T0}, {_, A1, T1}}, {Ai,Ti}) -> {Ai + (A1 - A0), Ti + (T1 - T0)} end, {0, 0}, lists:zip(Ts0,Ts1)), A/T.</input> -0.9769136803764825 -</pre> +0.9769136803764825</pre> <note> - <p><c>scheduler_wall_time</c> is by default disabled. Use <c>erlang:system_flag(scheduler_wall_time, true)</c> to enable it. </p> + <p><c>scheduler_wall_time</c> is by default disabled. To + enable it, use + <c>erlang:system_flag(scheduler_wall_time, true)</c>.</p> </note> </desc> </func> + <func> <name name="statistics" arity="1" clause_i="9"/> - <fsummary>Information about wall-clock</fsummary> + <fsummary>Information about wall clock.</fsummary> <desc> - <p><c>wall_clock</c> can be used in the same manner as + <p>Returns information about wall clock. <c>wall_clock</c> can + be used in the same manner as <c>runtime</c>, except that real time is measured as opposed to runtime or CPU time.</p> </desc> </func> + <func> <name name="suspend_process" arity="2"/> - <fsummary>Suspend a process</fsummary> + <fsummary>Suspends a process.</fsummary> <desc> <p>Increases the suspend count on the process identified by - <c><anno>Suspendee</anno></c> and puts it in the suspended state if it isn't - already in the suspended state. A suspended process will not be - scheduled for execution until the process has been resumed. - </p> - + <c><anno>Suspendee</anno></c> and puts it in the suspended + state if it is not + already in that state. A suspended process will not be + scheduled for execution until the process has been resumed.</p> <p>A process can be suspended by multiple processes and can be suspended multiple times by a single process. A suspended - process will not leave the suspended state until its suspend - count reach zero. The suspend count of <c><anno>Suspendee</anno></c> - is decreased when + process does not leave the suspended state until its suspend + count reaches zero. The suspend count of + <c><anno>Suspendee</anno></c> is decreased when <seealso marker="#resume_process/1">erlang:resume_process(<anno>Suspendee</anno>)</seealso> is called by the same process that called - <c>erlang:suspend_process(<anno>Suspendee</anno>)</c>. All increased suspend - counts on other processes acquired by a process will automatically be + <c>erlang:suspend_process(<anno>Suspendee</anno>)</c>. + All increased suspend + counts on other processes acquired by a process are automatically decreased when the process terminates.</p> - - <p>Currently the following options (<c><anno>Opt</anno></c>s) are available:</p> + <p>The options (<c><anno>Opt</anno></c>s) are as follows:</p> <taglist> <tag><c>asynchronous</c></tag> <item> A suspend request is sent to the process identified by - <c><anno>Suspendee</anno></c>. <c><anno>Suspendee</anno></c> will eventually suspend - unless it is resumed before it was able to suspend. The caller - of <c>erlang:suspend_process/2</c> will return immediately, - regardless of whether the <c><anno>Suspendee</anno></c> has suspended yet - or not. Note that the point in time when the <c><anno>Suspendee</anno></c> - will actually suspend cannot be deduced from other events - in the system. The only guarantee given is that the - <c><anno>Suspendee</anno></c> will <em>eventually</em> suspend (unless it - is resumed). If the <c>asynchronous</c> option has <em>not</em> - been passed, the caller of <c>erlang:suspend_process/2</c> will - be blocked until the <c><anno>Suspendee</anno></c> has actually suspended. + <c><anno>Suspendee</anno></c>. <c><anno>Suspendee</anno></c> + eventually suspends + unless it is resumed before it could suspend. The caller + of <c>erlang:suspend_process/2</c> returns immediately, + regardless of whether <c><anno>Suspendee</anno></c> has + suspended yet or not. The point in time when + <c><anno>Suspendee</anno></c> suspends cannot be deduced + from other events in the system. It is only guaranteed that + <c><anno>Suspendee</anno></c> <em>eventually</em> suspends + (unless it + is resumed). If option <c>asynchronous</c> has <em>not</em> + been passed, the caller of <c>erlang:suspend_process/2</c> is + blocked until <c><anno>Suspendee</anno></c> has suspended. </item> <tag><c>unless_suspending</c></tag> <item> - The process identified by <c><anno>Suspendee</anno></c> will be suspended - unless the calling process already is suspending the - <c><anno>Suspendee</anno></c>. If <c>unless_suspending</c> is combined - with the <c>asynchronous</c> option, a suspend request will be - sent unless the calling process already is suspending the - <c><anno>Suspendee</anno></c> or if a suspend request already has been sent - and is in transit. If the calling process already is suspending - the <c><anno>Suspendee</anno></c>, or if combined with the <c>asynchronous</c> - option and a send request already is in transit, - <c>false</c> is returned and the suspend count on <c><anno>Suspendee</anno></c> - will remain unchanged. + The process identified by <c><anno>Suspendee</anno></c> is + suspended unless the calling process already is suspending + <c><anno>Suspendee</anno></c>. + If <c>unless_suspending</c> is combined + with option <c>asynchronous</c>, a suspend request is + sent unless the calling process already is suspending + <c><anno>Suspendee</anno></c> or if a suspend request + already has been sent and is in transit. If the calling + process already is suspending <c><anno>Suspendee</anno></c>, + or if combined with option <c>asynchronous</c> + and a send request already is in transit, + <c>false</c> is returned and the suspend count on + <c><anno>Suspendee</anno></c> remains unchanged. </item> </taglist> - <p>If the suspend count on the process identified by - <c><anno>Suspendee</anno></c> was increased, <c>true</c> is returned; otherwise, - <c>false</c> is returned.</p> - + <c><anno>Suspendee</anno></c> is increased, <c>true</c> + is returned, otherwise <c>false</c>.</p> <warning> <p>This BIF is intended for debugging only.</p> </warning> @@ -5524,310 +5920,322 @@ ok <taglist> <tag><c>badarg</c></tag> <item> - If <c><anno>Suspendee</anno></c> isn't a process identifier. + If <c><anno>Suspendee</anno></c> is not a process identifier. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c><anno>Suspendee</anno></c> is same the process as - the process calling <c>erlang:suspend_process/2</c>. + If the process identified by <c><anno>Suspendee</anno></c> + is the same process + as the process calling <c>erlang:suspend_process/2</c>. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c><anno>Suspendee</anno></c> is not alive. + If the process identified by <c><anno>Suspendee</anno></c> + is not alive. </item> <tag><c>badarg</c></tag> <item> - If the process identified by <c><anno>Suspendee</anno></c> resides on another node. + If the process identified by <c><anno>Suspendee</anno></c> + resides on another node. </item> <tag><c>badarg</c></tag> <item> - If <c><anno>OptList</anno></c> isn't a proper list of valid <c><anno>Opt</anno></c>s. + If <c><anno>OptList</anno></c> is not a proper list of valid + <c><anno>Opt</anno></c>s. </item> <tag><c>system_limit</c></tag> <item> - If the process identified by <c><anno>Suspendee</anno></c> has been suspended more - times by the calling process than can be represented by the - currently used internal data structures. The current system limit - is larger than 2 000 000 000 suspends, and it will never be less - than that. + If the process identified by <c><anno>Suspendee</anno></c> + has been suspended + more times by the calling process than can be represented by the + currently used internal data structures. The system limit is + higher than 2,000,000,000 suspends and will never be lower. </item> </taglist> </desc> </func> + <func> <name name="suspend_process" arity="1"/> - <fsummary>Suspend a process</fsummary> + <fsummary>Suspends a process.</fsummary> <desc> - <p>Suspends the process identified by <c><anno>Suspendee</anno></c>. The - same as calling - <seealso marker="#suspend_process/2">erlang:suspend_process(<anno>Suspendee</anno>, [])</seealso>. For more information see the documentation of <seealso marker="#suspend_process/2">erlang:suspend_process/2</seealso>. - </p> + <p>Suspends the process identified by + <c><anno>Suspendee</anno></c>. The same as calling + <seealso marker="#suspend_process/2">erlang:suspend_process(<anno>Suspendee</anno>, + [])</seealso>.</p> <warning> <p>This BIF is intended for debugging only.</p> </warning> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="1"/> - <fsummary>Set system flag backtrace_depth</fsummary> + <fsummary>Sets system flag <c>backtrace_depth</c>.</fsummary> <desc> <p>Sets the maximum depth of call stack back-traces in the exit reason element of <c>'EXIT'</c> tuples.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="2"/> + <fsummary>Sets system flag <c>cpu_topology</c>.</fsummary> <type name="cpu_topology"/> <type name="level_entry"/> <type name="level_tag"/> <type name="sub_level"/> <type name="info_list"/> - <fsummary>Set system flag cpu_topology</fsummary> <desc> <warning> <p><marker id="system_flag_cpu_topology"></marker> - This argument is <em>deprecated</em> and - scheduled for removal in erts-5.10/OTP-R16. Instead of using - this argument you are advised to use the <c>erl</c> command - line argument <seealso marker="erts:erl#+sct">+sct</seealso>. - When this argument has been removed a final CPU topology to use - will be determined at emulator boot time.</p> + This argument is <em>deprecated</em> and scheduled for + removal in <c>ERTS</c> 5.10/OTP R16. Instead of using this + argument, use command-line argument + <seealso marker="erts:erl#+sct">+sct</seealso> in + <c>erl(1)</c>.</p> + <p>When this argument is removed, a final CPU topology + to use is determined at emulator boot time.</p> </warning> - <p>Sets the user defined <c><anno>CpuTopology</anno></c>. The user defined - CPU topology will override any automatically detected - CPU topology. By passing <c>undefined</c> as <c><anno>CpuTopology</anno></c> - the system will revert back to the CPU topology automatically + <p>Sets the user-defined <c><anno>CpuTopology</anno></c>. + The user-defined + CPU topology overrides any automatically detected + CPU topology. By passing <c>undefined</c> as + <c><anno>CpuTopology</anno></c>, + the system reverts to the CPU topology automatically detected. The returned value equals the value returned from <c>erlang:system_info(cpu_topology)</c> before the - change was made. - </p> + change was made.</p> <p>Returns the old value of the flag.</p> <p>The CPU topology is used when binding schedulers to logical processors. If schedulers are already bound when the CPU - topology is changed, the schedulers will be sent a request - to rebind according to the new CPU topology. - </p> - <p>The user defined CPU topology can also be set by passing - the <seealso marker="erts:erl#+sct">+sct</seealso> command - line argument to <c>erl</c>. - </p> - <p>For information on the <c><anno>CpuTopology</anno></c> type - and more, see the documentation of - <seealso marker="#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso>, - and the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> - and <seealso marker="erts:erl#+sbt">+sbt</seealso> - command line flags. - </p> + topology is changed, the schedulers are sent a request + to rebind according to the new CPU topology.</p> + <p>The user-defined CPU topology can also be set by passing + command-line argument + <seealso marker="erts:erl#+sct">+sct</seealso> to + <c>erl(1)</c>.</p> + <p>For information on type <c><anno>CpuTopology</anno></c> + and more, see + <seealso marker="#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso> + as well as the command-line flags + <seealso marker="erts:erl#+sct">+sct</seealso> and + <seealso marker="erts:erl#+sbt">+sbt</seealso> in + <c>erl(1)</c>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="3"/> - <fsummary>Set system flag dirty CPU schedulers online</fsummary> + <fsummary>Sets <c>system_flag_dirty_cpu_schedulers_online</c>.</fsummary> <desc> <p><marker id="system_flag_dirty_cpu_schedulers_online"></marker> - Sets the amount of dirty CPU schedulers online. Valid range is - <![CDATA[1 <= DirtyCPUSchedulersOnline <= N]]> where <c>N</c> is the - lesser of the return values of <c>erlang:system_info(dirty_cpu_schedulers)</c> and - <c>erlang:system_info(schedulers_online)</c>. - </p> + Sets the number of dirty CPU schedulers online. Range is + <![CDATA[1 <= DirtyCPUSchedulersOnline <= N]]>, where <c>N</c> + is the smallest of the return values of + <c>erlang:system_info(dirty_cpu_schedulers)</c> and + <c>erlang:system_info(schedulers_online)</c>.</p> <p>Returns the old value of the flag.</p> - <p>Note that the number of dirty CPU schedulers online may change if the number of - schedulers online changes. For example, if there are 12 schedulers and all are - online, and 6 dirty CPU schedulers, all online as well, and <c>system_flag/2</c> - is used to set the number of schedulers online to 6, then the number of dirty - CPU schedulers online is automatically decreased by half as well, down to 3. - Similarly, the number of dirty CPU schedulers online increases proportionally - to increases in the number of schedulers online.</p> - <p><em>Note that the dirty schedulers functionality is experimental</em>, and - that you have to enable support for dirty schedulers when building OTP in order - to try out the functionality.</p> - <p>For more information see + <p>The number of dirty CPU schedulers online can change if the + number of schedulers online changes. For example, if 12 + schedulers and 6 dirty CPU schedulers are online, and + <c>system_flag/2</c> is used to set the number of + schedulers online to 6, then the number of dirty CPU + schedulers online is automatically decreased by half as well, + down to 3. Similarly, the number of dirty CPU schedulers + online increases proportionally to increases in the number of + schedulers online.</p> + <note><p>The dirty schedulers functionality is experimental. + Enable support for dirty schedulers when building OTP to + try out the functionality.</p> + </note> + <p>For more information, see <seealso marker="#system_info_dirty_cpu_schedulers">erlang:system_info(dirty_cpu_schedulers)</seealso> and - <seealso marker="#system_info_dirty_cpu_schedulers_online">erlang:system_info(dirty_cpu_schedulers_online)</seealso>. - </p> + <seealso marker="#system_info_dirty_cpu_schedulers_online">erlang:system_info(dirty_cpu_schedulers_online)</seealso>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="4"/> - <fsummary>Set system flag fullsweep_after</fsummary> + <fsummary>Sets system flag <c>fullsweep_after</c>.</fsummary> <desc> - <p><c><anno>Number</anno></c> is a non-negative integer which indicates + <p>Sets system flag <c>fullsweep_after</c>. + <c><anno>Number</anno></c> is a non-negative integer indicating how many times generational garbage collections can be done without forcing a fullsweep collection. The value - applies to new processes; processes already running are + applies to new processes, while processes already running are not affected.</p> <p>Returns the old value of the flag.</p> <p>In low-memory systems (especially without virtual - memory), setting the value to 0 can help to conserve + memory), setting the value to <c>0</c> can help to conserve memory.</p> - <p>An alternative way to set this value is through the - (operating system) environment variable - <c>ERL_FULLSWEEP_AFTER</c>.</p> + <p>This value can also be set through (OS) + environment variable <c>ERL_FULLSWEEP_AFTER</c>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="5"/> - <fsummary>Set system flag min_heap_size</fsummary> - <desc> - <p>Sets the default minimum heap size for processes. The - size is given in words. The new <c>min_heap_size</c> only - effects processes spawned after the change of - <c>min_heap_size</c> has been made. - The <c>min_heap_size</c> can be set for individual - processes by use of + <fsummary>Sets system flag <c>min_heap_size</c>.</fsummary> + <desc> + <p>Sets the default minimum heap size for processes. The size + is given in words. The new <c>min_heap_size</c> effects + only processes spawned after the change of + <c>min_heap_size</c> has been made. <c>min_heap_size</c> + can be set for individual processes by using <seealso marker="#spawn_opt/4">spawn_opt/N</seealso> or - <seealso marker="#process_flag/2">process_flag/2</seealso>. </p> + <seealso marker="#process_flag/2">process_flag/2</seealso>.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="6"/> - <fsummary>Set system flag min_bin_vheap_size</fsummary> + <fsummary>Sets system flag <c>min_bin_vheap_size</c>.</fsummary> <desc> - <p>Sets the default minimum binary virtual heap size for processes. The - size is given in words. The new <c>min_bin_vhheap_size</c> only - effects processes spawned after the change of + <p>Sets the default minimum binary virtual heap size for + processes. The size is given in words. + The new <c>min_bin_vhheap_size</c> effects only + processes spawned after the change of <c>min_bin_vhheap_size</c> has been made. - The <c>min_bin_vheap_size</c> can be set for individual - processes by use of + <c>min_bin_vheap_size</c> can be set for individual + processes by using <seealso marker="#spawn_opt/4">spawn_opt/N</seealso> or - <seealso marker="#process_flag/2">process_flag/2</seealso>. </p> + <seealso marker="#process_flag/2">process_flag/2</seealso>.</p> <p>Returns the old value of the flag.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="7"/> - <fsummary>Set system flag multi_scheduling</fsummary> + <fsummary>Sets system flag <c>multi_scheduling</c>.</fsummary> <desc> <p><marker id="system_flag_multi_scheduling"></marker> If multi-scheduling is enabled, more than one scheduler thread is used by the emulator. Multi-scheduling can be - blocked. When multi-scheduling has been blocked, only - one scheduler thread will schedule Erlang processes.</p> - <p>If <c><anno>BlockState</anno> =:= block</c>, multi-scheduling will - be blocked. If <c><anno>BlockState</anno> =:= unblock</c> and no-one - else is blocking multi-scheduling and this process has - only blocked one time, multi-scheduling will be unblocked. - One process can block multi-scheduling multiple times. - If a process has blocked multiple times, it has to + blocked. When multi-scheduling is blocked, only + one scheduler thread schedules Erlang processes.</p> + <p>If <c><anno>BlockState</anno> =:= block</c>, multi-scheduling is + blocked. If <c><anno>BlockState</anno> =:= unblock</c> and no one + else blocks multi-scheduling, and this process has + blocked only once, multi-scheduling is unblocked.</p> + <p>One process can block multi-scheduling multiple times. + If a process has blocked multiple times, it must unblock exactly as many times as it has blocked before it has released its multi-scheduling block. If a process that - has blocked multi-scheduling exits, it will release its + has blocked multi-scheduling exits, it releases its blocking of multi-scheduling.</p> <p>The return values are <c>disabled</c>, <c>blocked</c>, or <c>enabled</c>. The returned value describes the state just after the call to <c>erlang:system_flag(multi_scheduling, <anno>BlockState</anno>)</c> - has been made. The return values are described in the - documentation of <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>.</p> - <p><em>NOTE</em>: Blocking of multi-scheduling should normally - not be needed. If you feel that you need to - block multi-scheduling, think through the - problem at least a couple of times again. - Blocking multi-scheduling should only be used - as a last resort since it will most likely be - a <em>very inefficient</em> way to solve the - problem.</p> - <p>See also <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, + has been made. For information about the return values, see + <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>.</p> + <note><p>Blocking of multi-scheduling is normally not needed. + If you feel that you need to block multi-scheduling, + consider it a few more times again. Blocking multi-scheduling + is only to be used as a last resort, as it is most likely + a <em>very inefficient</em> way to solve the problem.</p> + </note> + <p>See also + <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>, and <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="8"/> + <fsummary>Sets system flag <c>scheduler_bind_type</c>.</fsummary> <type name="scheduler_bind_type"/> - <fsummary>Set system flag scheduler_bind_type</fsummary> <desc> <warning> <p><marker id="system_flag_scheduler_bind_type"></marker> - This argument is <em>deprecated</em> and - scheduled for removal in erts-5.10/OTP-R16. Instead of using - this argument you are advised to use the <c>erl</c> command - line argument <seealso marker="erts:erl#+sbt">+sbt</seealso>. - When this argument has been removed a final scheduler bind type - to use will be determined at emulator boot time.</p> + This argument is <em>deprecated</em> and scheduled for + removal in <c>ERTS</c> 5.10/OTP R16. Instead of using this + argument, use command-line argument + <seealso marker="erts:erl#+sbt">+sbt</seealso> in <c>erl(1)</c>. + When this argument is removed, a final scheduler bind + type to use is determined at emulator boot time.</p> </warning> <p>Controls if and how schedulers are bound to logical processors.</p> - <p>When <c>erlang:system_flag(scheduler_bind_type, <anno>How</anno>)</c> is - called, an asynchronous signal is sent to all schedulers - online which causes them to try to bind or unbind as requested. - <em>NOTE:</em> If a scheduler fails to bind, this - will often be silently ignored. This since it isn't always - possible to verify valid logical processor identifiers. If - an error is reported, it will be reported to the - <c>error_logger</c>. If you want to verify that the - schedulers actually have bound as requested, call - <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. - </p> - <p>Schedulers can currently only be bound on newer Linux, + <p>When <c>erlang:system_flag(scheduler_bind_type, <anno>How</anno>)</c> + is called, an asynchronous signal is sent to all schedulers + online, causing them to try to bind or unbind as requested.</p> + <note><p>If a scheduler fails to bind, this is often silently + ignored, as it is not always possible to verify valid + logical processor identifiers. If an error is reported, + it is reported to <c>error_logger</c>. To verify that the + schedulers have bound as requested, call + <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>.</p> + </note> + <p>Schedulers can be bound on newer Linux, Solaris, FreeBSD, and Windows systems, but more systems will be - supported in the future. - </p> + supported in future releases.</p> <p>In order for the runtime system to be able to bind schedulers, - the CPU topology needs to be known. If the runtime system fails - to automatically detect the CPU topology, it can be defined. + the CPU topology must be known. If the runtime system fails + to detect the CPU topology automatically, it can be defined. For more information on how to define the CPU topology, see - the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> command - line flag. - </p> - <p>The runtime system will by default <em>not</em> bind schedulers - to logical processors. - </p> - <p><em>NOTE:</em> If the Erlang runtime system is the only - operating system process that binds threads to logical processors, - this improves the performance of the runtime system. However, - if other operating system processes (as for example another Erlang - runtime system) also bind threads to logical processors, there - might be a performance penalty instead. In some cases this - performance penalty might be severe. If this is the case, you - are advised to not bind the schedulers.</p> - <p>Schedulers can be bound in different ways. The <c><anno>How</anno></c> - argument determines how schedulers are bound. <c><anno>How</anno></c> can - currently be one of:</p> + command-line flag <seealso marker="erts:erl#+sct">+sct</seealso> + in <c>erl(1)</c>.</p> + <p>The runtime system does by default <em>not</em> bind schedulers + to logical processors.</p> + <note><p>If the Erlang runtime system is the only OS + process binding threads to logical processors, this + improves the performance of the runtime system. However, + if other OS processes (for example, another Erlang + runtime system) also bind threads to logical processors, + there can be a performance penalty instead. Sometimes this + performance penalty can be severe. If so, it is recommended + to not bind the schedulers.</p> + </note> + <p>Schedulers can be bound in different ways. Argument + <c><anno>How</anno></c> determines how schedulers are + bound and can be any of the following:</p> <taglist> <tag><c>unbound</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt u</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt u</seealso> in <c>erl(1)</c>. </p></item> <tag><c>no_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt ns</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt ns</seealso> in <c>erl(1)</c>. </p></item> <tag><c>thread_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt ts</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt ts</seealso> in <c>erl(1)</c>. </p></item> <tag><c>processor_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt ps</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt ps</seealso> in <c>erl(1)</c>. </p></item> <tag><c>spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt s</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt s</seealso> in <c>erl(1)</c>. </p></item> <tag><c>no_node_thread_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt nnts</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt nnts</seealso> in <c>erl(1)</c>. </p></item> <tag><c>no_node_processor_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt nnps</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt nnps</seealso> in <c>erl(1)</c>. </p></item> <tag><c>thread_no_node_processor_spread</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt tnnps</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt tnnps</seealso> in <c>erl(1)</c>. </p></item> <tag><c>default_bind</c></tag> - <item><p>Same as the <c>erl</c> command line argument - <seealso marker="erts:erl#+sbt">+sbt db</seealso>. + <item><p>Same as command-line argument + <seealso marker="erts:erl#+sbt">+sbt db</seealso> in <c>erl(1)</c>. </p></item> </taglist> - <p>The value returned equals <c><anno>How</anno></c> before the - <c>scheduler_bind_type</c> flag was changed.</p> - <p>Failure:</p> + <p>The returned value equals <c><anno>How</anno></c> before flag + <c>scheduler_bind_type</c> was changed.</p> + <p>Failures:</p> <taglist> <tag><c>notsup</c></tag> <item> @@ -5835,168 +6243,171 @@ ok </item> <tag><c>badarg</c></tag> <item> - <p>If <c>How</c> isn't one of the documented alternatives.</p> + <p>If <c><anno>How</anno></c> is not one of the documented + alternatives.</p> </item> <tag><c>badarg</c></tag> <item> - <p>If no CPU topology information is available.</p> + <p>If CPU topology information is unavailable.</p> </item> </taglist> <p>The scheduler bind type can also be set by passing - the <seealso marker="erts:erl#+sbt">+sbt</seealso> command - line argument to <c>erl</c>. - </p> + command-line argument + <seealso marker="erts:erl#+sbt">+sbt</seealso> to <c>erl(1)</c>.</p> <p>For more information, see <seealso marker="#system_info_scheduler_bind_type">erlang:system_info(scheduler_bind_type)</seealso>, <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>, - the <c>erl</c> <seealso marker="erts:erl#+sbt">+sbt</seealso> - and <seealso marker="erts:erl#+sct">+sct</seealso> command line - flags. - </p> + as well as command-line flags + <seealso marker="erts:erl#+sbt">+sbt</seealso> + and <seealso marker="erts:erl#+sct">+sct</seealso> + in <c>erl(1)</c>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="9"/> - <fsummary>Set system flag scheduler_wall_time</fsummary> + <fsummary>Sets system flag <c>scheduler_wall_time</c>.</fsummary> <desc><p><marker id="system_flag_scheduler_wall_time"></marker> - Turns on/off scheduler wall time measurements. </p> - <p>For more information see, - <seealso marker="#statistics_scheduler_wall_time">erlang:statistics(scheduler_wall_time)</seealso>. - </p> + Turns on or off scheduler wall time measurements.</p> + <p>For more information, see + <seealso marker="#statistics_scheduler_wall_time">erlang:statistics(scheduler_wall_time)</seealso>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="10"/> - <fsummary>Set system flag schedulers_online</fsummary> + <fsummary>Sets system flag <c>schedulers_online</c>.</fsummary> <desc> <p><marker id="system_flag_schedulers_online"></marker> - Sets the amount of schedulers online. Valid range is - <![CDATA[1 <= SchedulersOnline <= erlang:system_info(schedulers)]]>. - </p> + Sets the number of schedulers online. Range is + <![CDATA[1 <= SchedulersOnline <= erlang:system_info(schedulers)]]>.</p> <p>Returns the old value of the flag.</p> - <p>Note that if the emulator was built with support for <seealso - marker="#system_flag_dirty_cpu_schedulers_online">dirty schedulers</seealso>, - changing the number of schedulers online can also change the number of dirty - CPU schedulers online. For example, if there are 12 schedulers and all are - online, and 6 dirty CPU schedulers, all online as well, and <c>system_flag/2</c> - is used to set the number of schedulers online to 6, then the number of dirty - CPU schedulers online is automatically decreased by half as well, down to 3. - Similarly, the number of dirty CPU schedulers online increases proportionally - to increases in the number of schedulers online.</p> - <p>For more information see, - <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>, + <p>If the emulator was built with support for + <seealso marker="#system_flag_dirty_cpu_schedulers_online">dirty schedulers</seealso>, + changing the number of schedulers online can also change the + number of dirty CPU schedulers online. For example, if 12 + schedulers and 6 dirty CPU schedulers are online, and + <c>system_flag/2</c> is used to set the number of schedulers + online to 6, then the number of dirty CPU schedulers online + is automatically decreased by half as well, down to 3. + Similarly, the number of dirty CPU schedulers online increases + proportionally to increases in the number of schedulers online.</p> + <p>For more information, see + <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso> and - <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>. - </p> + <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>.</p> </desc> </func> + <func> <name name="system_flag" arity="2" clause_i="11"/> - <fsummary>Set system flag trace_control_word</fsummary> + <fsummary>Sets system flag <c>trace_control_word</c>.</fsummary> <desc> - <p>Sets the value of the node's trace control word to - <c><anno>TCW</anno></c>. <c><anno>TCW</anno></c> should be an unsigned integer. For - more information see documentation of the + <p>Sets the value of the node trace control word to + <c><anno>TCW</anno></c>, which is to be an unsigned integer. + For more information, see the function <seealso marker="erts:match_spec#set_tcw">set_tcw</seealso> - function in the match specification documentation in the - ERTS User's Guide.</p> + in Section "Match Specifications in Erlang" in the + User's Guide.</p> <p>Returns the old value of the flag.</p> </desc> </func> - <marker id="system_flag_time_offset"/> + <func> <name name="system_flag" arity="2" clause_i="12"/> <fsummary>Finalize the Time Offset</fsummary> <desc> - <p>Finalizes the <seealso marker="#time_offset/0">time offset</seealso> - when the <seealso marker="time_correction#Single_Time_Warp_Mode">single - time warp mode</seealso> is being used. If another time warp mode than - the "single time warp mode" is used, the time offset state will be left - unchanged.</p> - <p>Returns the old state identifier. That is, if:</p> + <p><marker id="system_flag_time_offset"></marker> + Finalizes the <seealso marker="#time_offset/0">time offset</seealso> + when <seealso marker="time_correction#Single_Time_Warp_Mode">single + time warp mode</seealso> is used. If another time warp mode + is used, the time offset state is left unchanged.</p> + <p>Returns the old state identifier. That is:</p> <list> - <item><p><c>preliminary</c> is returned, finalization was + <item><p>If <c>preliminary</c> is returned, finalization was performed and the time offset is now final.</p></item> - <item><p><c>final</c> is returned, the time offset was - already in the final state. This either due to another + <item><p>If <c>final</c> is returned, the time offset was + already in the final state. This either because another <c>erlang:system_flag(time_offset, finalize)</c> call, or - due to the - <seealso marker="time_correction#No_Time_Warp_Mode">no - time warp mode</seealso> being used.</p></item> + because <seealso marker="time_correction#No_Time_Warp_Mode">no + time warp mode</seealso> is used.</p></item> - <item><p><c>volatile</c> is returned, the time offset - cannot be finalized due to the + <item><p>If <c>volatile</c> is returned, the time offset + cannot be finalized because <seealso marker="time_correction#Multi_Time_Warp_Mode">multi - time warp mode</seealso> being used.</p></item> + time warp mode</seealso> is used.</p></item> </list> </desc> </func> + <func> <name name="system_info" arity="1" clause_i="1"/> <name name="system_info" arity="1" clause_i="2"/> <name name="system_info" arity="1" clause_i="3"/> <name name="system_info" arity="1" clause_i="4"/> <name name="system_info" arity="1" clause_i="5"/> + <fsummary>Information about the system allocators.</fsummary> <type variable="Allocator" name_i="2"/> <type variable="Version" name_i="2"/> <type variable="Features" name_i="2"/> <type variable="Settings" name_i="2"/> <type variable="Alloc" name_i="3"/> - <fsummary>Information about the allocators of the system</fsummary> <desc> - <p> - Returns various information about the - <marker id="system_info_allocator_tags">allocators</marker> of the + <marker id="system_info_allocator_tags"></marker> + <p>Returns various information about the allocators of the current system (emulator) as specified by <c><anno>Item</anno></c>:</p> + <marker id="system_info_allocated_areas"></marker> <taglist> - <tag><marker id="system_info_allocated_areas"><c>allocated_areas</c></marker></tag> + <tag><c>allocated_areas</c></tag> <item> <p>Returns a list of tuples with information about miscellaneous allocated memory areas.</p> - <p>Each tuple contains an atom describing type of memory as - first element and amount of allocated memory in bytes as - second element. In those cases when there is information - present about allocated and used memory, a third element - is present. This third element contains the amount of + <p>Each tuple contains an atom describing the type of + memory as first element and the amount of allocated + memory in bytes as second element. When information + about allocated and used memory is present, also a + third element is present, containing the amount of used memory in bytes.</p> <p><c>erlang:system_info(allocated_areas)</c> is intended - for debugging, and the content is highly implementation - dependent. The content of the results will therefore - change when needed without prior notice.</p> - <p><em>Note:</em> The sum of these values is <em>not</em> + for debugging, and the content is highly + implementation-dependent. The content of the results + therefore changes when needed without prior notice.</p> + <p>Notice that the sum of these values is <em>not</em> the total amount of memory allocated by the emulator. Some values are part of other values, and some memory - areas are not part of the result. If you are interested - in the total amount of memory allocated by the emulator - see <seealso marker="#memory/0">erlang:memory/0,1</seealso>.</p> + areas are not part of the result. For information about + the total amount of memory allocated by the emulator, see + <seealso marker="#memory/0">erlang:memory/0,1</seealso>.</p> </item> - <tag><marker id="system_info_allocator"><c>allocator</c></marker></tag> + <tag><c>allocator</c></tag> <item> - <p>Returns <c>{<anno>Allocator</anno>, <anno>Version</anno>, <anno>Features</anno>, <anno>Settings</anno>}.</c></p> - <p>Explanation:</p> + <marker id="system_info_allocator"></marker> + <p>Returns <c>{<anno>Allocator</anno>, <anno>Version</anno>, + <anno>Features</anno>, <anno>Settings</anno></c>, where:</p> <list type="bulleted"> <item> - <p><c><anno>Allocator</anno></c> corresponds to the <c>malloc()</c> - implementation used. If <c><anno>Allocator</anno></c> equals + <p><c><anno>Allocator</anno></c> corresponds to the + <c>malloc()</c> implementation used. If + <c><anno>Allocator</anno></c> equals <c>undefined</c>, the <c>malloc()</c> implementation - used could not be identified. Currently - <c>glibc</c> can be identified.</p> + used cannot be identified. <c>glibc</c> can be + identified.</p> </item> <item> - <p><c><anno>Version</anno></c> is a list of integers (but not a - string) representing the version of + <p><c><anno>Version</anno></c> is a list of integers + (but not a string) representing the version of the <c>malloc()</c> implementation used.</p> </item> <item> - <p><c><anno>Features</anno></c> is a list of atoms representing - allocation features used.</p> + <p><c><anno>Features</anno></c> is a list of atoms + representing the allocation features used.</p> </item> <item> - <p><c><anno>Settings</anno></c> is a list of subsystems, their - configurable parameters, and used values. Settings - may differ between different combinations of + <p><c><anno>Settings</anno></c> is a list of subsystems, + their configurable parameters, and used values. Settings + can differ between different combinations of platforms, allocators, and allocation features. Memory sizes are given in bytes.</p> </item> @@ -6004,165 +6415,169 @@ ok <p>See also "System Flags Effecting erts_alloc" in <seealso marker="erts:erts_alloc#flags">erts_alloc(3)</seealso>.</p> </item> - <tag><marker id="system_info_alloc_util_allocators"><c>alloc_util_allocators</c></marker></tag> + <tag><c>alloc_util_allocators</c></tag> <item> - <p>Returns a list of the names of all allocators - using the ERTS internal <c>alloc_util</c> framework - as atoms. For more information see the - <seealso marker="erts:erts_alloc#alloc_util">"the - alloc_util framework" section in the - erts_alloc(3)</seealso> documentation. - </p> + <marker id="system_info_alloc_util_allocators"></marker> + <p>Returns a list of the names of all allocators using + the <c>ERTS</c> internal <c>alloc_util</c> framework + as atoms. For more information, see Section + <seealso marker="erts:erts_alloc#alloc_util">"The + alloc_util framework" in erts_alloc(3)</seealso>.</p> </item> - <tag><marker id="system_info_allocator_tuple"><c>{allocator, <anno>Alloc</anno>}</c></marker></tag> + <tag><c>{allocator, <anno>Alloc</anno>}</c></tag> <item> + <marker id="system_info_allocator_tuple"></marker> <p>Returns information about the specified allocator. - As of erts version 5.6.1 the return value is a list - of <c>{instance, InstanceNo, InstanceInfo}</c> tuples + As from <c>ERTS</c> 5.6.1, the return value is a list + of <c>{instance, InstanceNo, InstanceInfo}</c> tuples, where <c>InstanceInfo</c> contains information about - a specific instance of the allocator. As of erts version - 5.10.4 the returned list when calling + a specific instance of the allocator. As from + <c>ERTS</c> 5.10.4, the returned list when calling <c>erlang:system_info({allocator, mseg_alloc})</c> also - include an <c>{erts_mmap, _}</c> tuple as one element - in the list. - If <c><anno>Alloc</anno></c> is not a recognized allocator, - <c>undefined</c> is returned. If <c><anno>Alloc</anno></c> is disabled, + includes an <c>{erts_mmap, _}</c> tuple as one element + in the list. If <c><anno>Alloc</anno></c> is not a + recognized allocator, <c>undefined</c> is returned. + If <c><anno>Alloc</anno></c> is disabled, <c>false</c> is returned.</p> - <p><em>Note:</em> The information returned is highly - implementation dependent and may be changed, or removed + <p>Notice that the information returned is highly + implementation-dependent and can be changed or removed at any time without prior notice. It was initially intended as a tool when developing new allocators, but - since it might be of interest for others it has been + as it can be of interest for others it has been briefly documented.</p> <p>The recognized allocators are listed in <seealso marker="erts:erts_alloc">erts_alloc(3)</seealso>. After reading the <c>erts_alloc(3)</c> documentation, the returned information - should more or less speak for itself. But it can be worth + more or less speaks for itself, but it can be worth explaining some things. Call counts are presented by two - values. The first value is giga calls, and the second - value is calls. <c>mbcs</c>, and <c>sbcs</c> are - abbreviations for, respectively, multi-block carriers, and - single-block carriers. Sizes are presented in bytes. When - it is not a size that is presented, it is the amount of - something. Sizes and amounts are often presented by three - values, the first is current value, the second is maximum - value since the last call to - <c>erlang:system_info({allocator, Alloc})</c>, and - the third is maximum value since the emulator was started. - If only one value is present, it is the current value. + values, the first value is giga calls, and the second + value is calls. <c>mbcs</c> and <c>sbcs</c> denote + multi-block carriers, and single-block carriers, + respectively. Sizes are presented in bytes. When a + size is not presented, it is the amount of something. + Sizes and amounts are often presented by three values:</p> + <list type="bulleted"> + <item>The first is the current value.</item> + <item>The second is the maximum value since the last call + to <c>erlang:system_info({allocator, Alloc})</c>.</item> + <item>The third is the maximum value since the emulator + was started.</item> + </list> + <p>If only one value is present, it is the current value. <c>fix_alloc</c> memory block types are presented by two - values. The first value is memory pool size and - the second value used memory size.</p> + values. The first value is the memory pool size and + the second value is the used memory size.</p> </item> - <tag><marker id="system_info_allocator_sizes"><c>{allocator_sizes, <anno>Alloc</anno>}</c></marker></tag> + <tag><c>{allocator_sizes, <anno>Alloc</anno>}</c></tag> <item> + <marker id="system_info_allocator_sizes"></marker> <p>Returns various size information for the specified allocator. The information returned is a subset of the information returned by - <seealso marker="#system_info_allocator_tuple">erlang:system_info({allocator, <anno>Alloc</anno>})</seealso>. + <seealso marker="#system_info_allocator_tuple"><c>erlang:system_info({allocator, <anno>Alloc</anno>})</c></seealso>. </p> </item> </taglist> </desc> </func> + <func> <name name="system_info" arity="1" clause_i="10"/> <name name="system_info" arity="1" clause_i="11"/> + <fsummary>Information about the CPU topology of the system.</fsummary> <type name="cpu_topology"/> <type name="level_entry"/> <type_desc name="cpu_topology"> - <marker id="system_info_cpu_topology"></marker> All <c><anno>LevelEntry</anno></c>s of a list must contain the same <c><anno>LevelTag</anno></c>, except on the top level where both <c>node</c> and - <c>processor</c> <c><anno>LevelTag</anno></c>s may co-exist. + <c>processor</c> <c><anno>LevelTag</anno></c>s can coexist. </type_desc> <type_desc name="level_entry"> - <c>{<anno>LevelTag</anno>, <anno>SubLevel</anno>} == {<anno>LevelTag</anno>, [], <anno>SubLevel</anno>}</c> + <c>{<anno>LevelTag</anno>, + <anno>SubLevel</anno>} == {<anno>LevelTag</anno>, [], + <anno>SubLevel</anno>}</c> </type_desc> <type name="level_tag"/> <type_desc name="level_tag"> - More <c><anno>LevelTag</anno></c>s may be introduced in the future. + More <c><anno>LevelTag</anno></c>s can be introduced in a + future release. </type_desc> <type name="sub_level"/> <type name="info_list"/> <type_desc name="info_list"> - The <c>info_list()</c> may be extended in the future. + The <c>info_list()</c> can be extended in a future release. </type_desc> - <fsummary>Information about the CPU topology of the system</fsummary> <desc> - <p>Returns various information about the - <marker id="system_info_cpu_topology_tags">CPU topology</marker> - of the current system - (emulator) as specified by <c><anno>Item</anno></c>:</p> + <marker id="system_info_cpu_topology_tags"></marker> + <marker id="system_info_cpu_topology"></marker> + <p>Returns various information about the CPU topology of + the current system (emulator) as specified by + <c><anno>Item</anno></c>:</p> <taglist> <tag><c>cpu_topology</c></tag> <item> - <p>Returns the <c><anno>CpuTopology</anno></c> which currently is used by the - emulator. The CPU topology is used when binding schedulers + <p>Returns the <c><anno>CpuTopology</anno></c> currently used by + the emulator. The CPU topology is used when binding schedulers to logical processors. The CPU topology used is the - <seealso marker="erlang#system_info_cpu_topology_defined">user - defined CPU topology</seealso> if such exists; otherwise, the - <seealso marker="erlang#system_info_cpu_topology_detected">automatically - detected CPU topology</seealso> if such exists. If no CPU topology + <seealso marker="erlang#system_info_cpu_topology_defined">user-defined CPU topology</seealso>, + if such exists, otherwise the + <seealso marker="erlang#system_info_cpu_topology_detected">automatically detected CPU topology</seealso>, + if such exists. If no CPU topology exists, <c>undefined</c> is returned.</p> - <p><c>node</c> refers to NUMA (non-uniform memory access) - nodes, and <c>thread</c> refers to hardware threads - (e.g. Intels hyper-threads).</p> - <p>A level in the <c><anno>CpuTopology</anno></c> term can be omitted if - only one entry exists and the <c><anno>InfoList</anno></c> is empty. - </p> + <p><c>node</c> refers to Non-Uniform Memory Access (NUMA) + nodes. <c>thread</c> refers to hardware threads + (for example, Intel hyper-threads).</p> + <p>A level in term <c><anno>CpuTopology</anno></c> can be + omitted if only one entry exists and + <c><anno>InfoList</anno></c> is empty.</p> <p><c>thread</c> can only be a sub level to <c>core</c>. - <c>core</c> can be a sub level to either <c>processor</c> - or <c>node</c>. <c>processor</c> can either be on the + <c>core</c> can be a sub level to <c>processor</c> + or <c>node</c>. <c>processor</c> can be on the top level or a sub level to <c>node</c>. <c>node</c> - can either be on the top level or a sub level to + can be on the top level or a sub level to <c>processor</c>. That is, NUMA nodes can be processor internal or processor external. A CPU topology can consist of a mix of processor internal and external - NUMA nodes, as long as each logical CPU belongs to one - and only one NUMA node. Cache hierarchy is not part of - the <c><anno>CpuTopology</anno></c> type yet, but will be in the - future. Other things may also make it into the CPU - topology in the future. In other words, expect the - <c><anno>CpuTopology</anno></c> type to change. - </p> - </item> - <tag><marker id="system_info_cpu_topology_defined"><c>{cpu_topology, defined}</c></marker></tag> - <item> - <p>Returns the user defined <c><anno>CpuTopology</anno></c>. For more - information see the documentation of - the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> command - line flag, and the documentation of the - <seealso marker="#system_info_cpu_topology">cpu_topology</seealso> - argument. - </p> - </item> - <tag><marker id="system_info_cpu_topology_detected"><c>{cpu_topology, detected}</c></marker></tag> - <item> - <p>Returns the automatically detected <c><anno>CpuTopology</anno></c>. The - emulator currently only detects the CPU topology on some newer - Linux, Solaris, FreeBSD, and Windows systems. On Windows system with - more than 32 logical processors the CPU topology is not detected. - </p> - <p>For more information see the documentation of the - <seealso marker="#system_info_cpu_topology">cpu_topology</seealso> - argument. - </p> + NUMA nodes, as long as each logical CPU belongs to + <em>one</em> NUMA node. Cache hierarchy is not part of + the <c><anno>CpuTopology</anno></c> type, but will be in a + future release. Other things can also make it into the CPU + topology in a future release. In other words, expect the + <c><anno>CpuTopology</anno></c> type to change.</p> + </item> + <tag><c>{cpu_topology, defined}</c></tag> + <item> + <marker id="system_info_cpu_topology_defined"></marker> + <p>Returns the user-defined <c><anno>CpuTopology</anno></c>. + For more information, see command-line flag + <seealso marker="erts:erl#+sct">+sct</seealso> in + <c>erl(1)</c> and argument + <seealso marker="#system_info_cpu_topology">cpu_topology</seealso>.</p> + </item> + <tag><c>{cpu_topology, detected}</c></tag> + <item> + <marker id="system_info_cpu_topology_detected"></marker> + <p>Returns the automatically detected + <c><anno>CpuTopology</anno>y</c>. The + emulator detects the CPU topology on some newer + Linux, Solaris, FreeBSD, and Windows systems. + On Windows system with more than 32 logical processors, + the CPU topology is not detected.</p> + <p>For more information, see argument + <seealso marker="#system_info_cpu_topology">cpu_topology</seealso>.</p> </item> <tag><c>{cpu_topology, used}</c></tag> <item> - <p>Returns the <c><anno>CpuTopology</anno></c> which is used by the - emulator. For more information see the - documentation of the - <seealso marker="#system_info_cpu_topology">cpu_topology</seealso> - argument. - </p> + <p>Returns <c><anno>CpuTopology</anno></c> used by the emulator. + For more information, see argument + <seealso marker="#system_info_cpu_topology">cpu_topology</seealso>.</p> </item> </taglist> </desc> </func> + <func> <name name="system_info" arity="1" clause_i="6"/> <name name="system_info" arity="1" clause_i="7"/> @@ -6224,7 +6639,7 @@ ok <name name="system_info" arity="1" clause_i="65"/> <name name="system_info" arity="1" clause_i="66"/> <name name="system_info" arity="1" clause_i="67"/> - <fsummary>Information about the system</fsummary> + <fsummary>Information about the system.</fsummary> <desc> <p>Returns various information about the current system (emulator) as specified by <c><anno>Item</anno></c>:</p> @@ -6241,8 +6656,7 @@ ok Other possible return values are <c>debug</c>, <c>purify</c>, <c>quantify</c>, <c>purecov</c>, <c>gcov</c>, <c>valgrind</c>, <c>gprof</c>, and <c>lcnt</c>. Possible return values - may be added and/or removed at any time without prior notice. - </p> + can be added or removed at any time without prior notice.</p> </item> <tag><c>c_compiler_used</c></tag> <item> @@ -6250,26 +6664,25 @@ ok compiling the runtime system. The first element is an atom describing the name of the compiler, or <c>undefined</c> if unknown. The second element is a term describing the - version of the compiler, or <c>undefined</c> if unknown. - </p> + version of the compiler, or <c>undefined</c> if unknown.</p> </item> <tag><c>check_io</c></tag> <item> <p>Returns a list containing miscellaneous information - regarding the emulators internal I/O checking. Note, - the content of the returned list may vary between - platforms and over time. The only thing guaranteed is + about the emulators internal I/O checking. Notice that + the content of the returned list can vary between + platforms and over time. It is only guaranteed that a list is returned.</p> </item> <tag><c>compat_rel</c></tag> <item> <p>Returns the compatibility mode of the local node as an integer. The integer returned represents the - Erlang/OTP release which the current emulator has been + Erlang/OTP release that the current emulator has been set to be backward compatible with. The compatibility - mode can be configured at startup by using the command - line flag <c>+R</c>, see - <seealso marker="erts:erl#compat_rel">erl(1)</seealso>.</p> + mode can be configured at startup by using command-line flag + <seealso marker="erts:erl#compat_rel">+R</seealso> in + <c>erl(1)</c>.</p> </item> <tag><c>cpu_topology</c></tag> <item> @@ -6282,144 +6695,150 @@ ok creation of a node is stored in process identifiers, port identifiers, and references. This makes it (to some extent) possible to distinguish between identifiers from - different incarnations of a node. Currently valid - creations are integers in the range 1..3, but this may - (probably will) change in the future. If the node is not - alive, 0 is returned.</p> + different incarnations of a node. The valid + creations are integers in the range 1..3, but this will + probably change in a future release. If the node is not + alive, <c>0</c> is returned.</p> </item> <tag><c>debug_compiled</c></tag> <item> <p>Returns <c>true</c> if the emulator has been debug - compiled; otherwise, <c>false</c>. - </p> + compiled, otherwise <c>false</c>.</p> </item> - <tag><marker id="system_info_delayed_node_table_gc"><c>delayed_node_table_gc</c></marker></tag> + <tag><c>delayed_node_table_gc</c></tag> <item> - <p>Returns the amount of time in seconds that garbage collection - of an entry in a node table will be delayed. This limit can be set - on startup by passing the - <seealso marker="erts:erl#+zdntgc">+zdntgc</seealso> command line - flag to <c>erl</c>. For more information see the documentation of the + <marker id="system_info_delayed_node_table_gc"></marker> + <p>Returns the amount of time in seconds garbage collection + of an entry in a node table is delayed. This limit can be set + on startup by passing the command line flag + <seealso marker="erts:erl#+zdntgc">+zdntgc</seealso> + to <c>erl</c>. For more information see the documentation of the command line flag.</p> </item> - <tag><marker id="system_info_dirty_cpu_schedulers"><c>dirty_cpu_schedulers</c></marker></tag> + <tag><c>dirty_cpu_schedulers</c></tag> <item> + <marker id="system_info_dirty_cpu_schedulers"></marker> <p>Returns the number of dirty CPU scheduler threads used by the emulator. Dirty CPU schedulers execute CPU-bound - native functions such as NIFs, linked-in driver code, and BIFs - that cannot be managed cleanly by the emulator's normal schedulers. - </p> - <p>The number of dirty CPU scheduler threads is determined at emulator - boot time and cannot be changed after that. The number of dirty CPU - scheduler threads online can however be changed at any time. The number of - dirty CPU schedulers can be set on startup by passing - the <seealso marker="erts:erl#+SDcpu">+SDcpu</seealso> or - <seealso marker="erts:erl#+SDPcpu">+SDPcpu</seealso> command line flags, - see <seealso marker="erts:erl#+SDcpu">erl(1)</seealso>. - </p> - <p><em>Note that the dirty schedulers functionality is experimental</em>, and - that you have to enable support for dirty schedulers when building OTP in - order to try out the functionality.</p> - <p>See also <seealso marker="#system_flag_dirty_cpu_schedulers_online">erlang:system_flag(dirty_cpu_schedulers_online, DirtyCPUSchedulersOnline)</seealso>, + native functions, such as NIFs, linked-in driver code, + and BIFs that cannot be managed cleanly by the normal + emulator schedulers.</p> + <p>The number of dirty CPU scheduler threads is determined + at emulator boot time and cannot be changed after that. + However, the number of dirty CPU scheduler threads online + can be changed at any time. The number of dirty CPU + schedulers can be set at startup by passing + command-line flag + <seealso marker="erts:erl#+SDcpu">+SDcpu</seealso> or + <seealso marker="erts:erl#+SDPcpu">+SDPcpu</seealso> in + <c>erl(1)</c>.</p> + <p>Notice that the dirty schedulers functionality is + experimental. Enable support for dirty schedulers when + building OTP to try out the functionality.</p> + <p>See also + <seealso marker="#system_flag_dirty_cpu_schedulers_online">erlang:system_flag(dirty_cpu_schedulers_online, DirtyCPUSchedulersOnline)</seealso>, <seealso marker="#system_info_dirty_cpu_schedulers_online">erlang:system_info(dirty_cpu_schedulers_online)</seealso>, <seealso marker="#system_info_dirty_io_schedulers">erlang:system_info(dirty_io_schedulers)</seealso>, <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>, <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>, and <seealso marker="#system_flag_schedulers_online">erlang:system_flag(schedulers_online, SchedulersOnline)</seealso>.</p> </item> - <tag><marker id="system_info_dirty_cpu_schedulers_online"><c>dirty_cpu_schedulers_online</c></marker></tag> - <item> - <p>Returns the number of dirty CPU schedulers online. The return value - satisfies the following relationship: - <c><![CDATA[1 <= DirtyCPUSchedulersOnline <= N]]></c>, where <c>N</c> is - the lesser of the return values of <c>erlang:system_info(dirty_cpu_schedulers)</c> and - <c>erlang:system_info(schedulers_online)</c>. - </p> - <p>The number of dirty CPU schedulers online can be set on startup by passing - the <seealso marker="erts:erl#+SDcpu">+SDcpu</seealso> command line flag, see - <seealso marker="erts:erl#+SDcpu">erl(1)</seealso>. - </p> - <p><em>Note that the dirty schedulers functionality is experimental</em>, and - that you have to enable support for dirty schedulers when building OTP in - order to try out the functionality.</p> + <tag><c>dirty_cpu_schedulers_online</c></tag> + <item> + <marker id="system_info_dirty_cpu_schedulers_online"></marker> + <p>Returns the number of dirty CPU schedulers online. + The return value satisfies + <c><![CDATA[1 <= DirtyCPUSchedulersOnline <= N]]></c>, + where <c>N</c> is the smallest of the return values of + <c>erlang:system_info(dirty_cpu_schedulers)</c> and + <c>erlang:system_info(schedulers_online)</c>.</p> + <p>The number of dirty CPU schedulers online can be set at + startup by passing command-line flag + <seealso marker="erts:erl#+SDcpu">+SDcpu</seealso> in + <c>erl(1)</c>.</p> + <p>Notice that the dirty schedulers functionality is + experimental. Enable support for dirty schedulers when + building OTP to try out the functionality.</p> <p>For more information, see <seealso marker="#system_info_dirty_cpu_schedulers">erlang:system_info(dirty_cpu_schedulers)</seealso>, <seealso marker="#system_info_dirty_io_schedulers">erlang:system_info(dirty_io_schedulers)</seealso>, <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>, and - <seealso marker="#system_flag_dirty_cpu_schedulers_online">erlang:system_flag(dirty_cpu_schedulers_online, DirtyCPUSchedulersOnline)</seealso>. - </p> - </item> - <tag><marker id="system_info_dirty_io_schedulers"><c>dirty_io_schedulers</c></marker></tag> - <item> - <p>Returns the number of dirty I/O schedulers as an integer. Dirty I/O schedulers - execute I/O-bound native functions such as NIFs and linked-in driver code that - cannot be managed cleanly by the emulator's normal schedulers. - </p> - <p>This value can be set on startup by passing - the <seealso marker="erts:erl#+SDio">+SDio</seealso> command line flag, see - <seealso marker="erts:erl#+SDio">erl(1)</seealso>. - </p> - <p><em>Note that the dirty schedulers functionality is experimental</em>, and - that you have to enable support for dirty schedulers when building OTP in - order to try out the functionality.</p> + <seealso marker="#system_flag_dirty_cpu_schedulers_online">erlang:system_flag(dirty_cpu_schedulers_online, DirtyCPUSchedulersOnline)</seealso>.</p> + </item> + <tag><c>dirty_io_schedulers</c></tag> + <item> + <marker id="system_info_dirty_io_schedulers"></marker> + <p>Returns the number of dirty I/O schedulers as an integer. + Dirty I/O schedulers execute I/O-bound native functions, + such as NIFs and linked-in driver code, which cannot be + managed cleanly by the normal emulator schedulers.</p> + <p>This value can be set at startup by passing command-line + argument <seealso marker="erts:erl#+SDio">+SDio</seealso> + in <c>erl(1)</c>.</p> + <p>Notice that the dirty schedulers functionality is + experimental. Enable support for dirty schedulers when + building OTP to try out the functionality.</p> <p>For more information, see <seealso marker="#system_info_dirty_cpu_schedulers">erlang:system_info(dirty_cpu_schedulers)</seealso>, <seealso marker="#system_info_dirty_cpu_schedulers_online">erlang:system_info(dirty_cpu_schedulers_online)</seealso>, and - <seealso marker="#system_flag_dirty_cpu_schedulers_online">erlang:system_flag(dirty_cpu_schedulers_online, DirtyCPUSchedulersOnline)</seealso>. - </p> + <seealso marker="#system_flag_dirty_cpu_schedulers_online">erlang:system_flag(dirty_cpu_schedulers_online, DirtyCPUSchedulersOnline)</seealso>.</p> </item> <tag><c>dist</c></tag> <item> <p>Returns a binary containing a string of distribution information formatted as in Erlang crash dumps. For more - information see the <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> - chapter in the ERTS User's Guide.</p> + information, see Section + <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> + in the User's Guide.</p> </item> - <tag><marker id="system_info_dist_buf_busy_limit"><c>dist_buf_busy_limit</c></marker></tag> + <tag><c>dist_buf_busy_limit</c></tag> <item> + <marker id="system_info_dist_buf_busy_limit"></marker> <p>Returns the value of the distribution buffer busy limit - in bytes. This limit can be set on startup by passing the - <seealso marker="erts:erl#+zdbbl">+zdbbl</seealso> command line - flag to <c>erl</c>.</p> + in bytes. This limit can be set at startup by passing + command-line flag + <seealso marker="erts:erl#+zdbbl">+zdbbl</seealso> + to <c>erl</c>.</p> </item> <tag><c>dist_ctrl</c></tag> <item> <p>Returns a list of tuples - <c>{Node, ControllingEntity}</c>, one entry for each - connected remote node. The <c><anno>Node</anno></c> is the name of the - node and the <c><anno>ControllingEntity</anno></c> is the port or pid - responsible for the communication to that node. More - specifically, the <c><anno>ControllingEntity</anno></c> for nodes - connected via TCP/IP (the normal case) is the socket - actually used in communication with the specific node.</p> + <c>{<anno>Node</anno>, <anno>ControllingEntity</anno>}</c>, + one entry for each connected remote node. + <c><anno>Node</anno></c> is the node name + and <c><anno>ControllingEntity</anno></c> is the port or process + identifier responsible for the communication to that node. + More specifically, <c><anno>ControllingEntity</anno></c> for + nodes connected through TCP/IP (the normal case) is the socket + used in communication with the specific node.</p> </item> <tag><c>driver_version</c></tag> <item> - <p>Returns a string containing the erlang driver version - used by the runtime system. It will be on the form + <p>Returns a string containing the Erlang driver version + used by the runtime system. It has the form <seealso marker="erts:erl_driver#version_management">"<major ver>.<minor ver>"</seealso>.</p> </item> <tag><c>dynamic_trace</c></tag> <item> <p>Returns an atom describing the dynamic trace framework - compiled into the virtual machine. It can currently be either - <c>dtrace</c>, <c>systemtap</c> or <c>none</c>. For a - commercial or standard build, this is always <c>none</c>, - the other return values indicate a custom configuration - (e.g. <c>./configure --with-dynamic-trace=dtrace</c>). See - the <seealso marker="runtime_tools:dyntrace">dyntrace - </seealso> manual page and the + compiled into the virtual machine. It can be + <c>dtrace</c>, <c>systemtap</c>, or <c>none</c>. For a + commercial or standard build, it is always <c>none</c>. + The other return values indicate a custom configuration + (for example, <c>./configure --with-dynamic-trace=dtrace</c>). + For more information about dynamic tracing, see the + <seealso marker="runtime_tools:dyntrace">dyntrace</seealso> + manual page and the <c>README.dtrace</c>/<c>README.systemtap</c> files in the - Erlang source code top directory for more information - about dynamic tracing.</p> + Erlang source code top directory.</p> </item> <tag><c>dynamic_trace_probes</c></tag> <item> - <p>Returns a <c>boolean()</c> indicating if dynamic trace probes - (either dtrace or systemtap) are built into the - emulator. This can only be <c>true</c> if the virtual - machine was built for dynamic tracing - (i.e. <c>system_info(dynamic_trace)</c> returns + <p>Returns a <c>boolean()</c> indicating if dynamic trace + probes (<c>dtrace</c> or <c>systemtap</c>) are built into + the emulator. This can only be <c>true</c> if the Virtual + Machine was built for dynamic tracing (that is, + <c>system_info(dynamic_trace)</c> returns <c>dtrace</c> or <c>systemtap</c>).</p> </item> <tag><marker id="system_info_end_time"/><c>end_time</c></tag> @@ -6433,42 +6852,43 @@ ok <tag><c>elib_malloc</c></tag> <item> <p>This option will be removed in a future release. - The return value will always be <c>false</c> since - the elib_malloc allocator has been removed.</p> + The return value will always be <c>false</c>, as the + <c>elib_malloc</c> allocator has been removed.</p> </item> - <tag><marker id="system_info_eager_check_io"><c>eager_check_io</c></marker></tag> + <tag><marker id="system_info_eager_check_io"/><c>eager_check_io</c></tag> <item> <p> - Returns the value of the <c>erl</c> - <seealso marker="erl#+secio">+secio</seealso> command line - flag which is either <c>true</c> or <c>false</c>. See the + Returns the value of the <c>erl</c> command line flag + <seealso marker="erl#+secio">+secio</seealso> + which is either <c>true</c> or <c>false</c>. See the documentation of the command line flag for information about the different values. </p> </item> <tag><c>ets_limit</c></tag> <item> - <p>Returns the maximum number of ETS tables allowed. This limit - can be increased on startup by passing the <seealso - marker="erts:erl#+e">+e</seealso> command line flag to - <c>erl</c> or by setting the environment variable - <c>ERL_MAX_ETS_TABLES</c> before starting the Erlang runtime - system.</p> + <p>Returns the maximum number of ETS tables allowed. This + limit can be increased at startup by passing + command-line flag + <seealso marker="erts:erl#+e">+e</seealso> to + <c>erl(1)</c> or by setting environment variable + <c>ERL_MAX_ETS_TABLES</c> before starting the Erlang + runtime system.</p> </item> <tag><c>fullsweep_after</c></tag> <item> - <p>Returns <c>{fullsweep_after, integer() >= 0}</c> which is the - <c>fullsweep_after</c> garbage collection setting used - by default. For more information see - <c>garbage_collection</c> described below.</p> + <p>Returns <c>{fullsweep_after, integer() >= 0}</c>, which is + the <c>fullsweep_after</c> garbage collection setting used + by default. For more information, see + <c>garbage_collection</c> described in the following.</p> </item> <tag><c>garbage_collection</c></tag> <item> <p>Returns a list describing the default garbage collection settings. A process spawned on the local node by a - <c>spawn</c> or <c>spawn_link</c> will use these + <c>spawn</c> or <c>spawn_link</c> uses these garbage collection settings. The default settings can be - changed by use of + changed by using <seealso marker="#system_flag/2">system_flag/2</seealso>. <seealso marker="#spawn_opt/4">spawn_opt/4</seealso> can spawn a process that does not use the default @@ -6482,8 +6902,8 @@ ok </item> <tag><c>heap_type</c></tag> <item> - <p>Returns the heap type used by the current emulator. - Currently only the following heap type exists:</p> + <p>Returns the heap type used by the current emulator. One + heap type exists:</p> <taglist> <tag><c>private</c></tag> <item> @@ -6498,51 +6918,51 @@ ok <item> <p>Returns a binary containing a string of miscellaneous system information formatted as in Erlang crash dumps. - For more information see the - <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> chapter in the ERTS - User's Guide.</p> + For more information, see Section + <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> + in the User's Guide.</p> </item> <tag><c>kernel_poll</c></tag> <item> <p>Returns <c>true</c> if the emulator uses some kind of - kernel-poll implementation; otherwise, <c>false</c>.</p> + kernel-poll implementation, otherwise <c>false</c>.</p> </item> <tag><c>loaded</c></tag> <item> <p>Returns a binary containing a string of loaded module information formatted as in Erlang crash dumps. For more - information see the <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> chapter - in the ERTS User's Guide.</p> + information, see Section + <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> + in the User's Guide.</p> </item> - <tag><marker id="logical_processors"><c>logical_processors</c></marker></tag> + <tag><c>logical_processors</c></tag> <item> + <marker id="logical_processors"></marker> <p>Returns the detected number of logical processors configured - on the system. The return value is either an integer, or - the atom <c>unknown</c> if the emulator wasn't able to - detect logical processors configured. - </p> + in the system. The return value is either an integer, or + the atom <c>unknown</c> if the emulator cannot + detect the configured logical processors.</p> </item> - <tag><marker id="logical_processors_available"><c>logical_processors_available</c></marker></tag> + <tag><c>logical_processors_available</c></tag> <item> - <p>Returns the detected number of logical processors available to - the Erlang runtime system. The return value is either an - integer, or the atom <c>unknown</c> if the emulator wasn't - able to detect logical processors available. The number - of logical processors available is less than or equal to - the number of <seealso marker="#logical_processors_online">logical - processors online</seealso>. - </p> + <marker id="logical_processors_available"></marker> + <p>Returns the detected number of logical processors available + to the Erlang runtime system. The return value is either an + integer, or the atom <c>unknown</c> if the emulator + cannot detect the available logical processors. The number + of available logical processors is less than or equal to + the number of + <seealso marker="#logical_processors_online">logical processors online</seealso>.</p> </item> - <tag><marker id="logical_processors_online"><c>logical_processors_online</c></marker></tag> + <tag><c>logical_processors_online</c></tag> <item> + <marker id="logical_processors_online"></marker> <p>Returns the detected number of logical processors online on the system. The return value is either an integer, - or the atom <c>unknown</c> if the emulator wasn't able to + or the atom <c>unknown</c> if the emulator cannot detect logical processors online. The number of logical processors online is less than or equal to the number of - <seealso marker="#logical_processors">logical processors - configured</seealso>. - </p> + <seealso marker="#logical_processors">logical processors configured</seealso>.</p> </item> <tag><c>machine</c></tag> <item> @@ -6550,27 +6970,30 @@ ok </item> <tag><c>min_heap_size</c></tag> <item> - <p>Returns <c>{min_heap_size, <anno>MinHeapSize</anno>}</c> where <c><anno>MinHeapSize</anno></c> is the current system wide - minimum heap size for spawned processes.</p> + <p>Returns <c>{min_heap_size, <anno>MinHeapSize</anno>}</c>, + where <c><anno>MinHeapSize</anno></c> is the current + system-wide minimum heap size for spawned processes.</p> </item> <tag><c>min_bin_vheap_size</c></tag> <item> - <p>Returns <c>{min_bin_vheap_size, <anno>MinBinVHeapSize</anno>}</c> where <c><anno>MinBinVHeapSize</anno></c> is the current system wide + <p>Returns <c>{min_bin_vheap_size, + <anno>MinBinVHeapSize</anno>}</c>, where + <c><anno>MinBinVHeapSize</anno></c> is the current system-wide minimum binary virtual heap size for spawned processes.</p> </item> <tag><c>modified_timing_level</c></tag> <item> - <p>Returns the modified timing level (an integer) if - modified timing has been enabled; otherwise, - <c>undefined</c>. See the <c>+T</c> command line flag - in the documentation of the - <seealso marker="erts:erl#+T">erl(1)</seealso> - command for more information on modified timing.</p> + <p>Returns the modified timing-level (an integer) if + modified timing is enabled, otherwise, <c>undefined</c>. + For more information about modified timing, see + command-line flag + <seealso marker="erts:erl#+T">+T</seealso> + in <c>erl(1)</c></p> </item> - <tag><marker id="system_info_multi_scheduling"><c>multi_scheduling</c></marker></tag> + <tag><c>multi_scheduling</c></tag> <item> - <p>Returns <c>disabled</c>, <c>blocked</c>, or <c>enabled</c>. - A description of the return values:</p> + <marker id="system_info_multi_scheduling"></marker> + <p>Returns <c>disabled</c>, <c>blocked</c>, or <c>enabled</c>:</p> <taglist> <tag><c>disabled</c></tag> <item> @@ -6581,93 +7004,99 @@ ok <tag><c>blocked</c></tag> <item> <p>The emulator has more than one scheduler thread, - but all scheduler threads but one have been blocked, - i.e., only one scheduler thread will schedule - Erlang processes and execute Erlang code.</p> + but all scheduler threads except one are blocked, + that is, only one scheduler thread schedules + Erlang processes and executes Erlang code.</p> </item> <tag><c>enabled</c></tag> <item> <p>The emulator has more than one scheduler thread, - and no scheduler threads have been blocked, i.e., - all available scheduler threads will schedule + and no scheduler threads are blocked, that is, + all available scheduler threads schedule Erlang processes and execute Erlang code.</p> </item> </taglist> - <p>See also <seealso marker="#system_flag_multi_scheduling">erlang:system_flag(multi_scheduling, BlockState)</seealso>, - <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>, and + <p>See also + <seealso marker="#system_flag_multi_scheduling">erlang:system_flag(multi_scheduling, BlockState)</seealso>, + <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>, + and <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> </item> - <tag><marker id="system_info_multi_scheduling_blockers"><c>multi_scheduling_blockers</c></marker></tag> + <tag><c>multi_scheduling_blockers</c></tag> <item> - <p>Returns a list of <c><anno>PID</anno></c>s when multi-scheduling - is blocked; otherwise, the empty list. The <c><anno>PID</anno></c>s - in the list is <c><anno>PID</anno></c>s of the processes currently - blocking multi-scheduling. A <c><anno>PID</anno></c> will only be - present once in the list, even if the corresponding + <marker id="system_info_multi_scheduling_blockers"></marker> + <p>Returns a list of <c><anno>Pid</anno></c>s when + multi-scheduling is blocked, otherwise the empty list is + returned. The <c><anno>Pid</anno></c>s in the list + represent all the processes currently + blocking multi-scheduling. A <c><anno>Pid</anno></c> occurs + only once in the list, even if the corresponding process has blocked multiple times.</p> - <p>See also <seealso marker="#system_flag_multi_scheduling">erlang:system_flag(multi_scheduling, BlockState)</seealso>, - <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, and + <p>See also + <seealso marker="#system_flag_multi_scheduling">erlang:system_flag(multi_scheduling, BlockState)</seealso>, + <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, + and <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> </item> <tag><c>nif_version</c></tag> <item> - <p>Returns a string containing the erlang NIF version - used by the runtime system. It will be on the form "<major ver>.<minor ver>".</p> + <p>Returns a string containing the version of the Erlang NIF interface + used by the runtime system. It is on the form + "<major ver>.<minor ver>".</p> </item> - <tag><marker id="system_info_otp_release"><c>otp_release</c></marker></tag> + <tag><c>otp_release</c></tag> <item> + <marker id="system_info_otp_release"></marker> <p>Returns a string containing the OTP release number of the - OTP release that the currently executing ERTS application is + OTP release that the currently executing <c>ERTS</c> application is part of.</p> - <p>As of OTP release 17, the OTP release number corresponds to - the major OTP version number. There is no - <c>erlang:system_info()</c> argument giving the exact OTP - version. This since the exact OTP version in the general case - is hard to determine. For more information see - <seealso marker="doc/system_principles:versions">the - documentation of versions in the system principles - guide</seealso>.</p> + <p>As from OTP 17, the OTP release number corresponds to + the major OTP version number. No + <c>erlang:system_info()</c> argument gives the exact OTP + version. This is because the exact OTP version in the general case + is difficult to determine. For more information, see the description + of versions in <seealso marker="doc/system_principles:versions"> + System principles</seealso> in System Documentation.</p> </item> - <tag><marker id="system_info_os_monotonic_time_source"><c>os_monotonic_time_source</c></marker></tag> + <tag><marker id="system_info_os_monotonic_time_source"/><c>os_monotonic_time_source</c></tag> <item> <p>Returns a list containing information about the source of <seealso marker="erts:time_correction#OS_Monotonic_Time">OS monotonic time</seealso> that is used by the runtime system.</p> - <p>In case <c>[]</c> is returned, no OS monotonic time is + <p>If <c>[]</c> is returned, no OS monotonic time is available. 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. Currently the following - tuples may be part of the list, but more tuples may be + 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> <tag><c>{function, Function}</c></tag> - <item><p><c>Function</c> is the name of the funcion + <item><p><c>Function</c> is the name of the function used. This tuple always exist if OS monotonic time is available to the runtime system.</p></item> <tag><c>{clock_id, ClockId}</c></tag> <item><p>This tuple only exist if <c>Function</c> can be used with different clocks. <c>ClockId</c> - corresponds to the clock identifer used when calling + corresponds to the clock identifier used when calling <c>Function</c>.</p></item> <tag><c>{resolution, OsMonotonicTimeResolution}</c></tag> <item><p>Highest possible <seealso marker="time_correction#Time_Resolution">resolution</seealso> of current OS monotonic time source as parts per - second. If no resolution information can be retreived - from the OS, <c>OsMonotonicTimeResolution</c> will be + second. If no resolution information can be retrieved + from the OS, <c>OsMonotonicTimeResolution</c> is set to the resolution of the time unit of <c>Function</c>s return value. That is, the actual - resolution may be lower than + resolution can be lower than <c>OsMonotonicTimeResolution</c>. Also note that the resolution does not say anything about the <seealso marker="time_correction#Time_Accuracy">accuracy</seealso>, - and that the + and whether the <seealso marker="time_correction#Time_Precision">precision</seealso> - might not align with the resolution. You do, - however, know that the precision won't be - better than + do align with the resolution. You do, + however, know that the precision is not better than <c>OsMonotonicTimeResolution</c>.</p></item> <tag><c>{extended, Extended}</c></tag> @@ -6692,15 +7121,15 @@ ok <seealso marker="#type_time_unit">time unit</seealso>.</p></item> </taglist> </item> - <tag><marker id="system_info_os_system_time_source"><c>os_system_time_source</c></marker></tag> + <tag><marker id="system_info_os_system_time_source"/><c>os_system_time_source</c></tag> <item> <p>Returns a list containing information about the source of <seealso marker="erts:time_correction#OS_System_Time">OS 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. Currently the following - tuples may be part of the list, but more tuples may be + order if these tuples is undefined. The following + tuples can be part of the list, but more tuples can be introduced in the future:</p> <taglist> <tag><c>{function, Function}</c></tag> @@ -6710,26 +7139,25 @@ ok <tag><c>{clock_id, ClockId}</c></tag> <item><p>This tuple only exist if <c>Function</c> can be used with different clocks. <c>ClockId</c> - corresponds to the clock identifer used when calling + corresponds to the clock identifier used when calling <c>Function</c>.</p></item> <tag><c>{resolution, OsSystemTimeResolution}</c></tag> <item><p>Highest possible <seealso marker="time_correction#Time_Resolution">resolution</seealso> of current OS system time source as parts per - second. If no resolution information can be retreived - from the OS, <c>OsSystemTimeResolution</c> will be + second. If no resolution information can be retrieved + from the OS, <c>OsSystemTimeResolution</c> is set to the resolution of the time unit of <c>Function</c>s return value. That is, the actual resolution may be lower than <c>OsSystemTimeResolution</c>. Also note that the resolution does not say anything about the <seealso marker="time_correction#Time_Accuracy">accuracy</seealso>, - and that the + and whether the <seealso marker="time_correction#Time_Precision">precision</seealso> - might not align with the resolution. You do, - however, know that the precision won't be - better than + do align with the resolution. You do, + however, know that the precision is not better than <c>OsSystemTimeResolution</c>.</p></item> <tag><c>{parallel, Parallel}</c></tag> @@ -6745,130 +7173,136 @@ ok <seealso marker="#type_time_unit">time unit</seealso>.</p></item> </taglist> </item> - <tag><marker id="system_info_port_parallelism"><c>port_parallelism</c></marker></tag> - <item><p>Returns the default port parallelism scheduling hint used. - For more information see the - <seealso marker="erl#+spp">+spp</seealso> command line argument - of <seealso marker="erl">erl(1)</seealso>.</p></item> + <tag><c>port_parallelism</c></tag> + <item> + <marker id="system_info_port_parallelism"></marker> + <p>Returns the default port parallelism scheduling hint used. + For more information, see command-line argument + <seealso marker="erl#+spp">+spp</seealso> in <c>erl(1)</c>.</p></item> <tag><marker id="system_info_port_count"/><c>port_count</c></tag> <item> - <p>Returns the number of ports currently existing at - the local node as an integer. The same value as - <c>length(erlang:ports())</c> returns, but more efficient.</p> + <p>Returns the number of ports currently existing at the + local node. The value is given as an integer. This is + the same value as returned by + <c>length(erlang:ports())</c>, but more efficient.</p> </item> - <tag><marker id="system_info_port_limit"><c>port_limit</c></marker></tag> + <tag><c>port_limit</c></tag> <item> + <marker id="system_info_port_limit"></marker> <p>Returns the maximum number of simultaneously existing - ports at the local node as an integer. This limit - can be configured at startup by using the - <seealso marker="erl#+Q">+Q</seealso> - command line flag of - <seealso marker="erl">erl(1)</seealso>.</p> + ports at the local node as an integer. This limit can be + configured at startup by using command-line flag + <seealso marker="erl#+Q">+Q</seealso> in <c>erl(1)</c>.</p> </item> <tag><marker id="system_info_process_count"/><c>process_count</c></tag> <item> - <p>Returns the number of processes currently existing at - the local node as an integer. The same value as - <c>length(processes())</c> returns, but more efficient.</p> + <p>Returns the number of processes currently existing at the + local node. The value is given as an integer. This is + the same value as returned by + <c>length(processes())</c>, but more efficient.</p> </item> - <tag><marker id="system_info_process_limit"><c>process_limit</c></marker></tag> + <tag><c>process_limit</c></tag> <item> + <marker id="system_info_process_limit"></marker> <p>Returns the maximum number of simultaneously existing - processes at the local node as an integer. This limit - can be configured at startup by using the - <seealso marker="erl#+P">+P</seealso> - command line flag of - <seealso marker="erl">erl(1)</seealso>.</p> + processes at the local node. The value is given as an + integer. This limit can be configured at startup by using + command-line flag <seealso marker="erl#+P">+P</seealso> + in <c>erl(1)</c>.</p> </item> <tag><c>procs</c></tag> <item> <p>Returns a binary containing a string of process and port information formatted as in Erlang crash dumps. For more - information see the <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> chapter - in the ERTS User's Guide.</p> + information, see Section + <seealso marker="erts:crash_dump">"How to interpret the Erlang crash dumps"</seealso> + in the User's Guide.</p> </item> - <tag><marker id="system_info_scheduler_bind_type"><c>scheduler_bind_type</c></marker></tag> + <tag><c>scheduler_bind_type</c></tag> <item> - <p>Returns information on how user has requested + <marker id="system_info_scheduler_bind_type"></marker> + <p>Returns information about how the user has requested schedulers to be bound or not bound.</p> - <p><em>NOTE:</em> Even though user has requested - schedulers to be bound, they might have silently failed - to bind. In order to inspect actual scheduler bindings call - <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. - </p> - <p>For more information, see - the <c>erl</c> <seealso marker="erts:erl#+sbt">+sbt</seealso> - command line argument, and - <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. - </p> - </item> - <tag><marker id="system_info_scheduler_bindings"><c>scheduler_bindings</c></marker></tag> - <item> - <p>Returns information on currently used scheduler + <p>Notice that even though a user has requested + schedulers to be bound, they can silently have failed + to bind. To inspect the scheduler bindings, call + <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>.</p> + <p>For more information, see command-line argument + <seealso marker="erts:erl#+sbt">+sbt</seealso> + in <c>erl(1)</c> and + <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>.</p> + </item> + <tag><c>scheduler_bindings</c></tag> + <item> + <marker id="system_info_scheduler_bindings"></marker> + <p>Returns information about the currently used scheduler bindings.</p> <p>A tuple of a size equal to - <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso> is returned. The elements of the tuple are integers + <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso> + is returned. The tuple elements are integers or the atom <c>unbound</c>. Logical processor identifiers are represented as integers. The <c>N</c>th element of the tuple equals the current binding for the scheduler with the scheduler identifier equal to - <c>N</c>. E.g., if the schedulers have been bound, + <c>N</c>. For example, if the schedulers are bound, <c>element(erlang:system_info(scheduler_id), - erlang:system_info(scheduler_bindings))</c> will return + erlang:system_info(scheduler_bindings))</c> returns the identifier of the logical processor that the calling - process is executing on. - </p> - <p>Note that only schedulers online can be bound to logical + process is executing on.</p> + <p>Notice that only schedulers online can be bound to logical processors.</p> - <p>For more information, see - the <c>erl</c> <seealso marker="erts:erl#+sbt">+sbt</seealso> - command line argument, + <p>For more information, see command-line argument + <seealso marker="erts:erl#+sbt">+sbt</seealso> + in <c>erl(1)</c> and <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>. </p> </item> - <tag><marker id="system_info_scheduler_id"><c>scheduler_id</c></marker></tag> + <tag><c>scheduler_id</c></tag> <item> - <p>Returns the scheduler id (<c>SchedulerId</c>) of the + <marker id="system_info_scheduler_id"></marker> + <p>Returns the scheduler ID (<c>SchedulerId</c>) of the scheduler thread that the calling process is executing - on. <c><anno>SchedulerId</anno></c> is a positive integer; where - <c><![CDATA[1 <= SchedulerId <= erlang:system_info(schedulers)]]></c>. See also + on. <c><anno>SchedulerId</anno></c> is a positive integer, + where + <c><![CDATA[1 <= SchedulerId <= erlang:system_info(schedulers)]]></c>. + See also <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>.</p> </item> - <tag><marker id="system_info_schedulers"><c>schedulers</c></marker></tag> + <tag><c>schedulers</c></tag> <item> + <marker id="system_info_schedulers"></marker> <p>Returns the number of scheduler threads used by the emulator. Scheduler threads online schedules Erlang processes and Erlang ports, and execute Erlang code - and Erlang linked in driver code.</p> + and Erlang linked-in driver code.</p> <p>The number of scheduler threads is determined at - emulator boot time and cannot be changed after - that. The amount of schedulers online can - however be changed at any time.</p> - <p>See also <seealso marker="#system_flag_schedulers_online">erlang:system_flag(schedulers_online, SchedulersOnline)</seealso>, + emulator boot time and cannot be changed later. + However, the number of schedulers online can + be changed at any time.</p> + <p>See also + <seealso marker="#system_flag_schedulers_online">erlang:system_flag(schedulers_online, SchedulersOnline)</seealso>, <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>, <seealso marker="#system_info_scheduler_id">erlang:system_info(scheduler_id)</seealso>, <seealso marker="#system_flag_multi_scheduling">erlang:system_flag(multi_scheduling, BlockState)</seealso>, - <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, and - and <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>.</p> + <seealso marker="#system_info_multi_scheduling">erlang:system_info(multi_scheduling)</seealso>, + and + <seealso marker="#system_info_multi_scheduling_blockers">erlang:system_info(multi_scheduling_blockers)</seealso>.</p> </item> - <tag><marker id="system_info_schedulers_online"><c>schedulers_online</c></marker></tag> + <tag><c>schedulers_online</c></tag> <item> - <p>Returns the amount of schedulers online. The scheduler - identifiers of schedulers online satisfy the following - relationship: - <c><![CDATA[1 <= SchedulerId <= erlang:system_info(schedulers_online)]]></c>. - </p> + <marker id="system_info_schedulers_online"></marker> + <p>Returns the number of schedulers online. The scheduler + identifiers of schedulers online satisfy the relationship + <c><![CDATA[1 <= SchedulerId <= erlang:system_info(schedulers_online)]]></c>.</p> <p>For more information, see - <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso>, + <seealso marker="#system_info_schedulers">erlang:system_info(schedulers)</seealso> and - <seealso marker="#system_flag_schedulers_online">erlang:system_flag(schedulers_online, SchedulersOnline)</seealso>. - </p> <name name="system_info" arity="1" clause_i="49"/> - + <seealso marker="#system_flag_schedulers_online">erlang:system_flag(schedulers_online, SchedulersOnline)</seealso>.</p> </item> <tag><c>smp_support</c></tag> <item> <p>Returns <c>true</c> if the emulator has been compiled - with smp support; otherwise, <c>false</c>.</p> + with SMP support, otherwise <c>false</c> is returned.</p> </item> <tag><marker id="system_info_start_time"/><c>start_time</c></tag> <item><p>The <seealso marker="#monotonic_time/0">Erlang monotonic @@ -6880,7 +7314,7 @@ ok <tag><c>system_version</c></tag> <item> <p>Returns a string containing version number and - some important properties such as the number of schedulers.</p> + some important properties, such as the number of schedulers.</p> </item> <tag><c>system_architecture</c></tag> <item> @@ -6890,23 +7324,28 @@ ok <tag><c>threads</c></tag> <item> <p>Returns <c>true</c> if the emulator has been compiled - with thread support; otherwise, <c>false</c> is - returned.</p> + with thread support, otherwise <c>false</c> is returned.</p> </item> - <tag><marker id="system_info_thread_pool_size"><c>thread_pool_size</c></marker></tag> + <tag><c>thread_pool_size</c></tag> <item> + <marker id="system_info_thread_pool_size"></marker> <p>Returns the number of async threads in the async thread pool used for asynchronous driver calls - (<seealso marker="erts:erl_driver#driver_async">driver_async()</seealso>) - as an integer.</p> + (<seealso marker="erts:erl_driver#driver_async">driver_async()</seealso>). + The value is given as an integer.</p> </item> - <tag><marker id="system_info_time_correction"/><c>time_correction</c></tag> - <item><p>Returns a boolean value indicating whether + + <tag><c>time_correction</c></tag> + <item> + <marker id="system_info_time_correction"></marker> + <p>Returns a boolean value indicating whether <seealso marker="time_correction#Time_Correction">time correction</seealso> is enabled or not. </p></item> - <tag><marker id="system_info_time_offset"/><c>time_offset</c></tag> - <item><p>Returns the state of the time offset:</p> + <tag><c>time_offset</c></tag> + <item> + <marker id="system_info_time_offset"></marker> + <p>Returns the state of the time offset:</p> <taglist> <tag><c>preliminary</c></tag> <item><p>The time offset is preliminary, and will be changed @@ -6916,19 +7355,18 @@ ok time warp mode</seealso>.</p></item> <tag><c>final</c></tag> - <item><p>The time offset is final. This - either due to the use of the + <item><p>The time offset is final. This either because <seealso marker="time_correction#No_Time_Warp_Mode">no - time warp mode</seealso>, or due to the time offset having - been finalized when using the + time warp mode</seealso> is used, or because the time + offset have been finalized when <seealso marker="time_correction#Single_Time_Warp_Mode">single - time warp mode</seealso>.</p></item> + time warp mode</seealso> is used.</p></item> <tag><c>volatile</c></tag> - <item><p>The time offset is volatile. That is, it may - change at any time. This due to the + <item><p>The time offset is volatile. That is, it can + change at any time. This is because <seealso marker="time_correction#Multi_Time_Warp_Mode">multi - time warp mode</seealso> being used.</p></item> + time warp mode</seealso> is used.</p></item> </taglist> </item> <tag><marker id="system_info_time_warp_mode"/><c>time_warp_mode</c></tag> @@ -6938,19 +7376,20 @@ ok <taglist> <tag><c>no_time_warp</c></tag> <item><p>The <seealso marker="time_correction#No_Time_Warp_Mode">no - time warp mode</seealso> is being used.</p></item> + time warp mode</seealso> is used.</p></item> <tag><c>single_time_warp</c></tag> <item><p>The <seealso marker="time_correction#Single_Time_Warp_Mode">single - time warp mode</seealso> is being used.</p></item> + time warp mode</seealso> is used.</p></item> <tag><c>multi_time_warp</c></tag> <item><p>The <seealso marker="time_correction#Multi_Time_Warp_Mode">multi - time warp mode</seealso> is being used.</p></item> + time warp mode</seealso> is used.</p></item> </taglist> </item> - <tag><marker id="system_info_tolerant_timeofday"><c>tolerant_timeofday</c></marker></tag> + <tag><c>tolerant_timeofday</c></tag> <item> + <marker id="system_info_tolerant_timeofday"></marker> <p>Returns whether a pre erts-7.0 backwards compatible compensation for sudden changes of system time is <c>enabled</c> or <c>disabled</c>. Such compensation is <c>enabled</c> when the @@ -6961,90 +7400,92 @@ ok </item> <tag><c>trace_control_word</c></tag> <item> - <p>Returns the value of the node's trace control word. - For more information see documentation of the function - <c>get_tcw</c> in "Match Specifications in Erlang", - <seealso marker="erts:match_spec#get_tcw">ERTS User's Guide</seealso>.</p> + <p>Returns the value of the node trace control word. For + more information, see function <c>get_tcw</c> in Section + <seealso marker="erts:match_spec#get_tcw">Match Specifications in Erlang</seealso> in the User's Guide.</p> </item> - <tag><marker id="update_cpu_info"><c>update_cpu_info</c></marker></tag> + <tag><c>update_cpu_info</c></tag> <item> - <p>The runtime system rereads the CPU information available and - updates its internally stored information about the - <seealso marker="#system_info_cpu_topology_detected">detected CPU - topology</seealso> and the amount of logical processors + <marker id="update_cpu_info"></marker> + <p>The runtime system rereads the CPU information available + and updates its internally stored information about the + <seealso marker="#system_info_cpu_topology_detected">detected + CPU topology</seealso> and the number of logical processors <seealso marker="#logical_processors">configured</seealso>, <seealso marker="#logical_processors_online">online</seealso>, and - <seealso marker="#logical_processors_available">available</seealso>. - If the CPU information has changed since the last time it was read, - the atom <c>changed</c> is returned; otherwise, the atom - <c>unchanged</c> is returned. If the CPU information has changed + <seealso marker="#logical_processors_available">available</seealso>.</p> + <p>If the CPU information has changed since the last time + it was read, the atom <c>changed</c> is returned, otherwise + the atom <c>unchanged</c>. If the CPU information has changed, you probably want to - <seealso marker="#system_flag_schedulers_online">adjust the amount - of schedulers online</seealso>. You typically want to have as - many schedulers online as - <seealso marker="#logical_processors_available">logical processors - available</seealso>. - </p> + <seealso marker="#system_flag_schedulers_online">adjust the + number of schedulers online</seealso>. You typically want + to have as many schedulers online as + <seealso marker="#logical_processors_available">logical + processors available</seealso>.</p> </item> - <tag><marker id="system_info_version"><c>version</c></marker></tag> + <tag><c>version</c></tag> <item> + <marker id="system_info_version"></marker> <p>Returns a string containing the version number of the emulator.</p> </item> <tag><c>wordsize</c></tag> <item> - <p>Same as <c>{wordsize, internal}.</c></p> + <p>Same as <c>{wordsize, internal}</c>.</p> </item> <tag><c>{wordsize, internal}</c></tag> <item> <p>Returns the size of Erlang term words in bytes as an - integer, i.e. on a 32-bit architecture 4 is returned, - and on a pure 64-bit architecture 8 is returned. On a + integer, that is, 4 is returned on a 32-bit architecture, + and 8 is returned on a pure 64-bit architecture. On a halfword 64-bit emulator, 4 is returned, as the Erlang - terms are stored using a virtual wordsize of half the - system's wordsize.</p> + terms are stored using a virtual word size of half the + system word size.</p> </item> <tag><c>{wordsize, external}</c></tag> <item> - <p>Returns the true wordsize of the emulator, i.e. the size - of a pointer, in bytes as an integer. On a pure 32-bit - architecture 4 is returned, on both a halfword and pure + <p>Returns the true word size of the emulator, that is, + the size of a pointer. The value is given in bytes + as an integer. On a pure 32-bit architecture, 4 is + returned. On both a half word and on a pure 64-bit architecture, 8 is returned.</p> </item> </taglist> <note> - <p>The <c>scheduler</c> argument has changed name to - <c>scheduler_id</c>. This in order to avoid mixup with - the <c>schedulers</c> argument. The <c>scheduler</c> - argument was introduced in ERTS version 5.5 and renamed - in ERTS version 5.5.1.</p> + <p>Argument <c>scheduler</c> has changed name to + <c>scheduler_id</c> to avoid mix up with argument + <c>schedulers</c>. Argument <c>scheduler</c> was + introduced in <c>ERTS</c> 5.5 and renamed in + <c>ERTS</c> 5.5.1.</p> </note> </desc> </func> <func> <name name="system_monitor" arity="0"/> + <fsummary>Current system performance monitoring settings.</fsummary> <type name="system_monitor_option"/> - <fsummary>Current system performance monitoring settings</fsummary> <desc> <p>Returns the current system monitoring settings set by <seealso marker="#system_monitor/2">erlang:system_monitor/2</seealso> - as <c>{<anno>MonitorPid</anno>, <anno>Options</anno>}</c>, or <c>undefined</c> if there - are no settings. The order of the options may be different + as <c>{<anno>MonitorPid</anno>, <anno>Options</anno>}</c>, + or <c>undefined</c> if there + are no settings. The order of the options can be different from the one that was set.</p> </desc> </func> <func> <name name="system_monitor" arity="1"/> + <fsummary>Sets or clears system performance monitoring options.</fsummary> <type name="system_monitor_option"/> - <fsummary>Set or clear system performance monitoring options</fsummary> <desc> - <p>When called with the argument <c>undefined</c>, all + <p>When called with argument <c>undefined</c>, all system performance monitoring settings are cleared.</p> - <p>Calling the function with <c>{<anno>MonitorPid</anno>, <anno>Options</anno>}</c> as - argument, is the same as calling - <seealso marker="#system_monitor/2">erlang:system_monitor(<anno>MonitorPid</anno>, <anno>Options</anno>)</seealso>.</p> + <p>Calling the function with <c>{<anno>MonitorPid</anno>, + <anno>Options</anno>}</c> as argument is the same as calling + <seealso marker="#system_monitor/2"><c>erlang:system_monitor(<anno>MonitorPid</anno>, <anno>Options</anno>)</c></seealso>.</p> <p>Returns the previous system monitor settings just like <seealso marker="#system_monitor/0">erlang:system_monitor/0</seealso>.</p> </desc> @@ -7052,102 +7493,101 @@ ok <func> <name name="system_monitor" arity="2"/> + <fsummary>Sets system performance monitoring options.</fsummary> <type name="system_monitor_option"/> - <fsummary>Set system performance monitoring options</fsummary> <desc> - <p>Sets system performance monitoring options. <c><anno>MonitorPid</anno></c> - is a local pid that will receive system monitor messages, and - the second argument is a list of monitoring options:</p> + <p>Sets the system performance monitoring options. + <c><anno>MonitorPid</anno></c> is a local process identifier (pid) + receiving system monitor messages. The + second argument is a list of monitoring options:</p> <taglist> <tag><c>{long_gc, Time}</c></tag> <item> <p>If a garbage collection in the system takes at least - <c>Time</c> wallclock milliseconds, a message + <c>Time</c> wall clock milliseconds, a message <c>{monitor, GcPid, long_gc, Info}</c> is sent to - <c><anno>MonitorPid</anno></c>. <c>GcPid</c> is the pid that was - garbage collected and <c>Info</c> is a list of two-element - tuples describing the result of the garbage collection. - One of the tuples is <c>{timeout, GcTime}</c> where - <c>GcTime</c> is the actual time for the garbage + <c><anno>MonitorPid</anno></c>. <c>GcPid</c> is the pid that + was garbage collected. <c>Info</c> is a list of two-element + tuples describing the result of the garbage collection.</p> + <p>One of the tuples is <c>{timeout, GcTime}</c>, where + <c>GcTime</c> is the time for the garbage collection in milliseconds. The other tuples are - tagged with <c>heap_size</c>, <c>heap_block_size</c>, - <c>stack_size</c>, <c>mbuf_size</c>, <c>old_heap_size</c>, - and <c>old_heap_block_size</c>. These tuples are - explained in the documentation of the - <seealso marker="#gc_start">gc_start</seealso> - trace message (see - <seealso marker="#trace/3">erlang:trace/3</seealso>). - New tuples may be added, and the order of the tuples in - the <c>Info</c> list may be changed at any time without prior - notice. - </p> + tagged with <c>heap_size</c>, <c>heap_block_size</c> + <c>stack_size</c>, <c>mbuf_size</c>, <c>old_heap_size</c>, + and <c>old_heap_block_size</c>. These tuples are + explained in the description of trace message + <seealso marker="#gc_start">gc_start</seealso> (see + <seealso marker="#trace/3">erlang:trace/3</seealso>). + New tuples can be added, and the order of the tuples in + the <c>Info</c> list can be changed at any time without + prior notice.</p> </item> <tag><c>{long_schedule, Time}</c></tag> <item> - <p>If a process or port in the system runs uninterrupted + <p>If a process or port in the system runs uninterrupted for at least <c>Time</c> wall clock milliseconds, a message <c>{monitor, PidOrPort, long_schedule, Info}</c> is sent to <c>MonitorPid</c>. <c>PidOrPort</c> is the - process or port that was running and <c>Info</c> is a - list of two-element tuples describing the event. In case - of a <c>pid()</c>, the tuples <c>{timeout, Millis}</c>, - <c>{in, Location}</c> and <c>{out, Location}</c> will be + process or port that was running. <c>Info</c> is a + list of two-element tuples describing the event.</p> + <p>If a <c>pid()</c>, the tuples <c>{timeout, Millis}</c>, + <c>{in, Location}</c>, and <c>{out, Location}</c> are present, where <c>Location</c> is either an MFA (<c>{Module, Function, Arity}</c>) describing the function where the process was scheduled in/out, or the - atom <c>undefined</c>. In case of a <c>port()</c>, the + atom <c>undefined</c>.</p> + <p>If a <c>port()</c>, the tuples <c>{timeout, Millis}</c> and <c>{port_op,Op}</c> - will be present. <c>Op</c> will be one of <c>proc_sig</c>, + are present. <c>Op</c> is one of <c>proc_sig</c>, <c>timeout</c>, <c>input</c>, <c>output</c>, - <c>event</c> or <c>dist_cmd</c>, depending on which - driver callback was executing. <c>proc_sig</c> is an - internal operation and should never appear, while the + <c>event</c>, or <c>dist_cmd</c>, depending on which + driver callback was executing.</p> + <p><c>proc_sig</c> is an + internal operation and is never to appear, while the others represent the corresponding driver callbacks <c>timeout</c>, <c>ready_input</c>, <c>ready_output</c>, - <c>event</c> and finally <c>outputv</c> (when the port - is used by distribution). The <c>Millis</c> value in - the <c>timeout</c> tuple will tell you the actual - uninterrupted execution time of the process or port, - which will always be <c>>=</c> the <c>Time</c> value - supplied when starting the trace. New tuples may be - added to the <c>Info</c> list in the future, and the - order of the tuples in the list may be changed at any - time without prior notice. - </p> - <p>This can be used to detect problems with NIF's or - drivers that take too long to execute. Generally, 1 ms - is considered a good maximum time for a driver callback - or a NIF. However, a time sharing system should usually - consider everything below 100 ms as "possible" and - fairly "normal". Schedule times above that might however - indicate swapping or a NIF/driver that is - misbehaving. Misbehaving NIF's and drivers could cause - bad resource utilization and bad overall performance of - the system.</p> + <c>event</c>, and <c>outputv</c> (when the port + is used by distribution). Value <c>Millis</c> in + the <c>timeout</c> tuple informs about the + uninterrupted execution time of the process or port, which + always is equal to or higher than the <c>Time</c> value + supplied when starting the trace. New tuples can be + added to the <c>Info</c> list in a future release. The + order of the tuples in the list can be changed at any + time without prior notice.</p> + <p>This can be used to detect problems with NIFs or + drivers that take too long to execute. 1 ms is + considered a good maximum time for a driver callback + or a NIF. However, a time-sharing system is usually to + consider everything below 100 ms as "possible" and + fairly "normal". However, longer schedule times can + indicate swapping or a misbehaving NIF/driver. + Misbehaving NIFs and drivers can cause bad resource + utilization and bad overall system performance.</p> </item> <tag><c>{large_heap, Size}</c></tag> <item> <p>If a garbage collection in the system results in the allocated size of a heap being at least <c>Size</c> words, a message <c>{monitor, GcPid, large_heap, Info}</c> - is sent to <c><anno>MonitorPid</anno></c>. <c>GcPid</c> and <c>Info</c> - are the same as for <c>long_gc</c> above, except that - the tuple tagged with <c>timeout</c> is not present. - <em>Note</em>: As of erts version 5.6 the monitor message - is sent if the sum of the sizes of all memory blocks allocated - for all heap generations is equal to or larger than <c>Size</c>. - Previously the monitor message was sent if the memory block - allocated for the youngest generation was equal to or larger - than <c>Size</c>. - </p> + is sent to <c><anno>MonitorPid</anno></c>. + <c>GcPid</c> and <c>Info</c> + are the same as for <c>long_gc</c> earlier, except that + the tuple tagged with <c>timeout</c> is not present.</p> + <p>As of <c>ERTS</c> 5.6, the monitor message is sent + if the sum of the sizes of all memory blocks allocated + for all heap generations is equal to or higher than <c>Size</c>. + Previously the monitor message was sent if the memory block + allocated for the youngest generation was equal to or higher + than <c>Size</c>.</p> </item> <tag><c>busy_port</c></tag> <item> <p>If a process in the system gets suspended because it sends to a busy port, a message <c>{monitor, SusPid, busy_port, Port}</c> is sent to - <c><anno>MonitorPid</anno></c>. <c>SusPid</c> is the pid that got - suspended when sending to <c>Port</c>.</p> + <c><anno>MonitorPid</anno></c>. <c>SusPid</c> is the pid + that got suspended when sending to <c>Port</c>.</p> </item> <tag><c>busy_dist_port</c></tag> <item> @@ -7155,8 +7595,8 @@ ok sends to a process on a remote node whose inter-node communication was handled by a busy port, a message <c>{monitor, SusPid, busy_dist_port, Port}</c> is sent to - <c><anno>MonitorPid</anno></c>. <c>SusPid</c> is the pid that got - suspended when sending through the inter-node + <c><anno>MonitorPid</anno></c>. <c>SusPid</c> is the pid + that got suspended when sending through the inter-node communication port <c>Port</c>.</p> </item> </taglist> @@ -7165,74 +7605,76 @@ ok <note> <p>If a monitoring process gets so large that it itself starts to cause system monitor messages when garbage - collecting, the messages will enlarge the process's + collecting, the messages enlarge the process message queue and probably make the problem worse.</p> <p>Keep the monitoring process neat and do not set the system monitor limits too tight.</p> </note> - <p>Failure: <c>badarg</c> if <c><anno>MonitorPid</anno></c> does not exist or is not a local process.</p> + <p>Failures:</p> + <taglist> + <tag><c>badarg</c></tag> + <item>If <c><anno>MonitorPid</anno></c> does not exist.</item> + <tag><c>badarg</c></tag> + <item>If <c><anno>MonitorPid</anno></c> is not a local process.</item> + </taglist> </desc> </func> <func> <name name="system_profile" arity="0"/> + <fsummary>Current system profiling settings.</fsummary> <type name="system_profile_option"/> - <fsummary>Current system profiling settings</fsummary> <desc> <p>Returns the current system profiling settings set by <seealso marker="#system_profile/2">erlang:system_profile/2</seealso> - as <c>{<anno>ProfilerPid</anno>, <anno>Options</anno>}</c>, or <c>undefined</c> if there - are no settings. The order of the options may be different + as <c>{<anno>ProfilerPid</anno>, <anno>Options</anno>}</c>, + or <c>undefined</c> if there + are no settings. The order of the options can be different from the one that was set.</p> </desc> </func> <func> <name name="system_profile" arity="2"/> + <fsummary>Current system profiling settings.</fsummary> <type name="system_profile_option"/> - <fsummary>Current system profiling settings</fsummary> <desc> <p>Sets system profiler options. <c><anno>ProfilerPid</anno></c> - is a local pid or port that will receive profiling messages. The - receiver is excluded from all profiling. + is a local process identifier (pid) or port receiving profiling + messages. The receiver is excluded from all profiling. The second argument is a list of profiling options:</p> <taglist> <tag><c>exclusive</c></tag> <item> - <p> - If a synchronous call to a port from a process is done, the + <p>If a synchronous call to a port from a process is done, the calling process is considered not runnable during the call runtime to the port. The calling process is notified as - <c>inactive</c> and subsequently <c>active</c> when the port - callback returns. - </p> + <c>inactive</c>, and later <c>active</c> when the port + callback returns.</p> </item> <tag><c>runnable_procs</c></tag> <item> - <p>If a process is put into or removed from the run queue a message, - <c>{profile, Pid, State, Mfa, Ts}</c>, is sent to - <c><anno>ProfilerPid</anno></c>. Running processes that is reinserted into the - run queue after having been preemptively scheduled out will not trigger this - message. - </p> + <p>If a process is put into or removed from the run queue, a + message, <c>{profile, Pid, State, Mfa, Ts}</c>, is sent to + <c><anno>ProfilerPid</anno></c>. Running processes that + are reinserted into the run queue after having been + preempted do not trigger this message.</p> </item> <tag><c>runnable_ports</c></tag> <item> - <p>If a port is put into or removed from the run queue a message, - <c>{profile, Port, State, 0, Ts}</c>, is sent to - <c><anno>ProfilerPid</anno></c>. - </p> + <p>If a port is put into or removed from the run queue, a + message, <c>{profile, Port, State, 0, Ts}</c>, is sent to + <c><anno>ProfilerPid</anno></c>.</p> </item> <tag><c>scheduler</c></tag> <item> - <p>If a scheduler is put to sleep or awoken a message, - <c>{profile, scheduler, Id, State, NoScheds, Ts}</c>, is sent - to <c><anno>ProfilerPid</anno></c>. - </p> + <p>If a scheduler is put to sleep or awoken, a message, + <c>{profile, scheduler, Id, State, NoScheds, Ts}</c>, is + sent to <c><anno>ProfilerPid</anno></c>.</p> </item> </taglist> - <note><p><c>erlang:system_profile</c> is considered experimental and - its behaviour may change in the future.</p> + <note><p><c>erlang:system_profile</c> is considered experimental + and its behavior can change in a future release.</p> </note> </desc> </func> @@ -7276,11 +7718,12 @@ ok </func> <func> <name name="term_to_binary" arity="1"/> - <fsummary>Encode a term to an Erlang external term format binary</fsummary> + <fsummary>Encodes a term to an Erlang external term format binary.</fsummary> <desc> - <p>Returns a binary data object which is the result of encoding - <c><anno>Term</anno></c> according to the Erlang external term format.</p> - <p>This can be used for a variety of purposes, for example + <p>Returns a binary data object that is the result of encoding + <c><anno>Term</anno></c> according to the Erlang external + term format.</p> + <p>This can be used for various purposes, for example, writing a term to a file in an efficient way, or sending an Erlang term to some type of communications channel not supported by distributed Erlang.</p> @@ -7288,67 +7731,81 @@ ok <seealso marker="#binary_to_term/1">binary_to_term/1</seealso>.</p> </desc> </func> + <func> <name name="term_to_binary" arity="2"/> - <fsummary>Encode a term to en Erlang external term format binary</fsummary> - <desc> - <p>Returns a binary data object which is the result of encoding - <c><anno>Term</anno></c> according to the Erlang external term format.</p> - <p>If the option <c>compressed</c> is provided, the external - term format will be compressed. The compressed format is - automatically recognized by <c>binary_to_term/1</c> in R7B and later.</p> - <p>It is also possible to specify a compression level by giving - the option <c>{compressed, <anno>Level</anno>}</c>, where <c><anno>Level</anno></c> is an - integer from 0 through 9. <c>0</c> means that no compression - will be done (it is the same as not giving any <c>compressed</c> option); - <c>1</c> will take the least time but may not compress as well as - the higher levels; <c>9</c> will take the most time and may produce - a smaller result. Note the "mays" in the preceding sentence; depending - on the input term, level 9 compression may or may not produce a smaller - result than level 1 compression.</p> - <p>Currently, <c>compressed</c> gives the same result as - <c>{compressed, 6}</c>.</p> - <p>The option <c>{minor_version, <anno>Version</anno>}</c> can be use to control - some details of the encoding. This option was - introduced in R11B-4. Currently, the allowed values for <c><anno>Version</anno></c> - are <c>0</c> and <c>1</c>.</p> - <p><c>{minor_version, 1}</c> is since 17.0 the default, it forces any floats in - the term to be encoded - in a more space-efficient and exact way (namely in the 64-bit IEEE format, - rather than converted to a textual representation). <c>binary_to_term/1</c> - in R11B-4 and later is able decode this representation.</p> - <p><c>{minor_version, 0}</c> meaning that floats - will be encoded using a textual representation; this option is useful if - you want to ensure that releases prior to R11B-4 can decode resulting + <fsummary>Encodes a term to en Erlang external term format binary.</fsummary> + <desc> + <p>Returns a binary data object that is the result of encoding + <c><anno>Term</anno></c> according to the Erlang external + term format.</p> + <p>If option <c>compressed</c> is provided, the external term + format is compressed. The compressed format is automatically + recognized by <c>binary_to_term/1</c> as from Erlang R7B.</p> + <p>A compression level can be specified by giving option + <c>{compressed, <anno>Level</anno>}</c>. + <c><anno>Level</anno></c> is an integer + with range 0..9, where:</p> + <list type="bulleted"> + <item><c>0</c> - No compression is done (it is the same as + giving no <c>compressed</c> option).</item> + <item><c>1</c> - Takes least time but may not compress + as well as the higher levels.</item> + <item><c>6</c> - Default level when option <c>compressed</c> + is provided.</item> + <item><c>9</c> - Takes most time and tries to produce a smaller + result. Notice "tries" in the preceding sentence; depending + on the input term, level 9 compression either does or does + not produce a smaller result than level 1 compression.</item> + </list> + <p>Option <c>{minor_version, <anno>Version</anno>}</c> + can be used to control + some encoding details. This option was introduced in OTP R11B-4. + The valid values for <c><anno>Version</anno></c> are + <c>0</c> and <c>1</c>.</p> + <p>As from OTP 17.0, <c>{minor_version, 1}</c> is the default. It + forces any floats in the term to be encoded in a more + space-efficient and exact way (namely in the 64-bit IEEE format, + rather than converted to a textual representation).</p> + <p>As from OTP R11B-4, <c>binary_to_term/1</c> can decode this + representation.</p> + <p><c>{minor_version, 0}</c> means that floats are encoded + using a textual representation. This option is useful to + ensure that releases before OTP R11B-4 can decode resulting binary.</p> <p>See also <seealso marker="#binary_to_term/1">binary_to_term/1</seealso>.</p> </desc> </func> + <func> <name name="throw" arity="1"/> - <fsummary>Throw an exception</fsummary> + <fsummary>Throws an exception.</fsummary> <desc> <p>A non-local return from a function. If evaluated within a - <c>catch</c>, <c>catch</c> will return the value <c><anno>Any</anno></c>.</p> + <c>catch</c>, <c>catch</c> returns value <c><anno>Any</anno></c>.</p> + <p>Example:</p> <pre> > <input>catch throw({hello, there}).</input> {hello,there}</pre> <p>Failure: <c>nocatch</c> if not evaluated within a catch.</p> </desc> </func> + <func> <name name="time" arity="0"/> - <fsummary>Current time</fsummary> + <fsummary>Current time.</fsummary> <desc> <p>Returns the current time as <c>{Hour, Minute, Second}</c>.</p> - <p>The time zone and daylight saving time correction depend on + <p>The time zone and Daylight Saving Time correction depend on the underlying OS.</p> + <p>Example:</p> <pre> > <input>time().</input> {9,42,44}</pre> </desc> </func> + <func> <name name="time_offset" arity="0"/> <fsummary>Current time offset</fsummary> @@ -7399,14 +7856,14 @@ ok </func> <func> <name name="timestamp" arity="0"/> - <type name="timestamp"/> <fsummary>Current Erlang System time</fsummary> + <type name="timestamp"/> <desc> <p>Returns current <seealso marker="time_correction#Erlang_System_Time">Erlang system time</seealso> on the format <c>{MegaSecs, Secs, MicroSecs}</c>. This format is - the same that <seealso marker="kernel:os#timestamp/0"><c>os:timestamp/0</c></seealso> - and the now deprecated <seealso marker="#now/0"><c>erlang:now/0</c></seealso> + the same as <seealso marker="kernel:os#timestamp/0"><c>os:timestamp/0</c></seealso> + and the deprecated <seealso marker="#now/0"><c>erlang:now/0</c></seealso> uses. The reason for the existence of <c>erlang:timestamp()</c> is purely to simplify usage for existing code that assumes this timestamp format. Current Erlang system time can more efficiently be retrieved in @@ -7420,7 +7877,7 @@ timestamp() -> Secs = ErlangSystemTime div 1000000 - MegaSecs*1000000, MicroSecs = ErlangSystemTime rem 1000000, {MegaSecs, Secs, MicroSecs}.</code> - <p>It however use a native implementation which does + <p>The BIF uses a native implementation which does not build garbage on the heap and with slightly better performance.</p> @@ -7433,186 +7890,190 @@ timestamp() -> </func> <func> <name name="tl" arity="1"/> - <fsummary>Tail of a list</fsummary> + <fsummary>Tail of a list.</fsummary> <desc> - <p>Returns the tail of <c><anno>List</anno></c>, that is, the list minus - the first element.</p> + <p>Returns the tail of <c><anno>List</anno></c>, that is, + the list minus the first element, for example:</p> <pre> > <input>tl([geesties, guilies, beasties]).</input> [guilies, beasties]</pre> <p>Allowed in guard tests.</p> - <p>Failure: <c>badarg</c> if <c><anno>List</anno></c> is the empty list [].</p> + <p>Failure: <c>badarg</c> if <c><anno>List</anno></c> + is the empty list <c>[]</c>.</p> </desc> </func> + <func> <name name="trace" arity="3"/> + <fsummary>Sets trace flags for a process or processes.</fsummary> <type name="trace_flag"/> - <fsummary>Set trace flags for a process or processes</fsummary> <desc> <p>Turns on (if <c><anno>How</anno> == true</c>) or off (if - <c><anno>How</anno> == false</c>) the trace flags in <c><anno>FlagList</anno></c> for - the process or processes represented by <c><anno>PidSpec</anno></c>.</p> - <p><c><anno>PidSpec</anno></c> is either a pid for a local process, or one of - the following atoms:</p> + <c><anno>How</anno> == false</c>) the trace flags in + <c><anno>FlagList</anno></c> for + the process or processes represented by + <c><anno>PidSpec</anno></c>.</p> + <p><c><anno>PidSpec</anno></c> is either a process identifier + (pid) for a local process, or one of the following atoms:</p> <taglist> <tag><c>existing</c></tag> <item> - <p>All processes currently existing.</p> + <p>All currently existing processes.</p> </item> <tag><c>new</c></tag> <item> - <p>All processes that will be created in the future.</p> + <p>All processes that are created in the future.</p> </item> <tag><c>all</c></tag> <item> <p>All currently existing processes and all processes that - will be created in the future.</p> + are created in the future.</p> </item> </taglist> - <p><c><anno>FlagList</anno></c> can contain any number of the following - flags (the "message tags" refers to the list of messages - following below):</p> + <p><c><anno>FlagList</anno></c> can contain any number of the + following flags (the "message tags" refers to the list of + <seealso marker="#trace_3_trace_messages">trace messages</seealso>):</p> <taglist> <tag><c>all</c></tag> <item> - <p>Set all trace flags except <c>{tracer, Tracer}</c> and - <c>cpu_timestamp</c> that are in their nature different + <p>Sets all trace flags except <c>{tracer, Tracer}</c> and + <c>cpu_timestamp</c>, which are in their nature different than the others.</p> </item> <tag><c>send</c></tag> <item> - <p>Trace sending of messages.</p> - <p>Message tags: <c>send</c>, + <p>Traces sending of messages.</p> + <p>Message tags: <c>send</c> and <c>send_to_non_existing_process</c>.</p> </item> <tag><c>'receive'</c></tag> <item> - <p>Trace receiving of messages.</p> + <p>Traces receiving of messages.</p> <p>Message tags: <c>'receive'</c>.</p> </item> <tag><c>procs</c></tag> <item> - <p>Trace process related events.</p> + <p>Traces process-related events.</p> <p>Message tags: <c>spawn</c>, <c>exit</c>, <c>register</c>, <c>unregister</c>, <c>link</c>, - <c>unlink</c>, <c>getting_linked</c>, + <c>unlink</c>, <c>getting_linked</c>, and <c>getting_unlinked</c>.</p> </item> <tag><c>call</c></tag> <item> - <p>Trace certain function calls. Specify which function + <p>Traces certain function calls. Specify which function calls to trace by calling <seealso marker="#trace_pattern/3">erlang:trace_pattern/3</seealso>.</p> - <p>Message tags: <c>call</c>, <c>return_from</c>.</p> + <p>Message tags: <c>call</c> and <c>return_from</c>.</p> </item> <tag><c>silent</c></tag> <item> - <p>Used in conjunction with the <c>call</c> trace flag. - The <c>call</c>, <c>return_from</c> and <c>return_to</c> - trace messages are inhibited if this flag is set, - but if there are match specs they are executed as normal.</p> + <p>Used with the <c>call</c> trace flag. + The <c>call</c>, <c>return_from</c>, and <c>return_to</c> + trace messages are inhibited if this flag is set, but they + are executed as normal if there are match specifications.</p> <p>Silent mode is inhibited by executing <c>erlang:trace(_, false, [silent|_])</c>, - or by a match spec executing the <c>{silent, false}</c> - function.</p> + or by a match specification executing the function + <c>{silent, false}</c>.</p> <p>The <c>silent</c> trace flag facilitates setting up a trace on many or even all processes in the system. - Then the interesting trace can be activated and - deactivated using the <c>{silent,Bool}</c> - match spec function, giving a high degree - of control of which functions with which - arguments that triggers the trace.</p> - <p>Message tags: <c>call</c>, <c>return_from</c>, + The trace can then be activated and deactivated using the match + specification function <c>{silent,Bool}</c>, giving + a high degree of control of which functions with which + arguments that trigger the trace.</p> + <p>Message tags: <c>call</c>, <c>return_from</c>, and <c>return_to</c>. Or rather, the absence of.</p> </item> <tag><c>return_to</c></tag> <item> - <p>Used in conjunction with the <c>call</c> trace flag. - Trace the actual return from a traced function back to + <p>Used with the <c>call</c> trace flag. + Traces the return from a traced function back to its caller. Only works for functions traced with - the <c>local</c> option to + option <c>local</c> to <seealso marker="#trace_pattern/3">erlang:trace_pattern/3</seealso>.</p> <p>The semantics is that a trace message is sent when a - call traced function actually returns, that is, when a - chain of tail recursive calls is ended. There will be - only one trace message sent per chain of tail recursive - calls, why the properties of tail recursiveness for + call traced function returns, that is, when a + chain of tail recursive calls ends. Only one trace + message is sent per chain of tail recursive calls, + so the properties of tail recursiveness for function calls are kept while tracing with this flag. Using <c>call</c> and <c>return_to</c> trace together makes it possible to know exactly in which function a process executes at any time.</p> <p>To get trace messages containing return values from - functions, use the <c>{return_trace}</c> match_spec - action instead.</p> + functions, use the <c>{return_trace}</c> match + specification action instead.</p> <p>Message tags: <c>return_to</c>.</p> </item> <tag><c>running</c></tag> <item> - <p>Trace scheduling of processes.</p> - <p>Message tags: <c>in</c>, and <c>out</c>.</p> + <p>Traces scheduling of processes.</p> + <p>Message tags: <c>in</c> and <c>out</c>.</p> </item> <tag><c>exiting</c></tag> <item> - <p>Trace scheduling of an exiting processes.</p> + <p>Traces scheduling of exiting processes.</p> <p>Message tags: <c>in_exiting</c>, <c>out_exiting</c>, and <c>out_exited</c>.</p> </item> <tag><c>garbage_collection</c></tag> <item> - <p>Trace garbage collections of processes.</p> - <p>Message tags: <c>gc_start</c>, <c>gc_end</c>.</p> + <p>Traces garbage collections of processes.</p> + <p>Message tags: <c>gc_start</c> and <c>gc_end</c>.</p> </item> <tag><c>timestamp</c></tag> <item> - <p>Include a time stamp in all trace messages. The time - stamp (Ts) is of the same form as returned by + <p>Includes a time-stamp in all trace messages. The + time-stamp (Ts) has the same form as returned by <c>erlang:now()</c>.</p> </item> <tag><c>cpu_timestamp</c></tag> <item> <p>A global trace flag for the Erlang node that makes all - trace timestamps be in CPU time, not wallclock. It is - only allowed with <c>PidSpec==all</c>. If the host - machine operating system does not support high resolution + trace time-stamps to be in CPU time, not wall clock time. + Only allowed with <c>PidSpec==all</c>. If the host + machine OS does not support high-resolution CPU time measurements, <c>trace/3</c> exits with - <c>badarg</c>. Note that most operating systems do + <c>badarg</c>. Notice that most OS do not synchronize this value across cores, so be prepared that time might seem to go backwards when using this option.</p> </item> <tag><c>arity</c></tag> <item> - <p>Used in conjunction with the <c>call</c> trace flag. - <c>{M, F, Arity}</c> will be specified instead of + <p>Used with the <c>call</c> trace flag. + <c>{M, F, Arity}</c> is specified instead of <c>{M, F, Args}</c> in call trace messages.</p> </item> <tag><c>set_on_spawn</c></tag> <item> <p>Makes any process created by a traced process inherit - its trace flags, including the <c>set_on_spawn</c> flag.</p> + its trace flags, including flag <c>set_on_spawn</c>.</p> </item> <tag><c>set_on_first_spawn</c></tag> <item> <p>Makes the first process created by a traced process - inherit its trace flags, excluding - the <c>set_on_first_spawn</c> flag.</p> + inherit its trace flags, excluding flag + <c>set_on_first_spawn</c>.</p> </item> <tag><c>set_on_link</c></tag> <item> <p>Makes any process linked by a traced process inherit its - trace flags, including the <c>set_on_link</c> flag.</p> + trace flags, including flag <c>set_on_link</c>.</p> </item> <tag><c>set_on_first_link</c></tag> <item> <p>Makes the first process linked to by a traced process - inherit its trace flags, excluding - the <c>set_on_first_link</c> flag.</p> + inherit its trace flags, excluding flag + <c>set_on_first_link</c>.</p> </item> <tag><c>{tracer, Tracer}</c></tag> <item> - <p>Specify where to send the trace messages. <c>Tracer</c> - must be the pid of a local process or the port identifier + <p>Specifies where to send the trace messages. <c>Tracer</c> + must be the process identifier of a local process + or the port identifier of a local port. If this flag is not given, trace - messages will be sent to the process that called + messages are sent to the process that called <c>erlang:trace/3</c>.</p> </item> </taglist> @@ -7620,27 +8081,27 @@ timestamp() -> <c>set_on_link</c> is the same as having <c>set_on_first_link</c> alone. Likewise for <c>set_on_spawn</c> and <c>set_on_first_spawn</c>.</p> - <p>If the <c>timestamp</c> flag is not given, the tracing - process will receive the trace messages described below. - <c>Pid</c> is the pid of the traced process in which - the traced event has occurred. The third element of the tuple - is the message tag.</p> - <p>If the <c>timestamp</c> flag is given, the first element of - the tuple will be <c>trace_ts</c> instead and the timestamp - is added last in the tuple.</p> + <p>The tracing process receives the <em>trace messages</em> described + in the following list. <c>Pid</c> is the process identifier of the + traced process in which the traced event has occurred. The + third tuple element is the message tag.</p> + <p>If flag <c>timestamp</c> is given, the first tuple + element is <c>trace_ts</c> instead, and the time-stamp + is added last in the message tuple.</p> + <marker id="trace_3_trace_messages"></marker> <taglist> <tag><c>{trace, Pid, 'receive', Msg}</c></tag> <item> - <p>When <c>Pid</c> receives the message <c>Msg</c>.</p> + <p>When <c>Pid</c> receives message <c>Msg</c>.</p> </item> <tag><c>{trace, Pid, send, Msg, To}</c></tag> <item> - <p>When <c>Pid</c> sends the message <c>Msg</c> to - the process <c>To</c>.</p> + <p>When <c>Pid</c> sends message <c>Msg</c> to + process <c>To</c>.</p> </item> <tag><c>{trace, Pid, send_to_non_existing_process, Msg, To}</c></tag> <item> - <p>When <c>Pid</c> sends the message <c>Msg</c> to + <p>When <c>Pid</c> sends message <c>Msg</c> to the non-existing process <c>To</c>.</p> </item> <tag><c>{trace, Pid, call, {M, F, Args}}</c></tag> @@ -7648,7 +8109,7 @@ timestamp() -> <p>When <c>Pid</c> calls a traced function. The return values of calls are never supplied, only the call and its arguments.</p> - <p>Note that the trace flag <c>arity</c> can be used to + <p>Trace flag <c>arity</c> can be used to change the contents of this message, so that <c>Arity</c> is specified instead of <c>Args</c>.</p> </item> @@ -7656,35 +8117,34 @@ timestamp() -> <item> <p>When <c>Pid</c> returns <em>to</em> the specified function. This trace message is sent if both - the <c>call</c> and the <c>return_to</c> flags are set, + the flags <c>call</c> and <c>return_to</c> are set, and the function is set to be traced on <em>local</em> function calls. The message is only sent when returning - from a chain of tail recursive function calls where at + from a chain of tail recursive function calls, where at least one call generated a <c>call</c> trace message - (that is, the functions match specification matched and + (that is, the functions match specification matched, and <c>{message, false}</c> was not an action).</p> </item> <tag><c>{trace, Pid, return_from, {M, F, Arity}, ReturnValue}</c></tag> <item> <p>When <c>Pid</c> returns <em>from</em> the specified - function. This trace message is sent if the <c>call</c> - flag is set, and the function has a match specification + function. This trace message is sent if flag <c>call</c> + is set, and the function has a match specification with a <c>return_trace</c> or <c>exception_trace</c> action.</p> </item> <tag><c>{trace, Pid, exception_from, {M, F, Arity}, {Class, Value}}</c></tag> <item> <p>When <c>Pid</c> exits <em>from</em> the specified - function due to an exception. This trace message is sent - if the <c>call</c> flag is set, and the function has + function because of an exception. This trace message is + sent if flag <c>call</c> is set, and the function has a match specification with an <c>exception_trace</c> action.</p> </item> <tag><c>{trace, Pid, spawn, Pid2, {M, F, Args}}</c></tag> <item> <p>When <c>Pid</c> spawns a new process <c>Pid2</c> with the specified function call as entry point.</p> - <p>Note that <c>Args</c> is supposed to be the argument - list, but may be any term in the case of an erroneous - spawn.</p> + <p><c>Args</c> is supposed to be the argument list, + but can be any term if the spawn is erroneous.</p> </item> <tag><c>{trace, Pid, exit, Reason}</c></tag> <item> @@ -7714,148 +8174,158 @@ timestamp() -> <tag><c>{trace, Pid, unregister, RegName}</c></tag> <item> <p>When <c>Pid</c> gets the name <c>RegName</c> unregistered. - Note that this is done automatically when a registered + This is done automatically when a registered process exits.</p> </item> <tag><c>{trace, Pid, in, {M, F, Arity} | 0}</c></tag> <item> - <p>When <c>Pid</c> is scheduled to run. The process will - run in function <c>{M, F, Arity}</c>. On some rare - occasions the current function cannot be determined, then - the last element <c>Arity</c> is 0.</p> + <p>When <c>Pid</c> is scheduled to run. The process + runs in function <c>{M, F, Arity}</c>. On some rare + occasions, the current function cannot be determined, + then the last element <c>Arity</c> is <c>0</c>.</p> </item> <tag><c>{trace, Pid, out, {M, F, Arity} | 0}</c></tag> <item> <p>When <c>Pid</c> is scheduled out. The process was - running in function {M, F, Arity}. On some rare occasions + running in function {M, F, Arity}. On some rare occasions, the current function cannot be determined, then the last - element <c>Arity</c> is 0.</p> + element <c>Arity</c> is <c>0</c>.</p> </item> - <tag><marker id="gc_start"><c>{trace, Pid, gc_start, Info}</c></marker></tag> + <tag><c>{trace, Pid, gc_start, Info}</c></tag> <item> + <marker id="gc_start"></marker> <p>Sent when garbage collection is about to be started. <c>Info</c> is a list of two-element tuples, where the first element is a key, and the second is the value. - You should not depend on the tuples have any defined - order. Currently, the following keys are defined:</p> + Do not depend on any order of the tuples. + The following keys are defined:</p> <taglist> <tag><c>heap_size</c></tag> <item>The size of the used part of the heap.</item> <tag><c>heap_block_size</c></tag> <item>The size of the memory block used for storing - the heap and the stack.</item> + the heap and the stack.</item> <tag><c>old_heap_size</c></tag> <item>The size of the used part of the old heap.</item> <tag><c>old_heap_block_size</c></tag> <item>The size of the memory block used for storing - the old heap.</item> + the old heap.</item> <tag><c>stack_size</c></tag> - <item>The actual size of the stack.</item> + <item>The size of the stack.</item> <tag><c>recent_size</c></tag> <item>The size of the data that survived the previous garbage - collection.</item> + collection.</item> <tag><c>mbuf_size</c></tag> <item>The combined size of message buffers associated with - the process.</item> - + the process.</item> <tag><c>bin_vheap_size</c></tag> - <item>The total size of unique off-heap binaries referenced from the process heap.</item> + <item>The total size of unique off-heap binaries referenced + from the process heap.</item> <tag><c>bin_vheap_block_size</c></tag> - <item>The total size of binaries, in words, allowed in the virtual - heap in the process before doing a garbage collection. </item> + <item>The total size of binaries allowed in the virtual + heap in the process before doing a garbage collection.</item> <tag><c>bin_old_vheap_size</c></tag> - <item>The total size of unique off-heap binaries referenced from the process old heap.</item> + <item>The total size of unique off-heap binaries referenced + from the process old heap.</item> <tag><c>bin_vheap_block_size</c></tag> - <item>The total size of binaries, in words, allowed in the virtual - old heap in the process before doing a garbage collection. </item> - - + <item>The total size of binaries allowed in the virtual + old heap in the process before doing a garbage collection.</item> </taglist> <p>All sizes are in words.</p> </item> <tag><c>{trace, Pid, gc_end, Info}</c></tag> <item> <p>Sent when garbage collection is finished. <c>Info</c> - contains the same kind of list as in the <c>gc_start</c> - message, but the sizes reflect the new sizes after + contains the same kind of list as in message <c>gc_start</c>, + but the sizes reflect the new sizes after garbage collection.</p> </item> </taglist> - <p>If the tracing process dies, the flags will be silently + <p>If the tracing process dies, the flags are silently removed.</p> - <p>Only one process can trace a particular process. For this - reason, attempts to trace an already traced process will fail.</p> + <p>Only one process can trace a particular process. Therefore, + attempts to trace an already traced process fail.</p> <p>Returns: A number indicating the number of processes that - matched <c><anno>PidSpec</anno></c>. If <c><anno>PidSpec</anno></c> is a pid, - the return value will be <c>1</c>. If <c><anno>PidSpec</anno></c> is - <c>all</c> or <c>existing</c> the return value will be + matched <c><anno>PidSpec</anno></c>. + If <c><anno>PidSpec</anno></c> is a process + identifier, the return value is <c>1</c>. + If <c><anno>PidSpec</anno></c> + is <c>all</c> or <c>existing</c>, the return value is the number of processes running, excluding tracer processes. - If <c><anno>PidSpec</anno></c> is <c>new</c>, the return value will be + If <c><anno>PidSpec</anno></c> is <c>new</c>, the return value is <c>0</c>.</p> - <p>Failure: If specified arguments are not supported. For - example <c>cpu_timestamp</c> is not supported on all - platforms.</p> + <p>Failure: <c>badarg</c> if the specified arguments are + not supported. For example, <c>cpu_timestamp</c> is not + supported on all platforms.</p> </desc> </func> + <func> <name name="trace_delivered" arity="1"/> - <fsummary>Notification when trace has been delivered</fsummary> + <fsummary>Notification when trace has been delivered.</fsummary> <desc> <p>The delivery of trace messages is dislocated on the time-line - compared to other events in the system. If you know that the - <c><anno>Tracee</anno></c> has passed some specific point in its execution, + compared to other events in the system. If you know that + <c><anno>Tracee</anno></c> has passed some specific point + in its execution, and you want to know when at least all trace messages - corresponding to events up to this point have reached the tracer - you can use <c>erlang:trace_delivered(<anno>Tracee</anno>)</c>. A + corresponding to events up to this point have reached the + tracer, use <c>erlang:trace_delivered(<anno>Tracee</anno>)</c>. A <c>{trace_delivered, <anno>Tracee</anno>, <anno>Ref</anno>}</c> message is sent to the caller of <c>erlang:trace_delivered(<anno>Tracee</anno>)</c> when it - is guaranteed that all trace messages have been delivered to - the tracer up to the point that the <c><anno>Tracee</anno></c> had reached + is guaranteed that all trace messages are delivered to + the tracer up to the point that <c><anno>Tracee</anno></c> reached at the time of the call to <c>erlang:trace_delivered(<anno>Tracee</anno>)</c>.</p> - <p>Note that the <c>trace_delivered</c> message does <em>not</em> - imply that trace messages have been delivered; instead, it implies - that all trace messages that <em>should</em> be delivered have - been delivered. It is not an error if <c><anno>Tracee</anno></c> isn't, and - hasn't been traced by someone, but if this is the case, - <em>no</em> trace messages will have been delivered when the + <p>Notice that message <c>trace_delivered</c> does <em>not</em> + imply that trace messages have been delivered. + Instead it implies that all trace messages that + <em>are to be delivered</em> have been delivered. + It is not an error if <c><anno>Tracee</anno></c> is not, and + has not been traced by someone, but if this is the case, + <em>no</em> trace messages have been delivered when the <c>trace_delivered</c> message arrives.</p> - <p>Note that <c><anno>Tracee</anno></c> has to refer to a process currently, + <p>Notice that that <c><anno>Tracee</anno></c> must refer + to a process currently, or previously existing on the same node as the caller of <c>erlang:trace_delivered(<anno>Tracee</anno>)</c> resides on. - The special <c><anno>Tracee</anno></c> atom <c>all</c> denotes all processes + The special <c><anno>Tracee</anno></c> atom <c>all</c> + denotes all processes that currently are traced in the node.</p> - <p>An example: Process <c>A</c> is <c><anno>Tracee</anno></c>, port <c>B</c> is - tracer, and process <c>C</c> is the port owner of <c>B</c>. - <c>C</c> wants to close <c>B</c> when <c>A</c> exits. <c>C</c> - can ensure that the trace isn't truncated by calling - <c>erlang:trace_delivered(A)</c> when <c>A</c> exits and wait - for the <c>{trace_delivered, A, <anno>Ref</anno>}</c> message before closing - <c>B</c>.</p> - <p>Failure: <c>badarg</c> if <c><anno>Tracee</anno></c> does not refer to a + <p>Example: Process <c>A</c> is <c><anno>Tracee</anno></c>, + port <c>B</c> is tracer, and process <c>C</c> is the port + owner of <c>B</c>. <c>C</c> wants to close <c>B</c> when + <c>A</c> exits. To ensure that the trace is not truncated, + <c>C</c> can call <c>erlang:trace_delivered(A)</c>, when + <c>A</c> exits, and wait for message <c>{trace_delivered, A, + <anno>Ref</anno>}</c> before closing <c>B</c>.</p> + <p>Failure: <c>badarg</c> if <c><anno>Tracee</anno></c> + does not refer to a process (dead or alive) on the same node as the caller of <c>erlang:trace_delivered(<anno>Tracee</anno>)</c> resides on.</p> </desc> </func> + <func> <name name="trace_info" arity="2"/> + <fsummary>Trace information about a process or function.</fsummary> <type name="trace_info_return"/> <type name="trace_info_item_result"/> <type name="trace_info_flag"/> <type name="trace_match_spec"/> - <fsummary>Trace information about a process or function</fsummary> <desc> <p>Returns trace information about a process or function.</p> - <p>To get information about a process, <c><anno>PidOrFunc</anno></c> should - be a pid or the atom <c>new</c>. The atom <c>new</c> means - that the default trace state for processes to be created will - be returned. <c><anno>Item</anno></c> must have one of the following - values:</p> + <p>To get information about a process, + <c><anno>PidOrFunc</anno></c> is to + be a process identifier (pid) or the atom <c>new</c>. + The atom <c>new</c> means that the default trace state for + processes to be created is returned.</p> + <p>The following <c>Item</c>s are valid:</p> <taglist> <tag><c>flags</c></tag> <item> - <p>Return a list of atoms indicating what kind of traces is - enabled for the process. The list will be empty if no + <p>Returns a list of atoms indicating what kind of traces is + enabled for the process. The list is empty if no traces are enabled, and one or more of the followings atoms if traces are enabled: <c>send</c>, <c>'receive'</c>, <c>set_on_spawn</c>, <c>call</c>, @@ -7866,337 +8336,354 @@ timestamp() -> </item> <tag><c>tracer</c></tag> <item> - <p>Return the identifier for process or port tracing this + <p>Returns the identifier for process or port tracing this process. If this process is not being traced, the return - value will be <c>[]</c>.</p> + value is <c>[]</c>.</p> </item> </taglist> - <p>To get information about a function, <c>PidOrFunc</c> should - be a three-element tuple: <c>{Module, Function, Arity}</c> or - the atom <c>on_load</c>. No wildcards are allowed. Returns - <c>undefined</c> if the function does not exist or - <c>false</c> if the function is not traced at all. <c>Item</c> - must have one of the following values:</p> + <p>To get information about a function, <c>PidOrFunc</c> is to + be the three-element tuple <c>{Module, Function, Arity}</c> or + the atom <c>on_load</c>. No wild cards are allowed. Returns + <c>undefined</c> if the function does not exist, or + <c>false</c> if the function is not traced.</p> + <p>The following <c>Item</c>s are valid::</p> <taglist> <tag><c>traced</c></tag> <item> - <p>Return <c>global</c> if this function is traced on + <p>Returns <c>global</c> if this function is traced on global function calls, <c>local</c> if this function is - traced on local function calls (i.e local and global - function calls), and <c>false</c> if neither local nor - global function calls are traced.</p> + traced on local function calls (that is, local and global + function calls), and <c>false</c> if local or + global function calls are not traced.</p> </item> <tag><c>match_spec</c></tag> <item> - <p>Return the match specification for this function, if it + <p>Returns the match specification for this function, if it has one. If the function is locally or globally traced but has no match specification defined, the returned value is <c>[]</c>.</p> </item> <tag><c>meta</c></tag> <item> - <p>Return the meta trace tracer process or port for this - function, if it has one. If the function is not meta - traced the returned value is <c>false</c>, and if - the function is meta traced but has once detected that - the tracer proc is invalid, the returned value is [].</p> + <p>Returns the meta-trace tracer process or port for this + function, if it has one. If the function is not + meta-traced, the returned value is <c>false</c>. If + the function is meta-traced but has once detected that + the tracer process is invalid, the returned value is [].</p> </item> <tag><c>meta_match_spec</c></tag> <item> - <p>Return the meta trace match specification for this - function, if it has one. If the function is meta traced + <p>Returns the meta-trace match specification for this + function, if it has one. If the function is meta-traced but has no match specification defined, the returned value is <c>[]</c>.</p> </item> <tag><c>call_count</c></tag> <item> - <p>Return the call count value for this function or + <p>Returns the call count value for this function or <c>true</c> for the pseudo function <c>on_load</c> if call - count tracing is active. Return <c>false</c> otherwise. + count tracing is active. Otherwise <c>false</c> is returned. See also <seealso marker="#trace_pattern/3">erlang:trace_pattern/3</seealso>.</p> </item> <tag><c>call_time</c></tag> <item> - <p>Return the call time values for this function or + <p>Returns the call time values for this function or <c>true</c> for the pseudo function <c>on_load</c> if call - time tracing is active. Returns <c>false</c> otherwise. + time tracing is active. Otherwise <c>false</c> is returned. The call time values returned, <c>[{Pid, Count, S, Us}]</c>, - is a list of each process that has executed the function and its specific counters. - See also + is a list of each process that executed the function + and its specific counters. See also <seealso marker="#trace_pattern/3">erlang:trace_pattern/3</seealso>.</p> </item> <tag><c>all</c></tag> <item> - <p>Return a list containing the <c>{<anno>Item</anno>, Value}</c> tuples - for all other items, or return <c>false</c> if no tracing + <p>Returns a list containing the + <c>{<anno>Item</anno>, Value}</c> tuples + for all other items, or returns <c>false</c> if no tracing is active for this function.</p> </item> </taglist> - <p>The actual return value will be <c>{<anno>Item</anno>, Value}</c>, where - <c>Value</c> is the requested information as described above. + <p>The return value is <c>{<anno>Item</anno>, Value}</c>, where + <c>Value</c> is the requested information as described earlier. If a pid for a dead process was given, or the name of a - non-existing function, <c>Value</c> will be <c>undefined</c>.</p> - <p>If <c><anno>PidOrFunc</anno></c> is the <c>on_load</c>, the information + non-existing function, <c>Value</c> is <c>undefined</c>.</p> + <p>If <c><anno>PidOrFunc</anno></c> is <c>on_load</c>, the information returned refers to the default value for code that will be loaded.</p> </desc> </func> + <func> <name name="trace_pattern" arity="2" clause_i="1"/> + <fsummary>Sets trace patterns for global call tracing.</fsummary> <type name="trace_pattern_mfa"/> <type name="trace_match_spec"/> - <fsummary>Set trace patterns for global call tracing</fsummary> <desc> <p>The same as <seealso marker="#trace_pattern/3">erlang:trace_pattern(MFA, MatchSpec, [])</seealso>, retained for backward compatibility.</p> </desc> </func> + <func> <name name="trace_pattern" arity="3"/> + <fsummary>Sets trace patterns for tracing of function calls.</fsummary> <type name="trace_pattern_mfa"/> <type name="trace_match_spec"/> <type name="trace_pattern_flag"/> - <fsummary>Set trace patterns for tracing of function calls</fsummary> <desc> - <p>This BIF is used to enable or disable call tracing for - exported functions. It must be combined with + <p>Enables or disables call tracing for + one or more functions. Must be combined with <seealso marker="#trace/3">erlang:trace/3</seealso> to set the <c>call</c> trace flag for one or more processes.</p> - <p>Conceptually, call tracing works like this: Inside - the Erlang virtual machine there is a set of processes to be - traced and a set of functions to be traced. Tracing will be - enabled on the intersection of the set. That is, if a process - included in the traced process set calls a function included - in the traced function set, the trace action will be taken. - Otherwise, nothing will happen.</p> - <p>Use - <seealso marker="#trace/3">erlang:trace/3</seealso> to - add or remove one or more processes to the set of traced - processes. Use <c>erlang:trace_pattern/2</c> to add or remove - exported functions to the set of traced functions.</p> - <p>The <c>erlang:trace_pattern/3</c> BIF can also add match - specifications to an exported function. A match specification - comprises a pattern that the arguments to the function must - match, a guard expression which must evaluate to <c>true</c> + <p>Conceptually, call tracing works as follows. Inside + the Erlang Virtual Machine, a set of processes and + a set of functions are to be traced. If a traced process + calls a traced function, the trace action is taken. + Otherwise, nothing happens.</p> + <p>To add or remove one or more processes to the set of traced + processes, use + <seealso marker="#trace/3">erlang:trace/3</seealso>.</p> + <p>To add or remove functions to the set of traced + functions, use <c>erlang:trace_pattern/3</c>.</p> + <p>The BIF <c>erlang:trace_pattern/3</c> can also add match + specifications to a function. A match specification + comprises a pattern that the function arguments must + match, a guard expression that must evaluate to <c>true</c>, and an action to be performed. The default action is to send a trace message. If the pattern does not match or the guard - fails, the action will not be executed.</p> - <p>The <c><anno>MFA</anno></c> argument should be a tuple like - <c>{Module, Function, Arity}</c> or the atom <c>on_load</c> - (described below). It can be the module, function, and arity - for an exported function (or a BIF in any module). - The <c>'_'</c> atom can be used to mean any of that kind. - Wildcards can be used in any of the following ways:</p> + fails, the action is not executed.</p> + <p>Argument <c><anno>MFA</anno></c> is to be a tuple, such as + <c>{Module, Function, Arity}</c>, or the atom <c>on_load</c> + (described in the following). It can be the module, function, + and arity for a function (or a BIF in any module). + The atom <c>'_'</c> can be used as a wild card in any of the + following ways:</p> <taglist> <tag><c>{Module,Function,'_'}</c></tag> <item> - <p>All exported functions of any arity named <c>Function</c> + <p>All functions of any arity named <c>Function</c> in module <c>Module</c>.</p> </item> <tag><c>{Module,'_','_'}</c></tag> <item> - <p>All exported functions in module <c>Module</c>.</p> + <p>All functions in module <c>Module</c>.</p> </item> <tag><c>{'_','_','_'}</c></tag> <item> - <p>All exported functions in all loaded modules.</p> + <p>All functions in all loaded modules.</p> </item> </taglist> <p>Other combinations, such as <c>{Module,'_',Arity}</c>, are - not allowed. Local functions will match wildcards only if - the <c>local</c> option is in the <c><anno>FlagList</anno></c>.</p> - <p>If the <c><anno>MFA</anno></c> argument is the atom <c>on_load</c>, - the match specification and flag list will be used on all + not allowed. Local functions match wild cards only if + option <c>local</c> is in <c><anno>FlagList</anno></c>.</p> + <p>If argument <c><anno>MFA</anno></c> is the atom <c>on_load</c>, + the match specification and flag list are used on all modules that are newly loaded.</p> - <p>The <c><anno>MatchSpec</anno></c> argument can take any of the following - forms:</p> + <p>Argument <c><anno>MatchSpec</anno></c> can take the + following forms:</p> <taglist> <tag><c>false</c></tag> <item> - <p>Disable tracing for the matching function(s). Any match - specification will be removed.</p> + <p>Disables tracing for the matching functions. + Any match specification is removed.</p> </item> <tag><c>true</c></tag> <item> - <p>Enable tracing for the matching function(s).</p> + <p>Enables tracing for the matching functions.</p> </item> <tag><c><anno>MatchSpecList</anno></c></tag> <item> <p>A list of match specifications. An empty list is - equivalent to <c>true</c>. See the ERTS User's Guide - for a description of match specifications.</p> + equivalent to <c>true</c>. For a description of match + specifications, see the User's Guide.</p> </item> <tag><c>restart</c></tag> <item> - <p>For the <c><anno>FlagList</anno></c> option <c>call_count</c> and <c>call_time</c>: - restart the existing counters. The behaviour is undefined + <p>For the <c><anno>FlagList</anno></c> options <c>call_count</c> + and <c>call_time</c>: restarts + the existing counters. The behavior is undefined for other <c><anno>FlagList</anno></c> options.</p> </item> <tag><c>pause</c></tag> <item> - <p>For the <c><anno>FlagList</anno></c> option <c>call_count</c> and <c>call_time</c>: pause - the existing counters. The behaviour is undefined for - other <c>FlagList</c> options.</p> + <p>For the <c><anno>FlagList</anno></c> options + <c>call_count</c> and <c>call_time</c>: pauses + the existing counters. The behavior is undefined for + other <c><anno>FlagList</anno></c> options.</p> </item> </taglist> - <p>The <c><anno>FlagList</anno></c> parameter is a list of options. - The following options are allowed:</p> + <p>Parameter <c><anno>FlagList</anno></c> is a list of options. + The following are the valid options:</p> <taglist> <tag><c>global</c></tag> <item> - <p>Turn on or off call tracing for global function calls + <p>Turns on or off call tracing for global function calls (that is, calls specifying the module explicitly). Only - exported functions will match and only global calls will - generate trace messages. This is the default.</p> + exported functions match and only global calls + generate trace messages. <em>This is the default</em>.</p> </item> <tag><c>local</c></tag> <item> - <p>Turn on or off call tracing for all types of function - calls. Trace messages will be sent whenever any of + <p>Turns on or off call tracing for all types of function + calls. Trace messages are sent whenever any of the specified functions are called, regardless of how they - are called. If the <c>return_to</c> flag is set for - the process, a <c>return_to</c> message will also be sent + are called. If flag <c>return_to</c> is set for + the process, a <c>return_to</c> message is also sent when this function returns to its caller.</p> </item> <tag><c>meta | {meta, <anno>Pid</anno>}</c></tag> <item> - <p>Turn on or off meta tracing for all types of function - calls. Trace messages will be sent to the tracer process + <p>Turns on or off meta-tracing for all types of function + calls. Trace messages are sent to the tracer process or port <c><anno>Pid</anno></c> whenever any of the specified functions are called, regardless of how they are called. - If no <c><anno>Pid</anno></c> is specified, <c>self()</c> is used as a - default tracer process.</p> - <p>Meta tracing traces all processes and does not care + If no <c><anno>Pid</anno></c> is specified, + <c>self()</c> is used as a default tracer process.</p> + <p>Meta-tracing traces all processes and does not care about the process trace flags set by <c>trace/3</c>, the trace flags are instead fixed to <c>[call, timestamp]</c>.</p> - <p>The match spec function <c>{return_trace}</c> works with - meta trace and send its trace message to the same tracer - process.</p> + <p>The match specification function <c>{return_trace}</c> + works with meta-trace and sends its trace message to the + same tracer process.</p> </item> <tag><c>call_count</c></tag> <item> <p>Starts (<c><anno>MatchSpec</anno> == true</c>) or stops - (<c><anno>MatchSpec</anno> == false</c>) call count tracing for all - types of function calls. For every function a counter is + (<c><anno>MatchSpec</anno> == false</c>) + call count tracing for all + types of function calls. For every function, a counter is incremented when the function is called, in any process. No process trace flags need to be activated.</p> <p>If call count tracing is started while already running, - the count is restarted from zero. Running counters can be - paused with <c><anno>MatchSpec</anno> == pause</c>. Paused and running - counters can be restarted from zero with + the count is restarted from zero. To pause running + counters, use <c><anno>MatchSpec</anno> == pause</c>. + Paused and running counters can be restarted from zero with <c><anno>MatchSpec</anno> == restart</c>.</p> - <p>The counter value can be read with + <p>To read the counter value, use <seealso marker="#trace_info/2">erlang:trace_info/2</seealso>.</p> </item> <tag><c>call_time</c></tag> <item> <p>Starts (<c><anno>MatchSpec</anno> == true</c>) or stops - (<c><anno>MatchSpec</anno> == false</c>) call time tracing for all - types of function calls. For every function a counter is - incremented when the function is called. Time spent in the function - is accumulated in two other counters, seconds and micro-seconds. + (<c><anno>MatchSpec</anno> == false</c>) call time + tracing for all + types of function calls. For every function, a counter is + incremented when the function is called. + Time spent in the function is accumulated in + two other counters, seconds and microseconds. The counters are stored for each call traced process.</p> <p>If call time tracing is started while already running, - the count and time is restarted from zero. Running counters can be - paused with <c><anno>MatchSpec</anno> == pause</c>. Paused and running - counters can be restarted from zero with + the count and time is restarted from zero. To pause + running counters, use <c><anno>MatchSpec</anno> == pause</c>. + Paused and running counters can be restarted from zero with <c><anno>MatchSpec</anno> == restart</c>.</p> - <p>The counter value can be read with + <p>To read the counter value, use <seealso marker="#trace_info/2">erlang:trace_info/2</seealso>.</p> </item> - </taglist> - <p>The <c>global</c> and <c>local</c> options are mutually - exclusive and <c>global</c> is the default (if no options are - specified). The <c>call_count</c> and <c>meta</c> options - perform a kind of local tracing, and can also not be combined - with <c>global</c>. A function can be either globally or + <p>The options <c>global</c> and <c>local</c> are mutually + exclusive, and <c>global</c> is the default (if no options are + specified). The options <c>call_count</c> and <c>meta</c> + perform a kind of local tracing, and cannot be combined + with <c>global</c>. A function can be globally or locally traced. If global tracing is specified for a - specified set of functions; local, meta, call time and call count - tracing for the matching set of local functions will be - disabled, and vice versa.</p> + set of functions, then local, meta, call time, and call count + tracing for the matching set of local functions is + disabled, and conversely.</p> <p>When disabling trace, the option must match the type of trace - that is set on the function, so that local tracing must be - disabled with the <c>local</c> option and global tracing with - the <c>global</c> option (or no option at all), and so forth.</p> - <p>There is no way to directly change part of a match - specification list. If a function has a match specification, - you can replace it with a completely new one. If you need to - change an existing match specification, use the + set on the function. That is, local tracing must be + disabled with option <c>local</c> and global tracing with + option <c>global</c> (or no option), and so forth.</p> + <p>Part of a match specification list cannot be changed directly. + If a function has a match specification, it can be replaced + with a new one. To change an existing match specification, + use the BIF <seealso marker="#trace_info/2">erlang:trace_info/2</seealso> - BIF to retrieve the existing match specification.</p> - <p>Returns the number of exported functions that matched - the <c><anno>MFA</anno></c> argument. This will be zero if none matched at - all.</p> + to retrieve the existing match specification.</p> + <p>Returns the number of functions matching + argument <c><anno>MFA</anno></c>. This is zero if none matched.</p> </desc> </func> + <func> <name name="trunc" arity="1"/> - <fsummary>Return an integer by the truncating a number</fsummary> + <fsummary>Returns an integer by truncating a number</fsummary> <desc> - <p>Returns an integer by the truncating <c><anno>Number</anno></c>.</p> + <p>Returns an integer by truncating <c><anno>Number</anno></c>, + for example:</p> <pre> > <input>trunc(5.5).</input> 5</pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="tuple_size" arity="1"/> - <fsummary>Return the size of a tuple</fsummary> + <fsummary>Returns the size of a tuple.</fsummary> <desc> - <p>Returns an integer which is the number of elements in <c><anno>Tuple</anno></c>.</p> + <p>Returns an integer that is the number of elements in + <c><anno>Tuple</anno></c>, for example:</p> <pre> > <input>tuple_size({morni, mulle, bwange}).</input> 3</pre> <p>Allowed in guard tests.</p> </desc> </func> + <func> <name name="tuple_to_list" arity="1"/> - <fsummary>Convert a tuple to a list</fsummary> + <fsummary>Converts a tuple to a list.</fsummary> <desc> - <p>Returns a list which corresponds to <c><anno>Tuple</anno></c>. - <c><anno>Tuple</anno></c> may contain any Erlang terms.</p> + <p>Returns a list corresponding to <c><anno>Tuple</anno></c>. + <c><anno>Tuple</anno></c> can contain any Erlang terms.</p> + <p>Example:</p> <pre> > <input>tuple_to_list({share, {'Ericsson_B', 163}}).</input> [share,{'Ericsson_B',163}]</pre> </desc> </func> + <func> <name name="universaltime" arity="0"/> - <fsummary>Current date and time according to Universal Time Coordinated (UTC)</fsummary> + <fsummary>Current date and time according to Universal Time Coordinated (UTC).</fsummary> <desc> <p>Returns the current date and time according to Universal - Time Coordinated (UTC), also called GMT, in the form + Time Coordinated (UTC) in the form <c>{{Year, Month, Day}, {Hour, Minute, Second}}</c> if - supported by the underlying operating system. If not, - <c>erlang:universaltime()</c> is equivalent to + supported by the underlying OS. + Otherwise <c>erlang:universaltime()</c> is equivalent to <c>erlang:localtime()</c>.</p> + <p>Example:</p> <pre> > <input>erlang:universaltime().</input> {{1996,11,6},{14,18,43}}</pre> </desc> </func> + <func> <name name="universaltime_to_localtime" arity="1"/> - <fsummary>Convert from Universal Time Coordinated (UTC) to local date and time</fsummary> + <fsummary>Converts from Universal Time Coordinated (UTC) to local date and time.</fsummary> <desc> <p>Converts Universal Time Coordinated (UTC) date and time to - local date and time, if this is supported by the underlying - OS. Otherwise, no conversion is done, and + local date and time in the form + <c>{{Year, Month, Day}, {Hour, Minute, Second}}</c> if + supported by the underlying OS. + Otherwise no conversion is done, and <c><anno>Universaltime</anno></c> is returned.</p> + <p>Example:</p> <pre> > <input>erlang:universaltime_to_localtime({{1996,11,6},{14,18,43}}).</input> {{1996,11,7},{15,18,43}}</pre> - <p>Failure: <c>badarg</c> if <c>Universaltime</c> does not denote - a valid date and time.</p> + <p>Failure: <c>badarg</c> if <c>Universaltime</c> denotes + an invalid date and time.</p> </desc> </func> + <func> <name name="unique_integer" arity="0"/> <fsummary>Get a unique integer value</fsummary> @@ -8221,23 +8708,23 @@ timestamp() -> Each integer value can of course be constructed by other means.</p> - <p>By default, i.e. when <c>[]</c> is passed as + <p>By default, when <c>[]</c> is passed as <c><anno>ModifierList</anno></c>, both negative and - positive integers will be returned. This is order - to be able to utilize the range of integers that do - not need to be heap allocated as much as possible. + positive integers can be returned. This in order + to utilize the range of integers that do + not need heap memory allocation as much as possible. By default the returned integers are also only - guaranteed to be unique, i.e., any integer returned - may be either smaller, or larger than previously + guaranteed to be unique, that is, any returned integer + can be smaller or larger than previously returned integers.</p> - <p>Currently valid <c><anno>Modifier</anno></c>s:</p> + <p>Valid <c><anno>Modifier</anno></c>s:</p> <taglist> <tag>positive</tag> <item><p>Return only positive integers.</p> <p>Note that by passing the <c>positive</c> modifier - you will get heap allocated integers (big-nums) + you will get heap allocated integers (bignums) quicker.</p> </item> @@ -8249,7 +8736,7 @@ timestamp() -> returned will always be larger than previously returned integers on the current runtime system instance.</p> - <p>These values can be used when ordering events + <p>These values can be used to determine order between events on the runtime system instance. That is, if both <c>X = erlang:unique_integer([monotonic])</c> and <c>Y = erlang:unique_integer([monotonic])</c> are @@ -8259,21 +8746,21 @@ timestamp() -> before <c>Y</c>.</p> <warning><p>Strictly monotonically increasing values are inherently quite expensive to generate and scales - poorly. This since the values needs to be - synchronized. That is, do not pass the <c>monotonic</c> + poorly. This is because the values need to be + synchronized between cpu cores. That is, do not pass the <c>monotonic</c> modifier unless you really need strictly monotonically increasing values.</p></warning> </item> </taglist> - <p>All currently valid <c><anno>Modifier</anno></c>s + <p>All valid <c><anno>Modifier</anno></c>s can be combined. Repeated (valid) <c><anno>Modifier</anno></c>s in the <c>ModifierList</c> are ignored.</p> <note><p>Note that the set of integers returned by - <c>unique_integer/1</c> using diffrent sets of + <c>unique_integer/1</c> using different sets of <c><anno>Modifier</anno></c>s <em>will overlap</em>. For example, by calling <c>unique_integer([monotonic])</c>, and <c>unique_integer([positive, monotonic])</c> @@ -8293,25 +8780,30 @@ timestamp() -> </func> <func> <name name="unlink" arity="1"/> - <fsummary>Remove a link, if there is one, to another process or port</fsummary> + <fsummary>Removes a link to another process or port.</fsummary> <desc> <p>Removes the link, if there is one, between the calling - process and the process or port referred to by <c><anno>Id</anno></c>.</p> + process and the process or port referred to by + <c><anno>Id</anno></c>.</p> <p>Returns <c>true</c> and does not fail, even if there is no - link to <c><anno>Id</anno></c>, or if <c><anno>Id</anno></c> does not exist.</p> - <p>Once <c>unlink(<anno>Id</anno>)</c> has returned it is guaranteed that + link to <c><anno>Id</anno></c>, or if <c><anno>Id</anno></c> + does not exist.</p> + <p>Once <c>unlink(<anno>Id</anno>)</c> has returned, + it is guaranteed that the link between the caller and the entity referred to by - <c><anno>Id</anno></c> has no effect on the caller in the future (unless - the link is setup again). If caller is trapping exits, an - <c>{'EXIT', <anno>Id</anno>, _}</c> message due to the link might have - been placed in the caller's message queue prior to the call, - though. Note, the <c>{'EXIT', <anno>Id</anno>, _}</c> message can be the - result of the link, but can also be the result of <c><anno>Id</anno></c> - calling <c>exit/2</c>. Therefore, it <em>may</em> be - appropriate to cleanup the message queue when trapping exits - after the call to <c>unlink(<anno>Id</anno>)</c>, as follow:</p> + <c><anno>Id</anno></c> has no effect on the caller + in the future (unless + the link is setup again). If the caller is trapping exits, an + <c>{'EXIT', <anno>Id</anno>, _}</c> message from the link + can have been placed in the caller's message queue before + the call.</p> + <p>Notice that the <c>{'EXIT', <anno>Id</anno>, _}</c> + message can be the + result of the link, but can also be the result of <c>Id</c> + calling <c>exit/2</c>. Therefore, it <em>can</em> be + appropriate to clean up the message queue when trapping exits + after the call to <c>unlink(<anno>Id</anno>)</c>, as follows:</p> <code type="none"> - unlink(Id), receive {'EXIT', Id, _} -> @@ -8320,23 +8812,25 @@ timestamp() -> true end</code> <note> - <p>Prior to OTP release R11B (erts version 5.5) <c>unlink/1</c> - behaved completely asynchronous, i.e., the link was active + <p>Before OTP R11B (<c>ERTS</c> 5.5) <c>unlink/1</c> + behaved asynchronous, that is, the link was active until the "unlink signal" reached the linked entity. This - had one undesirable effect, though. You could never know when + had an undesirable effect, as you could never know when you were guaranteed <em>not</em> to be effected by the link.</p> - <p>Current behavior can be viewed as two combined operations: + <p>The current behavior can be viewed as two combined operations: asynchronously send an "unlink signal" to the linked entity and ignore any future results of the link.</p> </note> </desc> </func> + <func> <name name="unregister" arity="1"/> - <fsummary>Remove the registered name for a process (or port)</fsummary> + <fsummary>Removes the registered name for a process (or port).</fsummary> <desc> - <p>Removes the registered name <c><anno>RegName</anno></c>, associated with a - pid or a port identifier.</p> + <p>Removes the registered name <c><anno>RegName</anno></c> + associated with a + process identifier or a port identifier, for example:</p> <pre> > <input>unregister(db).</input> true</pre> @@ -8345,31 +8839,34 @@ true</pre> name.</p> </desc> </func> + <func> <name name="whereis" arity="1"/> - <fsummary>Get the pid (or port) with a given registered name</fsummary> + <fsummary>Gets the pid (or port) with a given registered name.</fsummary> <desc> - <p>Returns the pid or port identifier with the registered name - <c>RegName</c>. Returns <c>undefined</c> if the name is not - registered.</p> + <p>Returns the process identifier or port identifier with + the registered name <c>RegName</c>. Returns <c>undefined</c> + if the name is not registered.</p> + <p>Example:</p> <pre> > <input>whereis(db).</input> <0.43.0></pre> </desc> </func> + <func> <name name="yield" arity="0"/> - <fsummary>Let other processes get a chance to execute</fsummary> + <fsummary>Lets other processes get a chance to execute.</fsummary> <desc> - <p>Voluntarily let other processes (if any) get a chance to + <p>Voluntarily lets other processes (if any) get a chance to execute. Using <c>erlang:yield()</c> is similar to <c>receive after 1 -> ok end</c>, except that <c>yield()</c> is faster.</p> <warning><p>There is seldom or never any need to use this BIF, - especially in the SMP-emulator as other processes will have a - chance to run in another scheduler thread anyway. - Using this BIF without a thorough grasp of how the scheduler - works may cause performance degradation.</p></warning> + especially in the SMP emulator, as other processes have a + chance to run in another scheduler thread anyway. + Using this BIF without a thorough grasp of how the scheduler + works can cause performance degradation.</p></warning> </desc> </func> </funcs> diff --git a/erts/doc/src/erts_alloc.xml b/erts/doc/src/erts_alloc.xml index 376cae4a95..15b78ffa10 100644 --- a/erts/doc/src/erts_alloc.xml +++ b/erts/doc/src/erts_alloc.xml @@ -4,7 +4,7 @@ <cref> <header> <copyright> - <year>2002</year><year>2014</year> + <year>2002</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -260,19 +260,19 @@ <p>The following flags are available for configuration of <c>mseg_alloc</c>:</p> <taglist> - <tag><marker id="MMamcbf"><c><![CDATA[+MMamcbf <size>]]></c></marker></tag> + <tag><marker id="MMamcbf"/><c><![CDATA[+MMamcbf <size>]]></c></tag> <item> Absolute max cache bad fit (in kilobytes). A segment in the memory segment cache is not reused if its size exceeds the requested size with more than the value of this parameter. Default value is 4096. </item> - <tag><marker id="MMrmcbf"><c><![CDATA[+MMrmcbf <ratio>]]></c></marker></tag> + <tag><marker id="MMrmcbf"/><c><![CDATA[+MMrmcbf <ratio>]]></c></tag> <item> Relative max cache bad fit (in percent). A segment in the memory segment cache is not reused if its size exceeds the requested size with more than relative max cache bad fit percent of the requested size. Default value is 20.</item> - <tag><marker id="MMsco"><c><![CDATA[+MMsco true|false]]></c></marker></tag> + <tag><marker id="MMsco"/><c><![CDATA[+MMsco true|false]]></c></tag> <item> Set <seealso marker="#MMscs">super carrier</seealso> only flag. This flag defaults to <c>true</c>. When a super carrier is used and this @@ -292,7 +292,7 @@ disabled on halfword heap systems. This flag will be ignored on halfword heap systems. </item> - <tag><marker id="MMscrfsd"><c><![CDATA[+MMscrfsd <amount>]]></c></marker></tag> + <tag><marker id="MMscrfsd"/><c><![CDATA[+MMscrfsd <amount>]]></c></tag> <item> Set <seealso marker="#MMscs">super carrier</seealso> reserved free segment descriptors. This parameter defaults to <c>65536</c>. @@ -305,7 +305,7 @@ <c>erts_mmap</c> tuple part of the result from calling <seealso marker="erts:erlang#system_info_allocator_tuple">erlang:system_info({allocator, mseg_alloc})</seealso>. </item> - <tag><marker id="MMscrpm"><c><![CDATA[+MMscrpm true|false]]></c></marker></tag> + <tag><marker id="MMscrpm"/><c><![CDATA[+MMscrpm true|false]]></c></tag> <item> Set <seealso marker="#MMscs">super carrier</seealso> reserve physical memory flag. This flag defaults to <c>true</c>. When this flag is @@ -328,7 +328,7 @@ disabled on halfword heap systems. This flag will be ignored on halfword heap systems. </item> - <tag><marker id="MMscs"><c><![CDATA[+MMscs <size in MB>]]></c></marker></tag> + <tag><marker id="MMscs"/><c><![CDATA[+MMscs <size in MB>]]></c></tag> <item> Set super carrier size (in MB). The super carrier size defaults to zero; i.e, the super carrier is by default disabled. The super @@ -343,7 +343,7 @@ disabled on halfword heap systems. This flag will be ignored on halfword heap systems. </item> - <tag><marker id="MMmcs"><c><![CDATA[+MMmcs <amount>]]></c></marker></tag> + <tag><marker id="MMmcs"/><c><![CDATA[+MMmcs <amount>]]></c></tag> <item> Max cached segments. The maximum number of memory segments stored in the memory segment cache. Valid range is @@ -352,15 +352,15 @@ <p>The following flags are available for configuration of <c>sys_alloc</c>:</p> <taglist> - <tag><marker id="MYe"><c>+MYe true</c></marker></tag> + <tag><marker id="MYe"/><c>+MYe true</c></tag> <item> Enable <c>sys_alloc</c>. Note: <c>sys_alloc</c> cannot be disabled.</item> - <tag><marker id="MYm"><c>+MYm libc</c></marker></tag> + <tag><marker id="MYm"/><c>+MYm libc</c></tag> <item> <c>malloc</c> library to use. Currently only <c>libc</c> is available. <c>libc</c> enables the standard <c>libc</c> malloc implementation. By default <c>libc</c> is used.</item> - <tag><marker id="MYtt"><c><![CDATA[+MYtt <size>]]></c></marker></tag> + <tag><marker id="MYtt"/><c><![CDATA[+MYtt <size>]]></c></tag> <item> Trim threshold size (in kilobytes). This is the maximum amount of free memory at the top of the heap (allocated by @@ -372,7 +372,7 @@ trim threshold is 128. <em>Note:</em> This flag will only have any effect when the emulator has been linked with the GNU C library, and uses its <c>malloc</c> implementation.</item> - <tag><marker id="MYtp"><c><![CDATA[+MYtp <size>]]></c></marker></tag> + <tag><marker id="MYtp"/><c><![CDATA[+MYtp <size>]]></c></tag> <item> Top pad size (in kilobytes). This is the amount of extra memory that will be allocated by <c>malloc</c> when @@ -390,7 +390,7 @@ subsystem identifier, only the specific allocator identified will be effected:</p> <taglist> - <tag><marker id="M_acul"><c><![CDATA[+M<S>acul <utilization>|de]]></c></marker></tag> + <tag><marker id="M_acul"/><c><![CDATA[+M<S>acul <utilization>|de]]></c></tag> <item> Abandon carrier utilization limit. A valid <c><![CDATA[<utilization>]]></c> is an integer in the range @@ -422,7 +422,7 @@ allocators based on the <c>alloc_util</c> framework with the exception of <c>temp_alloc</c> (which would be pointless). </item> - <tag><marker id="M_as"><c><![CDATA[+M<S>as bf|aobf|aoff|aoffcbf|aoffcaobf|gf|af]]></c></marker></tag> + <tag><marker id="M_as"/><c><![CDATA[+M<S>as bf|aobf|aoff|aoffcbf|aoffcaobf|gf|af]]></c></tag> <item> Allocation strategy. Valid strategies are <c>bf</c> (best fit), <c>aobf</c> (address order best fit), <c>aoff</c> (address order first fit), @@ -430,7 +430,7 @@ <c>aoffcaobf</c> (address order first fit carrier address order best fit), <c>gf</c> (good fit), and <c>af</c> (a fit). See <seealso marker="#strategy">the description of allocation strategies</seealso> in "the <c>alloc_util</c> framework" section.</item> - <tag><marker id="M_asbcst"><c><![CDATA[+M<S>asbcst <size>]]></c></marker></tag> + <tag><marker id="M_asbcst"/><c><![CDATA[+M<S>asbcst <size>]]></c></tag> <item> Absolute singleblock carrier shrink threshold (in kilobytes). When a block located in an @@ -438,23 +438,23 @@ will be left unchanged if the amount of unused memory is less than this threshold; otherwise, the carrier will be shrunk. See also <seealso marker="#M_rsbcst">rsbcst</seealso>.</item> - <tag><marker id="M_e"><c><![CDATA[+M<S>e true|false]]></c></marker></tag> + <tag><marker id="M_e"/><c><![CDATA[+M<S>e true|false]]></c></tag> <item> Enable allocator <c><![CDATA[<S>]]></c>.</item> - <tag><marker id="M_lmbcs"><c><![CDATA[+M<S>lmbcs <size>]]></c></marker></tag> + <tag><marker id="M_lmbcs"/><c><![CDATA[+M<S>lmbcs <size>]]></c></tag> <item> Largest (<c>mseg_alloc</c>) multiblock carrier size (in kilobytes). See <seealso marker="#mseg_mbc_sizes">the description on how sizes for mseg_alloc multiblock carriers are decided</seealso> in "the <c>alloc_util</c> framework" section. On 32-bit Unix style OS this limit can not be set higher than 128 megabyte.</item> - <tag><marker id="M_mbcgs"><c><![CDATA[+M<S>mbcgs <ratio>]]></c></marker></tag> + <tag><marker id="M_mbcgs"/><c><![CDATA[+M<S>mbcgs <ratio>]]></c></tag> <item> (<c>mseg_alloc</c>) multiblock carrier growth stages. See <seealso marker="#mseg_mbc_sizes">the description on how sizes for mseg_alloc multiblock carriers are decided</seealso> in "the <c>alloc_util</c> framework" section.</item> - <tag><marker id="M_mbsd"><c><![CDATA[+M<S>mbsd <depth>]]></c></marker></tag> + <tag><marker id="M_mbsd"/><c><![CDATA[+M<S>mbsd <depth>]]></c></tag> <item> Max block search depth. This flag has effect only if the good fit strategy has been selected for allocator @@ -464,40 +464,40 @@ search depth sets a limit on the maximum number of blocks to inspect in a free list during a search for suitable block satisfying the request.</item> - <tag><marker id="M_mmbcs"><c><![CDATA[+M<S>mmbcs <size>]]></c></marker></tag> + <tag><marker id="M_mmbcs"/><c><![CDATA[+M<S>mmbcs <size>]]></c></tag> <item> Main multiblock carrier size. Sets the size of the main multiblock carrier for allocator <c><![CDATA[<S>]]></c>. The main multiblock carrier is allocated via <c><![CDATA[sys_alloc]]></c> and is never deallocated.</item> - <tag><marker id="M_mmmbc"><c><![CDATA[+M<S>mmmbc <amount>]]></c></marker></tag> + <tag><marker id="M_mmmbc"/><c><![CDATA[+M<S>mmmbc <amount>]]></c></tag> <item> Max <c>mseg_alloc</c> multiblock carriers. Maximum number of multiblock carriers allocated via <c>mseg_alloc</c> by allocator <c><![CDATA[<S>]]></c>. When this limit has been reached, new multiblock carriers will be allocated via <c>sys_alloc</c>.</item> - <tag><marker id="M_mmsbc"><c><![CDATA[+M<S>mmsbc <amount>]]></c></marker></tag> + <tag><marker id="M_mmsbc"/><c><![CDATA[+M<S>mmsbc <amount>]]></c></tag> <item> Max <c>mseg_alloc</c> singleblock carriers. Maximum number of singleblock carriers allocated via <c>mseg_alloc</c> by allocator <c><![CDATA[<S>]]></c>. When this limit has been reached, new singleblock carriers will be allocated via <c>sys_alloc</c>.</item> - <tag><marker id="M_ramv"><c><![CDATA[+M<S>ramv <bool>]]></c></marker></tag> + <tag><marker id="M_ramv"/><c><![CDATA[+M<S>ramv <bool>]]></c></tag> <item> Realloc always moves. When enabled, reallocate operations will more or less be translated into an allocate, copy, free sequence. This often reduce memory fragmentation, but costs performance. </item> - <tag><marker id="M_rmbcmt"><c><![CDATA[+M<S>rmbcmt <ratio>]]></c></marker></tag> + <tag><marker id="M_rmbcmt"/><c><![CDATA[+M<S>rmbcmt <ratio>]]></c></tag> <item> Relative multiblock carrier move threshold (in percent). When a block located in a multiblock carrier is shrunk, the block will be moved if the ratio of the size of the returned memory compared to the previous size is more than this threshold; otherwise, the block will be shrunk at current location.</item> - <tag><marker id="M_rsbcmt"><c><![CDATA[+M<S>rsbcmt <ratio>]]></c></marker></tag> + <tag><marker id="M_rsbcmt"/><c><![CDATA[+M<S>rsbcmt <ratio>]]></c></tag> <item> Relative singleblock carrier move threshold (in percent). When a block located in a singleblock carrier is shrunk to @@ -506,7 +506,7 @@ the block will be left unchanged in the singleblock carrier if the ratio of unused memory is less than this threshold; otherwise, it will be moved into a multiblock carrier. </item> - <tag><marker id="M_rsbcst"><c><![CDATA[+M<S>rsbcst <ratio>]]></c></marker></tag> + <tag><marker id="M_rsbcst"/><c><![CDATA[+M<S>rsbcst <ratio>]]></c></tag> <item> Relative singleblock carrier shrink threshold (in percent). When a block located in an <c>mseg_alloc</c> @@ -514,20 +514,20 @@ unchanged if the ratio of unused memory is less than this threshold; otherwise, the carrier will be shrunk. See also <seealso marker="#M_asbcst">asbcst</seealso>.</item> - <tag><marker id="M_sbct"><c><![CDATA[+M<S>sbct <size>]]></c></marker></tag> + <tag><marker id="M_sbct"/><c><![CDATA[+M<S>sbct <size>]]></c></tag> <item> Singleblock carrier threshold. Blocks larger than this threshold will be placed in singleblock carriers. Blocks smaller than this threshold will be placed in multiblock carriers. On 32-bit Unix style OS this threshold can not be set higher than 8 megabytes.</item> - <tag><marker id="M_smbcs"><c><![CDATA[+M<S>smbcs <size>]]></c></marker></tag> + <tag><marker id="M_smbcs"/><c><![CDATA[+M<S>smbcs <size>]]></c></tag> <item> Smallest (<c>mseg_alloc</c>) multiblock carrier size (in kilobytes). See <seealso marker="#mseg_mbc_sizes">the description on how sizes for mseg_alloc multiblock carriers are decided</seealso> in "the <c>alloc_util</c> framework" section.</item> - <tag><marker id="M_t"><c><![CDATA[+M<S>t true|false]]></c></marker></tag> + <tag><marker id="M_t"/><c><![CDATA[+M<S>t true|false]]></c></tag> <item> <p>Multiple, thread specific instances of the allocator. This option will only have any effect on the runtime system @@ -544,20 +544,20 @@ <c>alloc_util</c>, i.e. all allocators based on <c>alloc_util</c> will be effected:</p> <taglist> - <tag><marker id="Muycs"><c><![CDATA[+Muycs <size>]]></c></marker></tag> + <tag><marker id="Muycs"/><c><![CDATA[+Muycs <size>]]></c></tag> <item> <c>sys_alloc</c> carrier size. Carriers allocated via <c>sys_alloc</c> will be allocated in sizes which are multiples of the <c>sys_alloc</c> carrier size. This is not true for main multiblock carriers and carriers allocated during a memory shortage, though.</item> - <tag><marker id="Mummc"><c><![CDATA[+Mummc <amount>]]></c></marker></tag> + <tag><marker id="Mummc"/><c><![CDATA[+Mummc <amount>]]></c></tag> <item> Max <c>mseg_alloc</c> carriers. Maximum number of carriers placed in separate memory segments. When this limit has been reached, new carriers will be placed in memory retrieved from <c>sys_alloc</c>.</item> - <tag><marker id="Musac"><c><![CDATA[+Musac <bool>]]></c></marker></tag> + <tag><marker id="Musac"/><c><![CDATA[+Musac <bool>]]></c></tag> <item> Allow <c>sys_alloc</c> carriers. By default <c>true</c>. If set to <c>false</c>, <c>sys_alloc</c> carriers will never be @@ -565,19 +565,19 @@ </taglist> <p>Instrumentation flags:</p> <taglist> - <tag><marker id="Mim"><c>+Mim true|false</c></marker></tag> + <tag><marker id="Mim"/><c>+Mim true|false</c></tag> <item> A map over current allocations is kept by the emulator. The allocation map can be retrieved via the <c>instrument</c> module. <c>+Mim true</c> implies <c>+Mis true</c>. <c>+Mim true</c> is the same as <seealso marker="erl#instr">-instr</seealso>.</item> - <tag><marker id="Mis"><c>+Mis true|false</c></marker></tag> + <tag><marker id="Mis"/><c>+Mis true|false</c></tag> <item> Status over allocated memory is kept by the emulator. The allocation status can be retrieved via the <c>instrument</c> module.</item> - <tag><marker id="Mit"><c>+Mit X</c></marker></tag> + <tag><marker id="Mit"/><c>+Mit X</c></tag> <item> Reserved for future use. Do <em>not</em> use this flag.</item> </taglist> @@ -587,7 +587,7 @@ </note> <p>Other flags:</p> <taglist> - <tag><marker id="Mea"><c>+Mea min|max|r9c|r10b|r11b|config</c></marker></tag> + <tag><marker id="Mea"/><c>+Mea min|max|r9c|r10b|r11b|config</c></tag> <item> <taglist> <tag><c>min</c></tag> @@ -617,7 +617,7 @@ </item> </taglist> </item> - <tag><marker id="Mlpm"><c>+Mlpm all|no</c></marker></tag> + <tag><marker id="Mlpm"/><c>+Mlpm all|no</c></tag> <item>Lock physical memory. The default value is <c>no</c>, i.e., no physical memory will be locked. If set to <c>all</c>, all memory mappings made by the runtime system, will be locked into diff --git a/erts/doc/src/escript.xml b/erts/doc/src/escript.xml index 46110333f9..f12f76890c 100644 --- a/erts/doc/src/escript.xml +++ b/erts/doc/src/escript.xml @@ -4,7 +4,7 @@ <comref> <header> <copyright> - <year>2007</year><year>2014</year> + <year>2007</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -96,8 +96,8 @@ $ <input>escript factorial 5</input> </pre> <note><p> The encoding specified by the above mentioned comment applies to the script itself. The encoding of the - I/O-server, however, has to be set explicitly like this: -<code>io:setopts([{encoding, unicode}])</code></p> + I/O-server, however, has to be set explicitly like this:</p> +<code>io:setopts([{encoding, unicode}])</code> <p>The default encoding of the I/O-server for <c>standard_io</c> is <c>latin1</c> since the script runs in a non-interactive terminal diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index bed1ac463d..f27e73b9d3 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2004</year><year>2013</year> + <year>2004</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -31,6 +31,129 @@ </header> <p>This document describes the changes made to the ERTS application.</p> +<section><title>Erts 7.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix bug in ETS that could cause stray objects marked for + deletion to occasionally be missed by the cleanup done by + <c>safe_fixtable(_,false)</c>.</p> + <p> + Own Id: OTP-12870</p> + </item> + <item> + <p> + Fixed VM crash that could occur if a trace port was + linked to a process, and the trace port terminated + abnormally while handling a trace message. This bug has + always existed in the runtime system with SMP support.</p> + <p> + Own Id: OTP-12901</p> + </item> + <item> + <p> + Instead of aborting, the vm now creates a crash dump when + a system process is terminated.</p> + <p> + Own Id: OTP-12934</p> + </item> + <item> + <p> + Fixed a rare emulator dead lock that occurred when + erlang:process_flag(priority,...) was called by a process + that was also scheduled for an internal system activity.</p> + <p> + Own Id: OTP-12943</p> + </item> + <item> + <p> + The runtime system on various posix platforms (except for + Linux and Solaris) could crash when large amounts of + file-descriptors were in use.</p> + <p> + Own Id: OTP-12954</p> + </item> + <item> + <p> + A beam file compiled by hipe for an incompatible runtime + system was sometimes not rejected by the loader, which + could lead to vm crash. This fix will also allow the same + hipe compiler to be used by both normal and debug-built + vm.</p> + <p> + Own Id: OTP-12962</p> + </item> + <item> + <p> + Fix bug in <c>maps:merge/2</c> when called by hipe + compiled code that could cause vm crash. Bug exists since + erts-7.0 (OTP 18.0).</p> + <p> + Own Id: OTP-12965</p> + </item> + <item> + <p> + When tracing with <c>process_dump</c> option, the VM + could abort if there was an ongoing binary match + somewhere in the call stack of the traced process.</p> + <p> + Own Id: OTP-12968</p> + </item> + <item> + <p> + Fixed possible output deadlock in tty driver when hitting + "CTRL-C" in a non-smp emulator shell on unix.</p> + <p> + Own Id: OTP-12987 Aux Id: Seq12947 </p> + </item> + <item> + <p> + Fix <c>binary_to_integer</c> to throw badarg for "+" and + "-" similar to <c>list_to_integer</c>.</p> + <p> + Own Id: OTP-12988</p> + </item> + <item> + <p> + Suppress warning of unused argument when using macro + enif_make_pid.</p> + <p> + Own Id: OTP-12989</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Changed default clock source used for OS system time on + MacOS X to <c>gettimeofday()</c> in order to improve + performance. The system can be configured during build to + use the previously used higher resolution clock source by + passing the switch <seealso + marker="doc/installation_guide:INSTALL#Advanced-configuration-and-build-of-ErlangOTP_Configuring"><c>--with-clock-resolution=high</c></seealso> + when configuring the build.</p> + <p> + Own Id: OTP-12945 Aux Id: OTP-12892 </p> + </item> + <item> + <p> + Added the <c>configure</c> option <seealso + marker="doc/installation_guide:INSTALL#Advanced-configuration-and-build-of-ErlangOTP_Configuring"><c>--disable-saved-compile-time</c></seealso> + which disables saving of compile date and time in the + emulator binary.</p> + <p> + Own Id: OTP-12971</p> + </item> + </list> + </section> + +</section> + <section><title>Erts 7.0.3</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -49,6 +172,14 @@ <p> Own Id: OTP-12942</p> </item> + <item> + <p> + When tracing with <c>process_dump</c> option, the VM + could abort if there was an ongoing binary match + somewhere in the call stack of the traced process./</p> + <p> + Own Id: OTP-12968</p> + </item> </list> </section> @@ -577,19 +708,20 @@ </item> <item> <p> - Use persistent hashmaps for large Maps <p>Maps will use a + Use persistent hashmaps for large Maps</p> + <p>Maps will use a persistent hashmap implementation when the number of pairs in a Map becomes sufficiently large. The change will occur when a Map reaches 33 pairs in size but this - limit might change in the future.</p></p> - <p>The most significant impact for the user by this + limit might change in the future.</p> + <p>The most significant impact for the user by this change is speed, and to a lesser degree memory consumption and introspection of Maps. Memory consumption size is probalistic but lesser than <c>gb_trees</c> or <c>dict</c> for instance. Any other impacts will be transparent for the user except for the following changes.</p> - <p>Semantics of Maps have changed in two incompatible + <p>Semantics of Maps have changed in two incompatible ways compared to the experimental implementation in OTP 17:</p> <list> <item>Hashing of maps is done different by <c>erlang:phash2/1,2</c>, <c>erlang:phash/1</c> and @@ -1237,7 +1369,7 @@ <p> Improved support for atomic memory operations provided by the <url - href="https://github.com/ivmai/libatomic_ops/"><c>libatomic_ops</c></url> + href="https://github.com/ivmai/libatomic_ops/">libatomic_ops</url> library. Most importantly support for use of native double word atomics when implemented by <c>libatomic_ops</c> (for example, implemented for ARM).</p> @@ -2204,22 +2336,28 @@ <p> EEP43: New data type - Maps</p> <p> - With Maps you may for instance: <taglist> <item><c>M0 = - #{ a => 1, b => 2}, % create - associations</c></item> <item><c>M1 = M0#{ a := 10 }, % - update values</c></item> <item><c>M2 = M1#{ "hi" => - "hello"}, % add new associations</c></item> <item><c>#{ - "hi" := V1, a := V2, b := V3} = M2. % match keys with - values</c></item> </taglist></p> + With Maps you may for instance:</p> + <taglist> + <tag/> <item><c>M0 = #{ a => 1, b => 2}, % create + associations</c></item> + <tag/><item><c>M1 = M0#{ a := 10 }, % update values</c></item> + <tag/><item><c>M2 = M1#{ "hi" => + "hello"}, % add new associations</c></item> + <tag/><item><c>#{ "hi" := V1, a := V2, b := V3} = M2. + % match keys with values</c></item> + </taglist> <p> For information on how to use Maps please see Map Expressions in the <seealso marker="doc/reference_manual:expressions#map_expressions"> Reference Manual</seealso>.</p> <p> The current implementation is without the following - features: <taglist> <item>No variable keys</item> - <item>No single value access</item> <item>No map - comprehensions</item> </taglist></p> + features:</p> + <taglist> + <tag/><item>No variable keys</item> + <tag/><item>No single value access</item> + <tag/><item>No map comprehensions</item> + </taglist> <p> Note that Maps is <em>experimental</em> during OTP 17.0.</p> <p> @@ -4379,8 +4517,7 @@ <p> Fix erl_prim_loader errors in handling of primary archive. The following errors have been corrected:</p> - <p> - <list> <item> If primary archive was named "xxx", then a + <list> <item> If primary archive was named "xxx", then a file in the same directory named "xxxyyy" would be interpreted as a file named "yyy" inside the archive. </item> <item> erl_prim_loader did not correctly create @@ -4395,7 +4532,8 @@ erl_prim_loader:list_dir/1 would sometimes return an empty string inside the file list. This was a virtual element representing the top directory of the archive. - This has been removed. </item> </list></p> + This has been removed. </item> + </list> <p> Thanks to Tuncer Ayaz and Shunichi Shinohara for reporting and co-authoring corrections.</p> @@ -6838,12 +6976,12 @@ Own Id: OTP-8726 Aux Id: seq11617 </p> </item> <item> - <p>Fix libm linking with --as-needed flag + <p>Fix libm linking with --as-needed flag</p> <p> When building with "--as-needed" linker flags on Linux the build will fail. This has now been fixed.</p> <p> - (Thanks to Christian Faulhammer)</p></p> + (Thanks to Christian Faulhammer)</p> <p> Own Id: OTP-8728</p> </item> diff --git a/erts/doc/src/run_erl.xml b/erts/doc/src/run_erl.xml index 0a5b2c6136..faec3c68c1 100644 --- a/erts/doc/src/run_erl.xml +++ b/erts/doc/src/run_erl.xml @@ -59,7 +59,7 @@ first argument to run_erl on the command line.</item> <tag>pipe_dir</tag> <item>This is where to put the named pipe, usually - <c><![CDATA[/tmp/]]></c> on Unix or <c><![CDATA[/pipe/]]></c> on OSE. It shall be suffixed by a <c><![CDATA[/]]></c> (slash), + <c><![CDATA[/tmp/]]></c>. It shall be suffixed by a <c><![CDATA[/]]></c> (slash), i.e. not <c><![CDATA[/tmp/epipies]]></c>, but <c><![CDATA[/tmp/epipes/]]></c>. </item> <tag>log_dir</tag> <item>This is where the log files are written. There will be one diff --git a/erts/doc/src/time_correction.xml b/erts/doc/src/time_correction.xml index aed38fbb92..236fe679cb 100644 --- a/erts/doc/src/time_correction.xml +++ b/erts/doc/src/time_correction.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1999</year><year>2014</year> + <year>1999</year><year>2015</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -35,31 +35,35 @@ <section> <title>New Extended Time Functionality</title> - <note><p>As of OTP 18 (ERTS version 7.0) the time functionality of - Erlang has been extended. This both includes a + <note><p>As of OTP 18 (<c>ERTS</c> version 7.0) the time functionality of + Erlang has been extended. This includes a <seealso marker="#The_New_Time_API">new API</seealso> - for time, as well as + for time and <seealso marker="#Time_Warp_Modes">time warp - modes</seealso> which alters the behavior of the system when + modes</seealso> that alter the system behavior when system time changes.</p> + <p>The <seealso marker="#No_Time_Warp_Mode">default time warp mode</seealso> has the same behavior as before, and the - old API will still work, so you are not required to change + old API still works. Thus, you are not required to change anything unless you want to. However, <em>you are strongly encouraged to use the new API</em> instead of the old API based on <seealso marker="erlang#now/0"><c>erlang:now/0</c></seealso>. - <c>erlang:now/0</c> has been deprecated since it is and forever - will be a scalability bottleneck. By using the new API you will + <c>erlang:now/0</c> is deprecated, as it is and + will be a scalability bottleneck.</p> + + <p>By using the new API, you automatically get scalability and performance improvements. This - will also enable you to use the - <seealso marker="#Multi_Time_Warp_Mode">multi time warp mode</seealso> - which improves accuracy, and precision of time measurements.</p></note> + also enables you to use the + <seealso marker="#Multi_Time_Warp_Mode">multi-time warp mode</seealso> + that improves accuracy and precision of time measurements.</p> + </note> </section> <section> - <title>Some Terminology</title> - <p>In order to make it easier to understand this document we first - define some terminology. This is a mixture of our own terminology + <title>Terminology</title> + <p>To make it easier to understand this section, some terms + are defined. This is a mix of our own terminology (Erlang/OS system time, Erlang/OS monotonic time, time warp) and globally accepted terminology.</p> @@ -67,7 +71,7 @@ <section> <title>Monotonically Increasing</title> <p>In a monotonically increasing sequence of values, all values - that have a predecessor are either larger than, or equal to its + that have a predecessor are either larger than or equal to its predecessor.</p> </section> @@ -82,19 +86,19 @@ <marker id="UT1"/> <section> <title>UT1</title> - <p>Universal Time. Based on the rotation of the earth. Conceptually - mean solar time at 0° longitude.</p> + <p>Universal Time. UT1 is based on the rotation of the earth + and conceptually means solar time at 0° longitude.</p> </section> <marker id="UTC"/> <section> <title>UTC</title> - <p>Coordinated Universal Time. UTC almost align with - <seealso marker="#UT1">UT1</seealso>, however, UTC uses the - SI definition of a second which is not exactly of the same length + <p>Coordinated Universal Time. UTC almost aligns with + <seealso marker="#UT1">UT1</seealso>. However, UTC uses the + SI definition of a second, which has not exactly the same length as the second used by UT1. This means that UTC slowly drifts from - UT1. In order to keep UTC relatively in sync with UT1, leap seconds - are inserted, and potentially also deleted. That is, an UTC day may + UT1. To keep UTC relatively in sync with UT1, leap seconds + are inserted, and potentially also deleted. That is, an UTC day can be 86400, 86401, or 86399 seconds long.</p> </section> @@ -104,14 +108,15 @@ <p>Time since <url href="http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap03.html#tag_21_03_00_17">Epoch</url>. Epoch is defined to be 00:00:00 <seealso marker="#UTC">UTC</seealso>, - January 1, 1970. + 1970-01-01. <url href="http://pubs.opengroup.org/onlinepubs/009604499/basedefs/xbd_chap04.html#tag_04_14">A day in POSIX time</url> is defined to be exactly 86400 seconds long. Strangely enough - Epoch is defined to be a time in UTC, and UTC have another + Epoch is defined to be a time in UTC, and UTC has another definition of how long a day is. Quoting the Open Group - <url href="http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_15">"POSIX time is therefore not necessarily UTC, despite its appearance"</url>. The effect of this is that when an UTC leap second is + <url href="http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_15">"POSIX time is therefore not necessarily UTC, despite its appearance"</url>. + The effect of this is that when an UTC leap second is inserted, POSIX time either stops for a second, or repeats the - last second. If an UTC leap second would be deleted (has never + last second. If an UTC leap second would be deleted (which has not happened yet), POSIX time would make a one second leap forward.</p> </section> @@ -125,11 +130,11 @@ <marker id="Time_Precision"/> <section> <title>Time Precision</title> - <p>The shortest time interval that can be be distinguished + <p>The shortest time interval that can be distinguished repeatedly and reliably when reading time values. Precision is limited by the <seealso marker="#Time_Resolution">resolution</seealso>, but - resolution and precision might differ significantly.</p> + resolution and precision can differ significantly.</p> </section> <marker id="Time_Accuracy"/> @@ -143,21 +148,23 @@ <title>Time Warp</title> <p>A time warp is a leap forwards or backwards in time. That is, the difference of time values taken before and after the - time warp will not correspond to the actual elapsed time.</p> + time warp does not correspond to the actual elapsed time.</p> </section> <marker id="OS_System_Time"/> <section> <title>OS System Time</title> <p>The operating systems view of - <seealso marker="#POSIX_Time">POSIX time</seealso>. It can be - retrieved by calling + <seealso marker="#POSIX_Time">POSIX time</seealso>. To + retrieve it, call <seealso marker="kernel:os#system_time/0"><c>os:system_time()</c></seealso>. This may or may not be an accurate view of POSIX time. This time may typically be adjusted both backwards and forwards without limitation. That is, <seealso marker="#Time_Warp">time warps</seealso> - may be observed. You can get information about the Erlang runtime - system's source of OS system time by calling + may be observed.</p> + + <p>To get information about the Erlang runtime + system's source of OS system time, call <seealso marker="erlang#system_info_os_system_time_source"><c>erlang:system_info(os_system_time_source)</c></seealso>.</p> </section> @@ -165,15 +172,17 @@ <section> <title>OS Monotonic Time</title> <p>A monotonically increasing time provided by the operating - system. This time does not leap and have a relatively steady + system. This time does not leap and has a relatively steady frequency although not completely correct. However, it is not - uncommon that the OS monotonic time stops if the system is - suspended. This time typically increase since some + uncommon that OS monotonic time stops if the system is + suspended. This time typically increases since some unspecified point in time that is not connected to - <seealso marker="#OS_System_Time">OS system time</seealso>. Note - that this type of time is not necessarily provided by all - operating systems. You can get information about the Erlang - runtime system's source of OS monotonic time by calling + <seealso marker="#OS_System_Time">OS system time</seealso>. + This type of time is not necessarily provided by all + operating systems.</p> + + <p>To get information about the Erlang + runtime system's source of OS monotonic time, call <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>.</p> </section> @@ -181,14 +190,17 @@ <section> <title>Erlang System Time</title> <p>The Erlang runtime systems view of - <seealso marker="#POSIX_Time">POSIX time</seealso>. It can be - retrieved by calling - <seealso marker="erlang#system_time/0"><c>erlang:system_time()</c></seealso>. - This time may or may not be an accurate view of POSIX time, and may + <seealso marker="#POSIX_Time">POSIX time</seealso>. To + retrieve it, call + <seealso marker="erlang#system_time/0"><c>erlang:system_time()</c></seealso>.</p> + + <p>This time may or may not be an accurate view of POSIX time, + and may or may not align with <seealso marker="#OS_System_Time">OS system time</seealso>. The runtime system works towards aligning the two - system times. Depending on <seealso marker="#Time_Warp_Modes">time - warp mode</seealso> used, this may be achieved by letting the Erlang + system times. Depending on the + <seealso marker="#Time_Warp_Modes">time warp mode</seealso> used, + this can be achieved by letting Erlang system time perform a <seealso marker="#Time_Warp">time warp</seealso>.</p> </section> @@ -197,35 +209,43 @@ <section> <title>Erlang Monotonic Time</title> <p>A monotonically increasing time provided by the - Erlang runtime system. The Erlang monotonic time increase since - some unspecified point in time. It can be retrieved by calling + Erlang runtime system. Erlang monotonic time increases since + some unspecified point in time. To retrieve it, call <seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time()</c></seealso>. - The - <seealso marker="#Time_Accuracy">accuracy</seealso>, and + </p> + + <p>The <seealso marker="#Time_Accuracy">accuracy</seealso> and <seealso marker="#Time_Precision">precision</seealso> of Erlang - monotonic time heavily depends on the accuracy and precision of - <seealso marker="#OS_Monotonic_Time">OS monotonic time</seealso>, - the accuracy and precision of - <seealso marker="#OS_System_Time">OS system time</seealso> as well - as on the - <seealso marker="#Time_Warp_Modes">time warp mode</seealso> - used. On a system that is lacking OS monotonic time, the Erlang - monotonic time can only guarantee monotonicity and can more or less - not give any other guarantees. The frequency adjustments made to - the Erlang monotonic time depends on the time warp mode - used.</p> - - <p>Internally in the runtime system the Erlang monotonic + monotonic time heavily depends on the following:</p> + + <list type="bulleted"> + <item>Accuracy and precision of + <seealso marker="#OS_Monotonic_Time">OS monotonic time</seealso> + </item> + <item>Accuracy and precision of + <seealso marker="#OS_System_Time">OS system time</seealso> + </item> + <item><seealso marker="#Time_Warp_Modes">time warp mode</seealso> used + </item> + </list> + + <p>On a system without OS monotonic time, Erlang monotonic + time guarantees monotonicity, but cannot give + other guarantees. The frequency adjustments made to + Erlang monotonic time depend on the time warp mode used.</p> + + <p>Internally in the runtime system, Erlang monotonic time is the "time engine" that is used for more or less - everything that has anything to do with time. All timers + everything that has anything to do with time. All timers, regardless of it is a <c>receive ... after</c> timer, BIF timer, - or a timer in the <c>timer</c> module are triggered + or a timer in the <c>timer</c> module, are triggered relative Erlang monotonic time. Even <seealso marker="#Erlang_System_Time">Erlang system time</seealso> is based on Erlang monotonic time. By adding current Erlang monotonic time with current time - offset you get current Erlang system time. Current time - offset can be retrieved by calling + offset, you get current Erlang system time.</p> + + <p>To retrieve current time offset, call <seealso marker="erlang#time_offset/0"><c>erlang:time_offset/0</c></seealso>. </p> </section> @@ -234,176 +254,169 @@ <section> <title>Introduction</title> - <p>Time is vital to an Erlang program and, more importantly, <em>correct</em> time is vital to an Erlang program. As Erlang is a language with - soft real time properties and we have the possibility to express - time in our programs, the Virtual Machine and the language has to be - very careful about what is considered a correct point in time and in + soft real-time properties and we can express + time in our programs, the Virtual Machine and the language must be + careful about what is considered a correct time and in how time functions behave.</p> - <p>In the beginning, Erlang was constructed assuming that the wall + <p>When Erlang was designed, it was assumed that the wall clock time in the system showed a monotonic time moving forward at - exactly the same pace as the definition of time. That more or less - meant that an atomic clock (or better) was expected to be attached + exactly the same pace as the definition of time. This more or less meant + that an atomic clock (or better time source) was expected to be attached to your hardware and that the hardware was then expected to be - locked away from any human (or unearthly) tinkering for all - eternity. While this might be a compelling thought, it's simply - never the case.</p> - - <p>A "normal" modern computer can not keep time. Not on itself and - not unless you actually have a chip level atomic clock wired to - it. Time, as perceived by your computer, will normally need to be - corrected. Hence the NTP protocol that together with the ntpd - process will do it's best to keep your computers time in sync with - the "real" time in the universe. Between NTP corrections, usually a + locked away from any human tinkering forever. While this can be a + compelling thought, it is simply never the case.</p> + + <p>A "normal" modern computer cannot keep time, not on itself and + not unless you have a chip-level atomic clock wired to it. Time, + as perceived by your computer, must normally be corrected. Hence + the Network Time Protocol (NTP) protocol, together with the <c>ntpd</c> + process, does its best to keep your computer time in sync with + the correct time. Between NTP corrections, usually a less potent time-keeper than an atomic clock is used.</p> - <p>But NTP is not fail safe. The NTP server can be unavailable, the - ntp.conf can be wrongly configured or your computer may from time to - time be disconnected from the internet. Furthermore you can have a - user (or even system administrator) on your system that thinks the - right way to handle daylight saving time is to adjust the clock one - hour two times a year (a tip, that is not the right way to do - it...). To further complicate things, this user fetched your - software from the internet and has never ever thought about what's - the correct time as perceived by a computer. The user simply does - not care about keeping the wall clock in sync with the rest of the - universe. The user expects your program to have omnipotent knowledge + <p>However, NTP is not fail-safe. The NTP server can be unavailable, + <c>ntp.conf</c> can be wrongly configured, or your computer may + sometimes be disconnected from Internet. Furthermore, you can have a + user (or even system administrator) who thinks the correct + way to handle Daylight Saving Time is to adjust the clock one + hour two times a year (which is the incorrect way to do it). + To complicate things further, this user fetched your + software from Internet and has not considered what + the correct time is as perceived by a computer. The user does + not care about keeping the wall clock in sync with the correct + time. The user expects your program to have unlimited knowledge about the time.</p> <p>Most programmers also expect time to be reliable, at least until - they realize that the wall clock time on their workstation is of by - a minute. Then they simply set it to the correct time, maybe or - maybe not in a smooth way. Most probably not in a smooth way.</p> + they realize that the wall clock time on their workstation is off by + a minute. Then they set it to the correct time, but most probably + not in a smooth way.</p> - <p>The amount of problems that arise when you expect the wall clock - time on the system to always be correct may be immense. Therefore Erlang + <p>The number of problems that arise when you always expect the wall clock + time on the system to be correct can be immense. Erlang therefore introduced the "corrected estimate of time", or the "time - correction" many years ago. The time correction relies on the fact + correction", many years ago. The time correction relies on the fact that most operating systems have some kind of monotonic clock, - either a real time extension or some built in "tick counter" that is - independent of the wall clock settings. This counter may have - microsecond resolution or much less, but generally it has a drift - that is not to be ignored.</p> - + either a real-time extension or some built-in "tick counter" that is + independent of the wall clock settings. This counter can have + microsecond resolution or much less, but it has a drift that cannot + be ignored.</p> </section> - <marker id="Time_Correction"/> <section> + <marker id="Time_Correction"/> <title>Time Correction</title> <p>If time correction is enabled, the Erlang runtime system - will make use of both + makes use of both <seealso marker="#OS_System_Time">OS system time</seealso> and <seealso marker="#OS_Monotonic_Time">OS monotonic time</seealso>, - in order to make adjustments of the frequency of the Erlang - monotonic clock. Time correction will ensure that + to adjust the frequency of the Erlang + monotonic clock. Time correction ensures that <seealso marker="#Erlang_Monotonic_Time">Erlang monotonic time</seealso> - will not warp, and that the frequency is relatively accurate. - The type of adjustments made to the frequency depends on the - time warp mode used. This will be discussed in more details in - the <seealso marker="#Time_Warp_Modes">time warp modes</seealso> - section below.</p> - - <p>By default time correction will be enabled if support for - it on the specific platform exist. Support for it includes - both an OS monotonic time provided by the OS, and an - implementation in the Erlang runtime system utilizing the - OS monotonic time. You can check if your system has support - for OS monotonic time by calling - <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>, - and you can check if time correction is enabled on your - system by calling + does not warp and that the frequency is relatively accurate. + The type of frequency adjustments depends on the time warp mode used. + Section <seealso marker="#Time_Warp_Modes">Time Warp Modes</seealso> + provides more details.</p> + + <p>By default time correction is enabled if support for + it exists on the specific platform. Support for it includes + both OS monotonic time, provided by the OS, and an + implementation in the Erlang runtime system using + OS monotonic time. To check if your system has support + for OS monotonic time, call + <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>. + To check if time correction is enabled on your system, call <seealso marker="erlang#system_info_time_correction"><c>erlang:system_info(time_correction)</c></seealso>.</p> - <p>Time correction is enabled or disabled by passing the + <p>To enable or disable time correction, pass command-line argument <seealso marker="erl#+c"><c>+c [true|false]</c></seealso> - command line argument to <c>erl</c>.</p> + to <c>erl</c>.</p> <p>If time correction is disabled, Erlang monotonic time - may warp forwards, it may stop and even freeze for extended - periods of time, and there are no guarantees that the frequency + may warp forwards or stop, or even freeze for extended + periods of time. There are then no guarantees that the frequency of the Erlang monotonic clock is accurate or stable.</p> <p><em>You typically never want to disable time correction</em>. - Previously there was a performance penalty associated with time - correction, but nowadays it is most often the other way around. - By disabling time correction you are likely to get bad scalability, + Previously a performance penalty was associated with time + correction, but nowadays it is usually the other way around. + If time correction is disabled, you probably get bad scalability, bad performance, and bad time measurements.</p> </section> - - <marker id="Time_Warp_Safe_Code"/> <section> + <marker id="Time_Warp_Safe_Code"/> <title>Time Warp Safe Code</title> - <p>Time warp safe code is code that is able to handle + <p>Time warp safe code can handle a <seealso marker="#Time_Warp">time warp</seealso> of - <seealso marker="#Erlang_System_Time">Erlang system time</seealso>. - </p> + <seealso marker="#Erlang_System_Time">Erlang system time</seealso>.</p> <p><seealso marker="erlang#now/0"><c>erlang:now/0</c></seealso> - behaves very bad when Erlang system time warps. When Erlang - system time do a time warp backwards, the values returned - from <c>erlang:now/0</c> will freeze (if you disregard the - micro second increments made due to the actual call) until - OS system time reach the point of the last value returned by - <c>erlang:now/0</c>. This freeze might continue for very - long periods of time. It might take years, decades, - and even longer than this until the freeze stops.</p> + behaves bad when Erlang system time warps. When Erlang + system time does a time warp backwards, the values returned + from <c>erlang:now/0</c> freeze (if you disregard the + microsecond increments made because of the actual call) until + OS system time reaches the point of the last value returned by + <c>erlang:now/0</c>. This freeze can continue for a long time. It + can take years, decades, and even longer until the freeze stops.</p> <p>All uses of <c>erlang:now/0</c> are not necessarily time warp unsafe. If you do not use it to get time, it - will be time warp safe. However <em>all uses of + is time warp safe. However, <em>all uses of <c>erlang:now/0</c> are suboptimal</em> from a performance and scalability perspective. So you really want to replace - the usage of it with other functionality. For examples - of how to replace the usage of <c>erlang:now/0</c>, - see the <seealso marker="#Dos_and_Donts">Dos and Donts</seealso> - section.</p> + the use of it with other functionality. For examples + of how to replace the use of <c>erlang:now/0</c>, see Section + <seealso marker="#Dos_and_Donts">How to Work with the New + API</seealso>.</p> </section> - <marker id="Time_Warp_Modes"/> <section> <title>Time Warp Modes</title> - + <marker id="Time_Warp_Modes"/> <p>Current <seealso marker="#Erlang_System_Time">Erlang system time</seealso> is determined by adding current <seealso marker="erlang#monotonic_time/0">Erlang monotonic time</seealso> with current <seealso marker="erlang#time_offset/0">time offset</seealso>. The time offset is managed differently depending on which time - warp mode you use. The time warp mode is set by passing the + warp mode you use.</p> + + <p>To set the time warp mode, pass command-line argument <seealso marker="erl#+C_"><c>+C [no_time_warp|single_time_warp|multi_time_warp]</c></seealso> - command line argument to <c>erl</c>.</p> + to <c>erl</c>.</p> <marker id="No_Time_Warp_Mode"/> <section> <title>No Time Warp Mode</title> <p>The time offset is determined at runtime system start - and will after this not change. This is the default behavior. - Not because it is the best mode (which it isn't). It is + and does not change later. This is the default behavior, but + not because it is the best mode (which it is not). It is default <em>only</em> because this is how the runtime system - always has behaved up until ERTS version 7.0, and you have to - ensure that your Erlang code that may execute during a time + behaved until <c>ERTS</c> 7.0. + Ensure that your Erlang code that may execute during a time warp is <seealso marker="#Time_Warp_Safe_Code">time warp - safe</seealso> before you can enable other modes.</p> + safe</seealso> before enabling other modes.</p> - <p>Since the time offset is not allowed to change, time - correction needs to adjust the frequency of the Erlang - monotonic clock in order to smoothly align Erlang system - time with OS system time. A big downside of this approach + <p>As the time offset is not allowed to change, time + correction must adjust the frequency of the Erlang + monotonic clock to align Erlang system time with OS + system time smoothly. A significant downside of this approach is that we on purpose will use a faulty frequency on the Erlang monotonic clock if adjustments are needed. This - error may be as big as 1%. This error will show up in all + error can be as large as 1%. This error will show up in all time measurements in the runtime system.</p> - <p>If time correction is not enabled, the Erlang monotonic - time will freeze when the OS system time leap backwards. - The freeze of the monotonic time will continue until - OS system time catch up. The freeze may continue for - a very long time. When OS system time leaps forwards, - Erlang monotonic time will also leap forward.</p> + <p>If time correction is not enabled, Erlang monotonic + time freezes when OS system time leaps backwards. + The freeze of monotonic time continues until + OS system time catches up. The freeze can continue for + a long time. When OS system time leaps forwards, + Erlang monotonic time also leaps forward.</p> </section> <marker id="Single_Time_Warp_Mode"/> @@ -411,26 +424,27 @@ <title>Single Time Warp Mode</title> <p>This mode is more or less a backwards compatibility mode as of its introduction.</p> + <p>On an embedded system it is not uncommon that the system - has no power supply at all, not even a battery, when it is - shut off. The system clock on such a system will typically - be way off when the system boots. If the + has no power supply, not even a battery, when it is + shut off. The system clock on such a system is typically + way off when the system boots. If <seealso marker="#No_Time_Warp_Mode">no time warp mode</seealso> is used, and the Erlang runtime system is started before - the OS system time has been corrected, the Erlang system - time may be wrong for a very long time, even centuries or - more.</p> - <p>If you for some reason need to use Erlang code that - is not + OS system time has been corrected, Erlang system time + can be wrong for a long time, centuries or even longer.</p> + + <p>If you need to use Erlang code that is not <seealso marker="#Time_Warp_Safe_Code">time warp safe</seealso>, - and you need to start the Erlang runtime system before the OS + and you need to start the Erlang runtime system before OS system time has been corrected, you may want to use the single - time warp mode. Note that there are limitations to when you can + time warp mode.</p> + + <note><p>There are limitations to when you can execute time warp unsafe code using this mode. If it is possible - to only utilize time warp safe code, it is <em>much</em> better - to use the <seealso marker="#Multi_Time_Warp_Mode">multi time - warp mode</seealso> instead. - </p> + to use time warp safe code only, it is <em>much</em> better + to use the <seealso marker="#Multi_Time_Warp_Mode">multi-time + warp mode</seealso> instead.</p></note> <p>Using the single time warp mode, the time offset is handled in two phases:</p> @@ -438,158 +452,150 @@ <taglist> <tag>Preliminary Phase</tag> <item> - <p>The preliminary phase starts when the runtime + <p>This phase starts when the runtime system starts. A preliminary time offset based on - current OS system time is determined. This offset will - from now on be fixed during the whole preliminary phase.</p> + current OS system time is determined. This offset is from + now on to be fixed during the whole preliminary phase.</p> <p>If time correction is enabled, adjustments to the - Erlang monotonic clock will be made to keep its - frequency as correct as possible, but <em>no</em> - adjustments will be made trying to align Erlang system - time and OS system time. That is, during the preliminary - Erlang system time and OS system time might diverge - from each other, and no attempt to prevent this will - be made.</p> + Erlang monotonic clock are made to keep its + frequency as correct as possible. However, <em>no</em> + adjustments are made trying to align Erlang system + time and OS system time. That is, during the preliminary phase + Erlang system time and OS system time can diverge + from each other, and no attempt is made to prevent this.</p> <p>If time correction is disabled, changes in OS system - time will effect the monotonic clock the same way as + time affects the monotonic clock the same way as when the <seealso marker="#No_Time_Warp_Mode">no time warp mode</seealso> is used.</p> </item> <tag>Final Phase</tag> <item> - - <p>The final phase begin when the user finalize the time + <p>This phase begins when the user finalizes the time offset by calling <seealso marker="erlang#system_flag_time_offset"><c>erlang:system_flag(time_offset, finalize)</c></seealso>. - The finalization can only be performed once. - </p> + The finalization can only be performed once.</p> <p>During finalization, the time offset is adjusted and - fixated so that current Erlang system time align with - current OS system time. Since the time offset may - change during the finalization, the Erlang system time - may do a time warp at this point. The time offset will - from now on be fixed until the runtime system terminates. + fixated so that current Erlang system time aligns with + current OS system time. As the time offset can + change during the finalization, Erlang system time + can do a time warp at this point. The time offset is + from now on fixed until the runtime system terminates. If time correction has been enabled, the time - correction will from now on also make adjustments - in order to align Erlang system time with OS system - time. When the system is in the final phase it behaves + correction from now on also makes adjustments + to align Erlang system time with OS system + time. When the system is in the final phase, it behaves exactly as in the <seealso marker="#No_Time_Warp_Mode">no time warp mode</seealso>.</p> - </item> </taglist> - <p>In order for this to work properly there are two - requirements that the user needs to ensure are - satisfied:</p> + <p>In order for this to work properly, the user must ensure + that the following two requirements are satisfied:</p> <taglist> <tag>Forward Time Warp</tag> <item><p>The time warp made when finalizing the time offset can only be done forwards without encountering problems. - This implies that the user has to ensure that the OS + This implies that the user must ensure that OS system time is set to a time earlier or equal to actual - POSIX time before starting the Erlang runtime system. If - you are not completely sure the OS system time is correct, + POSIX time before starting the Erlang runtime system.</p> + + <p>If you are not sure that OS system time is correct, set it to a time that is guaranteed to be earlier than actual POSIX time before starting the Erlang runtime - system just to be safe.</p></item> + system, just to be safe.</p> + </item> <tag>Finalize Correct OS System Time</tag> - <item><p>The OS system time needs to be correct when the - the user finalizes the time offset.</p></item> + <item><p>OS system time must be correct when + the user finalizes the time offset.</p> + </item> </taglist> <p>If these requirements are not fulfilled, the system - may behave very bad. - </p> - - <p>Assuming that the requirements above are fulfilled, - time correction is enabled, and that the OS system time - is adjusted using some time adjustment protocol like NTP - or similar, only small adjustments of the Erlang monotonic - time should be needed in order to keep system times - aligned after finilization. As long as the system is not - suspended, the largest adjustments needed should be for + may behave very bad.</p> + + <p>Assuming that these requirements are fulfilled, + time correction is enabled, and that OS system time + is adjusted using a time adjustment protocol such as NTP, + only small adjustments of Erlang monotonic + time are needed to keep system times + aligned after finalization. As long as the system is not + suspended, the largest adjustments needed are for inserted (or deleted) leap seconds.</p> - <warning><p>In order to be able to use this mode you have - to ensure that all Erlang code that will execute in - both phases are + <warning><p>To use this mode, ensure that + all Erlang code that will execute in both phases are <seealso marker="#Time_Warp_Safe_Code">time warp safe</seealso>.</p> - <p>Code that only execute in the final phase does not have + <p>Code executing only in the final phase does not have to be able to cope with the time warp.</p></warning> - </section> <marker id="Multi_Time_Warp_Mode"/> <section> - <title>Multi Time Warp Mode</title> - - <p><em>Multi time warp mode in combination with time - correction is the preferred configuration</em>. This since, - on almost all platforms, the Erlang runtime system will have - better performance, will scale better, will behave better, - and since the accuracy, and precision of time measurements - will be better. Only Erlang runtime systems executing on - ancient platforms will benefit from another configuration.</p> + <title>Multi-Time Warp Mode</title> + <p><em>Multi-time warp mode in combination with time + correction is the preferred configuration</em>. This as + the Erlang runtime system have better performance, scale + better, and behave better on almost all platforms. In + addition, the accuracy and precision of time measurements + are better. Only Erlang runtime systems executing on + ancient platforms benefit from another configuration.</p> <p>The time offset may change at any time without limitations. That is, Erlang system time may perform time warps both - forwards and backwards at <em>any</em> time. Since we align - the Erlang system time with the OS system time by changing + forwards and backwards at <em>any</em> time. As we align + Erlang system time with OS system time by changing the time offset, we can enable a time correction that tries to adjust the frequency of the Erlang monotonic clock to be as - correct as possible. This will make time measurements using - the Erlang monotonic time more accurate and precise.</p> + correct as possible. This makes time measurements using + Erlang monotonic time more accurate and precise.</p> <p>If time correction is disabled, Erlang monotonic time - will leap forward if OS system time leaps forward. If the - OS system time leaps backwards, Erlang monotonic time will - stop briefly but it does not freeze for extended periods - of time. This since the time offset is changed in order to + leaps forward if OS system time leaps forward. If + OS system time leaps backwards, Erlang monotonic time + stops briefly, but it does not freeze for extended periods + of time. This as the time offset is changed to align Erlang system time with OS system time.</p> - <warning><p>In order to be able to use this mode you have - to ensure that all Erlang code that will execute on the - runtime system is + <warning><p>To use this mode, ensure that all + Erlang code that will execute on the runtime system is <seealso marker="#Time_Warp_Safe_Code">time warp safe</seealso>.</p></warning> </section> </section> - <marker id="The_New_Time_API"/> <section> - <title>The New Time API</title> - + <title>New Time API</title> + <marker id="The_New_Time_API"/> <p>The old time API is based on <seealso marker="erlang#now/0"><c>erlang:now/0</c></seealso>. - The major issue with <c>erlang:now/0</c> is that it was - intended to be used for so many unrelated things. This - tied these unrelated operations together and unnecessarily - caused performance, scalability as well as accuracy, and - precision issues for operations that do not need to have - such issues. The new API spreads different functionality - over multiple functions in order to improve on this.</p> - - <p>In order to be backwards compatible <c>erlang:now/0</c> will - remain as is, but <em>you are strongly discouraged from using - it</em>. A lot of uses of <c>erlang:now/0</c> will also - prevent you from using the new - <seealso marker="#Multi_Time_Warp_Mode">multi time warp - mode</seealso> which is an important part of this + <c>erlang:now/0</c> was intended to be used for many unrelated + things. This tied these unrelated operations together and + caused issues with performance, scalability, accuracy, and + precision for operations that did not need to have + such issues. To improve this, the new API spreads different + functionality over multiple functions.</p> + + <p>To be backwards compatible, <c>erlang:now/0</c> + remains as is, but <em>you are strongly discouraged from using + it</em>. Many use cases of <c>erlang:now/0</c> + prevents you from using the new + <seealso marker="#Multi_Time_Warp_Mode">multi-time warp + mode</seealso>, which is an important part of this new time functionality improvement.</p> <p>Some of the new BIFs on some systems, perhaps surprisingly, - return negative integer values on a newly started run time - system. This is not a bug, but a memory usage optimization.</p> + return negative integer values on a newly started runtime + system. This is not a bug, but a memory use optimization.</p> + + <p>The new API consists of the following new BIFs:</p> - <p>The new API consists of a number of new BIFs:</p> <list> <item><p><seealso marker="erlang#convert_time_unit/3"><c>erlang:convert_time_unit/3</c></seealso></p></item> <item><p><seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time/0</c></seealso></p></item> @@ -604,7 +610,9 @@ <item><p><seealso marker="kernel:os#system_time/0"><c>os:system_time/0</c></seealso></p></item> <item><p><seealso marker="kernel:os#system_time/1"><c>os:system_time/1</c></seealso></p></item> </list> - <p>and a number of extensions of existing BIFs:</p> + + <p>The new API also consists of extensions of the following existing BIFs:</p> + <list> <item><p><seealso marker="erlang#monitor/2"><c>erlang:monitor(time_offset, clock_service)</c></seealso></p></item> <item><p><seealso marker="erlang#system_flag_time_offset"><c>erlang:system_flag(time_offset, finalize)</c></seealso></p></item> @@ -619,102 +627,99 @@ <marker id="The_New_Erlang_Monotonic_Time"/> <section> - <title>The New Erlang Monotonic Time</title> - <p>The Erlang monotonic time as such is new as of ERTS - version 7.0. It has been introduced in order to be able - to detach time measurements such as elapsed time from - calender time. It is very common that one is interested - in measuring elapsed time or specifying a time relative - to another point in time without having any need to know - what the involved times are in UTC or any other - globally defined time scale. By introducing a time scale - that has a local definition of where it starts, it is - possible to manage time that do not concern calender - time on that time scale. Erlang monotonic time use - such a time scale with a locally defined start.</p> - - <p>The introduction of Erlang monotonic time gives us - the possibility to adjust the two Erlang times (Erlang + <title>New Erlang Monotonic Time</title> + <p>Erlang monotonic time as such is new as of <c>ERTS</c> 7.0. + It is introduced to detach time measurements, such as elapsed + time from calendar time. In many use cases there is a need to + measure elapsed time or specify a time relative to another point + in time without the need to know the involved times in UTC or + any other globally defined time scale. By introducing a time + scale with a local definition of where it starts, time that do + not concern calendar time can be managed on that time + scale. Erlang monotonic time uses such a time scale with a + locally defined start.</p> + + <p>The introduction of Erlang monotonic time allows + us to adjust the two Erlang times (Erlang monotonic time and Erlang system time) separately. By - doing this, accuracy of elapsed time does not have to + doing this, the accuracy of elapsed time does not have to suffer just because the system time happened to be wrong at some point in time. Separate adjustments of the two times are only performed in the time warp modes, and only fully separated in the - <seealso marker="#Multi_Time_Warp_Mode">multi - time warp mode</seealso>. All other modes than the - multi time warp mode are there for backwards - compatibility reasons, and when using these the - accuracy of Erlang monotonic time suffer since + <seealso marker="#Multi_Time_Warp_Mode">multi-time + warp mode</seealso>. All other modes than the + multi-time warp mode are for backwards + compatibility reasons. When using these modes, the + accuracy of Erlang monotonic time suffer, as the adjustments of Erlang monotonic time in these - modes are more or less tied to the Erlang system - time.</p> + modes are more or less tied to Erlang system time.</p> <p>The adjustment of system time could have been made smother than using a time warp approach, but we think - that would be a bad choice. Since we are able to - express and measure time that aren't connected to - calender time by the use of Erlang monotonic time, it + that would be a bad choice. As we can + express and measure time that is not connected to + calendar time by the use of Erlang monotonic time, it is better to expose the change in Erlang system time - immediately. This since it makes it possible for the - Erlang applications executing on the system to react - on the change in system time as soon as possible. This - is also more or less exactly how most OSes handle this + immediately. This as the Erlang applications + executing on the system can react on the change in + system time as soon as possible. This is also more or + less exactly how most operating systems handle this (OS monotonic time and OS system time). By adjusting - system time smoothly we would just hide the fact that + system time smoothly, we would just hide the fact that system time changed and make it harder for the Erlang applications to react to the change in a sensible way.</p> - <p>In order to be able to react to a change in Erlang - system time you have to be able to detect that it + <p>To be able to react to a change in Erlang + system time, you must be able to detect that it happened. The change in Erlang system time occurs when current time offset is changed. We have therefore - introduced the possibility to monitor the time offset - using - <seealso marker="erlang#monitor/2"><c>erlang:monitor(time_offset, clock_service)</c></seealso>. A process monitoring the time - offset will be sent a message on the following format + introduced the possibility to monitor the time offset using + <seealso marker="erlang#monitor/2"><c>erlang:monitor(time_offset, clock_service)</c></seealso>. + A process monitoring the time + offset is sent a message on the following format when the time offset is changed:</p> + <code type="none">{'CHANGE', MonitorReference, time_offset, clock_service, NewTimeOffset}</code> </section> <marker id="Unique_Values"/> <section> <title>Unique Values</title> - <p>Besides reporting time <c>erlang:now/0</c> also - produce unique and strictly monotonically increasing - values. In order to detach this functionality from - time measurements we have introduced + <p>Besides reporting time, <c>erlang:now/0</c> also + produces unique and strictly monotonically increasing + values. To detach this functionality from + time measurements, we have introduced <seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer()</c></seealso>. </p> </section> <marker id="Dos_and_Donts"/> <section> - <title>Dos and Don'ts</title> + <title>How to Work with the New API</title> <p>Previously <c>erlang:now/0</c> was the only option for doing - quite a lot of things. We will look at a few different things - <c>erlang:now/0</c> could be used for, and how you want to do - this using the new API:</p> + many things. This section deals with some things that + <c>erlang:now/0</c> can be used for, and how you are to + these using the new API.</p> <marker id="Dos_and_Donts_Retrieve_Erlang_System_Time"/> <section> <title>Retrieve Erlang System Time</title> <dont> <p> - use <c>erlang:now/0</c> in order to retrieve current Erlang - system time. + Use <c>erlang:now/0</c> to retrieve current Erlang system time. </p> </dont> <do> <p> - use + Use <seealso marker="erlang#system_time/1"><c>erlang:system_time/1</c></seealso> - in order to retrieve current Erlang system time on the + to retrieve current Erlang system time on the <seealso marker="erlang#type_time_unit">time unit</seealso> of your choice.</p> <p>If you want the same format as returned by <c>erlang:now/0</c>, use <seealso marker="erlang#timestamp/0"><c>erlang:timestamp/0</c></seealso>. - </p> + </p> </do> </section> @@ -723,26 +728,27 @@ <title>Measure Elapsed Time</title> <dont> <p> - take timestamps with <c>erlang:now/0</c> and calculate + Take timestamps with <c>erlang:now/0</c> and calculate the difference in time with <seealso marker="stdlib:timer#now_diff/2"><c>timer:now_diff/2</c></seealso>. </p> </dont> <do> <p> - take timestamps with + Take timestamps with <seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time/0</c></seealso> and calculate the time difference using ordinary subtraction. The result will be in <c>native</c> <seealso marker="erlang#type_time_unit">time unit</seealso>. If you want to convert the - result to another time unit you can do this using + result to another time unit, you can use <seealso marker="erlang#convert_time_unit/3"><c>erlang:convert_time_unit/3</c></seealso>. </p> - <p>Another easier way of doing this is to use + + <p>An easier way to do this is to use <seealso marker="erlang#monotonic_time/1"><c>erlang:monotonic_time/1</c></seealso> - with desired time unit. However, you may lose accuracy, - and precision this way. + with the desired time unit. However, you can then lose accuracy + and precision. </p> </do> </section> @@ -752,16 +758,16 @@ <title>Determine Order of Events</title> <dont> <p> - determine the order of events by saving a timestamp - with <c>erlang:now/0</c> when the event happens. + Determine the order of events by saving a timestamp + with <c>erlang:now/0</c> when the event occurs. </p> </dont> <do> <p> - determine the order of events by saving the integer + Determine the order of events by saving the integer returned by <seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer([monotonic])</c></seealso> - when the event happens. These integers will be strictly + when the event occurs. These integers will be strictly monotonically ordered on current runtime system instance corresponding to creation time. </p> @@ -770,40 +776,43 @@ <marker id="Dos_and_Donts_Determine_Order_of_Events_With_Time_of_the_Event"/> <section> - <title>Determine Order of Events With Time of the Event</title> + <title>Determine Order of Events with Time of the Event</title> <dont> <p> - determine the order of events by saving a timestamp - with <c>erlang:now/0</c> when the event happens. + Determine the order of events by saving a timestamp + with <c>erlang:now/0</c> when the event occurs. </p> </dont> <do> <p> - determine the order of events by saving a tuple - containing + Determine the order of events by saving a tuple containing <seealso marker="erlang#monotonic_time/0">monotonic time</seealso> and a <seealso marker="erlang#unique_integer/1">strictly - monotonically increasing integer</seealso> like this:</p> + monotonically increasing integer</seealso> as follows:</p> + <code type="none"> Time = erlang:monotonic_time(), UMI = erlang:unique_integer([monotonic]), EventTag = {Time, UMI}</code> + <p>These tuples will be strictly monotonically ordered - on the current runtime system instance according to - creation time. Note that it is important that the + on current runtime system instance according to + creation time. It is important that the monotonic time is in the first element (the most significant element when comparing 2-tuples). Using the monotonic time in the tuples, you can calculate time between events.</p> - <p>If you are interested in the Erlang system time at the - time when the event occurred you can also save the time + + <p>If you are interested in Erlang system time at the + time when the event occurred, you can also save the time offset before or after saving the events using <seealso marker="erlang#time_offset/0"><c>erlang:time_offset/0</c></seealso>. Erlang monotonic time added with the time offset corresponds to Erlang system time.</p> + <p>If you are executing in a mode where time offset - may change and you want to be able to get the actual - Erlang system time when the event occurred you can + can change, and you want to get the actual + Erlang system time when the event occurred, you can save the time offset as a third element in the tuple (the least significant element when comparing 3-tuples).</p> </do> @@ -814,16 +823,15 @@ EventTag = {Time, UMI}</code> <title>Create a Unique Name</title> <dont> <p> - use the values returned from <c>erlang:now/0</c> - in order to create a name unique on the current - runtime system instance. + Use the values returned from <c>erlang:now/0</c> + to create a name unique on the current runtime system instance. </p> </dont> <do> <p> - use the value returned from + Use the value returned from <seealso marker="erlang#unique_integer/0"><c>erlang:unique_integer/0</c></seealso> - in order to create a name unique on the current runtime system + to create a name unique on the current runtime system instance. If you only want positive integers, you can use <seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer([positive])</c></seealso>. </p> @@ -832,49 +840,63 @@ EventTag = {Time, UMI}</code> <marker id="Dos_and_Donts_Seed_Random_Number_Generation_With_a_Unique_Value"/> <section> - <title>Seed Random Number Generation With a Unique Value</title> + <title>Seed Random Number Generation with a Unique Value</title> <dont> <p> - seed random number generation using <c>erlang:now()</c>. + Seed random number generation using <c>erlang:now()</c>. </p> </dont> <do> <p> - seed random number generation using a combination of + Seed random number generation using a combination of <seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time()</c></seealso>, <seealso marker="erlang#time_offset/0"><c>erlang:time_offset()</c></seealso>, - <seealso marker="erlang#unique_integer/0"><c>erlang:unique_integer()</c></seealso>, and other functionality. + <seealso marker="erlang#unique_integer/0"><c>erlang:unique_integer()</c></seealso>, + and other functionality. </p> </do> </section> - <p>To sum this section up: <em>Don't use <c>erlang:now/0</c>!</em></p> + <p>To sum up this section: <em>Do not use <c>erlang:now/0</c>.</em></p> </section> </section> - <marker id="Supporting_Both_New_and_Old_OTP_Releases"/> <section> - <title>Supporting Both New and Old OTP Releases</title> - <p>Your code may be required to be able to run on a variety + <marker id="Supporting_Both_New_and_Old_OTP_Releases"/> + <title>Support of Both New and Old OTP Releases</title> + <p>It can be required that your code must run on a variety of OTP installations of different OTP releases. If so, you - can not just use the new API out of the box, since it will + cannot use the new API out of the box, as it will not be available on old pre OTP 18 releases. The solution - is <em>not</em> to avoid using the new API, since your - code then won't be able to benefit from the scalability - and accuracy improvements made. Instead you want to use the + is <em>not</em> to avoid using the new API, as your + code then would not benefit from the scalability + and accuracy improvements made. Instead, use the new API when available, and fall back on <c>erlang:now/0</c> - when it is not available. Fortunately almost all of the new - API can easily be implemented using existing primitives - (except for - <seealso marker="erlang#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso>, - <seealso marker="erlang#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso>, - <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>, and - <seealso marker="erlang#system_info_os_system_time_source"><c>erlang:system_info(os_system_time_source)</c></seealso>). - By wrapping the API with functions that fall back on - <c>erlang:now/0</c> when the new API is not available, - and using these wrappers instead of using the API directly - the problem is solved. These wrappers can for example + when the new API is unavailable.</p> + + <p>Fortunately most of the new API can easily be + implemented using existing primitives, except for:</p> + + <list type="bulleted"> + <item> + <seealso marker="erlang#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso> + </item> + <item> + <seealso marker="erlang#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso> + </item> + <item> + <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso> + </item> + <item> + <seealso marker="erlang#system_info_os_system_time_source"><c>erlang:system_info(os_system_time_source)</c></seealso>) + </item> + </list> + + <p>By wrapping the API with functions that fall back on + <c>erlang:now/0</c> when the new API is unavailable, + and using these wrappers instead of using the API directly, + the problem is solved. These wrappers can, for example, be implemented as in - <url href="time_compat.erl"><c>$ERL_TOP/erts/example/time_compat.erl</c></url>.</p> + <url href="time_compat.erl">$ERL_TOP/erts/example/time_compat.erl</url>.</p> </section> </chapter> diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index a919f0e3ac..c5080d5b5d 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -23,10 +23,6 @@ include ../vsn.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk -include $(TARGET)/gen_git_version.mk -ifeq ($(findstring ose,$(TARGET)),ose) -include $(ERL_TOP)/make/$(TARGET)/ose_lm.mk -endif - ENABLE_ALLOC_TYPE_VARS = @ENABLE_ALLOC_TYPE_VARS@ HIPE_ENABLED=@HIPE_ENABLED@ DTRACE_ENABLED=@DTRACE_ENABLED@ @@ -245,9 +241,7 @@ HCC = @HCC@ LD = @LD@ DEXPORT = @DEXPORT@ RANLIB = @RANLIB@ -ifneq ($(findstring ose,$(TARGET)),ose) STRIP = strip -endif PERL = @PERL@ RM = @RM@ MKDIR = @MKDIR@ @@ -684,14 +678,6 @@ $(OBJDIR)/%.o: $(TTF_DIR)/%.c $(OBJDIR)/%.o: sys/$(ERLANG_OSTYPE)/%.c $(V_CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ -ifeq ($(findstring ose,$(TARGET)),ose) -$(OBJDIR)/ose_confd.o: $(OSE_CONFD) - $(V_CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ - -$(OBJDIR)/crt0_lm.o: $(CRT0_LM) - $(V_CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ -endif - $(OBJDIR)/%.o: sys/common/%.c $(V_CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@ @@ -810,29 +796,6 @@ OS_OBJS = \ $(OBJDIR)/dosmap.o else -ifeq ($(findstring ose,$(TARGET)),ose) -OS_OBJS = \ - $(OBJDIR)/sys.o \ - $(OBJDIR)/driver_tab.o \ - $(OBJDIR)/ose_efile.o \ - $(OBJDIR)/gzio.o \ - $(OBJDIR)/elib_memmove.o - -OS_OBJS += $(OBJDIR)/ose_confd.o \ - $(OBJDIR)/crt0_lm.o - -OS_OBJS += $(OBJDIR)/sys_float.o \ - $(OBJDIR)/sys_time.o - -DRV_OBJS = \ - $(OBJDIR)/efile_drv.o \ - $(OBJDIR)/ose_signal_drv.o \ - $(OBJDIR)/inet_drv.o \ - $(OBJDIR)/zlib_drv.o \ - $(OBJDIR)/ram_file_drv.o \ - $(OBJDIR)/ttsl_drv.o - -else OS_OBJS = \ $(OBJDIR)/sys.o \ $(OBJDIR)/driver_tab.o \ @@ -849,7 +812,6 @@ DRV_OBJS = \ $(OBJDIR)/ram_file_drv.o \ $(OBJDIR)/ttsl_drv.o endif -endif ifneq ($(STATIC_NIFS),no) STATIC_NIF_LIBS = $(STATIC_NIFS) @@ -1022,19 +984,12 @@ $(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS) $(STATIC_DRIVER_LIBS) $(LIBS) else -ifeq ($(findstring ose,$(TARGET)),ose) -$(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS) $(LCF) - $(call build-ose-load-module, $@, $(INIT_OBJS) $(OBJS), $(STATIC_NIF_LIBS) \ - $(STATIC_DRIVER_LIBS) $(LIBS), $(BEAM_LMCONF)) - -else $(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS) $(ld_verbose)$(PURIFY) $(LD) -o $(BINDIR)/$(EMULATOR_EXECUTABLE) \ $(HIPEBEAMLDFLAGS) $(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS) \ $(STATIC_NIF_LIBS) $(STATIC_DRIVER_LIBS) $(LIBS) endif -endif # ---------------------------------------------------------------------- # Dependencies diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 7a50b24818..967cf013f0 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -320,6 +320,7 @@ atom ldflags atom Le='=<' atom lf atom line +atom line_delimiter atom line_length atom linked_in_driver atom links @@ -436,13 +437,6 @@ atom orelse atom os_pid atom os_type atom os_version -atom ose_bg_proc -atom ose_int_proc -atom ose_phantom -atom ose_pri_proc -atom ose_process_prio -atom ose_process_type -atom ose_ti_proc atom out atom out_exited atom out_exiting diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 0e192b1ebd..11508a1b39 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -913,7 +913,7 @@ any_heap_ref_ptrs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size) switch (primary_tag(val)) { case TAG_PRIMARY_BOXED: case TAG_PRIMARY_LIST: - if (in_area(EXPAND_POINTER(val), mod_start, mod_size)) { + if (in_area(val, mod_start, mod_size)) { return 1; } break; @@ -933,7 +933,7 @@ any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size) switch (primary_tag(val)) { case TAG_PRIMARY_BOXED: case TAG_PRIMARY_LIST: - if (in_area(EXPAND_POINTER(val), mod_start, mod_size)) { + if (in_area(val, mod_start, mod_size)) { return 1; } break; @@ -943,7 +943,7 @@ any_heap_refs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size) if (header_is_bin_matchstate(val)) { ErlBinMatchState *ms = (ErlBinMatchState*) p; ErlBinMatchBuffer *mb = &(ms->mb); - if (in_area(EXPAND_POINTER(mb->orig), mod_start, mod_size)) { + if (in_area(mb->orig, mod_start, mod_size)) { return 1; } } diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index c774a70d4c..0e921d761c 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -79,7 +79,7 @@ erts_debug_breakpoint_2(BIF_ALIST_2) { Process* p = BIF_P; Eterm MFA = BIF_ARG_1; - Eterm bool = BIF_ARG_2; + Eterm boolean = BIF_ARG_2; Eterm* tp; Eterm mfa[3]; int i; @@ -87,7 +87,7 @@ erts_debug_breakpoint_2(BIF_ALIST_2) Eterm res; BpFunctions f; - if (bool != am_true && bool != am_false) + if (boolean != am_true && boolean != am_false) goto error; if (is_not_tuple(MFA)) { @@ -124,7 +124,7 @@ erts_debug_breakpoint_2(BIF_ALIST_2) erts_smp_thr_progress_block(); erts_bp_match_functions(&f, mfa, specified); - if (bool == am_true) { + if (boolean == am_true) { erts_set_debug_break(&f); erts_install_breakpoints(&f); erts_commit_staged_bp(); @@ -432,39 +432,33 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) while (*sign) { switch (*sign) { case 'r': /* x(0) */ - erts_print(to, to_arg, "x(0)"); + erts_print(to, to_arg, "r(0)"); break; case 'x': /* x(N) */ - if (reg_index(ap[0]) == 0) { - erts_print(to, to_arg, "x[0]"); - } else { - erts_print(to, to_arg, "x(%d)", reg_index(ap[0])); + { + Uint n = ap[0] / sizeof(Eterm); + erts_print(to, to_arg, "x(%d)", n); + ap++; } - ap++; break; case 'y': /* y(N) */ - erts_print(to, to_arg, "y(%d)", reg_index(ap[0]) - CP_SIZE); - ap++; + { + Uint n = ap[0] / sizeof(Eterm) - CP_SIZE; + erts_print(to, to_arg, "y(%d)", n); + ap++; + } break; case 'n': /* Nil */ erts_print(to, to_arg, "[]"); break; case 's': /* Any source (tagged constant or register) */ - tag = beam_reg_tag(*ap); - if (tag == X_REG_DEF) { - if (reg_index(*ap) == 0) { - erts_print(to, to_arg, "x[0]"); - } else { - erts_print(to, to_arg, "x(%d)", reg_index(*ap)); - } + tag = loader_tag(*ap); + if (tag == LOADER_X_REG) { + erts_print(to, to_arg, "x(%d)", loader_x_reg_index(*ap)); ap++; break; - } else if (tag == Y_REG_DEF) { - erts_print(to, to_arg, "y(%d)", reg_index(*ap) - CP_SIZE); - ap++; - break; - } else if (tag == R_REG_DEF) { - erts_print(to, to_arg, "x(0)"); + } else if (tag == LOADER_Y_REG) { + erts_print(to, to_arg, "y(%d)", loader_y_reg_index(*ap) - CP_SIZE); ap++; break; } @@ -481,20 +475,12 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) ap++; break; case 'd': /* Destination (x(0), x(N), y(N)) */ - switch (beam_reg_tag(*ap)) { - case X_REG_DEF: - if (reg_index(*ap) == 0) { - erts_print(to, to_arg, "x[0]"); - } else { - erts_print(to, to_arg, "x(%d)", reg_index(*ap)); - } - break; - case Y_REG_DEF: - erts_print(to, to_arg, "y(%d)", reg_index(*ap) - CP_SIZE); - break; - case R_REG_DEF: - erts_print(to, to_arg, "x(0)"); - break; + if (*ap & 1) { + erts_print(to, to_arg, "y(%d)", + *ap / sizeof(Eterm) - CP_SIZE); + } else { + erts_print(to, to_arg, "x(%d)", + *ap / sizeof(Eterm)); } ap++; break; @@ -561,7 +547,7 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) ap++; break; case 'l': /* fr(N) */ - erts_print(to, to_arg, "fr(%d)", reg_index(ap[0])); + erts_print(to, to_arg, "fr(%d)", loader_reg_index(ap[0])); ap++; break; default: @@ -580,7 +566,6 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) unpacked = ap; ap = addr + size; switch (op) { - case op_i_select_val_lins_rfI: case op_i_select_val_lins_xfI: case op_i_select_val_lins_yfI: { @@ -600,7 +585,6 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) } } break; - case op_i_select_val_bins_rfI: case op_i_select_val_bins_xfI: case op_i_select_val_bins_yfI: { @@ -614,7 +598,6 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) } } break; - case op_i_select_tuple_arity_rfI: case op_i_select_tuple_arity_xfI: case op_i_select_tuple_arity_yfI: { @@ -639,7 +622,6 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) } } break; - case op_i_jump_on_val_rfII: case op_i_jump_on_val_xfII: case op_i_jump_on_val_yfII: { @@ -651,7 +633,6 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) } } break; - case op_i_jump_on_val_zero_rfI: case op_i_jump_on_val_zero_xfI: case op_i_jump_on_val_zero_yfI: { @@ -663,7 +644,6 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) } } break; - case op_i_put_tuple_rI: case op_i_put_tuple_xI: case op_i_put_tuple_yI: case op_new_map_dII: @@ -673,20 +653,16 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) int n = unpacked[-1]; while (n > 0) { - if (!is_header(ap[0])) { + switch (loader_tag(ap[0])) { + case LOADER_X_REG: + erts_print(to, to_arg, " x(%d)", loader_x_reg_index(ap[0])); + break; + case LOADER_Y_REG: + erts_print(to, to_arg, " x(%d)", loader_y_reg_index(ap[0])); + break; + default: erts_print(to, to_arg, " %T", (Eterm) ap[0]); - } else { - switch ((ap[0] >> 2) & 0x03) { - case R_REG_DEF: - erts_print(to, to_arg, " x(0)"); - break; - case X_REG_DEF: - erts_print(to, to_arg, " x(%d)", ap[0] >> 4); - break; - case Y_REG_DEF: - erts_print(to, to_arg, " y(%d)", ap[0] >> 4); - break; - } + break; } ap++, size++, n--; } @@ -699,18 +675,16 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr) while (n > 0) { if (n % 3 == 1) { erts_print(to, to_arg, " %X", ap[0]); - } else if (!is_header(ap[0])) { - erts_print(to, to_arg, " %T", (Eterm) ap[0]); } else { - switch ((ap[0] >> 2) & 0x03) { - case R_REG_DEF: - erts_print(to, to_arg, " x(0)"); + switch (loader_tag(ap[0])) { + case LOADER_X_REG: + erts_print(to, to_arg, " x(%d)", loader_x_reg_index(ap[0])); break; - case X_REG_DEF: - erts_print(to, to_arg, " x(%d)", ap[0] >> 4); + case LOADER_Y_REG: + erts_print(to, to_arg, " y(%d)", loader_y_reg_index(ap[0])); break; - case Y_REG_DEF: - erts_print(to, to_arg, " y(%d)", ap[0] >> 4); + default: + erts_print(to, to_arg, " %T", (Eterm) ap[0]); break; } } diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 38def5d89f..faf496a030 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -99,10 +99,7 @@ do { \ do { \ int i_; \ int Arity_ = PC[-1]; \ - if (Arity_ > 0) { \ - CHECK_TERM(r(0)); \ - } \ - for (i_ = 1; i_ < Arity_; i_++) { \ + for (i_ = 0; i_ < Arity_; i_++) { \ CHECK_TERM(x(i_)); \ } \ } while (0) @@ -151,25 +148,21 @@ do { \ ASSERT(VALID_INSTR(* (Eterm *)(ip))); \ I = (ip) -#define FetchArgs(S1, S2) tmp_arg1 = (S1); tmp_arg2 = (S2) +/* + * Register target (X or Y register). + */ +#define REG_TARGET(Target) (*(((Target) & 1) ? &yb(Target-1) : &xb(Target))) /* * Store a result into a register given a destination descriptor. */ -#define StoreResult(Result, DestDesc) \ - do { \ - Eterm stb_reg; \ - stb_reg = (DestDesc); \ - CHECK_TERM(Result); \ - switch (beam_reg_tag(stb_reg)) { \ - case R_REG_DEF: \ - r(0) = (Result); break; \ - case X_REG_DEF: \ - xb(x_reg_offset(stb_reg)) = (Result); break; \ - default: \ - yb(y_reg_offset(stb_reg)) = (Result); break; \ - } \ +#define StoreResult(Result, DestDesc) \ + do { \ + Eterm stb_reg; \ + stb_reg = (DestDesc); \ + CHECK_TERM(Result); \ + REG_TARGET(stb_reg) = (Result); \ } while (0) #define StoreSimpleDest(Src, Dest) Dest = (Src) @@ -180,22 +173,16 @@ do { \ * be just before the next instruction. */ -#define StoreBifResult(Dst, Result) \ - do { \ - BeamInstr* stb_next; \ - Eterm stb_reg; \ - stb_reg = Arg(Dst); \ - I += (Dst) + 2; \ - stb_next = (BeamInstr *) *I; \ - CHECK_TERM(Result); \ - switch (beam_reg_tag(stb_reg)) { \ - case R_REG_DEF: \ - r(0) = (Result); Goto(stb_next); \ - case X_REG_DEF: \ - xb(x_reg_offset(stb_reg)) = (Result); Goto(stb_next); \ - default: \ - yb(y_reg_offset(stb_reg)) = (Result); Goto(stb_next); \ - } \ +#define StoreBifResult(Dst, Result) \ + do { \ + BeamInstr* stb_next; \ + Eterm stb_reg; \ + stb_reg = Arg(Dst); \ + I += (Dst) + 2; \ + stb_next = (BeamInstr *) *I; \ + CHECK_TERM(Result); \ + REG_TARGET(stb_reg) = (Result); \ + Goto(stb_next); \ } while (0) #define ClauseFail() goto jump_f @@ -293,7 +280,7 @@ void** beam_ops; #define Ib(N) (N) #define x(N) reg[N] #define y(N) E[N] -#define r(N) x##N +#define r(N) x(N) /* * Makes sure that there are StackNeed + HeapNeed + 1 words available @@ -309,12 +296,10 @@ void** beam_ops; needed = (StackNeed) + 1; \ if (E - HTOP < (needed + (HeapNeed))) { \ SWAPOUT; \ - reg[0] = r(0); \ PROCESS_MAIN_CHK_LOCKS(c_p); \ FCALLS -= erts_garbage_collect(c_p, needed + (HeapNeed), reg, (M)); \ ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); \ PROCESS_MAIN_CHK_LOCKS(c_p); \ - r(0) = reg[0]; \ SWAPIN; \ } \ E -= needed; \ @@ -363,12 +348,10 @@ void** beam_ops; unsigned need = (Nh); \ if ((E - HTOP < need) || (MSO(c_p).overhead + (VNh) >= BIN_VHEAP_SZ(c_p))) {\ SWAPOUT; \ - reg[0] = r(0); \ PROCESS_MAIN_CHK_LOCKS(c_p); \ FCALLS -= erts_garbage_collect(c_p, need, reg, (Live)); \ ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); \ PROCESS_MAIN_CHK_LOCKS(c_p); \ - r(0) = reg[0]; \ SWAPIN; \ } \ HEAP_SPACE_VERIFIED(need); \ @@ -386,12 +369,10 @@ void** beam_ops; unsigned need = (Nh); \ if (E - HTOP < need) { \ SWAPOUT; \ - reg[0] = r(0); \ PROCESS_MAIN_CHK_LOCKS(c_p); \ FCALLS -= erts_garbage_collect(c_p, need, reg, (Live)); \ ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); \ PROCESS_MAIN_CHK_LOCKS(c_p); \ - r(0) = reg[0]; \ SWAPIN; \ } \ HEAP_SPACE_VERIFIED(need); \ @@ -408,15 +389,11 @@ void** beam_ops; unsigned need = (Nh); \ if (E - HTOP < need) { \ SWAPOUT; \ - reg[0] = r(0); \ reg[Live] = Extra; \ PROCESS_MAIN_CHK_LOCKS(c_p); \ FCALLS -= erts_garbage_collect(c_p, need, reg, (Live)+1); \ ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); \ PROCESS_MAIN_CHK_LOCKS(c_p); \ - if (Live > 0) { \ - r(0) = reg[0]; \ - } \ Extra = reg[Live]; \ SWAPIN; \ } \ @@ -439,7 +416,6 @@ void** beam_ops; #define MakeFun(FunP, NumFree) \ do { \ SWAPOUT; \ - reg[0] = r(0); \ r(0) = new_fun(c_p, reg, (ErlFunEntry *) FunP, NumFree); \ SWAPIN; \ } while (0) @@ -531,15 +507,19 @@ void** beam_ops; ASSERT(VALID_INSTR(Dst)); \ Goto(Dst) -#define GetR(pos, tr) \ - do { \ - tr = Arg(pos); \ - switch (beam_reg_tag(tr)) { \ - case R_REG_DEF: tr = r(0); break; \ - case X_REG_DEF: tr = xb(x_reg_offset(tr)); break; \ - case Y_REG_DEF: ASSERT(y_reg_offset(tr) >= 1); tr = yb(y_reg_offset(tr)); break; \ - } \ - CHECK_TERM(tr); \ +#define GetR(pos, tr) \ + do { \ + tr = Arg(pos); \ + switch (loader_tag(tr)) { \ + case LOADER_X_REG: \ + tr = x(loader_x_reg_index(tr)); \ + break; \ + case LOADER_Y_REG: \ + ASSERT(loader_y_reg_index(tr) >= 1); \ + tr = y(loader_y_reg_index(tr)); \ + break; \ + } \ + CHECK_TERM(tr); \ } while (0) #define GetArg1(N, Dst) GetR((N), Dst) @@ -557,24 +537,93 @@ void** beam_ops; HTOP += 2; \ } while (0) +#define Swap(R1, R2) \ + do { \ + Eterm V = R1; \ + R1 = R2; \ + R2 = V; \ + } while (0) + +#define SwapTemp(R1, R2, Tmp) \ + do { \ + Eterm V = R1; \ + R1 = R2; \ + R2 = Tmp = V; \ + } while (0) + #define Move(Src, Dst, Store) \ do { \ Eterm term = (Src); \ Store(term, Dst); \ } while (0) -#define Move2(S1, D1, S2, D2) D1 = (S1); D2 = (S2) +#define Move2Par(S1, D1, S2, D2) \ + do { \ + Eterm V1, V2; \ + V1 = (S1); V2 = (S2); D1 = V1; D2 = V2; \ + } while (0) + +#define MoveShift(Src, SD, D) \ + do { \ + Eterm V; \ + V = Src; D = SD; SD = V; \ + } while (0) + +#define MoveDup(Src, D1, D2) \ + do { \ + D1 = D2 = (Src); \ + } while (0) + #define Move3(S1, D1, S2, D2, S3, D3) D1 = (S1); D2 = (S2); D3 = (S3) -#define MoveGenDest(src, dstp) \ - if ((dstp) == NULL) { r(0) = (src); } else { *(dstp) = src; } +#define MoveWindow3(S1, S2, S3, D) \ + do { \ + Eterm xt0, xt1, xt2; \ + Eterm *y = &D; \ + xt0 = S1; \ + xt1 = S2; \ + xt2 = S3; \ + y[0] = xt0; \ + y[1] = xt1; \ + y[2] = xt2; \ + } while (0) + +#define MoveWindow4(S1, S2, S3, S4, D) \ + do { \ + Eterm xt0, xt1, xt2, xt3; \ + Eterm *y = &D; \ + xt0 = S1; \ + xt1 = S2; \ + xt2 = S3; \ + xt3 = S4; \ + y[0] = xt0; \ + y[1] = xt1; \ + y[2] = xt2; \ + y[3] = xt3; \ + } while (0) -#define MoveReturn(Src, Dest) \ - (Dest) = (Src); \ - I = c_p->cp; \ - ASSERT(VALID_INSTR(*c_p->cp)); \ - c_p->cp = 0; \ - CHECK_TERM(r(0)); \ +#define MoveWindow5(S1, S2, S3, S4, S5, D) \ + do { \ + Eterm xt0, xt1, xt2, xt3, xt4; \ + Eterm *y = &D; \ + xt0 = S1; \ + xt1 = S2; \ + xt2 = S3; \ + xt3 = S4; \ + xt4 = S5; \ + y[0] = xt0; \ + y[1] = xt1; \ + y[2] = xt2; \ + y[3] = xt3; \ + y[4] = xt4; \ + } while (0) + +#define MoveReturn(Src) \ + x(0) = (Src); \ + I = c_p->cp; \ + ASSERT(VALID_INSTR(*c_p->cp)); \ + c_p->cp = 0; \ + CHECK_TERM(r(0)); \ Goto(*I) #define DeallocateReturn(Deallocate) \ @@ -586,26 +635,26 @@ void** beam_ops; Goto(*I); \ } while (0) -#define MoveDeallocateReturn(Src, Dest, Deallocate) \ - (Dest) = (Src); \ +#define MoveDeallocateReturn(Src, Deallocate) \ + x(0) = (Src); \ DeallocateReturn(Deallocate) -#define MoveCall(Src, Dest, CallDest, Size) \ - (Dest) = (Src); \ +#define MoveCall(Src, CallDest, Size) \ + x(0) = (Src); \ SET_CP(c_p, I+Size+1); \ - SET_I((BeamInstr *) CallDest); \ + SET_I((BeamInstr *) CallDest); \ Dispatch(); -#define MoveCallLast(Src, Dest, CallDest, Deallocate) \ - (Dest) = (Src); \ - RESTORE_CP(E); \ - E = ADD_BYTE_OFFSET(E, (Deallocate)); \ - SET_I((BeamInstr *) CallDest); \ +#define MoveCallLast(Src, CallDest, Deallocate) \ + x(0) = (Src); \ + RESTORE_CP(E); \ + E = ADD_BYTE_OFFSET(E, (Deallocate)); \ + SET_I((BeamInstr *) CallDest); \ Dispatch(); -#define MoveCallOnly(Src, Dest, CallDest) \ - (Dest) = (Src); \ - SET_I((BeamInstr *) CallDest); \ +#define MoveCallOnly(Src, CallDest) \ + x(0) = (Src); \ + SET_I((BeamInstr *) CallDest); \ Dispatch(); #define MoveJump(Src) \ @@ -613,58 +662,56 @@ void** beam_ops; SET_I((BeamInstr *) Arg(0)); \ Goto(*I); -#define GetList(Src, H, T) do { \ - Eterm* tmp_ptr = list_val(Src); \ - H = CAR(tmp_ptr); \ - T = CDR(tmp_ptr); } while (0) - -#define GetTupleElement(Src, Element, Dest) \ - do { \ - tmp_arg1 = (Eterm) COMPRESS_POINTER(((unsigned char *) tuple_val(Src)) + \ - (Element)); \ - (Dest) = (*(Eterm *) EXPAND_POINTER(tmp_arg1)); \ - } while (0) - -#define ExtractNextElement(Dest) \ - tmp_arg1 += sizeof(Eterm); \ - (Dest) = (* (Eterm *) (((unsigned char *) EXPAND_POINTER(tmp_arg1)))) - -#define ExtractNextElement2(Dest) \ - do { \ - Eterm* ene_dstp = &(Dest); \ - ene_dstp[0] = ((Eterm *) EXPAND_POINTER(tmp_arg1))[1]; \ - ene_dstp[1] = ((Eterm *) EXPAND_POINTER(tmp_arg1))[2]; \ - tmp_arg1 += sizeof(Eterm) + sizeof(Eterm); \ +#define GetList(Src, H, T) \ + do { \ + Eterm* tmp_ptr = list_val(Src); \ + Eterm hd, tl; \ + hd = CAR(tmp_ptr); \ + tl = CDR(tmp_ptr); \ + H = hd; T = tl; \ } while (0) -#define ExtractNextElement3(Dest) \ - do { \ - Eterm* ene_dstp = &(Dest); \ - ene_dstp[0] = ((Eterm *) EXPAND_POINTER(tmp_arg1))[1]; \ - ene_dstp[1] = ((Eterm *) EXPAND_POINTER(tmp_arg1))[2]; \ - ene_dstp[2] = ((Eterm *) EXPAND_POINTER(tmp_arg1))[3]; \ - tmp_arg1 += 3*sizeof(Eterm); \ +#define GetTupleElement(Src, Element, Dest) \ + do { \ + Eterm* src; \ + src = ADD_BYTE_OFFSET(tuple_val(Src), (Element)); \ + (Dest) = *src; \ } while (0) -#define ExtractNextElement4(Dest) \ - do { \ - Eterm* ene_dstp = &(Dest); \ - ene_dstp[0] = ((Eterm *) EXPAND_POINTER(tmp_arg1))[1]; \ - ene_dstp[1] = ((Eterm *) EXPAND_POINTER(tmp_arg1))[2]; \ - ene_dstp[2] = ((Eterm *) EXPAND_POINTER(tmp_arg1))[3]; \ - ene_dstp[3] = ((Eterm *) EXPAND_POINTER(tmp_arg1))[4]; \ - tmp_arg1 += 4*sizeof(Eterm); \ +#define GetTupleElement2(Src, Element, Dest) \ + do { \ + Eterm* src; \ + Eterm* dst; \ + Eterm E1, E2; \ + src = ADD_BYTE_OFFSET(tuple_val(Src), (Element)); \ + dst = &(Dest); \ + E1 = src[0]; \ + E2 = src[1]; \ + dst[0] = E1; \ + dst[1] = E2; \ } while (0) -#define ExtractElement(Element, Dest) \ - do { \ - tmp_arg1 += (Element); \ - (Dest) = (* (Eterm *) EXPAND_POINTER(tmp_arg1)); \ +#define GetTupleElement3(Src, Element, Dest) \ + do { \ + Eterm* src; \ + Eterm* dst; \ + Eterm E1, E2, E3; \ + src = ADD_BYTE_OFFSET(tuple_val(Src), (Element)); \ + dst = &(Dest); \ + E1 = src[0]; \ + E2 = src[1]; \ + E3 = src[2]; \ + dst[0] = E1; \ + dst[1] = E2; \ + dst[2] = E3; \ } while (0) #define EqualImmed(X, Y, Action) if (X != Y) { Action; } #define NotEqualImmed(X, Y, Action) if (X == Y) { Action; } #define EqualExact(X, Y, Action) if (!EQ(X,Y)) { Action; } +#define NotEqualExact(X, Y, Action) if (EQ(X,Y)) { Action; } +#define Equal(X, Y, Action) if (!CMP_EQ(X,Y)) { Action; } +#define NotEqual(X, Y, Action) if (!CMP_NE(X,Y)) { Action; } #define IsLessThan(X, Y, Action) if (CMP_GE(X, Y)) { Action; } #define IsGreaterEqual(X, Y, Action) if (CMP_LT(X, Y)) { Action; } @@ -690,18 +737,26 @@ void** beam_ops; if (is_not_list(Src)) { Fail; } \ A(Need, Alive) -#define IsNonemptyListTestHeap(Src, Need, Alive, Fail) \ - if (is_not_list(Src)) { Fail; } \ +#define IsNonemptyListTestHeap(Need, Alive, Fail) \ + if (is_not_list(x(0))) { Fail; } \ TestHeap(Need, Alive) +#define IsNonemptyListGetList(Src, H, T, Fail) \ + if (is_not_list(Src)) { \ + Fail; \ + } else { \ + Eterm* tmp_ptr = list_val(Src); \ + Eterm hd, tl; \ + hd = CAR(tmp_ptr); \ + tl = CDR(tmp_ptr); \ + H = hd; T = tl; \ + } + #define IsTuple(X, Action) if (is_not_tuple(X)) Action -#define IsArity(Pointer, Arity, Fail) \ - if (*(Eterm *) \ - EXPAND_POINTER(tmp_arg1 = (Eterm) \ - COMPRESS_POINTER(tuple_val(Pointer))) != (Arity)) \ - { \ - Fail; \ +#define IsArity(Pointer, Arity, Fail) \ + if (*tuple_val(Pointer) != (Arity)) { \ + Fail; \ } #define IsMap(Src, Fail) if (!is_map(Src)) { Fail; } @@ -738,15 +793,21 @@ void** beam_ops; } \ } while (0) -#define IsTupleOfArity(Src, Arity, Fail) \ - do { \ - if (is_not_tuple(Src) || \ - *(Eterm *) \ - EXPAND_POINTER(tmp_arg1 = \ - (Eterm) COMPRESS_POINTER(tuple_val(Src))) != Arity) { \ - Fail; \ - } \ +#ifdef DEBUG +#define IsTupleOfArity(Src, Arityval, Fail) \ + do { \ + if (!(is_tuple(Src) && *tuple_val(Src) == Arityval)) { \ + Fail; \ + } \ } while (0) +#else +#define IsTupleOfArity(Src, Arityval, Fail) \ + do { \ + if (!(is_boxed(Src) && *tuple_val(Src) == Arityval)) { \ + Fail; \ + } \ + } while (0) +#endif #define IsBoolean(X, Fail) if ((X) != am_true && (X) != am_false) { Fail; } @@ -756,7 +817,7 @@ void** beam_ops; #define IsBitstring(Src, Fail) \ if (is_not_binary(Src)) { Fail; } -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) #define BsSafeMul(A, B, Fail, Target) \ do { Uint64 _res = (A) * (B); \ if (_res / B != A) { Fail; } \ @@ -773,6 +834,7 @@ void** beam_ops; #define BsGetFieldSize(Bits, Unit, Fail, Target) \ do { \ Sint _signed_size; Uint _uint_size; \ + Uint temp_bits; \ if (is_small(Bits)) { \ _signed_size = signed_val(Bits); \ if (_signed_size < 0) { Fail; } \ @@ -787,6 +849,7 @@ void** beam_ops; #define BsGetUncheckedFieldSize(Bits, Unit, Fail, Target) \ do { \ Sint _signed_size; Uint _uint_size; \ + Uint temp_bits; \ if (is_small(Bits)) { \ _signed_size = signed_val(Bits); \ if (_signed_size < 0) { Fail; } \ @@ -998,23 +1061,17 @@ init_emulator(void) */ #if defined(__GNUC__) && defined(sparc) && !defined(DEBUG) -# define REG_x0 asm("%l0") # define REG_xregs asm("%l1") # define REG_htop asm("%l2") # define REG_stop asm("%l3") # define REG_I asm("%l4") # define REG_fcalls asm("%l5") -# define REG_tmp_arg1 asm("%l6") -# define REG_tmp_arg2 asm("%l7") #else -# define REG_x0 # define REG_xregs # define REG_htop # define REG_stop # define REG_I # define REG_fcalls -# define REG_tmp_arg1 -# define REG_tmp_arg2 #endif #ifdef USE_VM_PROBES @@ -1132,11 +1189,6 @@ void process_main(void) ERTS_DECLARE_DUMMY(Eterm pid); #endif - /* - * X register zero; also called r(0) - */ - register Eterm x0 REG_x0 = NIL; - /* Pointer to X registers: x(1)..x(N); reg[0] is used when doing GC, * in all other cases x0 is used. */ @@ -1164,17 +1216,6 @@ void process_main(void) register Sint FCALLS REG_fcalls = 0; /* - * Temporaries used for picking up arguments for instructions. - */ - register Eterm tmp_arg1 REG_tmp_arg1 = NIL; - register Eterm tmp_arg2 REG_tmp_arg2 = NIL; -#if HEAP_ON_C_STACK - Eterm tmp_big[2]; /* Temporary buffer for small bignums if HEAP_ON_C_STACK. */ -#else - Eterm *tmp_big; /* Temporary buffer for small bignums if !HEAP_ON_C_STACK. */ -#endif - - /* * X registers and floating point registers are located in * scheduler specific data. */ @@ -1185,8 +1226,6 @@ void process_main(void) */ int neg_o_reds = 0; - Eterm (*arith_func)(Process* p, Eterm* reg, Uint live); - #ifdef ERTS_OPCODE_COUNTER_SUPPORT static void* counting_opcodes[] = { DEFINE_COUNTING_OPCODES }; #else @@ -1197,8 +1236,6 @@ void process_main(void) #endif #endif - Uint temp_bits; /* Temporary used by BsSkipBits2 & BsGetInteger2 */ - Eterm pt_arity; /* Used by do_put_tuple */ Uint64 start_time = 0; /* Monitor long schedule */ @@ -1247,9 +1284,6 @@ void process_main(void) PROCESS_MAIN_CHK_LOCKS(c_p); ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p); -#if HALFWORD_HEAP - ASSERT(erts_get_scheduler_data()->num_tmp_heap_used == 0); -#endif ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); c_p = schedule(c_p, reds_used); ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); @@ -1267,9 +1301,6 @@ void process_main(void) reg = ERTS_PROC_GET_SCHDATA(c_p)->x_reg_array; freg = ERTS_PROC_GET_SCHDATA(c_p)->f_reg_array; -#if !HEAP_ON_C_STACK - tmp_big = ERTS_PROC_GET_SCHDATA(c_p)->beam_emu_tmp_heap; -#endif ERL_BITS_RELOAD_STATEP(c_p); { int reds; @@ -1278,7 +1309,7 @@ void process_main(void) int i; argp = c_p->arg_reg; - for (i = c_p->arity - 1; i > 0; i--) { + for (i = c_p->arity - 1; i >= 0; i--) { reg[i] = argp[i]; CHECK_TERM(reg[i]); } @@ -1302,12 +1333,6 @@ void process_main(void) } next = (BeamInstr *) *I; - r(0) = c_p->arg_reg[0]; -#ifdef HARDDEBUG - if (c_p->arity > 0) { - CHECK_TERM(r(0)); - } -#endif SWAPIN; ASSERT(VALID_INSTR(next)); @@ -1346,26 +1371,24 @@ void process_main(void) #endif #include "beam_hot.h" -#define STORE_ARITH_RESULT(res) StoreBifResult(2, (res)); -#define ARITH_FUNC(name) erts_gc_##name - { Eterm increment_reg_val; Eterm increment_val; Uint live; Eterm result; - OpCase(i_increment_yIId): - increment_reg_val = yb(Arg(0)); + OpCase(i_increment_rIId): + increment_reg_val = x(0); + I--; goto do_increment; OpCase(i_increment_xIId): increment_reg_val = xb(Arg(0)); goto do_increment; - OpCase(i_increment_rIId): - increment_reg_val = r(0); - I--; + OpCase(i_increment_yIId): + increment_reg_val = yb(Arg(0)); + goto do_increment; do_increment: increment_val = Arg(1); @@ -1374,229 +1397,133 @@ void process_main(void) ASSERT(MY_IS_SSMALL(i) == IS_SSMALL(i)); if (MY_IS_SSMALL(i)) { result = make_small(i); - store_result: StoreBifResult(3, result); } } live = Arg(2); SWAPOUT; - reg[0] = r(0); reg[live] = increment_reg_val; reg[live+1] = make_small(increment_val); result = erts_gc_mixed_plus(c_p, reg, live); - r(0) = reg[0]; SWAPIN; ERTS_HOLE_CHECK(c_p); if (is_value(result)) { - goto store_result; + StoreBifResult(3, result); } ASSERT(c_p->freason != BADMATCH || is_value(c_p->fvalue)); goto find_func_info; } -#define DO_BIG_ARITH(Func,Arg1,Arg2) \ - do { \ - Uint live = Arg(1); \ - SWAPOUT; \ - reg[0] = r(0); \ - reg[live] = (Arg1); \ - reg[live+1] = (Arg2); \ - result = (Func)(c_p, reg, live); \ - r(0) = reg[0]; \ - SWAPIN; \ - ERTS_HOLE_CHECK(c_p); \ - if (is_value(result)) { \ - StoreBifResult(4,result); \ - } \ - goto lb_Cl_error; \ - } while(0) +#define DO_OUTLINED_ARITH_2(name, Op1, Op2) \ + do { \ + Eterm result; \ + Uint live = Arg(1); \ + \ + SWAPOUT; \ + reg[live] = Op1; \ + reg[live+1] = Op2; \ + result = erts_gc_##name(c_p, reg, live); \ + SWAPIN; \ + ERTS_HOLE_CHECK(c_p); \ + if (is_value(result)) { \ + StoreBifResult(4, result); \ + } \ + goto lb_Cl_error; \ + } while (0) - OpCase(i_plus_jIxxd): { + Eterm PlusOp1, PlusOp2; Eterm result; - if (is_both_small(xb(Arg(2)), xb(Arg(3)))) { - Sint i = signed_val(xb(Arg(2))) + signed_val(xb(Arg(3))); + OpCase(i_plus_jIxxd): + PlusOp1 = xb(Arg(2)); + PlusOp2 = xb(Arg(3)); + goto do_plus; + + OpCase(i_plus_jIxyd): + PlusOp1 = xb(Arg(2)); + PlusOp2 = yb(Arg(3)); + goto do_plus; + + OpCase(i_plus_jIssd): + GetArg2(2, PlusOp1, PlusOp2); + goto do_plus; + + do_plus: + if (is_both_small(PlusOp1, PlusOp2)) { + Sint i = signed_val(PlusOp1) + signed_val(PlusOp2); ASSERT(MY_IS_SSMALL(i) == IS_SSMALL(i)); if (MY_IS_SSMALL(i)) { result = make_small(i); StoreBifResult(4, result); } } - DO_BIG_ARITH(ARITH_FUNC(mixed_plus), xb(Arg(2)), xb(Arg(3))); + DO_OUTLINED_ARITH_2(mixed_plus, PlusOp1, PlusOp2); } - OpCase(i_plus_jId): { + Eterm MinusOp1, MinusOp2; Eterm result; - if (is_both_small(tmp_arg1, tmp_arg2)) { - Sint i = signed_val(tmp_arg1) + signed_val(tmp_arg2); - ASSERT(MY_IS_SSMALL(i) == IS_SSMALL(i)); - if (MY_IS_SSMALL(i)) { - result = make_small(i); - STORE_ARITH_RESULT(result); - } - } - arith_func = ARITH_FUNC(mixed_plus); - goto do_big_arith2; - } - OpCase(i_minus_jIxxd): - { - Eterm result; - - if (is_both_small(xb(Arg(2)), xb(Arg(3)))) { - Sint i = signed_val(xb(Arg(2))) - signed_val(xb(Arg(3))); - ASSERT(MY_IS_SSMALL(i) == IS_SSMALL(i)); - if (MY_IS_SSMALL(i)) { - result = make_small(i); - StoreBifResult(4, result); - } - } - DO_BIG_ARITH(ARITH_FUNC(mixed_minus), xb(Arg(2)), xb(Arg(3))); - } + MinusOp1 = xb(Arg(2)); + MinusOp2 = xb(Arg(3)); + goto do_minus; - OpCase(i_minus_jId): - { - Eterm result; + OpCase(i_minus_jIssd): + GetArg2(2, MinusOp1, MinusOp2); + goto do_minus; - if (is_both_small(tmp_arg1, tmp_arg2)) { - Sint i = signed_val(tmp_arg1) - signed_val(tmp_arg2); + do_minus: + if (is_both_small(MinusOp1, MinusOp2)) { + Sint i = signed_val(MinusOp1) - signed_val(MinusOp2); ASSERT(MY_IS_SSMALL(i) == IS_SSMALL(i)); if (MY_IS_SSMALL(i)) { result = make_small(i); - STORE_ARITH_RESULT(result); + StoreBifResult(4, result); } } - arith_func = ARITH_FUNC(mixed_minus); - goto do_big_arith2; + DO_OUTLINED_ARITH_2(mixed_minus, MinusOp1, MinusOp2); } - OpCase(i_is_lt_f): - if (CMP_GE(tmp_arg1, tmp_arg2)) { - ClauseFail(); - } - Next(1); - - OpCase(i_is_ge_f): - if (CMP_LT(tmp_arg1, tmp_arg2)) { - ClauseFail(); - } - Next(1); - - OpCase(i_is_eq_f): - if (CMP_NE(tmp_arg1, tmp_arg2)) { - ClauseFail(); - } - Next(1); - - OpCase(i_is_ne_f): - if (CMP_EQ(tmp_arg1, tmp_arg2)) { - ClauseFail(); - } - Next(1); - - OpCase(i_is_eq_exact_f): - if (!EQ(tmp_arg1, tmp_arg2)) { - ClauseFail(); - } - Next(1); - { Eterm is_eq_exact_lit_val; - OpCase(i_is_eq_exact_literal_xfc): - is_eq_exact_lit_val = xb(Arg(0)); - I++; + OpCase(i_is_eq_exact_literal_fxc): + is_eq_exact_lit_val = xb(Arg(1)); goto do_is_eq_exact_literal; - OpCase(i_is_eq_exact_literal_yfc): - is_eq_exact_lit_val = yb(Arg(0)); - I++; + OpCase(i_is_eq_exact_literal_fyc): + is_eq_exact_lit_val = yb(Arg(1)); goto do_is_eq_exact_literal; - OpCase(i_is_eq_exact_literal_rfc): - is_eq_exact_lit_val = r(0); - do_is_eq_exact_literal: - if (!eq(Arg(1), is_eq_exact_lit_val)) { + if (!eq(Arg(2), is_eq_exact_lit_val)) { ClauseFail(); } - Next(2); + Next(3); } { Eterm is_ne_exact_lit_val; - OpCase(i_is_ne_exact_literal_xfc): - is_ne_exact_lit_val = xb(Arg(0)); - I++; + OpCase(i_is_ne_exact_literal_fxc): + is_ne_exact_lit_val = xb(Arg(1)); goto do_is_ne_exact_literal; - OpCase(i_is_ne_exact_literal_yfc): - is_ne_exact_lit_val = yb(Arg(0)); - I++; + OpCase(i_is_ne_exact_literal_fyc): + is_ne_exact_lit_val = yb(Arg(1)); goto do_is_ne_exact_literal; - OpCase(i_is_ne_exact_literal_rfc): - is_ne_exact_lit_val = r(0); - do_is_ne_exact_literal: - if (eq(Arg(1), is_ne_exact_lit_val)) { + if (eq(Arg(2), is_ne_exact_lit_val)) { ClauseFail(); } - Next(2); + Next(3); } - OpCase(move_window3_xxxy): { - BeamInstr *next; - Eterm xt0, xt1, xt2; - Eterm *y = (Eterm *)(((unsigned char *)E) + (Arg(3))); - PreFetch(4, next); - xt0 = xb(Arg(0)); - xt1 = xb(Arg(1)); - xt2 = xb(Arg(2)); - y[0] = xt0; - y[1] = xt1; - y[2] = xt2; - NextPF(4, next); - } - OpCase(move_window4_xxxxy): { - BeamInstr *next; - Eterm xt0, xt1, xt2, xt3; - Eterm *y = (Eterm *)(((unsigned char *)E) + (Arg(4))); - PreFetch(5, next); - xt0 = xb(Arg(0)); - xt1 = xb(Arg(1)); - xt2 = xb(Arg(2)); - xt3 = xb(Arg(3)); - y[0] = xt0; - y[1] = xt1; - y[2] = xt2; - y[3] = xt3; - NextPF(5, next); - } - OpCase(move_window5_xxxxxy): { - BeamInstr *next; - Eterm xt0, xt1, xt2, xt3, xt4; - Eterm *y = (Eterm *)(((unsigned char *)E) + (Arg(5))); - PreFetch(6, next); - xt0 = xb(Arg(0)); - xt1 = xb(Arg(1)); - xt2 = xb(Arg(2)); - xt3 = xb(Arg(3)); - xt4 = xb(Arg(4)); - y[0] = xt0; - y[1] = xt1; - y[2] = xt2; - y[3] = xt3; - y[4] = xt4; - NextPF(6, next); - } - - OpCase(i_move_call_only_fcr): { + OpCase(i_move_call_only_fc): { r(0) = Arg(1); } /* FALL THROUGH */ @@ -1606,7 +1533,7 @@ void process_main(void) Dispatch(); } - OpCase(i_move_call_last_fPcr): { + OpCase(i_move_call_last_fPc): { r(0) = Arg(2); } /* FALL THROUGH */ @@ -1618,7 +1545,7 @@ void process_main(void) Dispatch(); } - OpCase(i_move_call_crf): { + OpCase(i_move_call_cf): { r(0) = Arg(0); I++; } @@ -1630,7 +1557,7 @@ void process_main(void) Dispatch(); } - OpCase(i_move_call_ext_last_ePcr): { + OpCase(i_move_call_ext_last_ePc): { r(0) = Arg(2); } /* FALL THROUGH */ @@ -1646,7 +1573,7 @@ void process_main(void) DTRACE_GLOBAL_CALL_FROM_EXPORT(c_p, Arg(0)); Dispatchx(); - OpCase(i_move_call_ext_cre): { + OpCase(i_move_call_ext_ce): { r(0) = Arg(0); I++; } @@ -1656,7 +1583,7 @@ void process_main(void) DTRACE_GLOBAL_CALL_FROM_EXPORT(c_p, Arg(0)); Dispatchx(); - OpCase(i_move_call_ext_only_ecr): { + OpCase(i_move_call_ext_only_ec): { r(0) = Arg(1); } /* FALL THROUGH */ @@ -1722,7 +1649,6 @@ void process_main(void) PRE_BIF_SWAPOUT(c_p); c_p->fcalls = FCALLS - 1; - reg[0] = r(0); result = erl_send(c_p, r(0), x(1)); PreFetch(0, next); ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); @@ -1730,7 +1656,6 @@ void process_main(void) PROCESS_MAIN_CHK_LOCKS(c_p); if (c_p->mbuf || MSO(c_p).overhead >= BIN_VHEAP_SZ(c_p)) { result = erts_gc_after_bif_call(c_p, result, reg, 2); - r(0) = reg[0]; E = c_p->stop; } HTOP = HEAP_TOP(c_p); @@ -1743,7 +1668,6 @@ void process_main(void) SET_CP(c_p, I+1); SET_I(c_p->i); SWAPIN; - r(0) = reg[0]; Dispatch(); } goto find_func_info; @@ -1753,29 +1677,23 @@ void process_main(void) Eterm element_index; Eterm element_tuple; - OpCase(i_element_xjsd): - element_tuple = xb(Arg(0)); - I++; + OpCase(i_element_jxsd): + element_tuple = xb(Arg(1)); goto do_element; - OpCase(i_element_yjsd): - element_tuple = yb(Arg(0)); - I++; + OpCase(i_element_jysd): + element_tuple = yb(Arg(1)); goto do_element; - OpCase(i_element_rjsd): - element_tuple = r(0); - /* Fall through */ - do_element: - GetArg1(1, element_index); + GetArg1(2, element_index); if (is_small(element_index) && is_tuple(element_tuple)) { Eterm* tp = tuple_val(element_tuple); if ((signed_val(element_index) >= 1) && (signed_val(element_index) <= arityval(*tp))) { Eterm result = tp[signed_val(element_index)]; - StoreBifResult(2, result); + StoreBifResult(3, result); } } } @@ -1789,29 +1707,24 @@ void process_main(void) { Eterm fast_element_tuple; - OpCase(i_fast_element_rjId): - fast_element_tuple = r(0); + OpCase(i_fast_element_jxId): + fast_element_tuple = xb(Arg(1)); + goto do_fast_element; + + OpCase(i_fast_element_jyId): + fast_element_tuple = yb(Arg(1)); + goto do_fast_element; do_fast_element: if (is_tuple(fast_element_tuple)) { Eterm* tp = tuple_val(fast_element_tuple); - Eterm pos = Arg(1); /* Untagged integer >= 1 */ + Eterm pos = Arg(2); /* Untagged integer >= 1 */ if (pos <= arityval(*tp)) { Eterm result = tp[pos]; - StoreBifResult(2, result); + StoreBifResult(3, result); } } goto badarg; - - OpCase(i_fast_element_xjId): - fast_element_tuple = xb(Arg(0)); - I++; - goto do_fast_element; - - OpCase(i_fast_element_yjId): - fast_element_tuple = yb(Arg(0)); - I++; - goto do_fast_element; } OpCase(catch_yf): @@ -1917,7 +1830,7 @@ void process_main(void) * Pick up the next message and place it in x(0). * If no message, jump to a wait or wait_timeout instruction. */ - OpCase(i_loop_rec_fr): + OpCase(i_loop_rec_f): { BeamInstr *next; ErlMessage* msgp; @@ -1951,13 +1864,11 @@ void process_main(void) ErtsMoveMsgAttachmentIntoProc(msgp, c_p, E, HTOP, FCALLS, { SWAPOUT; - reg[0] = r(0); PROCESS_MAIN_CHK_LOCKS(c_p); }, { ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); PROCESS_MAIN_CHK_LOCKS(c_p); - r(0) = reg[0]; SWAPIN; }); if (is_non_value(ERL_MESSAGE_TERM(msgp))) { @@ -2131,8 +2042,6 @@ void process_main(void) * c_p->def_arg_reg[0]. Note that it is safe to use this * location because there are no living x registers in * a receive statement. - * Note that for the halfword emulator, the two first elements - * of the array are used. */ BeamInstr** pi = (BeamInstr**) c_p->def_arg_reg; *pi = I+3; @@ -2249,10 +2158,6 @@ void process_main(void) select_val2 = xb(Arg(0)); goto do_select_tuple_arity2; - OpCase(i_select_tuple_arity2_rfAAff): - select_val2 = r(0); - I--; - do_select_tuple_arity2: if (is_not_tuple(select_val2)) { goto select_val2_fail; @@ -2268,10 +2173,6 @@ void process_main(void) select_val2 = xb(Arg(0)); goto do_select_val2; - OpCase(i_select_val2_rfccff): - select_val2 = r(0); - I--; - do_select_val2: if (select_val2 == Arg(2)) { I += 3; @@ -2295,10 +2196,6 @@ void process_main(void) select_val = yb(Arg(0)); goto do_select_tuple_arity; - OpCase(i_select_tuple_arity_rfI): - select_val = r(0); - I--; - do_select_tuple_arity: if (is_tuple(select_val)) { select_val = *tuple_val(select_val); @@ -2315,10 +2212,6 @@ void process_main(void) select_val = yb(Arg(0)); goto do_linear_search; - OpCase(i_select_val_lins_rfI): - select_val = r(0); - I--; - do_linear_search: { BeamInstr *vs = &Arg(3); int ix = 0; @@ -2345,10 +2238,6 @@ void process_main(void) select_val = yb(Arg(0)); goto do_binary_search; - OpCase(i_select_val_bins_rfI): - select_val = r(0); - I--; - do_binary_search: { struct Pairs { @@ -2409,10 +2298,6 @@ void process_main(void) jump_on_val_zero_index = xb(Arg(0)); goto do_jump_on_val_zero_index; - OpCase(i_jump_on_val_zero_rfI): - jump_on_val_zero_index = r(0); - I--; - do_jump_on_val_zero_index: if (is_small(jump_on_val_zero_index)) { jump_on_val_zero_index = signed_val(jump_on_val_zero_index); @@ -2437,10 +2322,6 @@ void process_main(void) jump_on_val_index = xb(Arg(0)); goto do_jump_on_val_index; - OpCase(i_jump_on_val_rfII): - jump_on_val_index = r(0); - I--; - do_jump_on_val_index: if (is_small(jump_on_val_index)) { jump_on_val_index = (Uint) (signed_val(jump_on_val_index) - Arg(3)); @@ -2460,15 +2341,12 @@ void process_main(void) do { Eterm term = *I++; - switch (term & _TAG_IMMED1_MASK) { - case (R_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: - *hp++ = r(0); - break; - case (X_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: - *hp++ = x(term >> _TAG_IMMED1_SIZE); + switch (loader_tag(term)) { + case LOADER_X_REG: + *hp++ = x(loader_x_reg_index(term)); break; - case (Y_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: - *hp++ = y(term >> _TAG_IMMED1_SIZE); + case LOADER_Y_REG: + *hp++ = y(loader_y_reg_index(term)); break; default: *hp++ = term; @@ -2482,31 +2360,26 @@ void process_main(void) OpCase(new_map_dII): { Eterm res; - x(0) = r(0); SWAPOUT; res = new_map(c_p, reg, I-1); SWAPIN; - r(0) = x(0); StoreResult(res, Arg(0)); Next(3+Arg(2)); } -#define PUT_TERM_REG(term, desc) \ -do { \ - switch ((desc) & _TAG_IMMED1_MASK) { \ - case (R_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \ - r(0) = (term); \ - break; \ - case (X_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \ - x((desc) >> _TAG_IMMED1_SIZE) = (term); \ - break; \ - case (Y_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \ - y((desc) >> _TAG_IMMED1_SIZE) = (term); \ - break; \ - default: \ - ASSERT(0); \ - break; \ - } \ +#define PUT_TERM_REG(term, desc) \ +do { \ + switch (loader_tag(desc)) { \ + case LOADER_X_REG: \ + x(loader_x_reg_index(desc)) = (term); \ + break; \ + case LOADER_Y_REG: \ + y(loader_y_reg_index(desc)) = (term); \ + break; \ + default: \ + ASSERT(0); \ + break; \ + } \ } while(0) OpCase(i_get_map_elements_fsI): { @@ -2577,12 +2450,10 @@ do { \ Eterm map; GetArg1(1, map); - x(0) = r(0); SWAPOUT; res = update_map_assoc(c_p, reg, map, I); SWAPIN; if (is_value(res)) { - r(0) = x(0); StoreResult(res, Arg(2)); Next(5+Arg(4)); } else { @@ -2601,12 +2472,10 @@ do { \ Eterm map; GetArg1(1, map); - x(0) = r(0); SWAPOUT; res = update_map_exact(c_p, reg, map, I); SWAPIN; if (is_value(res)) { - r(0) = x(0); StoreResult(res, Arg(2)); Next(5+Arg(4)); } else { @@ -2688,13 +2557,10 @@ do { \ { typedef Eterm (*GcBifFunction)(Process*, Eterm*, Uint); GcBifFunction bf; - Eterm arg; Eterm result; Uint live = (Uint) Arg(3); - GetArg1(2, arg); - reg[0] = r(0); - reg[live] = arg; + GetArg1(2, x(live)); bf = (GcBifFunction) Arg(1); c_p->fcalls = FCALLS; SWAPOUT; @@ -2705,7 +2571,6 @@ do { \ ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p); PROCESS_MAIN_CHK_LOCKS(c_p); SWAPIN; - r(0) = reg[0]; ERTS_HOLE_CHECK(c_p); FCALLS = c_p->fcalls; if (is_value(result)) { @@ -2715,12 +2580,12 @@ do { \ SET_I((BeamInstr *) Arg(0)); Goto(*I); } - reg[0] = arg; + x(0) = x(live); I = handle_error(c_p, I, reg, translate_gc_bif((void *) bf)); goto post_error_handling; } - OpCase(i_gc_bif2_jIId): /* Note, one less parameter than the i_gc_bif1 + OpCase(i_gc_bif2_jIIssd): /* Note, one less parameter than the i_gc_bif1 and i_gc_bif3 */ { typedef Eterm (*GcBifFunction)(Process*, Eterm*, Uint); @@ -2728,9 +2593,13 @@ do { \ Eterm result; Uint live = (Uint) Arg(2); - reg[0] = r(0); - reg[live++] = tmp_arg1; - reg[live] = tmp_arg2; + GetArg2(3, x(live), x(live+1)); + /* + * XXX This calling convention does not make sense. 'live' + * should point out the first argument, not the second + * (i.e. 'live' should not be incremented below). + */ + live++; bf = (GcBifFunction) Arg(1); c_p->fcalls = FCALLS; SWAPOUT; @@ -2741,35 +2610,37 @@ do { \ ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p); PROCESS_MAIN_CHK_LOCKS(c_p); SWAPIN; - r(0) = reg[0]; ERTS_HOLE_CHECK(c_p); FCALLS = c_p->fcalls; if (is_value(result)) { - StoreBifResult(3, result); + StoreBifResult(5, result); } if (Arg(0) != 0) { SET_I((BeamInstr *) Arg(0)); Goto(*I); } - reg[0] = tmp_arg1; - reg[1] = tmp_arg2; + live--; + x(0) = x(live); + x(1) = x(live+1); I = handle_error(c_p, I, reg, translate_gc_bif((void *) bf)); goto post_error_handling; } - OpCase(i_gc_bif3_jIsId): + OpCase(i_gc_bif3_jIIssd): { typedef Eterm (*GcBifFunction)(Process*, Eterm*, Uint); GcBifFunction bf; - Eterm arg; Eterm result; - Uint live = (Uint) Arg(3); + Uint live = (Uint) Arg(2); - GetArg1(2, arg); - reg[0] = r(0); - reg[live++] = arg; - reg[live++] = tmp_arg1; - reg[live] = tmp_arg2; + x(live) = x(SCRATCH_X_REG); + GetArg2(3, x(live+1), x(live+2)); + /* + * XXX This calling convention does not make sense. 'live' + * should point out the first argument, not the third + * (i.e. 'live' should not be incremented below). + */ + live += 2; bf = (GcBifFunction) Arg(1); c_p->fcalls = FCALLS; SWAPOUT; @@ -2780,19 +2651,19 @@ do { \ ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p); PROCESS_MAIN_CHK_LOCKS(c_p); SWAPIN; - r(0) = reg[0]; ERTS_HOLE_CHECK(c_p); FCALLS = c_p->fcalls; if (is_value(result)) { - StoreBifResult(4, result); + StoreBifResult(5, result); } if (Arg(0) != 0) { SET_I((BeamInstr *) Arg(0)); Goto(*I); } - reg[0] = arg; - reg[1] = tmp_arg1; - reg[2] = tmp_arg2; + live -= 2; + x(0) = x(live); + x(1) = x(live+1); + x(2) = x(live+2); I = handle_error(c_p, I, reg, translate_gc_bif((void *) bf)); goto post_error_handling; } @@ -2800,12 +2671,13 @@ do { \ /* * Guards bifs and, or, xor in guards. */ - OpCase(i_bif2_fbd): + OpCase(i_bif2_fbssd): { - Eterm tmp_reg[2] = {tmp_arg1, tmp_arg2}; + Eterm tmp_reg[2]; Eterm (*bf)(Process*, Eterm*); Eterm result; + GetArg2(2, tmp_reg[0], tmp_reg[1]); bf = (BifFunction) Arg(1); c_p->fcalls = FCALLS; PROCESS_MAIN_CHK_LOCKS(c_p); @@ -2817,7 +2689,7 @@ do { \ ERTS_HOLE_CHECK(c_p); FCALLS = c_p->fcalls; if (is_value(result)) { - StoreBifResult(2, result); + StoreBifResult(4, result); } SET_I((BeamInstr *) Arg(0)); Goto(*I); @@ -2826,12 +2698,13 @@ do { \ /* * Guards bifs and, or, xor, relational operators in body. */ - OpCase(i_bif2_body_bd): + OpCase(i_bif2_body_bssd): { - Eterm tmp_reg[2] = {tmp_arg1, tmp_arg2}; + Eterm tmp_reg[2]; Eterm (*bf)(Process*, Eterm*); Eterm result; + GetArg2(1, tmp_reg[0], tmp_reg[1]); bf = (BifFunction) Arg(0); PROCESS_MAIN_CHK_LOCKS(c_p); ASSERT(!ERTS_PROC_IS_EXITING(c_p)); @@ -2842,10 +2715,10 @@ do { \ ERTS_HOLE_CHECK(c_p); if (is_value(result)) { ASSERT(!is_CP(result)); - StoreBifResult(1, result); + StoreBifResult(3, result); } - reg[0] = tmp_arg1; - reg[1] = tmp_arg2; + reg[0] = tmp_reg[0]; + reg[1] = tmp_reg[1]; SWAPOUT; I = handle_error(c_p, I, reg, bf); goto post_error_handling; @@ -2869,7 +2742,6 @@ do { \ PreFetch(1, next); ASSERT(!ERTS_PROC_IS_EXITING(c_p)); ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); - reg[0] = r(0); result = (*bf)(c_p, reg, I); ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(result)); ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); @@ -2891,7 +2763,6 @@ do { \ SET_CP(c_p, I+2); SET_I(c_p->i); SWAPIN; - r(0) = reg[0]; Dispatch(); } @@ -2907,111 +2778,81 @@ do { \ * Arithmetic operations. */ - OpCase(i_times_jId): + OpCase(i_times_jIssd): { - arith_func = ARITH_FUNC(mixed_times); - goto do_big_arith2; + Eterm Op1, Op2; + GetArg2(2, Op1, Op2); + DO_OUTLINED_ARITH_2(mixed_times, Op1, Op2); } - OpCase(i_m_div_jId): + OpCase(i_m_div_jIssd): { - arith_func = ARITH_FUNC(mixed_div); - goto do_big_arith2; + Eterm Op1, Op2; + GetArg2(2, Op1, Op2); + DO_OUTLINED_ARITH_2(mixed_div, Op1, Op2); } - OpCase(i_int_div_jId): + OpCase(i_int_div_jIssd): { - Eterm result; + Eterm Op1, Op2; - if (tmp_arg2 == SMALL_ZERO) { + GetArg2(2, Op1, Op2); + if (Op2 == SMALL_ZERO) { goto badarith; - } else if (is_both_small(tmp_arg1, tmp_arg2)) { - Sint ires = signed_val(tmp_arg1) / signed_val(tmp_arg2); + } else if (is_both_small(Op1, Op2)) { + Sint ires = signed_val(Op1) / signed_val(Op2); if (MY_IS_SSMALL(ires)) { - result = make_small(ires); - STORE_ARITH_RESULT(result); + Eterm result = make_small(ires); + StoreBifResult(4, result); } } - arith_func = ARITH_FUNC(int_div); - goto do_big_arith2; + DO_OUTLINED_ARITH_2(int_div, Op1, Op2); } - OpCase(i_rem_jIxxd): { - Eterm result; + Eterm RemOp1, RemOp2; - if (xb(Arg(3)) == SMALL_ZERO) { - goto badarith; - } else if (is_both_small(xb(Arg(2)), xb(Arg(3)))) { - result = make_small(signed_val(xb(Arg(2))) % signed_val(xb(Arg(3)))); + OpCase(i_rem_jIxxd): + RemOp1 = xb(Arg(2)); + RemOp2 = xb(Arg(3)); + goto do_rem; + + OpCase(i_rem_jIssd): + GetArg2(2, RemOp1, RemOp2); + goto do_rem; + + do_rem: + if (RemOp2 == SMALL_ZERO) { + goto badarith; + } else if (is_both_small(RemOp1, RemOp2)) { + Eterm result = make_small(signed_val(RemOp1) % signed_val(RemOp2)); StoreBifResult(4, result); + } else { + DO_OUTLINED_ARITH_2(int_rem, RemOp1, RemOp2); } - DO_BIG_ARITH(ARITH_FUNC(int_rem),xb(Arg(2)),xb(Arg(3))); } - OpCase(i_rem_jId): { - Eterm result; - - if (tmp_arg2 == SMALL_ZERO) { - goto badarith; - } else if (is_both_small(tmp_arg1, tmp_arg2)) { - result = make_small(signed_val(tmp_arg1) % signed_val(tmp_arg2)); - STORE_ARITH_RESULT(result); - } else { - arith_func = ARITH_FUNC(int_rem); - goto do_big_arith2; - } - } + Eterm BandOp1, BandOp2; OpCase(i_band_jIxcd): - { - Eterm result; + BandOp1 = xb(Arg(2)); + BandOp2 = Arg(3); + goto do_band; + + OpCase(i_band_jIssd): + GetArg2(2, BandOp1, BandOp2); + goto do_band; - if (is_both_small(xb(Arg(2)), Arg(3))) { + do_band: + if (is_both_small(BandOp1, BandOp2)) { /* * No need to untag -- TAG & TAG == TAG. */ - result = xb(Arg(2)) & Arg(3); + Eterm result = BandOp1 & BandOp2; StoreBifResult(4, result); } - DO_BIG_ARITH(ARITH_FUNC(band),xb(Arg(2)),Arg(3)); - } - - OpCase(i_band_jId): - { - Eterm result; - - if (is_both_small(tmp_arg1, tmp_arg2)) { - /* - * No need to untag -- TAG & TAG == TAG. - */ - result = tmp_arg1 & tmp_arg2; - STORE_ARITH_RESULT(result); - } - arith_func = ARITH_FUNC(band); - goto do_big_arith2; - } - -#undef DO_BIG_ARITH - - do_big_arith2: - { - Eterm result; - Uint live = Arg(1); - - SWAPOUT; - reg[0] = r(0); - reg[live] = tmp_arg1; - reg[live+1] = tmp_arg2; - result = arith_func(c_p, reg, live); - r(0) = reg[0]; - SWAPIN; - ERTS_HOLE_CHECK(c_p); - if (is_value(result)) { - STORE_ARITH_RESULT(result); - } - goto lb_Cl_error; + DO_OUTLINED_ARITH_2(band, BandOp1, BandOp2); } /* @@ -3032,97 +2873,102 @@ do { \ goto find_func_info; } - OpCase(i_bor_jId): + OpCase(i_bor_jIssd): { - Eterm result; + Eterm Op1, Op2; - if (is_both_small(tmp_arg1, tmp_arg2)) { + GetArg2(2, Op1, Op2); + if (is_both_small(Op1, Op2)) { /* * No need to untag -- TAG | TAG == TAG. */ - result = tmp_arg1 | tmp_arg2; - STORE_ARITH_RESULT(result); + Eterm result = Op1 | Op2; + StoreBifResult(4, result); } - arith_func = ARITH_FUNC(bor); - goto do_big_arith2; + DO_OUTLINED_ARITH_2(bor, Op1, Op2); } - OpCase(i_bxor_jId): + OpCase(i_bxor_jIssd): { - Eterm result; + Eterm Op1, Op2; - if (is_both_small(tmp_arg1, tmp_arg2)) { + GetArg2(2, Op1, Op2); + if (is_both_small(Op1, Op2)) { /* * We could extract the tag from one argument, but a tag extraction * could mean a shift. Therefore, play it safe here. */ - result = make_small(signed_val(tmp_arg1) ^ signed_val(tmp_arg2)); - STORE_ARITH_RESULT(result); + Eterm result = make_small(signed_val(Op1) ^ signed_val(Op2)); + StoreBifResult(4, result); } - arith_func = ARITH_FUNC(bxor); - goto do_big_arith2; + DO_OUTLINED_ARITH_2(bxor, Op1, Op2); } { + Eterm Op1, Op2; Sint i; Sint ires; Eterm* bigp; + Eterm tmp_big[2]; - OpCase(i_bsr_jId): - if (is_small(tmp_arg2)) { - i = -signed_val(tmp_arg2); - if (is_small(tmp_arg1)) { + OpCase(i_bsr_jIssd): + GetArg2(2, Op1, Op2); + if (is_small(Op2)) { + i = -signed_val(Op2); + if (is_small(Op1)) { goto small_shift; - } else if (is_big(tmp_arg1)) { + } else if (is_big(Op1)) { if (i == 0) { - StoreBifResult(2, tmp_arg1); + StoreBifResult(4, Op1); } goto big_shift; } - } else if (is_big(tmp_arg2)) { + } else if (is_big(Op2)) { /* * N bsr NegativeBigNum == N bsl MAX_SMALL * N bsr PositiveBigNum == N bsl MIN_SMALL */ - tmp_arg2 = make_small(bignum_header_is_neg(*big_val(tmp_arg2)) ? + Op2 = make_small(bignum_header_is_neg(*big_val(Op2)) ? MAX_SMALL : MIN_SMALL); goto do_bsl; } goto badarith; - OpCase(i_bsl_jId): + OpCase(i_bsl_jIssd): + GetArg2(2, Op1, Op2); + do_bsl: - if (is_small(tmp_arg2)) { - i = signed_val(tmp_arg2); + if (is_small(Op2)) { + i = signed_val(Op2); - if (is_small(tmp_arg1)) { + if (is_small(Op1)) { small_shift: - ires = signed_val(tmp_arg1); + ires = signed_val(Op1); if (i == 0 || ires == 0) { - StoreBifResult(2, tmp_arg1); + StoreBifResult(4, Op1); } else if (i < 0) { /* Right shift */ i = -i; if (i >= SMALL_BITS-1) { - tmp_arg1 = (ires < 0) ? SMALL_MINUS_ONE : SMALL_ZERO; + Op1 = (ires < 0) ? SMALL_MINUS_ONE : SMALL_ZERO; } else { - tmp_arg1 = make_small(ires >> i); + Op1 = make_small(ires >> i); } - StoreBifResult(2, tmp_arg1); + StoreBifResult(4, Op1); } else if (i < SMALL_BITS-1) { /* Left shift */ if ((ires > 0 && ((~(Uint)0 << ((SMALL_BITS-1)-i)) & ires) == 0) || ((~(Uint)0 << ((SMALL_BITS-1)-i)) & ~ires) == 0) { - tmp_arg1 = make_small(ires << i); - StoreBifResult(2, tmp_arg1); + Op1 = make_small(ires << i); + StoreBifResult(4, Op1); } } - tmp_arg1 = small_to_big(ires, tmp_big); + Op1 = small_to_big(ires, tmp_big); big_shift: if (i > 0) { /* Left shift. */ - ires = big_size(tmp_arg1) + (i / D_EXP); + ires = big_size(Op1) + (i / D_EXP); } else { /* Right shift. */ - ires = big_size(tmp_arg1); + ires = big_size(Op1); if (ires <= (-i / D_EXP)) ires = 3; /* ??? */ else @@ -3140,14 +2986,14 @@ do { \ c_p->freason = SYSTEM_LIMIT; goto lb_Cl_error; } - TestHeapPreserve(ires+1, Arg(1), tmp_arg1); + TestHeapPreserve(ires+1, Arg(1), Op1); bigp = HTOP; - tmp_arg1 = big_lshift(tmp_arg1, i, bigp); - if (is_big(tmp_arg1)) { + Op1 = big_lshift(Op1, i, bigp); + if (is_big(Op1)) { HTOP += bignum_header_arity(*HTOP) + 1; } HEAP_SPACE_VERIFIED(0); - if (is_nil(tmp_arg1)) { + if (is_nil(Op1)) { /* * This result must have been only slight larger * than allowed since it wasn't caught by the @@ -3157,25 +3003,25 @@ do { \ goto lb_Cl_error; } ERTS_HOLE_CHECK(c_p); - StoreBifResult(2, tmp_arg1); + StoreBifResult(4, Op1); } - } else if (is_big(tmp_arg1)) { + } else if (is_big(Op1)) { if (i == 0) { - StoreBifResult(2, tmp_arg1); + StoreBifResult(4, Op1); } goto big_shift; } - } else if (is_big(tmp_arg2)) { - if (bignum_header_is_neg(*big_val(tmp_arg2))) { + } else if (is_big(Op2)) { + if (bignum_header_is_neg(*big_val(Op2))) { /* * N bsl NegativeBigNum is either 0 or -1, depending on * the sign of N. Since we don't believe this case * is common, do the calculation with the minimum * amount of code. */ - tmp_arg2 = make_small(MIN_SMALL); + Op2 = make_small(MIN_SMALL); goto do_bsl; - } else if (is_small(tmp_arg1) || is_big(tmp_arg1)) { + } else if (is_small(Op1) || is_big(Op1)) { /* * N bsl PositiveBigNum is too large to represent. */ @@ -3200,10 +3046,8 @@ do { \ } else { Uint live = Arg(2); SWAPOUT; - reg[0] = r(0); reg[live] = bnot_val; bnot_val = erts_gc_bnot(c_p, reg, live); - r(0) = reg[0]; SWAPIN; ERTS_HOLE_CHECK(c_p); if (is_nil(bnot_val)) { @@ -3223,7 +3067,6 @@ do { \ next = apply(c_p, r(0), x(1), x(2), reg); SWAPIN; if (next != NULL) { - r(0) = reg[0]; SET_CP(c_p, I+1); SET_I(next); Dispatch(); @@ -3238,8 +3081,7 @@ do { \ next = apply(c_p, r(0), x(1), x(2), reg); SWAPIN; if (next != NULL) { - r(0) = reg[0]; - SET_CP(c_p, (BeamInstr *) EXPAND_POINTER(E[0])); + SET_CP(c_p, (BeamInstr *) E[0]); E = ADD_BYTE_OFFSET(E, Arg(0)); SET_I(next); Dispatch(); @@ -3254,7 +3096,6 @@ do { \ next = apply(c_p, r(0), x(1), x(2), reg); SWAPIN; if (next != NULL) { - r(0) = reg[0]; SET_I(next); Dispatch(); } @@ -3265,12 +3106,10 @@ do { \ OpCase(apply_I): { BeamInstr *next; - reg[0] = r(0); SWAPOUT; next = fixed_apply(c_p, reg, Arg(0)); SWAPIN; if (next != NULL) { - r(0) = reg[0]; SET_CP(c_p, I+2); SET_I(next); Dispatch(); @@ -3282,13 +3121,11 @@ do { \ OpCase(apply_last_IP): { BeamInstr *next; - reg[0] = r(0); SWAPOUT; next = fixed_apply(c_p, reg, Arg(0)); SWAPIN; if (next != NULL) { - r(0) = reg[0]; - SET_CP(c_p, (BeamInstr *) EXPAND_POINTER(E[0])); + SET_CP(c_p, (BeamInstr *) E[0]); E = ADD_BYTE_OFFSET(E, Arg(1)); SET_I(next); Dispatch(); @@ -3304,7 +3141,6 @@ do { \ next = apply_fun(c_p, r(0), x(1), reg); SWAPIN; if (next != NULL) { - r(0) = reg[0]; SET_CP(c_p, I+1); SET_I(next); Dispatchfun(); @@ -3319,8 +3155,7 @@ do { \ next = apply_fun(c_p, r(0), x(1), reg); SWAPIN; if (next != NULL) { - r(0) = reg[0]; - SET_CP(c_p, (BeamInstr *) EXPAND_POINTER(E[0])); + SET_CP(c_p, (BeamInstr *) E[0]); E = ADD_BYTE_OFFSET(E, Arg(0)); SET_I(next); Dispatchfun(); @@ -3335,7 +3170,6 @@ do { \ next = apply_fun(c_p, r(0), x(1), reg); SWAPIN; if (next != NULL) { - r(0) = reg[0]; SET_I(next); Dispatchfun(); } @@ -3346,12 +3180,9 @@ do { \ BeamInstr *next; SWAPOUT; - reg[0] = r(0); - next = call_fun(c_p, Arg(0), reg, THE_NON_VALUE); SWAPIN; if (next != NULL) { - r(0) = reg[0]; SET_CP(c_p, I+2); SET_I(next); Dispatchfun(); @@ -3363,12 +3194,10 @@ do { \ BeamInstr *next; SWAPOUT; - reg[0] = r(0); next = call_fun(c_p, Arg(0), reg, THE_NON_VALUE); SWAPIN; if (next != NULL) { - r(0) = reg[0]; - SET_CP(c_p, (BeamInstr *) EXPAND_POINTER(E[0])); + SET_CP(c_p, (BeamInstr *) E[0]); E = ADD_BYTE_OFFSET(E, Arg(1)); SET_I(next); Dispatchfun(); @@ -3452,10 +3281,9 @@ do { \ */ argp = c_p->arg_reg; - for (i = c_p->arity - 1; i > 0; i--) { + for (i = c_p->arity - 1; i >= 0; i--) { argp[i] = reg[i]; } - c_p->arg_reg[0] = r(0); SWAPOUT; c_p->i = I; goto do_schedule1; @@ -3468,19 +3296,14 @@ do { \ Eterm* p; PreFetch(3, next); - GetArg2(0, element, tuple); + GetArg1(0, element); + tuple = REG_TARGET(Arg(1)); ASSERT(is_tuple(tuple)); p = (Eterm *) ((unsigned char *) tuple_val(tuple) + Arg(2)); *p = element; NextPF(3, next); } - OpCase(i_is_ne_exact_f): - if (EQ(tmp_arg1, tmp_arg2)) { - ClauseFail(); - } - Next(1); - OpCase(normal_exit): { SWAPOUT; c_p->freason = EXC_NORMAL; @@ -3547,25 +3370,14 @@ do { \ { Eterm badmatch_val; - OpCase(badmatch_y): - badmatch_val = yb(Arg(0)); - goto do_badmatch; - OpCase(badmatch_x): badmatch_val = xb(Arg(0)); - goto do_badmatch; - - OpCase(badmatch_r): - badmatch_val = r(0); - - do_badmatch: c_p->fvalue = badmatch_val; c_p->freason = BADMATCH; } /* Fall through here */ find_func_info: { - reg[0] = r(0); SWAPOUT; I = handle_error(c_p, I, reg, NULL); goto post_error_handling; @@ -3583,9 +3395,7 @@ do { \ * code[4]: Not used */ SWAPOUT; - reg[0] = r(0); I = call_error_handler(c_p, I-3, reg, am_undefined_function); - r(0) = reg[0]; SWAPIN; if (I) { Goto(*I); @@ -3594,14 +3404,12 @@ do { \ /* Fall through */ OpCase(error_action_code): { handle_error: - reg[0] = r(0); SWAPOUT; I = handle_error(c_p, NULL, reg, NULL); post_error_handling: if (I == 0) { goto do_schedule; } else { - r(0) = reg[0]; ASSERT(!is_value(r(0))); if (c_p->mbuf) { erts_garbage_collect(c_p, 0, reg+1, 3); @@ -3644,7 +3452,6 @@ do { \ NifF* fp = vbf = (NifF*) I[1]; struct enif_environment_t env; erts_pre_nif(&env, c_p, (struct erl_module_nif*)I[2]); - reg[0] = r(0); nif_bif_result = (*fp)(&env, bif_nif_arity, reg); if (env.exception_thrown) nif_bif_result = THE_NON_VALUE; @@ -3683,7 +3490,7 @@ do { \ bif_nif_arity = I[-1]; ASSERT(bif_nif_arity <= 4); ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p); - reg[0] = r(0); + ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); { Eterm (*bf)(Process*, Eterm*, BeamInstr*) = vbf; ASSERT(!ERTS_PROC_IS_EXITING(c_p)); @@ -3713,7 +3520,6 @@ do { \ Goto(*I); } else if (c_p->freason == TRAP) { SET_I(c_p->i); - r(0) = reg[0]; if (c_p->flags & F_HIBERNATE_SCHED) { c_p->flags &= ~F_HIBERNATE_SCHED; goto do_schedule; @@ -3740,16 +3546,6 @@ do { \ OpCase(case_end_x): case_end_val = xb(Arg(0)); - goto do_case_end; - - OpCase(case_end_y): - case_end_val = yb(Arg(0)); - goto do_case_end; - - OpCase(case_end_r): - case_end_val = r(0); - - do_case_end: c_p->fvalue = case_end_val; c_p->freason = EXC_CASE_CLAUSE; goto find_func_info; @@ -3797,19 +3593,13 @@ do { \ goto do_bs_init_bits_known; } - OpCase(i_bs_init_bits_fail_heap_IjId): { - /* tmp_arg1 was fetched by an i_fetch instruction */ - num_bits_term = tmp_arg1; - alloc = Arg(0); - I++; + OpCase(i_bs_init_bits_fail_heap_sIjId): { + GetArg1(0, num_bits_term); + alloc = Arg(1); + I += 2; goto do_bs_init_bits; } - OpCase(i_bs_init_bits_fail_rjId): { - num_bits_term = r(0); - alloc = 0; - goto do_bs_init_bits; - } OpCase(i_bs_init_bits_fail_yjId): { num_bits_term = yb(Arg(0)); I++; @@ -3929,52 +3719,48 @@ do { \ } { - OpCase(i_bs_init_fail_heap_IjId): { - /* tmp_arg1 was fetched by an i_fetch instruction */ - tmp_arg2 = Arg(0); - I++; - goto do_bs_init; - } + Eterm BsOp1, BsOp2; - OpCase(i_bs_init_fail_rjId): { - tmp_arg1 = r(0); - tmp_arg2 = 0; + OpCase(i_bs_init_fail_heap_sIjId): { + GetArg1(0, BsOp1); + BsOp2 = Arg(1); + I += 2; goto do_bs_init; } OpCase(i_bs_init_fail_yjId): { - tmp_arg1 = yb(Arg(0)); - tmp_arg2 = 0; + BsOp1 = yb(Arg(0)); + BsOp2 = 0; I++; goto do_bs_init; } OpCase(i_bs_init_fail_xjId): { - tmp_arg1 = xb(Arg(0)); - tmp_arg2 = 0; + BsOp1 = xb(Arg(0)); + BsOp2 = 0; I++; } /* FALL THROUGH */ do_bs_init: - if (is_small(tmp_arg1)) { - Sint size = signed_val(tmp_arg1); + if (is_small(BsOp1)) { + Sint size = signed_val(BsOp1); if (size < 0) { goto badarg; } - tmp_arg1 = (Eterm) size; + BsOp1 = (Eterm) size; } else { Uint bytes; - if (!term_to_Uint(tmp_arg1, &bytes)) { + if (!term_to_Uint(BsOp1, &bytes)) { c_p->freason = bytes; goto lb_Cl_error; } if ((bytes >> (8*sizeof(Uint)-3)) != 0) { goto system_limit; } - tmp_arg1 = (Eterm) bytes; + BsOp1 = (Eterm) bytes; } - if (tmp_arg1 <= ERL_ONHEAP_BIN_LIMIT) { + if (BsOp1 <= ERL_ONHEAP_BIN_LIMIT) { goto do_heap_bin_alloc; } else { goto do_proc_bin_alloc; @@ -3982,15 +3768,15 @@ do { \ OpCase(i_bs_init_heap_IIId): { - tmp_arg1 = Arg(0); - tmp_arg2 = Arg(1); + BsOp1 = Arg(0); + BsOp2 = Arg(1); I++; goto do_proc_bin_alloc; } OpCase(i_bs_init_IId): { - tmp_arg1 = Arg(0); - tmp_arg2 = 0; + BsOp1 = Arg(0); + BsOp2 = 0; } /* FALL THROUGH */ do_proc_bin_alloc: { @@ -3999,13 +3785,13 @@ do { \ erts_bin_offset = 0; erts_writable_bin = 0; - TestBinVHeap(tmp_arg1 / sizeof(Eterm), - tmp_arg2 + PROC_BIN_SIZE + ERL_SUB_BIN_SIZE, Arg(1)); + TestBinVHeap(BsOp1 / sizeof(Eterm), + BsOp2 + PROC_BIN_SIZE + ERL_SUB_BIN_SIZE, Arg(1)); /* * Allocate the binary struct itself. */ - bptr = erts_bin_nrml_alloc(tmp_arg1); + bptr = erts_bin_nrml_alloc(BsOp1); erts_refc_init(&bptr->refc, 1); erts_current_bin = (byte *) bptr->orig_bytes; @@ -4015,28 +3801,28 @@ do { \ pb = (ProcBin *) HTOP; HTOP += PROC_BIN_SIZE; pb->thing_word = HEADER_PROC_BIN; - pb->size = tmp_arg1; + pb->size = BsOp1; pb->next = MSO(c_p).first; MSO(c_p).first = (struct erl_off_heap_header*) pb; pb->val = bptr; pb->bytes = (byte*) bptr->orig_bytes; pb->flags = 0; - OH_OVERHEAD(&(MSO(c_p)), tmp_arg1 / sizeof(Eterm)); + OH_OVERHEAD(&(MSO(c_p)), BsOp1 / sizeof(Eterm)); StoreBifResult(2, make_binary(pb)); } OpCase(i_bs_init_heap_bin_heap_IIId): { - tmp_arg1 = Arg(0); - tmp_arg2 = Arg(1); + BsOp1 = Arg(0); + BsOp2 = Arg(1); I++; goto do_heap_bin_alloc; } OpCase(i_bs_init_heap_bin_IId): { - tmp_arg1 = Arg(0); - tmp_arg2 = 0; + BsOp1 = Arg(0); + BsOp2 = 0; } /* Fall through */ do_heap_bin_alloc: @@ -4044,33 +3830,36 @@ do { \ ErlHeapBin* hb; Uint bin_need; - bin_need = heap_bin_size(tmp_arg1); + bin_need = heap_bin_size(BsOp1); erts_bin_offset = 0; erts_writable_bin = 0; - TestHeap(bin_need+tmp_arg2+ERL_SUB_BIN_SIZE, Arg(1)); + TestHeap(bin_need+BsOp2+ERL_SUB_BIN_SIZE, Arg(1)); hb = (ErlHeapBin *) HTOP; HTOP += bin_need; - hb->thing_word = header_heap_bin(tmp_arg1); - hb->size = tmp_arg1; + hb->thing_word = header_heap_bin(BsOp1); + hb->size = BsOp1; erts_current_bin = (byte *) hb->data; - tmp_arg1 = make_binary(hb); - StoreBifResult(2, tmp_arg1); + BsOp1 = make_binary(hb); + StoreBifResult(2, BsOp1); } } - OpCase(i_bs_add_jId): { - Uint Unit = Arg(1); - if (is_both_small(tmp_arg1, tmp_arg2)) { - Sint Arg1 = signed_val(tmp_arg1); - Sint Arg2 = signed_val(tmp_arg2); + OpCase(bs_add_jssId): { + Eterm Op1, Op2; + Uint Unit = Arg(3); + + GetArg2(1, Op1, Op2); + if (is_both_small(Op1, Op2)) { + Sint Arg1 = signed_val(Op1); + Sint Arg2 = signed_val(Op2); if (Arg1 >= 0 && Arg2 >= 0) { - BsSafeMul(Arg2, Unit, goto system_limit, tmp_arg1); - tmp_arg1 += Arg1; + BsSafeMul(Arg2, Unit, goto system_limit, Op1); + Op1 += Arg1; store_bs_add_result: - if (MY_IS_SSMALL((Sint) tmp_arg1)) { - tmp_arg1 = make_small(tmp_arg1); + if (MY_IS_SSMALL((Sint) Op1)) { + Op1 = make_small(Op1); } else { /* * May generate a heap fragment, but in this @@ -4082,10 +3871,10 @@ do { \ * references (such as the heap). */ SWAPOUT; - tmp_arg1 = erts_make_integer(tmp_arg1, c_p); + Op1 = erts_make_integer(Op1, c_p); HTOP = HEAP_TOP(c_p); } - StoreBifResult(2, tmp_arg1); + StoreBifResult(4, Op1); } goto badarg; } else { @@ -4108,16 +3897,16 @@ do { \ * an Uint, the reason is SYSTEM_LIMIT. */ - if (!term_to_Uint(tmp_arg1, &a)) { + if (!term_to_Uint(Op1, &a)) { if (a == BADARG) { goto badarg; } - if (!term_to_Uint(tmp_arg2, &b)) { + if (!term_to_Uint(Op2, &b)) { c_p->freason = b; goto lb_Cl_error; } goto system_limit; - } else if (!term_to_Uint(tmp_arg2, &b)) { + } else if (!term_to_Uint(Op2, &b)) { c_p->freason = b; goto lb_Cl_error; } @@ -4127,8 +3916,8 @@ do { \ */ BsSafeMul(b, Unit, goto system_limit, c); - tmp_arg1 = a + c; - if (tmp_arg1 < a) { + Op1 = a + c; + if (Op1 < a) { /* * If the result is less than one of the * arguments, there must have been an overflow. @@ -4150,48 +3939,43 @@ do { \ } /* - * tmp_arg1 = Number of bytes to build - * tmp_arg2 = Source binary - * Operands: Fail ExtraHeap Live Unit Dst + * x(SCRATCH_X_REG); + * Operands: Fail ExtraHeap Live Unit Size Dst */ - OpCase(i_bs_append_jIIId): { + OpCase(i_bs_append_jIIIsd): { Uint live = Arg(2); Uint res; + Eterm Size; + GetArg1(4, Size); SWAPOUT; - reg[0] = r(0); - reg[live] = tmp_arg2; - res = erts_bs_append(c_p, reg, live, tmp_arg1, Arg(1), Arg(3)); - r(0) = reg[0]; + reg[live] = x(SCRATCH_X_REG); + res = erts_bs_append(c_p, reg, live, Size, Arg(1), Arg(3)); SWAPIN; if (is_non_value(res)) { /* c_p->freason is already set (may be either BADARG or SYSTEM_LIMIT). */ goto lb_Cl_error; } - StoreBifResult(4, res); + StoreBifResult(5, res); } /* - * tmp_arg1 = Number of bytes to build - * tmp_arg2 = Source binary - * Operands: Fail Unit Dst + * Operands: Fail Size Src Unit Dst */ - OpCase(i_bs_private_append_jId): { + OpCase(i_bs_private_append_jIssd): { Eterm res; + Eterm Size, Src; - res = erts_bs_private_append(c_p, tmp_arg2, tmp_arg1, Arg(1)); + GetArg2(2, Size, Src); + res = erts_bs_private_append(c_p, Src, Size, Arg(1)); if (is_non_value(res)) { /* c_p->freason is already set (may be either BADARG or SYSTEM_LIMIT). */ goto lb_Cl_error; } - StoreBifResult(2, res); + StoreBifResult(4, res); } - /* - * tmp_arg1 = Initial size of writable binary - * Operands: Live Dst - */ OpCase(bs_init_writable): { SWAPOUT; r(0) = erts_bs_init_writable(c_p, r(0)); @@ -4286,26 +4070,29 @@ do { \ /* * Only used for validating a value matched out. - * - * tmp_arg1 = Integer to validate - * tmp_arg2 = Match context */ - OpCase(i_bs_validate_unicode_retract_j): { - /* - * There is no need to untag the integer, but it IS necessary - * to make sure it is small (a bignum pointer could fall in - * the valid range). - */ - if (is_not_small(tmp_arg1) || tmp_arg1 > make_small(0x10FFFFUL) || - (make_small(0xD800UL) <= tmp_arg1 && - tmp_arg1 <= make_small(0xDFFFUL))) { - ErlBinMatchBuffer *mb = ms_matchbuffer(tmp_arg2); + OpCase(i_bs_validate_unicode_retract_jss): { + Eterm i; /* Integer to validate */ - mb->offset -= 32; - goto badarg; - } - Next(1); - } + /* + * There is no need to untag the integer, but it IS necessary + * to make sure it is small (a bignum pointer could fall in + * the valid range). + */ + + GetArg1(1, i); + if (is_not_small(i) || i > make_small(0x10FFFFUL) || + (make_small(0xD800UL) <= i && i <= make_small(0xDFFFUL))) { + Eterm ms; /* Match context */ + ErlBinMatchBuffer* mb; + + GetArg1(2, ms); + mb = ms_matchbuffer(ms); + mb->offset -= 32; + goto badarg; + } + Next(3); + } /* * Matching of binaries. @@ -4317,9 +4104,6 @@ do { \ Uint slots; Eterm context; - OpCase(i_bs_start_match2_rfIId): { - context = r(0); - do_start_match: slots = Arg(2); if (!is_boxed(context)) { @@ -4366,7 +4150,7 @@ do { \ ClauseFail(); } NextPF(4, next); - } + OpCase(i_bs_start_match2_xfIId): { context = xb(Arg(0)); I++; @@ -4379,18 +4163,6 @@ do { \ } } - OpCase(bs_test_zero_tail2_fr): { - BeamInstr *next; - ErlBinMatchBuffer *_mb; - - PreFetch(1, next); - _mb = (ErlBinMatchBuffer*) ms_matchbuffer(r(0)); - if (_mb->size != _mb->offset) { - ClauseFail(); - } - NextPF(1, next); - } - OpCase(bs_test_zero_tail2_fx): { BeamInstr *next; ErlBinMatchBuffer *_mb; @@ -4403,16 +4175,6 @@ do { \ NextPF(2, next); } - OpCase(bs_test_tail_imm2_frI): { - BeamInstr *next; - ErlBinMatchBuffer *_mb; - PreFetch(2, next); - _mb = ms_matchbuffer(r(0)); - if (_mb->size - _mb->offset != Arg(1)) { - ClauseFail(); - } - NextPF(2, next); - } OpCase(bs_test_tail_imm2_fxI): { BeamInstr *next; ErlBinMatchBuffer *_mb; @@ -4424,16 +4186,6 @@ do { \ NextPF(3, next); } - OpCase(bs_test_unit_frI): { - BeamInstr *next; - ErlBinMatchBuffer *_mb; - PreFetch(2, next); - _mb = ms_matchbuffer(r(0)); - if ((_mb->size - _mb->offset) % Arg(1)) { - ClauseFail(); - } - NextPF(2, next); - } OpCase(bs_test_unit_fxI): { BeamInstr *next; ErlBinMatchBuffer *_mb; @@ -4445,16 +4197,6 @@ do { \ NextPF(3, next); } - OpCase(bs_test_unit8_fr): { - BeamInstr *next; - ErlBinMatchBuffer *_mb; - PreFetch(1, next); - _mb = ms_matchbuffer(r(0)); - if ((_mb->size - _mb->offset) & 7) { - ClauseFail(); - } - NextPF(1, next); - } OpCase(bs_test_unit8_fx): { BeamInstr *next; ErlBinMatchBuffer *_mb; @@ -4469,19 +4211,11 @@ do { \ { Eterm bs_get_integer8_context; - OpCase(i_bs_get_integer_8_rfd): { - bs_get_integer8_context = r(0); - goto do_bs_get_integer_8; - } - OpCase(i_bs_get_integer_8_xfd): { - bs_get_integer8_context = xb(Arg(0)); - I++; - } - - do_bs_get_integer_8: { ErlBinMatchBuffer *_mb; Eterm _result; + bs_get_integer8_context = xb(Arg(0)); + I++; _mb = ms_matchbuffer(bs_get_integer8_context); if (_mb->size - _mb->offset < 8) { ClauseFail(); @@ -4499,15 +4233,10 @@ do { \ { Eterm bs_get_integer_16_context; - OpCase(i_bs_get_integer_16_rfd): - bs_get_integer_16_context = r(0); - goto do_bs_get_integer_16; - OpCase(i_bs_get_integer_16_xfd): bs_get_integer_16_context = xb(Arg(0)); I++; - do_bs_get_integer_16: { ErlBinMatchBuffer *_mb; Eterm _result; @@ -4528,17 +4257,10 @@ do { \ { Eterm bs_get_integer_32_context; - OpCase(i_bs_get_integer_32_rfId): - bs_get_integer_32_context = r(0); - goto do_bs_get_integer_32; - - OpCase(i_bs_get_integer_32_xfId): bs_get_integer_32_context = xb(Arg(0)); I++; - - do_bs_get_integer_32: { ErlBinMatchBuffer *_mb; Uint32 _integer; @@ -4551,11 +4273,11 @@ do { \ _integer = get_int32(_mb->base + _mb->offset/8); } _mb->offset += 32; -#if !defined(ARCH_64) || HALFWORD_HEAP +#if !defined(ARCH_64) if (IS_USMALL(0, _integer)) { #endif _result = make_small(_integer); -#if !defined(ARCH_64) || HALFWORD_HEAP +#if !defined(ARCH_64) } else { TestHeap(BIG_UINT_HEAP_SIZE, Arg(1)); _result = uint_to_big((Uint) _integer, HTOP); @@ -4567,103 +4289,82 @@ do { \ } } - /* Operands: Size Live Fail Flags Dst */ - OpCase(i_bs_get_integer_imm_rIIfId): { - tmp_arg1 = r(0); - /* Operands: Size Live Fail Flags Dst */ - goto do_bs_get_integer_imm_test_heap; - } + { + Eterm Ms, Sz; - /* Operands: x(Reg) Size Live Fail Flags Dst */ + /* Operands: x(Reg) Size Live Fail Flags Dst */ OpCase(i_bs_get_integer_imm_xIIfId): { - tmp_arg1 = xb(Arg(0)); - I++; - /* Operands: Size Live Fail Flags Dst */ - goto do_bs_get_integer_imm_test_heap; - } - - /* - * tmp_arg1 = match context - * Operands: Size Live Fail Flags Dst - */ - do_bs_get_integer_imm_test_heap: { - Uint wordsneeded; - tmp_arg2 = Arg(0); - wordsneeded = 1+WSIZE(NBYTES(tmp_arg2)); - TestHeapPreserve(wordsneeded, Arg(1), tmp_arg1); - I += 2; - /* Operands: Fail Flags Dst */ - goto do_bs_get_integer_imm; - } - - /* Operands: Size Fail Flags Dst */ - OpCase(i_bs_get_integer_small_imm_rIfId): { - tmp_arg1 = r(0); - tmp_arg2 = Arg(0); - I++; - /* Operands: Fail Flags Dst */ - goto do_bs_get_integer_imm; - } + Uint wordsneeded; + Ms = xb(Arg(0)); + Sz = Arg(1); + wordsneeded = 1+WSIZE(NBYTES(Sz)); + TestHeapPreserve(wordsneeded, Arg(2), Ms); + I += 3; + /* Operands: Fail Flags Dst */ + goto do_bs_get_integer_imm; + } - /* Operands: x(Reg) Size Fail Flags Dst */ + /* Operands: x(Reg) Size Fail Flags Dst */ OpCase(i_bs_get_integer_small_imm_xIfId): { - tmp_arg1 = xb(Arg(0)); - tmp_arg2 = Arg(1); - I += 2; - /* Operands: Fail Flags Dst */ - goto do_bs_get_integer_imm; - } + Ms = xb(Arg(0)); + Sz = Arg(1); + I += 2; + /* Operands: Fail Flags Dst */ + goto do_bs_get_integer_imm; + } - /* - * tmp_arg1 = match context - * tmp_arg2 = size of field - * Operands: Fail Flags Dst - */ + /* + * Ms = match context + * Sz = size of field + * Operands: Fail Flags Dst + */ do_bs_get_integer_imm: { - ErlBinMatchBuffer* mb; - Eterm result; + ErlBinMatchBuffer* mb; + Eterm result; - mb = ms_matchbuffer(tmp_arg1); - LIGHT_SWAPOUT; - result = erts_bs_get_integer_2(c_p, tmp_arg2, Arg(1), mb); - LIGHT_SWAPIN; - HEAP_SPACE_VERIFIED(0); - if (is_non_value(result)) { - ClauseFail(); + mb = ms_matchbuffer(Ms); + LIGHT_SWAPOUT; + result = erts_bs_get_integer_2(c_p, Sz, Arg(1), mb); + LIGHT_SWAPIN; + HEAP_SPACE_VERIFIED(0); + if (is_non_value(result)) { + ClauseFail(); + } + StoreBifResult(2, result); } - StoreBifResult(2, result); } /* - * tmp_arg1 = Match context - * tmp_arg2 = Size field - * Operands: Fail Live FlagsAndUnit Dst + * Operands: Fail Live FlagsAndUnit Ms Sz Dst */ - OpCase(i_bs_get_integer_fIId): { + OpCase(i_bs_get_integer_fIIssd): { Uint flags; Uint size; + Eterm Ms; + Eterm Sz; ErlBinMatchBuffer* mb; Eterm result; flags = Arg(2); - BsGetFieldSize(tmp_arg2, (flags >> 3), ClauseFail(), size); + GetArg2(3, Ms, Sz); + BsGetFieldSize(Sz, (flags >> 3), ClauseFail(), size); if (size >= SMALL_BITS) { Uint wordsneeded; - /* check bits size before potential gc. + /* Check bits size before potential gc. * We do not want a gc and then realize we don't need - * the allocated space (i.e. if the op fails) + * the allocated space (i.e. if the op fails). * - * remember to reacquire the matchbuffer after gc. + * Remember to re-acquire the matchbuffer after gc. */ - mb = ms_matchbuffer(tmp_arg1); + mb = ms_matchbuffer(Ms); if (mb->size - mb->offset < size) { ClauseFail(); } wordsneeded = 1+WSIZE(NBYTES((Uint) size)); - TestHeapPreserve(wordsneeded, Arg(1), tmp_arg1); + TestHeapPreserve(wordsneeded, Arg(1), Ms); } - mb = ms_matchbuffer(tmp_arg1); + mb = ms_matchbuffer(Ms); LIGHT_SWAPOUT; result = erts_bs_get_integer_2(c_p, size, flags, mb); LIGHT_SWAPIN; @@ -4671,18 +4372,13 @@ do { \ if (is_non_value(result)) { ClauseFail(); } - StoreBifResult(3, result); + StoreBifResult(5, result); } { Eterm get_utf8_context; /* Operands: MatchContext Fail Dst */ - OpCase(i_bs_get_utf8_rfd): { - get_utf8_context = r(0); - goto do_bs_get_utf8; - } - OpCase(i_bs_get_utf8_xfd): { get_utf8_context = xb(Arg(0)); I++; @@ -4693,7 +4389,7 @@ do { \ * Operands: Fail Dst */ - do_bs_get_utf8: { + { Eterm result = erts_bs_get_utf8(ms_matchbuffer(get_utf8_context)); if (is_non_value(result)) { ClauseFail(); @@ -4706,12 +4402,7 @@ do { \ Eterm get_utf16_context; /* Operands: MatchContext Fail Flags Dst */ - OpCase(i_bs_get_utf16_rfId): { - get_utf16_context = r(0); - goto do_bs_get_utf16; - } - - OpCase(i_bs_get_utf16_xfId): { + OpCase(i_bs_get_utf16_xfId): { get_utf16_context = xb(Arg(0)); I++; } @@ -4720,7 +4411,7 @@ do { \ * get_utf16_context = match_context * Operands: Fail Flags Dst */ - do_bs_get_utf16: { + { Eterm result = erts_bs_get_utf16(ms_matchbuffer(get_utf16_context), Arg(1)); if (is_non_value(result)) { @@ -4739,26 +4430,10 @@ do { \ Uint orig; Uint hole_size; - OpCase(bs_context_to_binary_r): { - context_to_binary_context = x0; - I -= 2; - goto do_context_to_binary; - } - - /* Unfortunately, inlining can generate this instruction. */ - OpCase(bs_context_to_binary_y): { - context_to_binary_context = yb(Arg(0)); - goto do_context_to_binary0; - } - - OpCase(bs_context_to_binary_x): { + OpCase(bs_context_to_binary_x): context_to_binary_context = xb(Arg(0)); - - do_context_to_binary0: I--; - } - do_context_to_binary: if (is_boxed(context_to_binary_context) && header_is_bin_matchstate(*boxed_val(context_to_binary_context))) { ErlBinMatchState* ms; @@ -4770,17 +4445,11 @@ do { \ } Next(2); - OpCase(i_bs_get_binary_all_reuse_rfI): { - context_to_binary_context = x0; - goto do_bs_get_binary_all_reuse; - } - OpCase(i_bs_get_binary_all_reuse_xfI): { context_to_binary_context = xb(Arg(0)); I++; } - do_bs_get_binary_all_reuse: mb = ms_matchbuffer(context_to_binary_context); size = mb->size - mb->offset; if (size % Arg(1) != 0) { @@ -4808,16 +4477,11 @@ do { \ { Eterm match_string_context; - OpCase(i_bs_match_string_rfII): { - match_string_context = r(0); - goto do_bs_match_string; - } OpCase(i_bs_match_string_xfII): { match_string_context = xb(Arg(0)); I++; } - do_bs_match_string: { BeamInstr *next; byte* bytes; @@ -4845,14 +4509,6 @@ do { \ } } - OpCase(i_bs_save2_rI): { - BeamInstr *next; - ErlBinMatchState *_ms; - PreFetch(1, next); - _ms = (ErlBinMatchState*) boxed_val((Eterm) r(0)); - _ms->save_offset[Arg(0)] = _ms->mb.offset; - NextPF(1, next); - } OpCase(i_bs_save2_xI): { BeamInstr *next; ErlBinMatchState *_ms; @@ -4862,14 +4518,6 @@ do { \ NextPF(2, next); } - OpCase(i_bs_restore2_rI): { - BeamInstr *next; - ErlBinMatchState *_ms; - PreFetch(1, next); - _ms = (ErlBinMatchState*) boxed_val((Eterm) r(0)); - _ms->mb.offset = _ms->save_offset[Arg(0)]; - NextPF(1, next); - } OpCase(i_bs_restore2_xI): { BeamInstr *next; ErlBinMatchState *_ms; @@ -4917,9 +4565,7 @@ do { \ BeamInstr real_I; ASSERT(I[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); SWAPOUT; - reg[0] = r(0); real_I = erts_generic_breakpoint(c_p, I, reg); - r(0) = reg[0]; SWAPIN; ASSERT(VALID_INSTR(real_I)); Goto(real_I); @@ -4979,7 +4625,7 @@ do { \ BeamInstr *next; PreFetch(2, next); - GetR(0, targ1); + targ1 = REG_TARGET(Arg(0)); /* Arg(0) == HEADER_FLONUM */ GET_DOUBLE(targ1, *(FloatDef*)ADD_BYTE_OFFSET(freg, fr)); NextPF(2, next); @@ -4999,7 +4645,7 @@ do { \ Eterm fr = Arg(1); BeamInstr *next; - GetR(0, targ1); + targ1 = REG_TARGET(Arg(0)); PreFetch(2, next); if (is_small(targ1)) { fb(fr) = (double) signed_val(targ1); @@ -5095,7 +4741,12 @@ do { \ #ifdef HIPE { - unsigned cmd; +#define HIPE_MODE_SWITCH(Cmd) \ + SWAPOUT; \ + c_p->fcalls = FCALLS; \ + c_p->def_arg_reg[4] = -neg_o_reds; \ + c_p = hipe_mode_switch(c_p, Cmd, reg); \ + goto L_post_hipe_mode_switch OpCase(hipe_trap_call): { /* @@ -5109,52 +4760,45 @@ do { \ */ ASSERT(I[-5] == (Uint) OpCode(i_func_info_IaaI)); c_p->hipe.u.ncallee = (void(*)(void)) I[-4]; - cmd = HIPE_MODE_SWITCH_CMD_CALL | (I[-1] << 8); ++hipe_trap_count; - goto L_hipe_mode_switch; + HIPE_MODE_SWITCH(HIPE_MODE_SWITCH_CMD_CALL | (I[-1] << 8)); } OpCase(hipe_trap_call_closure): { ASSERT(I[-5] == (Uint) OpCode(i_func_info_IaaI)); c_p->hipe.u.ncallee = (void(*)(void)) I[-4]; - cmd = HIPE_MODE_SWITCH_CMD_CALL_CLOSURE | (I[-1] << 8); ++hipe_trap_count; - goto L_hipe_mode_switch; + HIPE_MODE_SWITCH(HIPE_MODE_SWITCH_CMD_CALL_CLOSURE | (I[-1] << 8)); } OpCase(hipe_trap_return): { - cmd = HIPE_MODE_SWITCH_CMD_RETURN; - goto L_hipe_mode_switch; + HIPE_MODE_SWITCH(HIPE_MODE_SWITCH_CMD_RETURN); } OpCase(hipe_trap_throw): { - cmd = HIPE_MODE_SWITCH_CMD_THROW; - goto L_hipe_mode_switch; + HIPE_MODE_SWITCH(HIPE_MODE_SWITCH_CMD_THROW); } OpCase(hipe_trap_resume): { - cmd = HIPE_MODE_SWITCH_CMD_RESUME; - goto L_hipe_mode_switch; + HIPE_MODE_SWITCH(HIPE_MODE_SWITCH_CMD_RESUME); } - L_hipe_mode_switch: - /* XXX: this abuse of def_arg_reg[] is horrid! */ - SWAPOUT; - c_p->fcalls = FCALLS; - c_p->def_arg_reg[4] = -neg_o_reds; - reg[0] = r(0); - c_p = hipe_mode_switch(c_p, cmd, reg); +#undef HIPE_MODE_SWITCH + + L_post_hipe_mode_switch: reg = ERTS_PROC_GET_SCHDATA(c_p)->x_reg_array; freg = ERTS_PROC_GET_SCHDATA(c_p)->f_reg_array; ERL_BITS_RELOAD_STATEP(c_p); + /* XXX: this abuse of def_arg_reg[] is horrid! */ neg_o_reds = -c_p->def_arg_reg[4]; FCALLS = c_p->fcalls; SWAPIN; - switch( c_p->def_arg_reg[3] ) { /* Halfword wont work with hipe yet! */ + switch( c_p->def_arg_reg[3] ) { case HIPE_MODE_SWITCH_RES_RETURN: ASSERT(is_value(reg[0])); - MoveReturn(reg[0], r(0)); + SET_I(c_p->cp); + c_p->cp = 0; + Goto(*I); case HIPE_MODE_SWITCH_RES_CALL_EXPORTED: c_p->i = c_p->hipe.u.callee_exp->addressv[erts_active_code_ix()]; /*fall through*/ case HIPE_MODE_SWITCH_RES_CALL_BEAM: SET_I(c_p->i); - r(0) = reg[0]; Dispatch(); case HIPE_MODE_SWITCH_RES_CALL_CLOSURE: /* This can be used to call any function value, but currently it's @@ -5165,7 +4809,6 @@ do { \ next = call_fun(c_p, c_p->arity - 1, reg, THE_NON_VALUE); SWAPIN; if (next != NULL) { - r(0) = reg[0]; SET_I(next); Dispatchfun(); } @@ -5225,9 +4868,7 @@ do { \ OpCase(i_debug_breakpoint): { SWAPOUT; - reg[0] = r(0); I = call_error_handler(c_p, I-3, reg, am_breakpoint); - r(0) = reg[0]; SWAPIN; if (I) { Goto(*I); @@ -6644,23 +6285,20 @@ static Eterm get_map_element_hash(Eterm map, Eterm key, Uint32 hx) return vs ? *vs : THE_NON_VALUE; } -#define GET_TERM(term, dest) \ -do { \ - Eterm src = (Eterm)(term); \ - switch (src & _TAG_IMMED1_MASK) { \ - case (R_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \ - dest = x(0); \ - break; \ - case (X_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \ - dest = x(src >> _TAG_IMMED1_SIZE); \ - break; \ - case (Y_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER: \ - dest = y(src >> _TAG_IMMED1_SIZE); \ - break; \ - default: \ - dest = src; \ - break; \ - } \ +#define GET_TERM(term, dest) \ +do { \ + Eterm src = (Eterm)(term); \ + switch (loader_tag(src)) { \ + case LOADER_X_REG: \ + dest = x(loader_x_reg_index(src)); \ + break; \ + case LOADER_Y_REG: \ + dest = y(loader_y_reg_index(src)); \ + break; \ + default: \ + dest = src; \ + break; \ + } \ } while(0) @@ -7114,6 +6752,15 @@ erts_is_builtin(Eterm Mod, Eterm Name, int arity) Export e; Export* ep; + if (Mod == am_erlang && Name == am_apply && arity == 3) { + /* + * Special case. apply/3 is built-in (implemented in C), + * but implemented in a different way than all other + * BIFs. + */ + return 1; + } + e.code[0] = Mod; e.code[1] = Name; e.code[2] = arity; diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index b70e5b9a2d..a9d47eb7b0 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -1847,9 +1847,7 @@ load_code(LoaderState* stp) case TAG_o: break; case TAG_x: - if (last_op->a[arg].val == 0) { - last_op->a[arg].type = TAG_r; - } else if (last_op->a[arg].val >= MAX_REG) { + if (last_op->a[arg].val >= MAX_REG) { LoadError1(stp, "invalid x register number: %u", last_op->a[arg].val); } @@ -1894,15 +1892,14 @@ load_code(LoaderState* stp) */ { Eterm* hp; -/* XXX:PaN - Halfword should use ARCH_64 variant instead */ -#if !defined(ARCH_64) || HALFWORD_HEAP +#if !defined(ARCH_64) Uint high, low; # endif last_op->a[arg].val = new_literal(stp, &hp, FLOAT_SIZE_OBJECT); hp[0] = HEADER_FLONUM; last_op->a[arg].type = TAG_q; -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) GetInt(stp, 8, hp[1]); # else GetInt(stp, 4, high); @@ -2056,7 +2053,42 @@ load_code(LoaderState* stp) if (((opc[specific].mask[0] & mask[0]) == mask[0]) && ((opc[specific].mask[1] & mask[1]) == mask[1]) && ((opc[specific].mask[2] & mask[2]) == mask[2])) { - break; + + if (!opc[specific].involves_r) { + break; /* No complications - match */ + } + + /* + * The specific operation uses the 'r' operand, + * which is shorthand for x(0). Now things + * get complicated. First we must check whether + * all operands that should be of type 'r' use + * x(0) (as opposed to some other X register). + */ + for (arg = 0; arg < arity; arg++) { + if (opc[specific].involves_r & (1 << arg) && + tmp_op->a[arg].type == TAG_x) { + if (tmp_op->a[arg].val != 0) { + break; /* Other X register than 0 */ + } + } + } + + if (arg == arity) { + /* + * All 'r' operands use x(0) in the generic + * operation. That means a match. Now we + * will need to rewrite the generic instruction + * to actually use 'r' instead of 'x(0)'. + */ + for (arg = 0; arg < arity; arg++) { + if (opc[specific].involves_r & (1 << arg) && + tmp_op->a[arg].type == TAG_x) { + tmp_op->a[arg].type = TAG_r; + } + } + break; /* Match */ + } } specific++; } @@ -2167,14 +2199,11 @@ load_code(LoaderState* stp) break; case 's': /* Any source (tagged constant or register) */ switch (tag) { - case TAG_r: - code[ci++] = make_rreg(); - break; case TAG_x: - code[ci++] = make_xreg(tmp_op->a[arg].val); + code[ci++] = make_loader_x_reg(tmp_op->a[arg].val); break; case TAG_y: - code[ci++] = make_yreg(tmp_op->a[arg].val); + code[ci++] = make_loader_y_reg(tmp_op->a[arg].val); break; case TAG_i: code[ci++] = (BeamInstr) make_small((Uint)tmp_op->a[arg].val); @@ -2185,6 +2214,10 @@ load_code(LoaderState* stp) case TAG_n: code[ci++] = NIL; break; + case TAG_q: + new_literal_patch(stp, ci); + code[ci++] = tmp_op->a[arg].val; + break; default: LoadError1(stp, "bad tag %d for general source", tmp_op->a[arg].type); @@ -2193,14 +2226,11 @@ load_code(LoaderState* stp) break; case 'd': /* Destination (x(0), x(N), y(N) */ switch (tag) { - case TAG_r: - code[ci++] = make_rreg(); - break; case TAG_x: - code[ci++] = make_xreg(tmp_op->a[arg].val); + code[ci++] = tmp_op->a[arg].val * sizeof(Eterm); break; case TAG_y: - code[ci++] = make_yreg(tmp_op->a[arg].val); + code[ci++] = tmp_op->a[arg].val * sizeof(Eterm) + 1; break; default: LoadError1(stp, "bad tag %d for destination", @@ -2357,20 +2387,13 @@ load_code(LoaderState* stp) stp->labels[tmp_op->a[arg].val].patches = ci; ci++; break; - case TAG_r: - CodeNeed(1); - code[ci++] = (R_REG_DEF << _TAG_PRIMARY_SIZE) | - TAG_PRIMARY_HEADER; - break; case TAG_x: CodeNeed(1); - code[ci++] = (tmp_op->a[arg].val << _TAG_IMMED1_SIZE) | - (X_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER; + code[ci++] = make_loader_x_reg(tmp_op->a[arg].val); break; case TAG_y: CodeNeed(1); - code[ci++] = (tmp_op->a[arg].val << _TAG_IMMED1_SIZE) | - (Y_REG_DEF << _TAG_PRIMARY_SIZE) | TAG_PRIMARY_HEADER; + code[ci++] = make_loader_y_reg(tmp_op->a[arg].val); break; case TAG_n: CodeNeed(1); @@ -2458,7 +2481,6 @@ load_code(LoaderState* stp) stp->on_load = ci; break; case op_bs_put_string_II: - case op_i_bs_match_string_rfII: case op_i_bs_match_string_xfII: new_string_patch(stp, ci-1); break; @@ -2680,6 +2702,12 @@ same_label(LoaderState* stp, GenOpArg Target, GenOpArg Label) Target.val == Label.val; } +static int +is_killed(LoaderState* stp, GenOpArg Reg, GenOpArg Live) +{ + return Reg.type == TAG_x && Live.type == TAG_u && + Live.val <= Reg.val; +} /* * Generate an instruction for element/2. @@ -2696,17 +2724,17 @@ gen_element(LoaderState* stp, GenOpArg Fail, GenOpArg Index, op->next = NULL; if (Index.type == TAG_i && Index.val > 0 && - (Tuple.type == TAG_r || Tuple.type == TAG_x || Tuple.type == TAG_y)) { + (Tuple.type == TAG_x || Tuple.type == TAG_y)) { op->op = genop_i_fast_element_4; - op->a[0] = Tuple; - op->a[1] = Fail; + op->a[0] = Fail; + op->a[1] = Tuple; op->a[2].type = TAG_u; op->a[2].val = Index.val; op->a[3] = Dst; } else { op->op = genop_i_element_4; - op->a[0] = Tuple; - op->a[1] = Fail; + op->a[0] = Fail; + op->a[1] = Tuple; op->a[2] = Index; op->a[3] = Dst; } @@ -2832,23 +2860,16 @@ gen_get_integer2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live, goto generic; } } else { - GenOp* op2; - NEW_GENOP(stp, op2); - - op->op = genop_i_fetch_2; - op->arity = 2; - op->a[0] = Ms; - op->a[1] = Size; - op->next = op2; - - op2->op = genop_i_bs_get_integer_4; - op2->arity = 4; - op2->a[0] = Fail; - op2->a[1] = Live; - op2->a[2].type = TAG_u; - op2->a[2].val = (Unit.val << 3) | Flags.val; - op2->a[3] = Dst; - op2->next = NULL; + op->op = genop_i_bs_get_integer_6; + op->arity = 6; + op->a[0] = Fail; + op->a[1] = Live; + op->a[2].type = TAG_u; + op->a[2].val = (Unit.val << 3) | Flags.val; + op->a[3] = Ms; + op->a[4] = Size; + op->a[5] = Dst; + op->next = NULL; return op; } op->next = NULL; @@ -3272,14 +3293,14 @@ gen_literal_timeout(LoaderState* stp, GenOpArg Fail, GenOpArg Time) op->a[1].type = TAG_u; if (Time.type == TAG_i && (timeout = Time.val) >= 0 && -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) (timeout >> 32) == 0 #else 1 #endif ) { op->a[1].val = timeout; -#if !defined(ARCH_64) || HALFWORD_HEAP +#if !defined(ARCH_64) } else if (Time.type == TAG_q) { Eterm big; @@ -3296,7 +3317,7 @@ gen_literal_timeout(LoaderState* stp, GenOpArg Fail, GenOpArg Time) } #endif } else { -#if !defined(ARCH_64) || HALFWORD_HEAP +#if !defined(ARCH_64) error: #endif op->op = genop_i_wait_error_0; @@ -3319,14 +3340,14 @@ gen_literal_timeout_locked(LoaderState* stp, GenOpArg Fail, GenOpArg Time) op->a[1].type = TAG_u; if (Time.type == TAG_i && (timeout = Time.val) >= 0 && -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) (timeout >> 32) == 0 #else 1 #endif ) { op->a[1].val = timeout; -#if !defined(ARCH_64) || HALFWORD_HEAP +#if !defined(ARCH_64) } else if (Time.type == TAG_q) { Eterm big; @@ -3343,7 +3364,7 @@ gen_literal_timeout_locked(LoaderState* stp, GenOpArg Fail, GenOpArg Time) } #endif } else { -#if !defined(ARCH_64) || HALFWORD_HEAP +#if !defined(ARCH_64) error: #endif op->op = genop_i_wait_error_locked_0; @@ -3899,9 +3920,7 @@ gen_make_fun2(LoaderState* stp, GenOpArg idx) /* * Rewrite gc_bifs with one parameter (the common case). Utilized * in ops.tab to rewrite instructions calling bif's in guards - * to use a garbage collecting implementation. The instructions - * are sometimes once again rewritten to handle literals (putting the - * parameter in the mostly unused r[0] before the instruction is executed). + * to use a garbage collecting implementation. */ static GenOp* gen_guard_bif1(LoaderState* stp, GenOpArg Fail, GenOpArg Live, GenOpArg Bif, @@ -3956,10 +3975,6 @@ gen_guard_bif1(LoaderState* stp, GenOpArg Fail, GenOpArg Live, GenOpArg Bif, /* * This is used by the ops.tab rule that rewrites gc_bifs with two parameters. - * The instruction returned is then again rewritten to an i_load instruction - * followed by i_gc_bif2_jIId, to handle literals properly. - * As opposed to the i_gc_bif1_jIsId, the instruction i_gc_bif2_jIId is - * always rewritten, regardless of if there actually are any literals. */ static GenOp* gen_guard_bif2(LoaderState* stp, GenOpArg Fail, GenOpArg Live, GenOpArg Bif, @@ -3986,23 +4001,19 @@ gen_guard_bif2(LoaderState* stp, GenOpArg Fail, GenOpArg Live, GenOpArg Bif, op->a[2].val = stp->import[Bif.val].arity; return op; } - op->op = genop_ii_gc_bif2_6; + op->op = genop_i_gc_bif2_6; op->arity = 6; op->a[0] = Fail; op->a[1].type = TAG_u; - op->a[2] = S1; - op->a[3] = S2; - op->a[4] = Live; + op->a[2] = Live; + op->a[3] = S1; + op->a[4] = S2; op->a[5] = Dst; return op; } /* * This is used by the ops.tab rule that rewrites gc_bifs with three parameters. - * The instruction returned is then again rewritten to a move instruction that - * uses r[0] for temp storage, followed by an i_load instruction, - * followed by i_gc_bif3_jIsId, to handle literals properly. Rewriting - * always occur, as with the gc_bif2 counterpart. */ static GenOp* gen_guard_bif3(LoaderState* stp, GenOpArg Fail, GenOpArg Live, GenOpArg Bif, @@ -4033,10 +4044,10 @@ gen_guard_bif3(LoaderState* stp, GenOpArg Fail, GenOpArg Live, GenOpArg Bif, op->arity = 7; op->a[0] = Fail; op->a[1].type = TAG_u; - op->a[2] = S1; - op->a[3] = S2; - op->a[4] = S3; - op->a[5] = Live; + op->a[2] = Live; + op->a[3] = S1; + op->a[4] = S2; + op->a[5] = S3; op->a[6] = Dst; op->next = NULL; return op; @@ -4323,7 +4334,7 @@ gen_has_map_fields(LoaderState* stp, GenOpArg Fail, GenOpArg Src, for (i = 0; i < n; i++) { op->a[3+2*i] = Rest[i]; op->a[3+2*i+1].type = TAG_x; - op->a[3+2*i+1].val = 0; /* x(0); normally not used */ + op->a[3+2*i+1].val = SCRATCH_X_REG; /* Ignore result */ } return op; } @@ -4801,7 +4812,8 @@ transform_engine(LoaderState* st) if (var[i].type != instr->a[ap].type) goto restart; switch (var[i].type) { - case TAG_r: case TAG_n: break; + case TAG_n: + break; default: if (var[i].val != instr->a[ap].val) goto restart; @@ -5868,7 +5880,7 @@ make_stub(BeamInstr* fp, Eterm mod, Eterm func, Uint arity, Uint native, BeamIns fp[4] = arity; #ifdef HIPE if (native) { - fp[5] = BeamOpCode(op_move_return_nr); + fp[5] = BeamOpCode(op_move_return_n); hipe_mfa_save_orig_beam_op(mod, func, arity, fp+5); } #endif @@ -6304,7 +6316,7 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) #ifdef HIPE op = (Eterm) BeamOpCode(op_hipe_trap_call); /* Might be changed later. */ #else - op = (Eterm) BeamOpCode(op_move_return_nr); + op = (Eterm) BeamOpCode(op_move_return_n); #endif fp = make_stub(fp, Mod, func, arity, (Uint)native_address, op); } diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h index d5af634fad..eedb5ee4cd 100644 --- a/erts/emulator/beam/beam_load.h +++ b/erts/emulator/beam/beam_load.h @@ -52,6 +52,7 @@ extern BeamInstr* em_call_error_handler; extern BeamInstr* em_apply_bif; extern BeamInstr* em_call_nif; + /* * The following variables keep a sorted list of address ranges for * each module. It allows us to quickly find a function given an diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 4e3a1cef69..453ac74c90 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -616,7 +616,7 @@ erts_queue_monitor_message(Process *p, } static BIF_RETTYPE -local_pid_monitor(Process *p, Eterm target, Eterm mon_ref, int bool) +local_pid_monitor(Process *p, Eterm target, Eterm mon_ref, int boolean) { BIF_RETTYPE ret; Process *rp; @@ -634,7 +634,7 @@ local_pid_monitor(Process *p, Eterm target, Eterm mon_ref, int bool) if (!rp) { erts_smp_proc_unlock(p, ERTS_PROC_LOCK_LINK); p_locks &= ~ERTS_PROC_LOCK_LINK; - if (bool) + if (boolean) ret = am_false; else erts_queue_monitor_message(p, &p_locks, @@ -643,7 +643,7 @@ local_pid_monitor(Process *p, Eterm target, Eterm mon_ref, int bool) else { ASSERT(rp != p); - if (bool) + if (boolean) ret = am_true; erts_add_monitor(&ERTS_P_MONITORS(p), MON_ORIGIN, mon_ref, target, NIL); @@ -4117,16 +4117,9 @@ BIF_RETTYPE make_fun_3(BIF_ALIST_3) if (arity < 0) { goto error; } -#if HALFWORD_HEAP - hp = HAlloc(BIF_P, 3); - hp[0] = HEADER_EXPORT; - /* Yes, May be misaligned, but X86_64 will fix it... */ - *((Export **) (hp+1)) = erts_export_get_or_make_stub(BIF_ARG_1, BIF_ARG_2, (Uint) arity); -#else hp = HAlloc(BIF_P, 2); hp[0] = HEADER_EXPORT; hp[1] = (Eterm) erts_export_get_or_make_stub(BIF_ARG_1, BIF_ARG_2, (Uint) arity); -#endif BIF_RET(make_export(hp)); } @@ -4631,7 +4624,7 @@ BIF_RETTYPE hash_2(BIF_ALIST_2) if ((range = signed_val(BIF_ARG_2)) <= 0) { /* [1..MAX_SMALL] */ BIF_ERROR(BIF_P, BADARG); } -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) if (range > ((1L << 27) - 1)) BIF_ERROR(BIF_P, BADARG); #endif @@ -4703,7 +4696,7 @@ BIF_RETTYPE phash2_2(BIF_ALIST_2) /* * Return either a small or a big. Use the heap for bigs if there is room. */ -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) BIF_RET(make_small(final_hash)); #else if (IS_USMALL(0, final_hash)) { diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c index 044bf6a34e..02d37e24df 100644 --- a/erts/emulator/beam/big.c +++ b/erts/emulator/beam/big.c @@ -1487,20 +1487,8 @@ Eterm uint_to_big(Uint x, Eterm *y) Eterm uword_to_big(UWord x, Eterm *y) { -#if HALFWORD_HEAP - Uint upper = x >> 32; - Uint lower = x & 0xFFFFFFFFUL; - if (upper == 0) { - *y = make_pos_bignum_header(1); - } else { - *y = make_pos_bignum_header(2); - BIG_DIGIT(y, 1) = upper; - } - BIG_DIGIT(y, 0) = lower; -#else *y = make_pos_bignum_header(1); BIG_DIGIT(y, 0) = x; -#endif return make_big(y); } @@ -1525,7 +1513,7 @@ Eterm small_to_big(Sint x, Eterm *y) Eterm erts_uint64_to_big(Uint64 x, Eterm **hpp) { Eterm *hp = *hpp; -#if defined(ARCH_32) || HALFWORD_HEAP +#if defined(ARCH_32) if (x >= (((Uint64) 1) << 32)) { *hp = make_pos_bignum_header(2); BIG_DIGIT(hp, 0) = (Uint) (x & ((Uint) 0xffffffff)); @@ -1555,7 +1543,7 @@ Eterm erts_sint64_to_big(Sint64 x, Eterm **hpp) neg = 1; ux = -(Uint64)x; } -#if defined(ARCH_32) || HALFWORD_HEAP +#if defined(ARCH_32) if (ux >= (((Uint64) 1) << 32)) { if (neg) *hp = make_neg_bignum_header(2); @@ -1588,7 +1576,7 @@ erts_uint64_array_to_big(Uint **hpp, int neg, int len, Uint64 *array) pot_digits = digits = 0; for (i = 0; i < len; i++) { -#if defined(ARCH_32) || HALFWORD_HEAP +#if defined(ARCH_32) Uint low_val = array[i] & ((Uint) 0xffffffff); Uint high_val = (array[i] >> 32) & ((Uint) 0xffffffff); BIG_DIGIT(headerp, pot_digits) = low_val; @@ -1651,8 +1639,6 @@ big_to_double(Wterm x, double* resp) /* * Logic has been copied from erl_bif_guard.c and slightly * modified to use a static instead of dynamic heap - * - * HALFWORD: Return relative term with 'heap' as base. */ Eterm double_to_big(double x, Eterm *heap, Uint hsz) @@ -1683,7 +1669,7 @@ double_to_big(double x, Eterm *heap, Uint hsz) sz = BIG_NEED_SIZE(ds); /* number of words including arity */ hp = heap; - res = make_big_rel(hp, heap); + res = make_big(hp); xp = (ErtsDigit*) (hp + 1); ASSERT(ds < hsz); @@ -2618,6 +2604,9 @@ Eterm erts_chars_to_integer(Process *BIF_P, char *bytes, size--; } + if (size == 0) + goto bytebuf_to_integer_1_error; + if (size < SMALL_DIGITS && base <= 10) { /* * * Take shortcut if we know that all chars are '0' < b < '9' and diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h index 4aa9724ae3..94f9bce10e 100644 --- a/erts/emulator/beam/big.h +++ b/erts/emulator/beam/big.h @@ -35,7 +35,7 @@ typedef Uint ErtsDigit; -#if ((SIZEOF_VOID_P == 4) || HALFWORD_HEAP) && defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == 8) +#if (SIZEOF_VOID_P == 4) && defined(SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == 8) /* Assume 32-bit machine with long long support */ typedef Uint64 ErtsDoubleDigit; typedef Uint16 ErtsHalfDigit; @@ -90,13 +90,9 @@ typedef Uint dsize_t; /* Vector size type */ #define BIG_UINT_HEAP_SIZE (1 + 1) /* always, since sizeof(Uint) <= sizeof(Eterm) */ -#if HALFWORD_HEAP -#define BIG_UWORD_HEAP_SIZE(UW) (((UW) >> (sizeof(Uint) * 8)) ? 3 : 2) -#else #define BIG_UWORD_HEAP_SIZE(UW) BIG_UINT_HEAP_SIZE -#endif -#if defined(ARCH_32) || HALFWORD_HEAP +#if defined(ARCH_32) #define ERTS_UINT64_BIG_HEAP_SIZE__(X) \ ((X) >= (((Uint64) 1) << 32) ? (1 + 2) : (1 + 1)) @@ -178,4 +174,3 @@ Eterm erts_sint64_to_big(Sint64, Eterm **); Eterm erts_chars_to_integer(Process *, char*, Uint, const int); #endif - diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 64c8bc5e58..4ce9d24479 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -536,7 +536,9 @@ do_break(void) erts_printf("Erlang (%s) emulator version " ERLANG_VERSION "\n", EMULATOR); +#if ERTS_SAVED_COMPILE_TIME erts_printf("Compiled on " ERLANG_COMPILE_DATE "\n"); +#endif return; case 'd': distribution_info(ERTS_PRINT_STDOUT, NULL); @@ -774,7 +776,9 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) } erts_fdprintf(fd, "System version: "); erts_print_system_version(fd, NULL, NULL); +#if ERTS_SAVED_COMPILE_TIME erts_fdprintf(fd, "%s\n", "Compiled: " ERLANG_COMPILE_DATE); +#endif erts_fdprintf(fd, "Taints: "); erts_print_nif_taints(fd, NULL); diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c index 8849dadd00..ec769c3b49 100644 --- a/erts/emulator/beam/copy.c +++ b/erts/emulator/beam/copy.c @@ -40,40 +40,37 @@ static void move_one_frag(Eterm** hpp, ErlHeapFragment*, ErlOffHeap*); /* * Copy object "obj" to process p. */ -Eterm -copy_object(Eterm obj, Process* to) -{ - Uint size = size_object(obj); - Eterm* hp = HAlloc(to, size); - Eterm res; +Eterm copy_object_x(Eterm obj, Process* to, Uint extra) { + if (!is_immed(obj)) { + Uint size = size_object(obj); + Eterm* hp = HAllocX(to, size, extra); + Eterm res; #ifdef USE_VM_PROBES - if (DTRACE_ENABLED(copy_object)) { - DTRACE_CHARBUF(proc_name, 64); + if (DTRACE_ENABLED(copy_object)) { + DTRACE_CHARBUF(proc_name, 64); - erts_snprintf(proc_name, sizeof(DTRACE_CHARBUF_NAME(proc_name)), - "%T", to->common.id); - DTRACE2(copy_object, proc_name, size); - } + erts_snprintf(proc_name, sizeof(DTRACE_CHARBUF_NAME(proc_name)), + "%T", to->common.id); + DTRACE2(copy_object, proc_name, size); + } #endif - res = copy_struct(obj, size, &hp, &to->off_heap); + res = copy_struct(obj, size, &hp, &to->off_heap); #ifdef DEBUG - if (eq(obj, res) == 0) { - erl_exit(ERTS_ABORT_EXIT, "copy not equal to source\n"); - } + if (eq(obj, res) == 0) { + erl_exit(ERTS_ABORT_EXIT, "copy not equal to source\n"); + } #endif - return res; + return res; + } + return obj; } /* * Return the "flat" size of the object. */ -#if HALFWORD_HEAP -Uint size_object_rel(Eterm obj, Eterm* base) -#else Uint size_object(Eterm obj) -#endif { Uint sum = 0; Eterm* ptr; @@ -84,7 +81,7 @@ Uint size_object(Eterm obj) switch (primary_tag(obj)) { case TAG_PRIMARY_LIST: sum += 2; - ptr = list_val_rel(obj,base); + ptr = list_val(obj); obj = *ptr++; if (!IS_CONST(obj)) { ESTACK_PUSH(s, obj); @@ -93,11 +90,11 @@ Uint size_object(Eterm obj) break; case TAG_PRIMARY_BOXED: { - Eterm hdr = *boxed_val_rel(obj,base); + Eterm hdr = *boxed_val(obj); ASSERT(is_header(hdr)); switch (hdr & _TAG_HEADER_MASK) { case ARITYVAL_SUBTAG: - ptr = tuple_val_rel(obj,base); + ptr = tuple_val(obj); arity = header_arity(hdr); sum += arity + 1; if (arity == 0) { /* Empty tuple -- unusual. */ @@ -113,7 +110,7 @@ Uint size_object(Eterm obj) break; case FUN_SUBTAG: { - Eterm* bptr = fun_val_rel(obj,base); + Eterm* bptr = fun_val(obj); ErlFunThing* funp = (ErlFunThing *) bptr; unsigned eterms = 1 /* creator */ + funp->num_free; unsigned sz = thing_arityval(hdr); @@ -134,7 +131,7 @@ Uint size_object(Eterm obj) { Uint n; flatmap_t *mp; - mp = (flatmap_t*)flatmap_val_rel(obj,base); + mp = (flatmap_t*)flatmap_val(obj); ptr = (Eterm *)mp; n = flatmap_get_size(mp) + 1; sum += n + 2; @@ -153,7 +150,7 @@ Uint size_object(Eterm obj) { Eterm *head; Uint sz; - head = hashmap_val_rel(obj, base); + head = hashmap_val(obj); sz = hashmap_bitcount(MAP_HEADER_VAL(hdr)); sum += 1 + sz + header_arity(hdr); head += 1 + header_arity(hdr); @@ -182,7 +179,7 @@ Uint size_object(Eterm obj) Uint bitoffs; Uint extra_bytes; Eterm hdr; - ERTS_GET_REAL_BIN_REL(obj, real_bin, offset, bitoffs, bitsize, base); + ERTS_GET_REAL_BIN(obj, real_bin, offset, bitoffs, bitsize); if ((bitsize + bitoffs) > 8) { sum += ERL_SUB_BIN_SIZE; extra_bytes = 2; @@ -192,11 +189,11 @@ Uint size_object(Eterm obj) } else { extra_bytes = 0; } - hdr = *binary_val_rel(real_bin,base); + hdr = *binary_val(real_bin); if (thing_subtag(hdr) == REFC_BINARY_SUBTAG) { sum += PROC_BIN_SIZE; } else { - sum += heap_bin_size(binary_size_rel(obj,base)+extra_bytes); + sum += heap_bin_size(binary_size(obj)+extra_bytes); } goto pop_next; } @@ -227,12 +224,7 @@ Uint size_object(Eterm obj) /* * Copy a structure to a heap. */ -#if HALFWORD_HEAP -Eterm copy_struct_rel(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap, - Eterm* src_base, Eterm* dst_base) -#else Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) -#endif { char* hstart; Uint hsize; @@ -268,7 +260,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) switch (primary_tag(obj)) { case TAG_PRIMARY_LIST: argp = &res; - objp = list_val_rel(obj,src_base); + objp = list_val(obj); goto L_copy_list; case TAG_PRIMARY_BOXED: argp = &res; goto L_copy_boxed; default: @@ -286,14 +278,11 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) hp++; break; case TAG_PRIMARY_LIST: - objp = list_val_rel(obj,src_base); - #if !HALFWORD_HEAP || defined(DEBUG) + objp = list_val(obj); if (in_area(objp,hstart,hsize)) { - ASSERT(!HALFWORD_HEAP); hp++; break; } - #endif argp = hp++; /* Fall through */ @@ -309,23 +298,15 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) } else { CAR(htop) = elem; - #if HALFWORD_HEAP - CDR(htop) = CDR(objp); - *tailp = make_list_rel(htop,dst_base); - htop += 2; - goto L_copy; - #else tailp = &CDR(htop); htop += 2; - #endif } - ASSERT(!HALFWORD_HEAP || tp < hp || tp >= hbot); - *tp = make_list_rel(tailp - 1, dst_base); + *tp = make_list(tailp - 1); obj = CDR(objp); if (!is_list(obj)) { break; } - objp = list_val_rel(obj,src_base); + objp = list_val(obj); } switch (primary_tag(obj)) { case TAG_PRIMARY_IMMED1: *tailp = obj; goto L_copy; @@ -337,24 +318,21 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) } case TAG_PRIMARY_BOXED: - #if !HALFWORD_HEAP || defined(DEBUG) - if (in_area(boxed_val_rel(obj,src_base),hstart,hsize)) { - ASSERT(!HALFWORD_HEAP); + if (in_area(boxed_val(obj),hstart,hsize)) { hp++; break; } - #endif argp = hp++; L_copy_boxed: - objp = boxed_val_rel(obj, src_base); + objp = boxed_val(obj); hdr = *objp; switch (hdr & _TAG_HEADER_MASK) { case ARITYVAL_SUBTAG: { int const_flag = 1; /* assume constant tuple */ i = arityval(hdr); - *argp = make_tuple_rel(htop, dst_base); + *argp = make_tuple(htop); tp = htop; /* tp is pointer to new arity value */ *htop++ = *objp++; /* copy arity value */ while (i--) { @@ -383,7 +361,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) while (i--) { *tp++ = *objp++; } - *argp = make_binary_rel(hbot, dst_base); + *argp = make_binary(hbot); pb = (ProcBin*) hbot; erts_refc_inc(&pb->val->refc, 2); pb->next = off_heap->first; @@ -410,7 +388,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) extra_bytes = 0; } real_size = size+extra_bytes; - objp = binary_val_rel(real_bin,src_base); + objp = binary_val(real_bin); if (thing_subtag(*objp) == HEAP_BINARY_SUBTAG) { ErlHeapBin* from = (ErlHeapBin *) objp; ErlHeapBin* to; @@ -440,7 +418,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) off_heap->first = (struct erl_off_heap_header*) to; OH_OVERHEAD(off_heap, to->size / sizeof(Eterm)); } - *argp = make_binary_rel(hbot, dst_base); + *argp = make_binary(hbot); if (extra_bytes != 0) { ErlSubBin* res; hbot -= ERL_SUB_BIN_SIZE; @@ -452,7 +430,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) res->offs = 0; res->is_writable = 0; res->orig = *argp; - *argp = make_binary_rel(hbot, dst_base); + *argp = make_binary(hbot); } break; } @@ -470,7 +448,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) funp->next = off_heap->first; off_heap->first = (struct erl_off_heap_header*) funp; erts_refc_inc(&funp->fe->refc, 2); - *argp = make_fun_rel(tp, dst_base); + *argp = make_fun(tp); } break; case EXTERNAL_PID_SUBTAG: @@ -490,7 +468,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) off_heap->first = (struct erl_off_heap_header*)etp; erts_refc_inc(&etp->node->refc, 2); - *argp = make_external_rel(tp, dst_base); + *argp = make_external(tp); } break; case MAP_SUBTAG: @@ -498,7 +476,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) switch (MAP_HEADER_TYPE(hdr)) { case MAP_HEADER_TAG_FLATMAP_HEAD : i = flatmap_get_size(objp) + 3; - *argp = make_flatmap_rel(htop, dst_base); + *argp = make_flatmap(htop); while (i--) { *htop++ = *objp++; } @@ -509,7 +487,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) case MAP_HEADER_TAG_HAMT_NODE_BITMAP : i = 1 + hashmap_bitcount(MAP_HEADER_VAL(hdr)); while (i--) { *htop++ = *objp++; } - *argp = make_hashmap_rel(tp, dst_base); + *argp = make_hashmap(tp); break; default: erl_exit(ERTS_ABORT_EXIT, "copy_struct: bad hashmap type %d\n", MAP_HEADER_TYPE(hdr)); @@ -522,7 +500,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) i = thing_arityval(hdr)+1; hbot -= i; tp = hbot; - *argp = make_boxed_rel(hbot, dst_base); + *argp = make_boxed(hbot); while (i--) { *tp++ = *objp++; } @@ -563,21 +541,12 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) * * NOTE: Assumes that term is a tuple (ptr is an untagged tuple ptr). */ -#if HALFWORD_HEAP -Eterm copy_shallow_rel(Eterm* ptr, Uint sz, Eterm** hpp, ErlOffHeap* off_heap, - Eterm* src_base) -#else Eterm copy_shallow(Eterm* ptr, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) -#endif { Eterm* tp = ptr; Eterm* hp = *hpp; const Eterm res = make_tuple(hp); -#if HALFWORD_HEAP - const Sint offs = COMPRESS_POINTER(hp - (tp - src_base)); -#else const Sint offs = (hp - tp) * sizeof(Eterm); -#endif while (sz--) { Eterm val = *tp++; diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 23897a49ae..10dd6cf206 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -45,6 +45,8 @@ #include "erl_thr_progress.h" #include "dtrace-wrapper.h" +#define DIST_CTL_DEFAULT_SIZE 64 + /* Turn this on to get printouts of all distribution messages * which go on the line */ @@ -66,9 +68,13 @@ static void bw(byte *buf, ErlDrvSizeT sz) static void dist_msg_dbg(ErtsDistExternal *edep, char *what, byte *buf, int sz) { + ErtsHeapFactory factory; + DeclareTmpHeapNoproc(ctl_default,DIST_CTL_DEFAULT_SIZE); + Eterm* ctl = ctl_default; byte *extp = edep->extp; Eterm msg; - Sint size = erts_decode_dist_ext_size(edep); + Sint ctl_len; + Sint size = ctl_len = erts_decode_dist_ext_size(edep); if (size < 0) { erts_fprintf(stderr, "DIST MSG DEBUG: erts_decode_dist_ext_size(%s) failed:\n", @@ -76,10 +82,9 @@ dist_msg_dbg(ErtsDistExternal *edep, char *what, byte *buf, int sz) bw(buf, sz); } else { - Eterm *hp; ErlHeapFragment *mbuf = new_message_buffer(size); - hp = mbuf->mem; - msg = erts_decode_dist_ext(&hp, &mbuf->off_heap, edep); + erts_factory_static_init(&factory, ctl, ctl_len, &mbuf->off_heap); + msg = erts_decode_dist_ext(&factory, edep); if (is_value(msg)) erts_fprintf(stderr, " %s: %T\n", what, msg); else { @@ -732,19 +737,11 @@ Eterm erts_dsend_export_trap_context(Process* p, ErtsSendContext* ctx) Binary* ctx_bin = erts_create_magic_binary(sizeof(struct exported_ctx), erts_dsend_context_dtor); struct exported_ctx* dst = ERTS_MAGIC_BIN_DATA(ctx_bin); - Uint ctl_size = !HALFWORD_HEAP ? 0 : (arityval(ctx->ctl_heap[0]) + 1); - Eterm* hp = HAlloc(p, ctl_size + PROC_BIN_SIZE); + Eterm* hp = HAlloc(p, PROC_BIN_SIZE); sys_memcpy(&dst->ctx, ctx, sizeof(ErtsSendContext)); ASSERT(ctx->dss.ctl == make_tuple(ctx->ctl_heap)); -#if !HALFWORD_HEAP dst->ctx.dss.ctl = make_tuple(dst->ctx.ctl_heap); -#else - /* Must put control tuple in low mem */ - sys_memcpy(hp, ctx->ctl_heap, ctl_size*sizeof(Eterm)); - dst->ctx.dss.ctl = make_tuple(hp); - hp += ctl_size; -#endif if (ctx->dss.acmp) { sys_memcpy(&dst->acm, ctx->dss.acmp, sizeof(ErtsAtomCacheMap)); dst->ctx.dss.acmp = &dst->acm; @@ -1136,7 +1133,6 @@ int erts_net_message(Port *prt, byte *buf, ErlDrvSizeT len) { -#define DIST_CTL_DEFAULT_SIZE 64 ErtsDistExternal ede; byte *t; Sint ctl_len; @@ -1790,8 +1786,8 @@ erts_dsig_send(ErtsDSigData *dsdp, struct erts_dsig_send_context* ctx) #ifdef ERTS_DIST_MSG_DBG erts_fprintf(stderr, ">>%s CTL: %T\n", ctx->pass_through_size ? "P" : " ", ctx->ctl); - if (is_value(msg)) - erts_fprintf(stderr, " MSG: %T\n", msg); + if (is_value(ctx->msg)) + erts_fprintf(stderr, " MSG: %T\n", ctx->msg); #endif ctx->data_size = ctx->pass_through_size; @@ -2061,9 +2057,9 @@ dist_port_commandv(Port *prt, ErtsDistOutputBuf *obuf) } -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) #define ERTS_PORT_REDS_MASK__ 0x003fffffffffffffL -#elif defined(ARCH_32) || HALFWORD_HEAP +#elif defined(ARCH_32) #define ERTS_PORT_REDS_MASK__ 0x003fffff #else # error "Ohh come on ... !?!" diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index 55c164bf11..d68f22d573 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -123,10 +123,6 @@ typedef union { static ErtsAllocatorState_t std_alloc_state; static ErtsAllocatorState_t ll_alloc_state; -#if HALFWORD_HEAP -static ErtsAllocatorState_t std_low_alloc_state; -static ErtsAllocatorState_t ll_low_alloc_state; -#endif static ErtsAllocatorState_t sl_alloc_state; static ErtsAllocatorState_t temp_alloc_state; static ErtsAllocatorState_t eheap_alloc_state; @@ -150,24 +146,10 @@ typedef struct { #define ERTS_ALC_INFO_A_MSEG_ALLOC (ERTS_ALC_A_MAX + 2) #define ERTS_ALC_INFO_A_MAX ERTS_ALC_INFO_A_MSEG_ALLOC -#if !HALFWORD_HEAP ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(aireq, - ErtsAllocInfoReq, - 5, - ERTS_ALC_T_AINFO_REQ) -#else -static ERTS_INLINE ErtsAllocInfoReq * -aireq_alloc(void) -{ - return erts_alloc(ERTS_ALC_T_AINFO_REQ, sizeof(ErtsAllocInfoReq)); -} - -static ERTS_INLINE void -aireq_free(ErtsAllocInfoReq *ptr) -{ - erts_free(ERTS_ALC_T_AINFO_REQ, ptr); -} -#endif + ErtsAllocInfoReq, + 5, + ERTS_ALC_T_AINFO_REQ) ErtsAlcType_t erts_fix_core_allocator_ix; @@ -229,10 +211,6 @@ typedef struct { struct au_init ets_alloc; struct au_init driver_alloc; struct au_init fix_alloc; -#if HALFWORD_HEAP - struct au_init std_low_alloc; - struct au_init ll_low_alloc; -#endif } erts_alc_hndl_args_init_t; #define ERTS_AU_INIT__ {0, 0, 1, GOODFIT, DEFAULT_ALLCTR_INIT, {1,1,1,1}} @@ -259,10 +237,6 @@ set_default_sl_alloc_opts(struct au_init *ip) #endif ip->init.util.ts = ERTS_ALC_MTA_SHORT_LIVED; ip->init.util.rsbcst = 80; -#if HALFWORD_HEAP - ip->init.util.force = 1; - ip->init.util.low_mem = 1; -#endif ip->init.util.acul = ERTS_ALC_DEFAULT_ACUL; } @@ -328,10 +302,6 @@ set_default_temp_alloc_opts(struct au_init *ip) ip->init.util.ts = ERTS_ALC_MTA_TEMPORARY; ip->init.util.rsbcst = 90; ip->init.util.rmbcmt = 100; -#if HALFWORD_HEAP - ip->init.util.force = 1; - ip->init.util.low_mem = 1; -#endif } static void @@ -350,10 +320,6 @@ set_default_eheap_alloc_opts(struct au_init *ip) #endif ip->init.util.ts = ERTS_ALC_MTA_EHEAP; ip->init.util.rsbcst = 50; -#if HALFWORD_HEAP - ip->init.util.force = 1; - ip->init.util.low_mem = 1; -#endif ip->init.util.acul = ERTS_ALC_DEFAULT_ACUL_EHEAP_ALLOC; } @@ -560,12 +526,10 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_PROC)] = sizeof(Process); -#if !HALFWORD_HEAP fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_MONITOR_SH)] = ERTS_MONITOR_SH_SIZE * sizeof(Uint); fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_NLINK_SH)] = ERTS_LINK_SH_SIZE * sizeof(Uint); -#endif fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_DRV_EV_D_STATE)] = sizeof(ErtsDrvEventDataState); fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_DRV_SEL_D_STATE)] @@ -745,24 +709,6 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) erts_allctrs[ERTS_ALC_A_SYSTEM].free = erts_sys_free; erts_allctrs_info[ERTS_ALC_A_SYSTEM].enabled = 1; -#if HALFWORD_HEAP - /* Init low memory variants by cloning */ - init.std_low_alloc = init.std_alloc; - init.std_low_alloc.init.util.name_prefix = "std_low_"; - init.std_low_alloc.init.util.alloc_no = ERTS_ALC_A_STANDARD_LOW; - init.std_low_alloc.init.util.force = 1; - init.std_low_alloc.init.util.low_mem = 1; - - init.ll_low_alloc = init.ll_alloc; - init.ll_low_alloc.init.util.name_prefix = "ll_low_"; - init.ll_low_alloc.init.util.alloc_no = ERTS_ALC_A_LONG_LIVED_LOW; - init.ll_low_alloc.init.util.force = 1; - init.ll_low_alloc.init.util.low_mem = 1; - - set_au_allocator(ERTS_ALC_A_STANDARD_LOW, &init.std_low_alloc, ncpu); - set_au_allocator(ERTS_ALC_A_LONG_LIVED_LOW, &init.ll_low_alloc, ncpu); -#endif /* HALFWORD */ - set_au_allocator(ERTS_ALC_A_TEMPORARY, &init.temp_alloc, ncpu); set_au_allocator(ERTS_ALC_A_SHORT_LIVED, &init.sl_alloc, ncpu); set_au_allocator(ERTS_ALC_A_STANDARD, &init.std_alloc, ncpu); @@ -805,14 +751,6 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) start_au_allocator(ERTS_ALC_A_LONG_LIVED, &init.ll_alloc, &ll_alloc_state); -#if HALFWORD_HEAP - start_au_allocator(ERTS_ALC_A_LONG_LIVED_LOW, - &init.ll_low_alloc, - &ll_low_alloc_state); - start_au_allocator(ERTS_ALC_A_STANDARD_LOW, - &init.std_low_alloc, - &std_low_alloc_state); -#endif start_au_allocator(ERTS_ALC_A_EHEAP, &init.eheap_alloc, &eheap_alloc_state); @@ -836,9 +774,7 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) erts_mtrace_install_wrapper_functions(); extra_block_size += erts_instr_init(init.instr.stat, init.instr.map); -#if !HALFWORD_HEAP init_aireq_alloc(); -#endif #ifdef DEBUG extra_block_size += install_debug_functions(); @@ -1238,9 +1174,6 @@ get_acul_value(struct au_init *auip, char *param_end, char** argv, int* ip) if (sys_strcmp(value, "de") == 0) { switch (auip->init.util.alloc_no) { case ERTS_ALC_A_LONG_LIVED: -#if HALFWORD_HEAP - case ERTS_ALC_A_LONG_LIVED_LOW: -#endif return ERTS_ALC_DEFAULT_ENABLED_ACUL_LL_ALLOC; case ERTS_ALC_A_EHEAP: return ERTS_ALC_DEFAULT_ENABLED_ACUL_EHEAP_ALLOC; @@ -1957,48 +1890,6 @@ alcu_size(ErtsAlcType_t ai, ErtsAlcUFixInfo_t *fi, int fisz) return res; } -#if HALFWORD_HEAP -static ERTS_INLINE int -alcu_is_low(ErtsAlcType_t ai) -{ - int is_low = 0; - ASSERT(erts_allctrs_info[ai].enabled); - ASSERT(erts_allctrs_info[ai].alloc_util); - - if (!erts_allctrs_info[ai].thr_spec) { - Allctr_t *allctr = erts_allctrs_info[ai].extra; - is_low = allctr->mseg_opt.low_mem; - } - else { - ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[ai]; - int i; -# ifdef DEBUG - int found_one = 0; -# endif - - ASSERT(tspec->enabled); - - for (i = tspec->size - 1; i >= 0; i--) { - Allctr_t *allctr = tspec->allctr[i]; - if (allctr) { -# ifdef DEBUG - if (!found_one) { - is_low = allctr->mseg_opt.low_mem; - found_one = 1; - } - else ASSERT(is_low == allctr->mseg_opt.low_mem); -# else - is_low = allctr->mseg_opt.low_mem; - break; -# endif - } - } - ASSERT(found_one); - } - return is_low; -} -#endif /* HALFWORD */ - static ERTS_INLINE void add_fix_values(UWord *ap, UWord *up, ErtsAlcUFixInfo_t *fi, ErtsAlcType_t type) { @@ -2028,9 +1919,6 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) int code; int ets; int maximum; -#if HALFWORD_HEAP - int low; -#endif } want = {0}; struct { UWord total; @@ -2043,9 +1931,6 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) UWord code; UWord ets; UWord maximum; -#if HALFWORD_HEAP - UWord low; -#endif } size = {0}; Eterm atoms[sizeof(size)/sizeof(UWord)]; UWord *uintps[sizeof(size)/sizeof(UWord)]; @@ -2104,11 +1989,6 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) atoms[length] = am_maximum; uintps[length++] = &size.maximum; } -#if HALFWORD_HEAP - want.low = 1; - atoms[length] = am_low; - uintps[length++] = &size.low; -#endif } else { DeclareTmpHeapNoproc(tmp_heap,2); @@ -2202,15 +2082,6 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) return am_badarg; } break; -#if HALFWORD_HEAP - case am_low: - if (!want.low) { - want.low = 1; - atoms[length] = am_low; - uintps[length++] = &size.low; - } - break; -#endif default: UnUseTmpHeapNoproc(2); return am_badarg; @@ -2288,11 +2159,6 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) if (save) *save = asz; size.total += asz; -#if HALFWORD_HEAP - if (alcu_is_low(ai)) { - size.low += asz; - } -#endif } } } @@ -2319,7 +2185,6 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) &size.processes_used, fi, ERTS_ALC_T_PROC); -#if !HALFWORD_HEAP add_fix_values(&size.processes, &size.processes_used, fi, @@ -2329,7 +2194,6 @@ erts_memory(int *print_to_p, void *print_to_arg, void *proc, Eterm earg) &size.processes_used, fi, ERTS_ALC_T_NLINK_SH); -#endif add_fix_values(&size.processes, &size.processes_used, fi, diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index b1d511ab78..4804fb407d 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -87,11 +87,6 @@ allocator EHEAP true eheap_alloc allocator ETS true ets_alloc allocator FIXED_SIZE true fix_alloc -+if halfword -allocator LONG_LIVED_LOW true ll_low_alloc -allocator STANDARD_LOW true std_low_alloc -+endif - +else # Non smp build allocator TEMPORARY false temp_alloc @@ -102,11 +97,6 @@ allocator EHEAP false eheap_alloc allocator ETS false ets_alloc allocator FIXED_SIZE false fix_alloc -+if halfword -allocator LONG_LIVED_LOW false ll_low_alloc -allocator STANDARD_LOW false std_low_alloc -+endif - +endif allocator BINARY true binary_alloc @@ -349,29 +339,6 @@ type SSB SHORT_LIVED PROCESSES ssb +endif - -+if halfword - -type DDLL_PROCESS STANDARD_LOW SYSTEM ddll_processes -type MONITOR_LH STANDARD_LOW PROCESSES monitor_lh -type NLINK_LH STANDARD_LOW PROCESSES nlink_lh -type CODE LONG_LIVED_LOW CODE code -type DB_HEIR_DATA STANDARD_LOW ETS db_heir_data -type DB_MS_PSDO_PROC LONG_LIVED_LOW ETS db_match_pseudo_proc -type SCHDLR_DATA LONG_LIVED_LOW SYSTEM scheduler_data -type LL_TEMP_TERM LONG_LIVED_LOW SYSTEM ll_temp_term - -type NIF_TRAP_EXPORT STANDARD_LOW CODE nif_trap_export_entry -type EXPORT LONG_LIVED_LOW CODE export_entry -type MONITOR_SH STANDARD_LOW PROCESSES monitor_sh -type NLINK_SH STANDARD_LOW PROCESSES nlink_sh -type AINFO_REQ STANDARD_LOW SYSTEM alloc_info_request -type SCHED_WTIME_REQ STANDARD_LOW SYSTEM sched_wall_time_request -type GC_INFO_REQ STANDARD_LOW SYSTEM gc_info_request -type PORT_DATA_HEAP STANDARD_LOW SYSTEM port_data_heap - -+else # "fullword" - type DDLL_PROCESS STANDARD SYSTEM ddll_processes type MONITOR_LH STANDARD PROCESSES monitor_lh type NLINK_LH STANDARD PROCESSES nlink_lh @@ -390,9 +357,6 @@ type SCHED_WTIME_REQ SHORT_LIVED SYSTEM sched_wall_time_request type GC_INFO_REQ SHORT_LIVED SYSTEM gc_info_request type PORT_DATA_HEAP STANDARD SYSTEM port_data_heap -+endif - - # # Types used by system specific code # @@ -430,21 +394,6 @@ type SYS_WRITE_BUF BINARY SYSTEM sys_write_buf +endif -+if ose - -type SYS_READ_BUF TEMPORARY SYSTEM sys_read_buf -type FD_TAB LONG_LIVED SYSTEM fd_tab -type FD_ENTRY_BUF STANDARD SYSTEM fd_entry_buf -type FD_SIG_LIST SHORT_LIVED SYSTEM fd_sig_list -type DRV_EV STANDARD SYSTEM driver_event -type CS_PROG_PATH LONG_LIVED SYSTEM cs_prog_path -type ENVIRONMENT TEMPORARY SYSTEM environment -type PUTENV_STR SYSTEM SYSTEM putenv_string -type PRT_REP_EXIT STANDARD SYSTEM port_report_exit - -+endif - - +if win32 type DRV_DATA_BUF SYSTEM SYSTEM drv_data_buf diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c index 236ee35d18..db4c30b9eb 100644 --- a/erts/emulator/beam/erl_alloc_util.c +++ b/erts/emulator/beam/erl_alloc_util.c @@ -2074,7 +2074,7 @@ mbc_alloc_block(Allctr_t *allctr, Uint size, Uint *blk_szp) if (!blk) { blk = create_carrier(allctr, get_blk_sz, CFLG_MBC); -#if !HALFWORD_HEAP && !ERTS_SUPER_ALIGNED_MSEG_ONLY +#if !ERTS_SUPER_ALIGNED_MSEG_ONLY if (!blk) { /* Emergency! We couldn't create the carrier as we wanted. Try to place it in a sys_alloced sbc. */ @@ -3511,8 +3511,7 @@ create_carrier(Allctr_t *allctr, Uint umem_sz, UWord flags) int is_mseg = 0; #endif - if (HALFWORD_HEAP - || (ERTS_SUPER_ALIGNED_MSEG_ONLY && (flags & CFLG_MBC)) + if ((ERTS_SUPER_ALIGNED_MSEG_ONLY && (flags & CFLG_MBC)) || !allow_sys_alloc_carriers) { flags |= CFLG_FORCE_MSEG; flags &= ~CFLG_FORCE_SYS_ALLOC; @@ -3749,11 +3748,6 @@ resize_carrier(Allctr_t *allctr, Block_t *old_blk, Uint umem_sz, UWord flags) DEBUG_SAVE_ALIGNMENT(new_crr); return new_blk; } -#if HALFWORD_HEAP - /* Old carrier unchanged; restore stat */ - STAT_MSEG_SBC_ALLOC(allctr, old_crr_sz, old_blk_sz); - return NULL; -#endif create_flags |= CFLG_FORCE_SYS_ALLOC; /* since mseg_realloc() failed */ } @@ -3942,9 +3936,6 @@ static struct { Eterm e; Eterm t; Eterm ramv; -#if HALFWORD_HEAP - Eterm low; -#endif Eterm sbct; #if HAVE_ERTS_MSEG Eterm asbcst; @@ -4035,9 +4026,6 @@ init_atoms(Allctr_t *allctr) AM_INIT(e); AM_INIT(t); AM_INIT(ramv); -#if HALFWORD_HEAP - AM_INIT(low); -#endif AM_INIT(sbct); #if HAVE_ERTS_MSEG AM_INIT(asbcst); @@ -4643,9 +4631,6 @@ info_options(Allctr_t *allctr, "option e: true\n" "option t: %s\n" "option ramv: %s\n" -#if HALFWORD_HEAP - "option low: %s\n" -#endif "option sbct: %beu\n" #if HAVE_ERTS_MSEG "option asbcst: %bpu\n" @@ -4664,9 +4649,6 @@ info_options(Allctr_t *allctr, "option acul: %d\n", topt, allctr->ramv ? "true" : "false", -#if HALFWORD_HEAP - allctr->mseg_opt.low_mem ? "true" : "false", -#endif allctr->sbc_threshold, #if HAVE_ERTS_MSEG allctr->mseg_opt.abs_shrink_th, @@ -4729,9 +4711,6 @@ info_options(Allctr_t *allctr, add_2tup(hpp, szp, &res, am.sbct, bld_uint(hpp, szp, allctr->sbc_threshold)); -#if HALFWORD_HEAP - add_2tup(hpp, szp, &res, am.low, allctr->mseg_opt.low_mem ? am_true : am_false); -#endif add_2tup(hpp, szp, &res, am.ramv, allctr->ramv ? am_true : am_false); add_2tup(hpp, szp, &res, am.t, (allctr->t ? am_true : am_false)); add_2tup(hpp, szp, &res, am.e, am_true); @@ -5416,11 +5395,7 @@ do_erts_alcu_realloc(ErtsAlcType_t type, Block_t *new_blk; if(IS_SBC_BLK(blk)) { do_carrier_resize: -#if HALFWORD_HEAP - new_blk = resize_carrier(allctr, blk, size, CFLG_SBC | CFLG_FORCE_MSEG); -#else new_blk = resize_carrier(allctr, blk, size, CFLG_SBC); -#endif res = new_blk ? BLK2UMEM(new_blk) : NULL; } else if (alcu_flgs & ERTS_ALCU_FLG_FAIL_REALLOC_MOVE) @@ -5714,11 +5689,8 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init) #ifdef ERTS_SMP if (init->tspec || init->tpref) allctr->mseg_opt.sched_spec = 1; -#endif -# if HALFWORD_HEAP - allctr->mseg_opt.low_mem = init->low_mem; -# endif -#endif +#endif /* ERTS_SMP */ +#endif /* HAVE_ERTS_MSEG */ allctr->name_prefix = init->name_prefix; if (!allctr->name_prefix) @@ -5875,7 +5847,7 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init) CFLG_MBC | CFLG_FORCE_SIZE | CFLG_NO_CPOOL -#if !HALFWORD_HEAP && !ERTS_SUPER_ALIGNED_MSEG_ONLY +#if !ERTS_SUPER_ALIGNED_MSEG_ONLY | CFLG_FORCE_SYS_ALLOC #endif | CFLG_MAIN_CARRIER); diff --git a/erts/emulator/beam/erl_alloc_util.h b/erts/emulator/beam/erl_alloc_util.h index df1f0aa65a..792f8c63ac 100644 --- a/erts/emulator/beam/erl_alloc_util.h +++ b/erts/emulator/beam/erl_alloc_util.h @@ -45,7 +45,6 @@ typedef struct { int tspec; int tpref; int ramv; - int low_mem; /* HALFWORD only */ UWord sbct; UWord asbcst; UWord rsbcst; @@ -90,7 +89,6 @@ typedef struct { 0, /* (bool) tspec: thread specific */\ 0, /* (bool) tpref: thread preferred */\ 0, /* (bool) ramv: realloc always moves */\ - 0, /* (bool) low_mem: HALFWORD only */\ 512*1024, /* (bytes) sbct: sbc threshold */\ 2*1024*2024, /* (amount) asbcst: abs sbc shrink threshold */\ 20, /* (%) rsbcst: rel sbc shrink threshold */\ @@ -125,7 +123,6 @@ typedef struct { 0, /* (bool) tspec: thread specific */\ 0, /* (bool) tpref: thread preferred */\ 0, /* (bool) ramv: realloc always moves */\ - 0, /* (bool) low_mem: HALFWORD only */\ 64*1024, /* (bytes) sbct: sbc threshold */\ 2*1024*2024, /* (amount) asbcst: abs sbc shrink threshold */\ 20, /* (%) rsbcst: rel sbc shrink threshold */\ diff --git a/erts/emulator/beam/erl_arith.c b/erts/emulator/beam/erl_arith.c index b8c5ef9b09..3671025d22 100644 --- a/erts/emulator/beam/erl_arith.c +++ b/erts/emulator/beam/erl_arith.c @@ -42,15 +42,8 @@ # define MAX(x, y) (((x) > (y)) ? (x) : (y)) #endif -#if !HEAP_ON_C_STACK -# define DECLARE_TMP(VariableName,N,P) \ - Eterm *VariableName = ((ERTS_PROC_GET_SCHDATA(P)->erl_arith_tmp_heap) + (2 * N)) -#else -# define DECLARE_TMP(VariableName,N,P) \ - Eterm VariableName[2] -#endif -# define ARG_IS_NOT_TMP(Arg,Tmp) ((Arg) != make_big((Tmp))) - +#define DECLARE_TMP(VariableName,N,P) Eterm VariableName[2] +#define ARG_IS_NOT_TMP(Arg,Tmp) ((Arg) != make_big((Tmp))) static Eterm shift(Process* p, Eterm arg1, Eterm arg2, int right); diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c index f071898046..be0bc0cfec 100644 --- a/erts/emulator/beam/erl_async.c +++ b/erts/emulator/beam/erl_async.c @@ -167,7 +167,6 @@ async_ready_q(Uint sched_id) #endif - void erts_init_async(void) { diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c index b1ebf0327e..b9640e211d 100644 --- a/erts/emulator/beam/erl_bif_binary.c +++ b/erts/emulator/beam/erl_bif_binary.c @@ -2786,7 +2786,6 @@ BIF_RETTYPE binary_referenced_byte_size_1(BIF_ALIST_1) } pb = (ProcBin *) binary_val(bin); if (pb->thing_word == HEADER_PROC_BIN) { - /* XXX:PaN - Halfword - orig_size is a long, we should handle that */ res = erts_make_integer((Uint) pb->val->orig_size, BIF_P); } else { /* heap binary */ res = erts_make_integer((Uint) ((ErlHeapBin *) pb)->size, BIF_P); @@ -2804,7 +2803,7 @@ BIF_RETTYPE binary_referenced_byte_size_1(BIF_ALIST_1) #endif static int get_need(Uint u) { -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) if (u > 0xFFFFFFFFUL) { if (u > 0xFFFFFFFFFFFFUL) { if (u > 0xFFFFFFFFFFFFFFUL) { diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index b44382cde8..9a132ee007 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -73,9 +73,6 @@ static char otp_version[] = ERLANG_OTP_VERSION; static char erts_system_version[] = ("Erlang/OTP " ERLANG_OTP_RELEASE "%s" " [erts-" ERLANG_VERSION "]" -#if !HEAP_ON_C_STACK && !HALFWORD_HEAP - " [no-c-stack-objects]" -#endif #ifndef OTP_RELEASE #ifdef ERLANG_GIT_VERSION " [source-" ERLANG_GIT_VERSION "]" @@ -84,12 +81,8 @@ static char erts_system_version[] = ("Erlang/OTP " ERLANG_OTP_RELEASE #endif #endif #ifdef ARCH_64 -#if HALFWORD_HEAP - " [64-bit halfword]" -#else " [64-bit]" #endif -#endif #ifdef ERTS_SMP " [smp:%beu:%beu]" #endif @@ -671,18 +664,12 @@ static Eterm pi_1_keys[] = { #define ERTS_PI_1_NO_OF_KEYS (sizeof(pi_1_keys)/sizeof(Eterm)) static Eterm pi_1_keys_list; -#if HEAP_ON_C_STACK static Eterm pi_1_keys_list_heap[2*ERTS_PI_1_NO_OF_KEYS]; -#endif static void process_info_init(void) { -#if HEAP_ON_C_STACK Eterm *hp = &pi_1_keys_list_heap[0]; -#else - Eterm *hp = erts_alloc(ERTS_ALC_T_LL_TEMP_TERM,sizeof(Eterm)*2*ERTS_PI_1_NO_OF_KEYS); -#endif int i; pi_1_keys_list = NIL; diff --git a/erts/emulator/beam/erl_bif_op.c b/erts/emulator/beam/erl_bif_op.c index c9192fc420..d53a9e11ca 100644 --- a/erts/emulator/beam/erl_bif_op.c +++ b/erts/emulator/beam/erl_bif_op.c @@ -258,7 +258,7 @@ Eterm erl_is_function(Process* p, Eterm arg1, Eterm arg2) BIF_RET(am_true); } } else if (is_export(arg1)) { - Export* exp = (Export *) EXPAND_POINTER((export_val(arg1))[1]); + Export* exp = (Export *) (export_val(arg1)[1]); if (exp->code[2] == (Uint) arity) { BIF_RET(am_true); diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c index 3ff54c7a60..e47d7bcbbb 100644 --- a/erts/emulator/beam/erl_bif_port.c +++ b/erts/emulator/beam/erl_bif_port.c @@ -1329,7 +1329,8 @@ BIF_RETTYPE decode_packet_3(BIF_ALIST_3) ErlSubBin* rest; Eterm res; Eterm options; - int code; + int code; + char delimiter = '\n'; if (!is_binary(BIF_ARG_2) || (!is_list(BIF_ARG_3) && !is_nil(BIF_ARG_3))) { @@ -1370,6 +1371,11 @@ BIF_RETTYPE decode_packet_3(BIF_ALIST_3) case am_line_length: trunc_len = val; goto next_option; + case am_line_delimiter: + if (type == TCP_PB_LINE_LF && val >= 0 && val <= 255) { + delimiter = (char)val; + goto next_option; + } } } } @@ -1390,7 +1396,7 @@ BIF_RETTYPE decode_packet_3(BIF_ALIST_3) pca.aligned_ptr = bin_ptr; } packet_sz = packet_get_length(type, (char*)pca.aligned_ptr, pca.bin_sz, - max_plen, trunc_len, &http_state); + max_plen, trunc_len, delimiter, &http_state); if (!(packet_sz > 0 && packet_sz <= pca.bin_sz)) { if (packet_sz < 0) { goto error; diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c index 86951f32b0..7f7cd376ac 100644 --- a/erts/emulator/beam/erl_bif_re.c +++ b/erts/emulator/beam/erl_bif_re.c @@ -100,7 +100,7 @@ Sint erts_re_set_loop_limit(Sint limit) static int term_to_int(Eterm term, int *sp) { -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) if (is_small(term)) { Uint x = signed_val(term); @@ -151,7 +151,7 @@ static int term_to_int(Eterm term, int *sp) static Eterm make_signed_integer(int x, Process *p) { -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) return make_small(x); #else Eterm* hp; diff --git a/erts/emulator/beam/erl_bif_unique.c b/erts/emulator/beam/erl_bif_unique.c index 5eca09c5a6..c4a39b8897 100644 --- a/erts/emulator/beam/erl_bif_unique.c +++ b/erts/emulator/beam/erl_bif_unique.c @@ -338,7 +338,7 @@ static struct { } w; } raw_unique_monotonic_integer erts_align_attribute(ERTS_CACHE_LINE_SIZE); -#if defined(ARCH_32) || HALFWORD_HEAP +#if defined(ARCH_32) # define ERTS_UNIQUE_MONOTONIC_OFFSET ERTS_SINT64_MIN #else # define ERTS_UNIQUE_MONOTONIC_OFFSET MIN_SMALL @@ -368,7 +368,7 @@ get_unique_monotonic_integer_heap_size(Uint64 raw, int positive) Sint64 value = ((Sint64) raw) + ERTS_UNIQUE_MONOTONIC_OFFSET; if (IS_SSMALL(value)) return 0; -#if defined(ARCH_32) || HALFWORD_HEAP +#if defined(ARCH_32) return ERTS_SINT64_HEAP_SIZE(value); #else return ERTS_UINT64_HEAP_SIZE((Uint64) value); @@ -393,7 +393,7 @@ make_unique_monotonic_integer_value(Eterm *hp, Uint hsz, Uint64 raw, int positiv if (hsz == 0) res = make_small(value); else { -#if defined(ARCH_32) || HALFWORD_HEAP +#if defined(ARCH_32) res = erts_sint64_to_big(value, &hp); #else res = erts_uint64_to_big((Uint64) value, &hp); diff --git a/erts/emulator/beam/erl_binary.h b/erts/emulator/beam/erl_binary.h index ea01bf08f0..e181b5555d 100644 --- a/erts/emulator/beam/erl_binary.h +++ b/erts/emulator/beam/erl_binary.h @@ -72,7 +72,6 @@ typedef struct erl_heap_bin { */ #define binary_size(Bin) (binary_val(Bin)[1]) -#define binary_size_rel(Bin,BasePtr) (binary_val_rel(Bin,BasePtr)[1]) #define binary_bitsize(Bin) \ ((*binary_val(Bin) == HEADER_SUB_BIN) ? \ @@ -95,12 +94,9 @@ typedef struct erl_heap_bin { * Bitsize: output variable (Uint) */ -#define ERTS_GET_BINARY_BYTES(Bin,Bytep,Bitoffs,Bitsize) \ - ERTS_GET_BINARY_BYTES_REL(Bin,Bytep,Bitoffs,Bitsize,NULL) - -#define ERTS_GET_BINARY_BYTES_REL(Bin,Bytep,Bitoffs,Bitsize,BasePtr) \ +#define ERTS_GET_BINARY_BYTES(Bin,Bytep,Bitoffs,Bitsize) \ do { \ - Eterm* _real_bin = binary_val_rel(Bin,BasePtr); \ + Eterm* _real_bin = binary_val(Bin); \ Uint _offs = 0; \ Bitoffs = Bitsize = 0; \ if (*_real_bin == HEADER_SUB_BIN) { \ @@ -108,7 +104,7 @@ do { \ _offs = _sb->offs; \ Bitoffs = _sb->bitoffs; \ Bitsize = _sb->bitsize; \ - _real_bin = binary_val_rel(_sb->orig,BasePtr); \ + _real_bin = binary_val(_sb->orig); \ } \ if (*_real_bin == HEADER_PROC_BIN) { \ Bytep = ((ProcBin *) _real_bin)->bytes + _offs; \ @@ -131,11 +127,8 @@ do { \ */ #define ERTS_GET_REAL_BIN(Bin, RealBin, ByteOffset, BitOffset, BitSize) \ - ERTS_GET_REAL_BIN_REL(Bin, RealBin, ByteOffset, BitOffset, BitSize, NULL) - -#define ERTS_GET_REAL_BIN_REL(Bin, RealBin, ByteOffset, BitOffset, BitSize, BasePtr) \ do { \ - ErlSubBin* _sb = (ErlSubBin *) binary_val_rel(Bin,BasePtr); \ + ErlSubBin* _sb = (ErlSubBin *) binary_val(Bin); \ if (_sb->thing_word == HEADER_SUB_BIN) { \ RealBin = _sb->orig; \ ByteOffset = _sb->offs; \ diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c index 01734c55d7..11d83686a3 100644 --- a/erts/emulator/beam/erl_bits.c +++ b/erts/emulator/beam/erl_bits.c @@ -282,7 +282,7 @@ erts_bs_get_integer_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuff * Simply shift whole bytes into the result. */ switch (BYTE_OFFSET(n)) { -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) case 7: w = (w << 8) | *bp++; case 6: w = (w << 8) | *bp++; case 5: w = (w << 8) | *bp++; @@ -387,7 +387,7 @@ erts_bs_get_integer_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuff case 3: v32 = LSB[0] + (LSB[1]<<8) + (LSB[2]<<16); goto big_small; -#if !defined(ARCH_64) || HALFWORD_HEAP +#if !defined(ARCH_64) case 4: v32 = (LSB[0] + (LSB[1]<<8) + (LSB[2]<<16) + (LSB[3]<<24)); if (!IS_USMALL(sgn, v32)) { diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 878ee32b47..9ec14ab5ae 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -1774,15 +1774,9 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1) * (it looks like an continuation pointer), but that is will crash the * emulator if this BIF is call traced. */ -#if HALFWORD_HEAP - Eterm *hp = HAlloc(BIF_P, 3); - hp[0] = make_pos_bignum_header(2); - *((UWord *) (UWord) (hp+1)) = (UWord) tb; -#else Eterm *hp = HAlloc(BIF_P, 2); hp[0] = make_pos_bignum_header(1); hp[1] = (Eterm) tb; -#endif BIF_TRAP1(&ets_delete_continue_exp, BIF_P, make_big(hp)); } else { @@ -2840,7 +2834,7 @@ BIF_RETTYPE ets_match_spec_run_r_3(BIF_ALIST_3) BIF_TRAP3(bif_export[BIF_ets_match_spec_run_r_3], BIF_P,lst,BIF_ARG_2,ret); } - res = db_prog_match(BIF_P, mp, CAR(list_val(lst)), NULL, NULL, 0, + res = db_prog_match(BIF_P, mp, CAR(list_val(lst)), NULL, 0, ERTS_PAM_COPY_RESULT, &dummy); if (is_value(res)) { hp = HAlloc(BIF_P, 2); @@ -3652,11 +3646,8 @@ static BIF_RETTYPE ets_delete_trap(BIF_ALIST_1) Eterm* ptr = big_val(cont); DbTable *tb = *((DbTable **) (UWord) (ptr + 1)); -#if HALFWORD_HEAP - ASSERT(*ptr == make_pos_bignum_header(2)); -#else ASSERT(*ptr == make_pos_bignum_header(1)); -#endif + db_lock(tb, LCK_WRITE); trap = free_table_cont(p, tb, 0, 1); db_unlock(tb, LCK_WRITE); diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c index 98a2e2842a..cff65f244d 100644 --- a/erts/emulator/beam/erl_db_hash.c +++ b/erts/emulator/beam/erl_db_hash.c @@ -469,9 +469,6 @@ static ERTS_INLINE void try_shrink(DbTableHash* tb) } } -#define EQ_REL(x,y,y_base) \ - (is_same(x,NULL,y,y_base) || (is_not_both_immed((x),(y)) && eq_rel((x),NULL,(y),y_base))) - /* Is this a live object (not pseodo-deleted) with the specified key? */ static ERTS_INLINE int has_live_key(DbTableHash* tb, HashDbTerm* b, @@ -481,7 +478,7 @@ static ERTS_INLINE int has_live_key(DbTableHash* tb, HashDbTerm* b, else { Eterm itemKey = GETKEY(tb, b->dbterm.tpl); ASSERT(!is_header(itemKey)); - return EQ_REL(key, itemKey, b->dbterm.tpl); + return EQ(key, itemKey); } } @@ -494,7 +491,7 @@ static ERTS_INLINE int has_key(DbTableHash* tb, HashDbTerm* b, else { Eterm itemKey = GETKEY(tb, b->dbterm.tpl); ASSERT(!is_header(itemKey)); - return EQ_REL(key, itemKey, b->dbterm.tpl); + return EQ(key, itemKey); } } @@ -2204,11 +2201,11 @@ static void db_print_hash(int to, void *to_arg, int show, DbTable *tbl) erts_print(to, to_arg, "*"); if (tb->common.compress) { Eterm key = GETKEY(tb, list->dbterm.tpl); - erts_print(to, to_arg, "key=%R", key, list->dbterm.tpl); + erts_print(to, to_arg, "key=%T", key); } else { - Eterm obj = make_tuple_rel(list->dbterm.tpl,list->dbterm.tpl); - erts_print(to, to_arg, "%R", obj, list->dbterm.tpl); + Eterm obj = make_tuple(list->dbterm.tpl); + erts_print(to, to_arg, "%T", obj); } if (list->next != 0) erts_print(to, to_arg, ","); @@ -2899,9 +2896,6 @@ Ldone: handle->dbterm = &b->dbterm; handle->flags = flags; handle->new_size = b->dbterm.size; -#if HALFWORD_HEAP - handle->abs_vec = NULL; -#endif handle->lck = lck; return 1; } diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c index 465aa566ad..311b69d114 100644 --- a/erts/emulator/beam/erl_db_tree.c +++ b/erts/emulator/beam/erl_db_tree.c @@ -280,7 +280,7 @@ struct select_delete_context { /* ** Forward declarations */ -static TreeDbTerm *linkout_tree(DbTableTree *tb, Eterm key, Eterm* key_base); +static TreeDbTerm *linkout_tree(DbTableTree *tb, Eterm key); static TreeDbTerm *linkout_object_tree(DbTableTree *tb, Eterm object); static int do_free_tree_cont(DbTableTree *tb, int num_left); @@ -291,15 +291,15 @@ static int delsub(TreeDbTerm **this); static TreeDbTerm *slot_search(Process *p, DbTableTree *tb, Sint slot); static TreeDbTerm *find_node(DbTableTree *tb, Eterm key); static TreeDbTerm **find_node2(DbTableTree *tb, Eterm key); -static TreeDbTerm *find_next(DbTableTree *tb, DbTreeStack*, Eterm key, Eterm* kbase); -static TreeDbTerm *find_prev(DbTableTree *tb, DbTreeStack*, Eterm key, Eterm* kbase); +static TreeDbTerm *find_next(DbTableTree *tb, DbTreeStack*, Eterm key); +static TreeDbTerm *find_prev(DbTableTree *tb, DbTreeStack*, Eterm key); static TreeDbTerm *find_next_from_pb_key(DbTableTree *tb, DbTreeStack*, Eterm key); static TreeDbTerm *find_prev_from_pb_key(DbTableTree *tb, DbTreeStack*, Eterm key); static void traverse_backwards(DbTableTree *tb, DbTreeStack*, - Eterm lastkey, Eterm* lk_base, + Eterm lastkey, int (*doit)(DbTableTree *tb, TreeDbTerm *, void *, @@ -307,7 +307,7 @@ static void traverse_backwards(DbTableTree *tb, void *context); static void traverse_forward(DbTableTree *tb, DbTreeStack*, - Eterm lastkey, Eterm* lk_base, + Eterm lastkey, int (*doit)(DbTableTree *tb, TreeDbTerm *, void *, @@ -315,8 +315,8 @@ static void traverse_forward(DbTableTree *tb, void *context); static int key_given(DbTableTree *tb, Eterm pattern, TreeDbTerm **ret, Eterm *partly_bound_key); -static Sint cmp_partly_bound(Eterm partly_bound_key, Eterm bound_key, Eterm* bk_base); -static Sint do_cmp_partly_bound(Eterm a, Eterm b, Eterm* b_base, int *done); +static Sint cmp_partly_bound(Eterm partly_bound_key, Eterm bound_key); +static Sint do_cmp_partly_bound(Eterm a, Eterm b, int *done); static int analyze_pattern(DbTableTree *tb, Eterm pattern, struct mp_info *mpi); @@ -517,7 +517,7 @@ static int db_next_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret) if (is_atom(key) && key == am_EOT) return DB_ERROR_BADKEY; stack = get_any_stack(tb); - this = find_next(tb, stack, key, NULL); + this = find_next(tb, stack, key); release_stack(tb,stack); if (this == NULL) { *ret = am_EOT; @@ -563,7 +563,7 @@ static int db_prev_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret) if (is_atom(key) && key == am_EOT) return DB_ERROR_BADKEY; stack = get_any_stack(tb); - this = find_prev(tb, stack, key, NULL); + this = find_prev(tb, stack, key); release_stack(tb,stack); if (this == NULL) { *ret = am_EOT; @@ -573,19 +573,13 @@ static int db_prev_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret) return DB_ERROR_NONE; } -static ERTS_INLINE Sint cmp_key(DbTableTree* tb, Eterm key, Eterm* key_base, - TreeDbTerm* obj) -{ - return cmp_rel(key, key_base, - GETKEY(tb,obj->dbterm.tpl), obj->dbterm.tpl); +static ERTS_INLINE Sint cmp_key(DbTableTree* tb, Eterm key, TreeDbTerm* obj) { + return CMP(key, GETKEY(tb,obj->dbterm.tpl)); } -static ERTS_INLINE int cmp_key_eq(DbTableTree* tb, Eterm key, Eterm* key_base, - TreeDbTerm* obj) -{ +static ERTS_INLINE int cmp_key_eq(DbTableTree* tb, Eterm key, TreeDbTerm* obj) { Eterm obj_key = GETKEY(tb,obj->dbterm.tpl); - return is_same(key, key_base, obj_key, obj->dbterm.tpl) - || cmp_rel(key, key_base, obj_key, obj->dbterm.tpl) == 0; + return is_same(key, obj_key) || CMP(key, obj_key) == 0; } static int db_put_tree(DbTable *tbl, Eterm obj, int key_clash_fail) @@ -619,7 +613,7 @@ static int db_put_tree(DbTable *tbl, Eterm obj, int key_clash_fail) (*this)->balance = 0; (*this)->left = (*this)->right = NULL; break; - } else if ((c = cmp_key(tb, key, NULL, *this)) < 0) { + } else if ((c = cmp_key(tb, key, *this)) < 0) { /* go lefts */ dstack[dpos++] = DIR_LEFT; tstack[tpos++] = this; @@ -774,7 +768,7 @@ static int db_erase_tree(DbTable *tbl, Eterm key, Eterm *ret) *ret = am_true; - if ((res = linkout_tree(tb, key, NULL)) != NULL) { + if ((res = linkout_tree(tb, key)) != NULL) { free_term(tb, res); } return DB_ERROR_NONE; @@ -970,15 +964,15 @@ static int db_select_continue_tree(Process *p, stack = get_any_stack(tb); if (chunk_size) { if (reverse) { - traverse_backwards(tb, stack, lastkey, NULL, &doit_select_chunk, &sc); + traverse_backwards(tb, stack, lastkey, &doit_select_chunk, &sc); } else { - traverse_forward(tb, stack, lastkey, NULL, &doit_select_chunk, &sc); + traverse_forward(tb, stack, lastkey, &doit_select_chunk, &sc); } } else { if (reverse) { - traverse_forward(tb, stack, lastkey, NULL, &doit_select, &sc); + traverse_forward(tb, stack, lastkey, &doit_select, &sc); } else { - traverse_backwards(tb, stack, lastkey, NULL, &doit_select, &sc); + traverse_backwards(tb, stack, lastkey, &doit_select, &sc); } } release_stack(tb,stack); @@ -1003,9 +997,9 @@ static int db_select_continue_tree(Process *p, } key = GETKEY(tb, sc.lastobj); - sz = size_object_rel(key,sc.lastobj); + sz = size_object(key); hp = HAlloc(p, 9 + sz); - key = copy_struct_rel(key, sz, &hp, &MSO(p), sc.lastobj, NULL); + key = copy_struct(key, sz, &hp, &MSO(p)); continuation = TUPLE8 (hp, tptr[1], @@ -1026,8 +1020,8 @@ static int db_select_continue_tree(Process *p, key = GETKEY(tb, sc.lastobj); if (chunk_size) { if (end_condition != NIL && - ((!reverse && cmp_partly_bound(end_condition,key,sc.lastobj) < 0) || - (reverse && cmp_partly_bound(end_condition,key,sc.lastobj) > 0))) { + ((!reverse && cmp_partly_bound(end_condition,key) < 0) || + (reverse && cmp_partly_bound(end_condition,key) > 0))) { /* done anyway */ if (!sc.got) { RET_TO_BIF(am_EOT, DB_ERROR_NONE); @@ -1039,16 +1033,16 @@ static int db_select_continue_tree(Process *p, } } else { if (end_condition != NIL && - ((!reverse && cmp_partly_bound(end_condition,key,sc.lastobj) > 0) || - (reverse && cmp_partly_bound(end_condition,key,sc.lastobj) < 0))) { + ((!reverse && cmp_partly_bound(end_condition,key) > 0) || + (reverse && cmp_partly_bound(end_condition,key) < 0))) { /* done anyway */ RET_TO_BIF(sc.accum,DB_ERROR_NONE); } } /* Not done yet, let's trap. */ - sz = size_object_rel(key,sc.lastobj); + sz = size_object(key); hp = HAlloc(p, 9 + sz); - key = copy_struct_rel(key, sz, &hp, &MSO(p), sc.lastobj, NULL); + key = copy_struct(key, sz, &hp, &MSO(p)); continuation = TUPLE8 (hp, tptr[1], @@ -1075,7 +1069,6 @@ static int db_select_tree(Process *p, DbTable *tbl, struct select_context sc; struct mp_info mpi; Eterm lastkey = THE_NON_VALUE; - Eterm* lk_base = NULL; Eterm key; Eterm continuation; unsigned sz; @@ -1127,20 +1120,18 @@ static int db_select_tree(Process *p, DbTable *tbl, if (mpi.some_limitation) { if ((this = find_prev_from_pb_key(tb, stack, mpi.least)) != NULL) { lastkey = GETKEY(tb, this->dbterm.tpl); - lk_base = this->dbterm.tpl; } sc.end_condition = mpi.most; } - traverse_forward(tb, stack, lastkey, lk_base, &doit_select, &sc); + traverse_forward(tb, stack, lastkey, &doit_select, &sc); } else { if (mpi.some_limitation) { if ((this = find_next_from_pb_key(tb, stack, mpi.most)) != NULL) { lastkey = GETKEY(tb, this->dbterm.tpl); - lk_base = this->dbterm.tpl; } sc.end_condition = mpi.least; } - traverse_backwards(tb, stack, lastkey, lk_base, &doit_select, &sc); + traverse_backwards(tb, stack, lastkey, &doit_select, &sc); } release_stack(tb,stack); #ifdef HARDDEBUG @@ -1153,9 +1144,9 @@ static int db_select_tree(Process *p, DbTable *tbl, } key = GETKEY(tb, sc.lastobj); - sz = size_object_rel(key, sc.lastobj); + sz = size_object(key); hp = HAlloc(p, 9 + sz + PROC_BIN_SIZE); - key = copy_struct_rel(key, sz, &hp, &MSO(p), sc.lastobj, NULL); + key = copy_struct(key, sz, &hp, &MSO(p)); if (mpi.all_objects) (mpi.mp)->flags |= BIN_FLAG_ALL_OBJECTS; mpb=db_make_mp_binary(p,mpi.mp,&hp); @@ -1236,7 +1227,7 @@ static int db_select_count_continue_tree(Process *p, } stack = get_any_stack(tb); - traverse_backwards(tb, stack, lastkey, NULL, &doit_select_count, &sc); + traverse_backwards(tb, stack, lastkey, &doit_select_count, &sc); release_stack(tb,stack); BUMP_REDS(p, 1000 - sc.max); @@ -1246,12 +1237,12 @@ static int db_select_count_continue_tree(Process *p, } key = GETKEY(tb, sc.lastobj); if (end_condition != NIL && - (cmp_partly_bound(end_condition,key,sc.lastobj) > 0)) { + (cmp_partly_bound(end_condition,key) > 0)) { /* done anyway */ RET_TO_BIF(make_small(sc.got),DB_ERROR_NONE); } /* Not done yet, let's trap. */ - sz = size_object_rel(key, sc.lastobj); + sz = size_object(key); if (IS_USMALL(0, sc.got)) { hp = HAlloc(p, sz + 6); egot = make_small(sc.got); @@ -1261,7 +1252,7 @@ static int db_select_count_continue_tree(Process *p, egot = uint_to_big(sc.got, hp); hp += BIG_UINT_HEAP_SIZE; } - key = copy_struct_rel(key, sz, &hp, &MSO(p), sc.lastobj, NULL); + key = copy_struct(key, sz, &hp, &MSO(p)); continuation = TUPLE5 (hp, tptr[1], @@ -1284,7 +1275,6 @@ static int db_select_count_tree(Process *p, DbTable *tbl, struct select_count_context sc; struct mp_info mpi; Eterm lastkey = THE_NON_VALUE; - Eterm* lk_base = NULL; Eterm key; Eterm continuation; unsigned sz; @@ -1334,12 +1324,11 @@ static int db_select_count_tree(Process *p, DbTable *tbl, if (mpi.some_limitation) { if ((this = find_next_from_pb_key(tb, stack, mpi.most)) != NULL) { lastkey = GETKEY(tb, this->dbterm.tpl); - lk_base = this->dbterm.tpl; } sc.end_condition = mpi.least; } - traverse_backwards(tb, stack, lastkey, lk_base, &doit_select_count, &sc); + traverse_backwards(tb, stack, lastkey, &doit_select_count, &sc); release_stack(tb,stack); BUMP_REDS(p, 1000 - sc.max); if (sc.max > 0) { @@ -1347,7 +1336,7 @@ static int db_select_count_tree(Process *p, DbTable *tbl, } key = GETKEY(tb, sc.lastobj); - sz = size_object_rel(key, sc.lastobj); + sz = size_object(key); if (IS_USMALL(0, sc.got)) { hp = HAlloc(p, sz + PROC_BIN_SIZE + 6); egot = make_small(sc.got); @@ -1357,7 +1346,7 @@ static int db_select_count_tree(Process *p, DbTable *tbl, egot = uint_to_big(sc.got, hp); hp += BIG_UINT_HEAP_SIZE; } - key = copy_struct_rel(key, sz, &hp, &MSO(p), sc.lastobj, NULL); + key = copy_struct(key, sz, &hp, &MSO(p)); if (mpi.all_objects) (mpi.mp)->flags |= BIN_FLAG_ALL_OBJECTS; mpb = db_make_mp_binary(p,mpi.mp,&hp); @@ -1388,7 +1377,6 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl, struct select_context sc; struct mp_info mpi; Eterm lastkey = THE_NON_VALUE; - Eterm* lk_base = NULL; Eterm key; Eterm continuation; unsigned sz; @@ -1445,20 +1433,18 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl, if (mpi.some_limitation) { if ((this = find_next_from_pb_key(tb, stack, mpi.most)) != NULL) { lastkey = GETKEY(tb, this->dbterm.tpl); - lk_base = this->dbterm.tpl; } sc.end_condition = mpi.least; } - traverse_backwards(tb, stack, lastkey, lk_base, &doit_select_chunk, &sc); + traverse_backwards(tb, stack, lastkey, &doit_select_chunk, &sc); } else { if (mpi.some_limitation) { if ((this = find_prev_from_pb_key(tb, stack, mpi.least)) != NULL) { lastkey = GETKEY(tb, this->dbterm.tpl); - lk_base = this->dbterm.tpl; } sc.end_condition = mpi.most; } - traverse_forward(tb, stack, lastkey, lk_base, &doit_select_chunk, &sc); + traverse_forward(tb, stack, lastkey, &doit_select_chunk, &sc); } release_stack(tb,stack); @@ -1483,9 +1469,9 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl, } key = GETKEY(tb, sc.lastobj); - sz = size_object_rel(key, sc.lastobj); + sz = size_object(key); hp = HAlloc(p, 9 + sz + PROC_BIN_SIZE); - key = copy_struct_rel(key, sz, &hp, &MSO(p), sc.lastobj, NULL); + key = copy_struct(key, sz, &hp, &MSO(p)); if (mpi.all_objects) (mpi.mp)->flags |= BIN_FLAG_ALL_OBJECTS; mpb = db_make_mp_binary(p,mpi.mp,&hp); @@ -1508,9 +1494,9 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl, } key = GETKEY(tb, sc.lastobj); - sz = size_object_rel(key, sc.lastobj); + sz = size_object(key); hp = HAlloc(p, 9 + sz + PROC_BIN_SIZE); - key = copy_struct_rel(key, sz, &hp, &MSO(p), sc.lastobj, NULL); + key = copy_struct(key, sz, &hp, &MSO(p)); if (mpi.all_objects) (mpi.mp)->flags |= BIN_FLAG_ALL_OBJECTS; @@ -1586,7 +1572,7 @@ static int db_select_delete_continue_tree(Process *p, sc.keypos = tb->common.keypos; ASSERT(!erts_smp_atomic_read_nob(&tb->is_stack_busy)); - traverse_backwards(tb, &tb->static_stack, lastkey, NULL, &doit_select_delete, &sc); + traverse_backwards(tb, &tb->static_stack, lastkey, &doit_select_delete, &sc); BUMP_REDS(p, 1000 - sc.max); @@ -1595,11 +1581,11 @@ static int db_select_delete_continue_tree(Process *p, } key = GETKEY(tb, (sc.lastterm)->dbterm.tpl); if (end_condition != NIL && - cmp_partly_bound(end_condition,key,sc.lastterm->dbterm.tpl) > 0) { /* done anyway */ + cmp_partly_bound(end_condition,key) > 0) { /* done anyway */ RET_TO_BIF(erts_make_integer(sc.accum,p),DB_ERROR_NONE); } /* Not done yet, let's trap. */ - sz = size_object_rel(key, sc.lastterm->dbterm.tpl); + sz = size_object(key); if (IS_USMALL(0, sc.accum)) { hp = HAlloc(p, sz + 6); eaccsum = make_small(sc.accum); @@ -1609,7 +1595,7 @@ static int db_select_delete_continue_tree(Process *p, eaccsum = uint_to_big(sc.accum, hp); hp += BIG_UINT_HEAP_SIZE; } - key = copy_struct_rel(key, sz, &hp, &MSO(p), sc.lastterm->dbterm.tpl, NULL); + key = copy_struct(key, sz, &hp, &MSO(p)); continuation = TUPLE5 (hp, tptr[1], @@ -1630,7 +1616,6 @@ static int db_select_delete_tree(Process *p, DbTable *tbl, struct select_delete_context sc; struct mp_info mpi; Eterm lastkey = THE_NON_VALUE; - Eterm* lk_base = NULL; Eterm key; Eterm continuation; unsigned sz; @@ -1683,12 +1668,11 @@ static int db_select_delete_tree(Process *p, DbTable *tbl, if (mpi.some_limitation) { if ((this = find_next_from_pb_key(tb, &tb->static_stack, mpi.most)) != NULL) { lastkey = GETKEY(tb, this->dbterm.tpl); - lk_base = this->dbterm.tpl; } sc.end_condition = mpi.least; } - traverse_backwards(tb, &tb->static_stack, lastkey, lk_base, &doit_select_delete, &sc); + traverse_backwards(tb, &tb->static_stack, lastkey, &doit_select_delete, &sc); BUMP_REDS(p, 1000 - sc.max); if (sc.max > 0) { @@ -1696,7 +1680,7 @@ static int db_select_delete_tree(Process *p, DbTable *tbl, } key = GETKEY(tb, (sc.lastterm)->dbterm.tpl); - sz = size_object_rel(key, sc.lastterm->dbterm.tpl); + sz = size_object(key); if (IS_USMALL(0, sc.accum)) { hp = HAlloc(p, sz + PROC_BIN_SIZE + 6); eaccsum = make_small(sc.accum); @@ -1706,7 +1690,7 @@ static int db_select_delete_tree(Process *p, DbTable *tbl, eaccsum = uint_to_big(sc.accum, hp); hp += BIG_UINT_HEAP_SIZE; } - key = copy_struct_rel(key, sz, &hp, &MSO(p), sc.lastterm->dbterm.tpl, NULL); + key = copy_struct(key, sz, &hp, &MSO(p)); mpb = db_make_mp_binary(p,mpi.mp,&hp); continuation = TUPLE5 @@ -1734,7 +1718,7 @@ static int db_take_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret) TreeDbTerm *this; *ret = NIL; - this = linkout_tree(tb, key, NULL); + this = linkout_tree(tb, key); if (this) { Eterm copy, *hp, *hend; @@ -1845,9 +1829,7 @@ do_db_tree_foreach_offheap(TreeDbTerm *tdbt, do_db_tree_foreach_offheap(tdbt->right, func, arg); } -static TreeDbTerm *linkout_tree(DbTableTree *tb, - Eterm key, Eterm* key_base) -{ +static TreeDbTerm *linkout_tree(DbTableTree *tb, Eterm key) { TreeDbTerm **tstack[STACK_NEED]; int tpos = 0; int dstack[STACK_NEED+1]; @@ -1869,7 +1851,7 @@ static TreeDbTerm *linkout_tree(DbTableTree *tb, for (;;) { if (!*this) { /* Failure */ return NULL; - } else if ((c = cmp_key(tb, key, key_base, *this)) < 0) { + } else if ((c = cmp_key(tb, key, *this)) < 0) { dstack[dpos++] = DIR_LEFT; tstack[tpos++] = this; this = &((*this)->left); @@ -1933,7 +1915,7 @@ static TreeDbTerm *linkout_object_tree(DbTableTree *tb, for (;;) { if (!*this) { /* Failure */ return NULL; - } else if ((c = cmp_key(tb,key,NULL,*this)) < 0) { + } else if ((c = cmp_key(tb,key,*this)) < 0) { dstack[dpos++] = DIR_LEFT; tstack[tpos++] = this; this = &((*this)->left); @@ -2319,15 +2301,13 @@ done: * Find next and previous in sort order */ -static TreeDbTerm *find_next(DbTableTree *tb, DbTreeStack* stack, - Eterm key, Eterm* key_base) -{ +static TreeDbTerm *find_next(DbTableTree *tb, DbTreeStack* stack, Eterm key) { TreeDbTerm *this; TreeDbTerm *tmp; Sint c; if(( this = TOP_NODE(stack)) != NULL) { - if (!cmp_key_eq(tb,key,key_base,this)) { + if (!cmp_key_eq(tb,key,this)) { /* Start from the beginning */ stack->pos = stack->slot = 0; } @@ -2337,7 +2317,7 @@ static TreeDbTerm *find_next(DbTableTree *tb, DbTreeStack* stack, return NULL; for (;;) { PUSH_NODE(stack, this); - if (( c = cmp_key(tb,key,key_base,this) ) > 0) { + if (( c = cmp_key(tb,key,this) ) > 0) { if (this->right == NULL) /* We are at the previos and the element does not exist */ @@ -2377,15 +2357,13 @@ static TreeDbTerm *find_next(DbTableTree *tb, DbTreeStack* stack, return this; } -static TreeDbTerm *find_prev(DbTableTree *tb, DbTreeStack* stack, - Eterm key, Eterm* key_base) -{ +static TreeDbTerm *find_prev(DbTableTree *tb, DbTreeStack* stack, Eterm key) { TreeDbTerm *this; TreeDbTerm *tmp; Sint c; if(( this = TOP_NODE(stack)) != NULL) { - if (!cmp_key_eq(tb,key,key_base,this)) { + if (!cmp_key_eq(tb,key,this)) { /* Start from the beginning */ stack->pos = stack->slot = 0; } @@ -2395,7 +2373,7 @@ static TreeDbTerm *find_prev(DbTableTree *tb, DbTreeStack* stack, return NULL; for (;;) { PUSH_NODE(stack, this); - if (( c = cmp_key(tb,key,key_base,this) ) < 0) { + if (( c = cmp_key(tb,key,this) ) < 0) { if (this->left == NULL) /* We are at the next and the element does not exist */ @@ -2448,8 +2426,7 @@ static TreeDbTerm *find_next_from_pb_key(DbTableTree *tb, DbTreeStack* stack, return NULL; for (;;) { PUSH_NODE(stack, this); - if (( c = cmp_partly_bound(key,GETKEY(tb, this->dbterm.tpl), - this->dbterm.tpl) ) >= 0) { + if (( c = cmp_partly_bound(key,GETKEY(tb, this->dbterm.tpl))) >= 0) { if (this->right == NULL) { do { tmp = POP_NODE(stack); @@ -2482,8 +2459,7 @@ static TreeDbTerm *find_prev_from_pb_key(DbTableTree *tb, DbTreeStack* stack, return NULL; for (;;) { PUSH_NODE(stack, this); - if (( c = cmp_partly_bound(key,GETKEY(tb, this->dbterm.tpl), - this->dbterm.tpl) ) <= 0) { + if (( c = cmp_partly_bound(key,GETKEY(tb, this->dbterm.tpl))) <= 0) { if (this->left == NULL) { do { tmp = POP_NODE(stack); @@ -2514,10 +2490,10 @@ static TreeDbTerm *find_node(DbTableTree *tb, Eterm key) DbTreeStack* stack = get_static_stack(tb); if(!stack || EMPTY_NODE(stack) - || !cmp_key_eq(tb, key, NULL, (this=TOP_NODE(stack)))) { + || !cmp_key_eq(tb, key, (this=TOP_NODE(stack)))) { this = tb->root; - while (this != NULL && (res = cmp_key(tb,key,NULL,this)) != 0) { + while (this != NULL && (res = cmp_key(tb,key,this)) != 0) { if (res < 0) this = this->left; else @@ -2539,7 +2515,7 @@ static TreeDbTerm **find_node2(DbTableTree *tb, Eterm key) Sint res; this = &tb->root; - while ((*this) != NULL && (res = cmp_key(tb, key, NULL, *this)) != 0) { + while ((*this) != NULL && (res = cmp_key(tb, key, *this)) != 0) { if (res < 0) this = &((*this)->left); else @@ -2589,9 +2565,6 @@ db_lookup_dbterm_tree(Process *p, DbTable *tbl, Eterm key, Eterm obj, handle->flags = flags; handle->bp = (void**) pp; handle->new_size = (*pp)->dbterm.size; -#if HALFWORD_HEAP - handle->abs_vec = NULL; -#endif return 1; } @@ -2622,7 +2595,7 @@ db_finalize_dbterm_tree(int cret, DbUpdateHandle *handle) */ static void traverse_backwards(DbTableTree *tb, DbTreeStack* stack, - Eterm lastkey, Eterm* lk_base, + Eterm lastkey, int (*doit)(DbTableTree *, TreeDbTerm *, void *, @@ -2641,16 +2614,15 @@ static void traverse_backwards(DbTableTree *tb, this = this->right; } this = TOP_NODE(stack); - next = find_prev(tb, stack, GETKEY(tb, this->dbterm.tpl), - this->dbterm.tpl); + next = find_prev(tb, stack, GETKEY(tb, this->dbterm.tpl)); if (!((*doit)(tb, this, context, 0))) return; } else { - next = find_prev(tb, stack, lastkey, lk_base); + next = find_prev(tb, stack, lastkey); } while ((this = next) != NULL) { - next = find_prev(tb, stack, GETKEY(tb, this->dbterm.tpl), this->dbterm.tpl); + next = find_prev(tb, stack, GETKEY(tb, this->dbterm.tpl)); if (!((*doit)(tb, this, context, 0))) return; } @@ -2661,7 +2633,7 @@ static void traverse_backwards(DbTableTree *tb, */ static void traverse_forward(DbTableTree *tb, DbTreeStack* stack, - Eterm lastkey, Eterm* lk_base, + Eterm lastkey, int (*doit)(DbTableTree *, TreeDbTerm *, void *, @@ -2680,15 +2652,15 @@ static void traverse_forward(DbTableTree *tb, this = this->left; } this = TOP_NODE(stack); - next = find_next(tb, stack, GETKEY(tb, this->dbterm.tpl), this->dbterm.tpl); + next = find_next(tb, stack, GETKEY(tb, this->dbterm.tpl)); if (!((*doit)(tb, this, context, 1))) return; } else { - next = find_next(tb, stack, lastkey, lk_base); + next = find_next(tb, stack, lastkey); } while ((this = next) != NULL) { - next = find_next(tb, stack, GETKEY(tb, this->dbterm.tpl), this->dbterm.tpl); + next = find_next(tb, stack, GETKEY(tb, this->dbterm.tpl)); if (!((*doit)(tb, this, context, 1))) return; } @@ -2725,7 +2697,7 @@ static int key_given(DbTableTree *tb, Eterm pattern, TreeDbTerm **ret, -static Sint do_cmp_partly_bound(Eterm a, Eterm b, Eterm* b_base, int *done) +static Sint do_cmp_partly_bound(Eterm a, Eterm b, int *done) { Eterm* aa; Eterm* bb; @@ -2739,44 +2711,44 @@ static Sint do_cmp_partly_bound(Eterm a, Eterm b, Eterm* b_base, int *done) *done = 1; return 0; } - if (is_same(a,NULL,b,b_base)) + if (is_same(a,b)) return 0; switch (a & _TAG_PRIMARY_MASK) { case TAG_PRIMARY_LIST: if (!is_list(b)) { - return cmp_rel(a,NULL,b,b_base); + return CMP(a,b); } aa = list_val(a); - bb = list_val_rel(b,b_base); + bb = list_val(b); while (1) { - if ((j = do_cmp_partly_bound(*aa++, *bb++, b_base, done)) != 0 || *done) + if ((j = do_cmp_partly_bound(*aa++, *bb++, done)) != 0 || *done) return j; - if (is_same(*aa, NULL, *bb, b_base)) + if (is_same(*aa, *bb)) return 0; if (is_not_list(*aa) || is_not_list(*bb)) - return do_cmp_partly_bound(*aa, *bb, b_base, done); + return do_cmp_partly_bound(*aa, *bb, done); aa = list_val(*aa); - bb = list_val_rel(*bb,b_base); + bb = list_val(*bb); } case TAG_PRIMARY_BOXED: if ((b & _TAG_PRIMARY_MASK) != TAG_PRIMARY_BOXED) { - return cmp_rel(a,NULL,b,b_base); + return CMP(a,b); } a_hdr = ((*boxed_val(a)) & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE; - b_hdr = ((*boxed_val_rel(b,b_base)) & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE; + b_hdr = ((*boxed_val(b)) & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE; if (a_hdr != b_hdr) { - return cmp_rel(a, NULL, b, b_base); + return CMP(a,b); } if (a_hdr == (_TAG_HEADER_ARITYVAL >> _TAG_PRIMARY_SIZE)) { aa = tuple_val(a); - bb = tuple_val_rel(b, b_base); + bb = tuple_val(b); /* compare the arities */ i = arityval(*aa); /* get the arity*/ if (i < arityval(*bb)) return(-1); if (i > arityval(*bb)) return(1); while (i--) { - if ((j = do_cmp_partly_bound(*++aa, *++bb, b_base, done)) != 0 + if ((j = do_cmp_partly_bound(*++aa, *++bb, done)) != 0 || *done) return j; } @@ -2784,14 +2756,13 @@ static Sint do_cmp_partly_bound(Eterm a, Eterm b, Eterm* b_base, int *done) } /* Drop through */ default: - return cmp_rel(a, NULL, b, b_base); + return CMP(a,b); } } -static Sint cmp_partly_bound(Eterm partly_bound_key, Eterm bound_key, Eterm* bk_base) -{ +static Sint cmp_partly_bound(Eterm partly_bound_key, Eterm bound_key) { int done = 0; - Sint ret = do_cmp_partly_bound(partly_bound_key, bound_key, bk_base, &done); + Sint ret = do_cmp_partly_bound(partly_bound_key, bound_key, &done); #ifdef HARDDEBUG erts_fprintf(stderr,"\ncmp_partly_bound: %T", partly_bound_key); if (ret < 0) @@ -2800,7 +2771,7 @@ static Sint cmp_partly_bound(Eterm partly_bound_key, Eterm bound_key, Eterm* bk_ erts_fprintf(stderr," > "); else erts_fprintf(stderr," == "); - erts_fprintf(stderr,"%R\n", bound_key, bk_base); + erts_fprintf(stderr,"%T\n", bound_key); #endif return ret; } @@ -3017,12 +2988,10 @@ static int doit_select(DbTableTree *tb, TreeDbTerm *this, void *ptr, if (sc->end_condition != NIL && ((forward && cmp_partly_bound(sc->end_condition, - GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl), - this->dbterm.tpl) < 0) || + GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl)) < 0) || (!forward && cmp_partly_bound(sc->end_condition, - GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl), - this->dbterm.tpl) > 0))) { + GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl)) > 0))) { return 0; } ret = db_match_dbterm(&tb->common,sc->p,sc->mp,sc->all_objects, @@ -3054,8 +3023,7 @@ static int doit_select_count(DbTableTree *tb, TreeDbTerm *this, void *ptr, /* Always backwards traversing */ if (sc->end_condition != NIL && (cmp_partly_bound(sc->end_condition, - GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl), - this->dbterm.tpl) > 0)) { + GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl)) > 0)) { return 0; } ret = db_match_dbterm(&tb->common, sc->p, sc->mp, 0, @@ -3081,12 +3049,10 @@ static int doit_select_chunk(DbTableTree *tb, TreeDbTerm *this, void *ptr, if (sc->end_condition != NIL && ((forward && cmp_partly_bound(sc->end_condition, - GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl), - this->dbterm.tpl) < 0) || + GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl)) < 0) || (!forward && cmp_partly_bound(sc->end_condition, - GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl), - this->dbterm.tpl) > 0))) { + GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl)) > 0))) { return 0; } @@ -3124,14 +3090,13 @@ static int doit_select_delete(DbTableTree *tb, TreeDbTerm *this, void *ptr, if (sc->end_condition != NIL && cmp_partly_bound(sc->end_condition, - GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl), - this->dbterm.tpl) > 0) + GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl)) > 0) return 0; ret = db_match_dbterm(&tb->common, sc->p, sc->mp, 0, &this->dbterm, NULL, 0); if (ret == am_true) { key = GETKEY(sc->tb, this->dbterm.tpl); - linkout_tree(sc->tb, key, this->dbterm.tpl); + linkout_tree(sc->tb, key); sc->erase_lastterm = 1; ++sc->accum; } @@ -3157,11 +3122,10 @@ static void do_dump_tree2(DbTableTree* tb, int to, void *to_arg, int show, } else { prefix = ""; - term = make_tuple_rel(t->dbterm.tpl,t->dbterm.tpl); + term = make_tuple(t->dbterm.tpl); } - erts_print(to, to_arg, "%*s%s%R (addr = %p, bal = %d)\n", - offset, "", prefix, term, t->dbterm.tpl, - t, t->balance); + erts_print(to, to_arg, "%*s%s%T (addr = %p, bal = %d)\n", + offset, "", prefix, term, t, t->balance); } do_dump_tree2(tb, to, to_arg, show, t->left, offset + 4); } diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index dab357a079..0bf9558ac9 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -239,11 +239,7 @@ typedef enum { matchCall2, matchCall3, matchPushV, -#if HALFWORD_HEAP - matchPushVGuard, /* First guard-only variable reference */ -#endif - matchPushVResult, /* First variable reference in result, or (if HALFWORD) - in guard if also referenced in result */ + matchPushVResult, /* First variable reference in result */ matchPushExpr, /* Push the whole expression we're matching ('$_') */ matchPushArrayAsList, /* Only when parameter is an Array and not an erlang term (DCOMP_TRACE) */ @@ -310,9 +306,6 @@ DMC_DECLARE_STACK_TYPE(unsigned); typedef struct DMCVariable { int is_bound; int is_in_body; -#if HALFWORD_HEAP - int first_guard_label; /* to maybe change from PushVGuard to PushVResult */ -#endif } DMCVariable; typedef struct DMCHeap { @@ -374,7 +367,6 @@ typedef struct MatchVariable { Eterm term; #ifdef DEBUG Process* proc; - Eterm* base; #endif } MatchVariable; @@ -415,7 +407,7 @@ cleanup_match_pseudo_process(ErtsMatchPseudoProcess *mpsp, int keep_heap) else { int i; for (i = 0; i < ERTS_DEFAULT_MS_HEAP_SIZE; i++) { -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) mpsp->default_heap[i] = (Eterm) 0xdeadbeefdeadbeef; #else mpsp->default_heap[i] = (Eterm) 0xdeadbeef; @@ -1240,7 +1232,7 @@ Eterm erts_match_set_run(Process *p, Binary *mpsp, { Eterm ret; - ret = db_prog_match(p, mpsp, NIL, NULL, args, num_args, + ret = db_prog_match(p, mpsp, NIL, args, num_args, in_flags, return_flags); #if defined(HARDDEBUG) if (is_non_value(ret)) { @@ -1265,7 +1257,7 @@ static Eterm erts_match_set_run_ets(Process *p, Binary *mpsp, { Eterm ret; - ret = db_prog_match(p, mpsp, args, NULL, NULL, num_args, + ret = db_prog_match(p, mpsp, args, NULL, num_args, ERTS_PAM_COPY_RESULT, return_flags); #if defined(HARDDEBUG) @@ -1755,71 +1747,6 @@ static Eterm dpm_array_to_list(Process *psp, Eterm *arr, int arity) return ret; } - -#if HALFWORD_HEAP -struct heap_checkpoint_t -{ - Process *p; - Eterm* htop; - ErlHeapFragment* mbuf; - unsigned used_size; - ErlOffHeap off_heap; -}; - -static void heap_checkpoint_init(Process* p, struct heap_checkpoint_t* hcp) -{ - hcp->p = p; - hcp->htop = HEAP_TOP(p); - hcp->mbuf = MBUF(p); - hcp->used_size = hcp->mbuf ? hcp->mbuf->used_size : 0; - hcp->off_heap = MSO(p); -} - -static void heap_checkpoint_revert(struct heap_checkpoint_t* hcp) -{ - struct erl_off_heap_header* oh = MSO(hcp->p).first; - - if (oh != hcp->off_heap.first) { - ASSERT(oh != NULL); - if (hcp->off_heap.first) { - while (oh->next != hcp->off_heap.first) { - oh = oh->next; - } - oh->next = NULL; - } - erts_cleanup_offheap(&MSO(hcp->p)); - MSO(hcp->p) = hcp->off_heap; - } - if (MBUF(hcp->p) != hcp->mbuf) { - ErlHeapFragment* hf = MBUF(hcp->p); - ASSERT(hf != NULL); - if (hcp->mbuf) { - while (hf->next != hcp->mbuf) { - hf = hf->next; - } - hf->next = NULL; - } - free_message_buffer(MBUF(hcp->p)); - MBUF(hcp->p) = hcp->mbuf; - } - if (hcp->mbuf != NULL && hcp->mbuf->used_size != hcp->used_size) { - hcp->mbuf->used_size = hcp->used_size; - } - HEAP_TOP(hcp->p) = hcp->htop; -} -#endif /* HALFWORD_HEAP */ - -static ERTS_INLINE Eterm copy_object_rel(Process* p, Eterm term, Eterm* base) -{ - if (!is_immed(term)) { - Uint sz = size_object_rel(term, base); - Eterm* top = HAllocX(p, sz, HEAP_XTRA); - return copy_struct_rel(term, sz, &top, &MSO(p), base, NULL); - } - return term; -} - - /* ** Execution of the match program, this is Pam. ** May return THE_NON_VALUE, which is a bailout. @@ -1827,7 +1754,7 @@ static ERTS_INLINE Eterm copy_object_rel(Process* p, Eterm term, Eterm* base) ** i.e. 'DCOMP_TRACE' was specified */ Eterm db_prog_match(Process *c_p, Binary *bprog, - Eterm term, Eterm* base, + Eterm term, Eterm *termp, int arity, enum erts_pam_run_flags in_flags, @@ -1855,17 +1782,12 @@ Eterm db_prog_match(Process *c_p, Binary *bprog, Eterm bif_args[3]; int fail_label; int atomic_trace; -#if HALFWORD_HEAP - struct heap_checkpoint_t c_p_checkpoint = {}; -#endif #ifdef DMC_DEBUG Uint *heap_fence; Uint *stack_fence; Uint save_op; #endif /* DMC_DEBUG */ - ASSERT(base==NULL || HALFWORD_HEAP); - mpsp = get_match_pseudo_process(c_p, prog->heap_size); psp = &mpsp->process; @@ -1916,11 +1838,7 @@ Eterm db_prog_match(Process *c_p, Binary *bprog, do_catch != 0 */ *return_flags = 0U; - variables = mpsp->u.variables; -#if HALFWORD_HEAP - c_p_checkpoint.p = NULL; -#endif restart: ep = &term; @@ -1931,14 +1849,12 @@ restart: fail_label = -1; build_proc = psp; esdp->current_process = psp; - ASSERT_HALFWORD(!c_p_checkpoint.p); #ifdef DEBUG ASSERT(variables == mpsp->u.variables); for (i=0; i<prog->num_bindings; i++) { variables[i].term = THE_NON_VALUE; variables[i].proc = NULL; - variables[i].base = base; } #endif @@ -1974,9 +1890,9 @@ restart: variables[n].term = dpm_array_to_list(psp, termp, arity); break; case matchTuple: /* *ep is a tuple of arity n */ - if (!is_tuple_rel(*ep,base)) + if (!is_tuple(*ep)) FAIL(); - ep = tuple_val_rel(*ep,base); + ep = tuple_val(*ep); n = *pc++; if (arityval(*ep) != n) FAIL(); @@ -1984,9 +1900,9 @@ restart: break; case matchPushT: /* *ep is a tuple of arity n, push ptr to first element */ - if (!is_tuple_rel(*ep,base)) + if (!is_tuple(*ep)) FAIL(); - tp = tuple_val_rel(*ep,base); + tp = tuple_val(*ep); n = *pc++; if (arityval(*tp) != n) FAIL(); @@ -1996,51 +1912,51 @@ restart: case matchList: if (!is_list(*ep)) FAIL(); - ep = list_val_rel(*ep,base); + ep = list_val(*ep); break; case matchPushL: if (!is_list(*ep)) FAIL(); - *sp++ = list_val_rel(*ep,base); + *sp++ = list_val(*ep); ++ep; break; case matchMap: - if (!is_map_rel(*ep, base)) { + if (!is_map(*ep)) { FAIL(); } n = *pc++; - if (is_flatmap_rel(*ep,base)) { - if (flatmap_get_size(flatmap_val_rel(*ep, base)) < n) { + if (is_flatmap(*ep)) { + if (flatmap_get_size(flatmap_val(*ep)) < n) { FAIL(); } } else { - ASSERT(is_hashmap_rel(*ep,base)); - if (hashmap_size_rel(*ep, base) < n) { + ASSERT(is_hashmap(*ep)); + if (hashmap_size(*ep) < n) { FAIL(); } } - ep = flatmap_val_rel(*ep, base); + ep = flatmap_val(*ep); break; case matchPushM: - if (!is_map_rel(*ep, base)) { + if (!is_map(*ep)) { FAIL(); } n = *pc++; - if (is_flatmap_rel(*ep,base)) { - if (flatmap_get_size(flatmap_val_rel(*ep, base)) < n) { + if (is_flatmap(*ep)) { + if (flatmap_get_size(flatmap_val(*ep)) < n) { FAIL(); } } else { - ASSERT(is_hashmap_rel(*ep,base)); - if (hashmap_size_rel(*ep, base) < n) { + ASSERT(is_hashmap(*ep)); + if (hashmap_size(*ep) < n) { FAIL(); } } - *sp++ = flatmap_val_rel(*ep++, base); + *sp++ = flatmap_val(*ep++); break; case matchKey: t = (Eterm) *pc++; - tp = erts_maps_get_rel(t, make_boxed_rel(ep, base), base); + tp = erts_maps_get(t, make_boxed(ep)); if (!tp) { FAIL(); } @@ -2061,29 +1977,29 @@ restart: break; case matchCmp: n = *pc++; - if (!eq_rel(variables[n].term, base, *ep, base)) + if (!EQ(variables[n].term, *ep)) FAIL(); ++ep; break; case matchEqBin: t = (Eterm) *pc++; - if (!eq_rel(t,NULL,*ep,base)) + if (!EQ(t,*ep)) FAIL(); ++ep; break; case matchEqFloat: - if (!is_float_rel(*ep,base)) + if (!is_float(*ep)) FAIL(); - if (memcmp(float_val_rel(*ep,base) + 1, pc, sizeof(double))) + if (memcmp(float_val(*ep) + 1, pc, sizeof(double))) FAIL(); pc += TermWords(2); ++ep; break; case matchEqRef: { Eterm* epc = (Eterm*)pc; - if (!is_ref_rel(*ep,base)) + if (!is_ref(*ep)) FAIL(); - if (!eq_rel(make_internal_ref_rel(epc, epc), epc, *ep, base)) { + if (!EQ(make_internal_ref(epc), *ep)) { FAIL(); } i = thing_arityval(*epc); @@ -2092,9 +2008,9 @@ restart: break; } case matchEqBig: - if (!is_big_rel(*ep,base)) + if (!is_big(*ep)) FAIL(); - tp = big_val_rel(*ep,base); + tp = big_val(*ep); { Eterm *epc = (Eterm *) pc; if (*tp != *epc) @@ -2236,62 +2152,36 @@ restart: esp -= 2; esp[-1] = t; break; - - #if HALFWORD_HEAP - case matchPushVGuard: - if (!base) goto case_matchPushV; - /* Build NULL-based copy on pseudo heap for easy disposal */ - n = *pc++; - ASSERT(is_value(variables[n].term)); - ASSERT(!variables[n].proc); - variables[n].term = copy_object_rel(psp, variables[n].term, base); - *esp++ = variables[n].term; - #ifdef DEBUG - variables[n].proc = psp; - variables[n].base = NULL; - #endif - break; - #endif case matchPushVResult: if (!(in_flags & ERTS_PAM_COPY_RESULT)) goto case_matchPushV; - - /* Build (NULL-based) copy on callers heap */ - #if HALFWORD_HEAP - if (!do_catch && !c_p_checkpoint.p) { - heap_checkpoint_init(c_p, &c_p_checkpoint); - } - #endif + /* Build copy on callers heap */ n = *pc++; ASSERT(is_value(variables[n].term)); ASSERT(!variables[n].proc); - variables[n].term = copy_object_rel(c_p, variables[n].term, base); + variables[n].term = copy_object_x(variables[n].term, c_p, HEAP_XTRA); *esp++ = variables[n].term; #ifdef DEBUG variables[n].proc = c_p; - variables[n].base = NULL; #endif break; case matchPushV: case_matchPushV: n = *pc++; ASSERT(is_value(variables[n].term)); - ASSERT(!variables[n].base); *esp++ = variables[n].term; break; case matchPushExpr: if (in_flags & ERTS_PAM_COPY_RESULT) { Uint sz; Eterm* top; - sz = size_object_rel(term, base); + sz = size_object(term); top = HAllocX(build_proc, sz, HEAP_XTRA); if (in_flags & ERTS_PAM_CONTIGUOUS_TUPLE) { - ASSERT(is_tuple_rel(term,base)); - *esp++ = copy_shallow_rel(tuple_val_rel(term,base), sz, - &top, &MSO(build_proc), base); + ASSERT(is_tuple(term)); + *esp++ = copy_shallow(tuple_val(term), sz, &top, &MSO(build_proc)); } else { - *esp++ = copy_struct_rel(term, sz, &top, &MSO(build_proc), - base, NULL); + *esp++ = copy_struct(term, sz, &top, &MSO(build_proc)); } } else { @@ -2299,7 +2189,6 @@ restart: } break; case matchPushArrayAsList: - ASSERT_HALFWORD(base == NULL); n = arity; /* Only happens when 'term' is an array */ tp = termp; ehp = HAllocX(build_proc, n*2, HEAP_XTRA); @@ -2315,7 +2204,6 @@ restart: break; case matchPushArrayAsListU: /* This instruction is NOT efficient. */ - ASSERT_HALFWORD(base == NULL); *esp++ = dpm_array_to_list(build_proc, termp, arity); break; case matchTrue: @@ -2619,13 +2507,6 @@ restart: } } fail: -#if HALFWORD_HEAP - if (c_p_checkpoint.p) { - /* Dispose garbage built by guards on caller heap */ - heap_checkpoint_revert(&c_p_checkpoint); - c_p_checkpoint.p = NULL; - } -#endif *return_flags = 0U; if (fail_label >= 0) { /* We failed during a "TryMeElse", lets restart, with the next match @@ -2788,13 +2669,6 @@ Wterm db_do_read_element(DbUpdateHandle* handle, Sint position) { Eterm elem = handle->dbterm->tpl[position]; if (!is_header(elem)) { -#if HALFWORD_HEAP - if (!is_immed(elem) - && !handle->tb->common.compress - && !(handle->abs_vec && handle->abs_vec[position])) { - return rterm2wterm(elem, handle->dbterm->tpl); - } -#endif return elem; } @@ -2822,9 +2696,6 @@ void db_do_update_element(DbUpdateHandle* handle, Eterm* oldp; Uint newval_sz; Uint oldval_sz; -#if HALFWORD_HEAP - Eterm* old_base; -#endif if (is_both_immed(newval,oldval)) { handle->dbterm->tpl[position] = newval; @@ -2841,15 +2712,8 @@ void db_do_update_element(DbUpdateHandle* handle, handle->dbterm); handle->flags |= DB_MUST_RESIZE; oldval = handle->dbterm->tpl[position]; - #if HALFWORD_HEAP - old_base = NULL; - #endif } else { - #if HALFWORD_HEAP - ASSERT(!handle->abs_vec); - old_base = handle->dbterm->tpl; - #endif if (is_boxed(newval)) { newp = boxed_val(newval); switch (*newp & _TAG_HEADER_MASK) { @@ -2859,7 +2723,7 @@ void db_do_update_element(DbUpdateHandle* handle, case _TAG_HEADER_HEAP_BIN: newval_sz = header_arity(*newp) + 1; if (is_boxed(oldval)) { - oldp = boxed_val_rel(oldval,old_base); + oldp = boxed_val(oldval); switch (*oldp & _TAG_HEADER_MASK) { case _TAG_HEADER_POS_BIG: case _TAG_HEADER_NEG_BIG: @@ -2879,20 +2743,13 @@ void db_do_update_element(DbUpdateHandle* handle, } } } -#if HALFWORD_HEAP - else { - old_base = (handle->tb->common.compress - || (handle->abs_vec && handle->abs_vec[position])) ? - NULL : handle->dbterm->tpl; - } -#endif /* Not possible for simple memcpy or dbterm is already non-contiguous, */ /* need to realloc... */ newval_sz = is_immed(newval) ? 0 : size_object(newval); new_size_set: - oldval_sz = is_immed(oldval) ? 0 : size_object_rel(oldval,old_base); + oldval_sz = is_immed(oldval) ? 0 : size_object(oldval); both_size_set: handle->new_size = handle->new_size - oldval_sz + newval_sz; @@ -2900,19 +2757,6 @@ both_size_set: /* write new value in old dbterm, finalize will make a flat copy */ handle->dbterm->tpl[position] = newval; handle->flags |= DB_MUST_RESIZE; - -#if HALFWORD_HEAP - if (old_base && newval_sz > 0) { - ASSERT(!handle->tb->common.compress); - if (!handle->abs_vec) { - int i = header_arity(handle->dbterm->tpl[0]); - handle->abs_vec = erts_alloc(ERTS_ALC_T_TMP, (i+1)*sizeof(char)); - sys_memset(handle->abs_vec, 0, i+1); - /* abs_vec[0] not used */ - } - handle->abs_vec[position] = 1; - } -#endif } static ERTS_INLINE byte* db_realloc_term(DbTableCommon* tb, void* old, @@ -3011,7 +2855,7 @@ static void* copy_to_comp(DbTableCommon* tb, Eterm obj, DbTerm* dest, tpl[arity + 1] = alloc_size; tmp_offheap.first = NULL; - tpl[tb->keypos] = copy_struct_rel(key, size_object(key), &top.ep, &tmp_offheap, NULL, tpl); + tpl[tb->keypos] = copy_struct(key, size_object(key), &top.ep, &tmp_offheap); dest->first_oh = tmp_offheap.first; for (i=1; i<=arity; i++) { if (i != tb->keypos) { @@ -3030,7 +2874,7 @@ static void* copy_to_comp(DbTableCommon* tb, Eterm obj, DbTerm* dest, Eterm* dbg_top = erts_alloc(ERTS_ALC_T_DB_TERM, dest->size * sizeof(Eterm)); dest->debug_clone = dbg_top; tmp_offheap.first = dest->first_oh; - copy_struct_rel(obj, dest->size, &dbg_top, &tmp_offheap, NULL, dbg_top); + copy_struct(obj, dest->size, &dbg_top, &tmp_offheap); dest->first_oh = tmp_offheap.first; ASSERT(dbg_top == dest->debug_clone + dest->size); } @@ -3077,7 +2921,7 @@ void* db_store_term(DbTableCommon *tb, DbTerm* old, Uint offset, Eterm obj) newp->size = size; top = newp->tpl; tmp_offheap.first = NULL; - copy_struct_rel(obj, size, &top, &tmp_offheap, NULL, top); + copy_struct(obj, size, &top, &tmp_offheap); newp->first_oh = tmp_offheap.first; #ifdef DEBUG_CLONE newp->debug_clone = NULL; @@ -3160,29 +3004,8 @@ void db_finalize_resize(DbUpdateHandle* handle, Uint offset) tmp_offheap.first = NULL; - #if HALFWORD_HEAP - if (handle->abs_vec) { - int i, arity = header_arity(handle->dbterm->tpl[0]); - - top[0] = tpl[0]; - top += arity + 1; - for (i=1; i<=arity; i++) { - Eterm* src_base = handle->abs_vec[i] ? NULL : tpl; - - newDbTerm->tpl[i] = copy_struct_rel(tpl[i], - size_object_rel(tpl[i],src_base), - &top, &tmp_offheap, src_base, - newDbTerm->tpl); - } - newDbTerm->first_oh = tmp_offheap.first; - ASSERT((byte*)top <= (newp + alloc_sz)); - erts_free(ERTS_ALC_T_TMP, handle->abs_vec); - } - else - #endif /* HALFWORD_HEAP */ { - copy_struct_rel(make_tuple_rel(tpl,tpl), handle->new_size, &top, - &tmp_offheap, tpl, top); + copy_struct(make_tuple(tpl), handle->new_size, &top, &tmp_offheap); newDbTerm->first_oh = tmp_offheap.first; ASSERT((byte*)top == (newp + alloc_sz)); } @@ -3199,9 +3022,9 @@ Eterm db_copy_from_comp(DbTableCommon* tb, DbTerm* bp, Eterm** hpp, hp[0] = bp->tpl[0]; *hpp += arity + 1; - hp[tb->keypos] = copy_struct_rel(bp->tpl[tb->keypos], - size_object_rel(bp->tpl[tb->keypos], bp->tpl), - hpp, off_heap, bp->tpl, NULL); + hp[tb->keypos] = copy_struct(bp->tpl[tb->keypos], + size_object(bp->tpl[tb->keypos]), + hpp, off_heap); erts_factory_static_init(&factory, *hpp, bp->size - (arity+1), off_heap); @@ -3221,7 +3044,7 @@ Eterm db_copy_from_comp(DbTableCommon* tb, DbTerm* bp, Eterm** hpp, ASSERT((*hpp - hp) <= bp->size); #ifdef DEBUG_CLONE - ASSERT(eq_rel(make_tuple(hp),NULL,make_tuple(bp->debug_clone),bp->debug_clone)); + ASSERT(EQ(make_tuple(hp),make_tuple(bp->debug_clone))); #endif return make_tuple(hp); } @@ -3245,14 +3068,14 @@ Eterm db_copy_element_from_ets(DbTableCommon* tb, Process* p, *hpp = erts_produce_heap(&factory, extra, 0); erts_factory_close(&factory); #ifdef DEBUG_CLONE - ASSERT(eq_rel(copy, NULL, obj->debug_clone[pos], obj->debug_clone)); + ASSERT(EQ(copy, obj->debug_clone[pos])); #endif return copy; } else { - Uint sz = size_object_rel(obj->tpl[pos], obj->tpl); + Uint sz = size_object(obj->tpl[pos]); *hpp = HAlloc(p, sz + extra); - return copy_struct_rel(obj->tpl[pos], sz, hpp, &MSO(p), obj->tpl, NULL); + return copy_struct(obj->tpl[pos], sz, hpp, &MSO(p)); } } @@ -3599,26 +3422,10 @@ static DMCRet dmc_one_term(DMCContext *context, { Eterm* ref_val = internal_ref_val(c); DMC_PUSH(*text, matchEqRef); -#if HALFWORD_HEAP - { - union { - UWord u; - Uint t[2]; - } fiddle; - ASSERT(thing_arityval(ref_val[0]) == 3); - fiddle.t[0] = ref_val[0]; - fiddle.t[1] = ref_val[1]; - DMC_PUSH(*text, fiddle.u); - fiddle.t[0] = ref_val[2]; - fiddle.t[1] = ref_val[3]; - DMC_PUSH(*text, fiddle.u); - } -#else n = thing_arityval(ref_val[0]); for (i = 0; i <= n; ++i) { DMC_PUSH(*text, ref_val[i]); } -#endif break; } case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): @@ -3627,53 +3434,19 @@ static DMCRet dmc_one_term(DMCContext *context, Eterm* bval = big_val(c); n = thing_arityval(bval[0]); DMC_PUSH(*text, matchEqBig); -#if HALFWORD_HEAP - { - union { - UWord u; - Uint t[2]; - } fiddle; - ASSERT(n >= 1); - fiddle.t[0] = bval[0]; - fiddle.t[1] = bval[1]; - DMC_PUSH(*text, fiddle.u); - for (i = 2; i <= n; ++i) { - fiddle.t[0] = bval[i]; - if (++i <= n) { - fiddle.t[1] = bval[i]; - } else { - fiddle.t[1] = (Uint) 0; - } - DMC_PUSH(*text, fiddle.u); - } - } -#else for (i = 0; i <= n; ++i) { DMC_PUSH(*text, (Uint) bval[i]); } -#endif break; } case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): DMC_PUSH(*text,matchEqFloat); -#if HALFWORD_HEAP - { - union { - UWord u; - Uint t[2]; - } fiddle; - fiddle.t[0] = float_val(c)[1]; - fiddle.t[1] = float_val(c)[2]; - DMC_PUSH(*text, fiddle.u); - } -#else DMC_PUSH(*text, (Uint) float_val(c)[1]); #ifdef ARCH_64 DMC_PUSH(*text, (Uint) 0); #else DMC_PUSH(*text, (Uint) float_val(c)[2]); #endif -#endif break; default: /* BINARY, FUN, VECTOR, or EXTERNAL */ DMC_PUSH(*text, matchEqBin); @@ -3997,24 +3770,8 @@ static void dmc_add_pushv_variant(DMCContext *context, DMCHeap *heap, MatchOps instr = matchPushV; ASSERT(n < heap->vars_used && v->is_bound); - if (context->is_guard) { - #if HALFWORD_HEAP - if (!v->first_guard_label) { - v->first_guard_label = DMC_STACK_NUM(*text); - ASSERT(v->first_guard_label); - instr = matchPushVGuard; /* may be changed to PushVResult below */ - } - #endif - } - else { /* body */ - #if HALFWORD_HEAP - if (v->first_guard_label) { - /* Avoid double-copy, copy to result heap at first encounter in guard */ - DMC_POKE(*text, v->first_guard_label, matchPushVResult); - v->is_in_body = 1; - } - #endif - if (!v->is_in_body) { + if (!context->is_guard) { + if(!v->is_in_body) { instr = matchPushVResult; v->is_in_body = 1; } @@ -5443,16 +5200,13 @@ Eterm db_match_dbterm(DbTableCommon* tb, Process* c_p, Binary* bprog, int all, DbTerm* obj, Eterm** hpp, Uint extra) { Uint32 dummy; - Eterm* base; Eterm res; if (tb->compress) { obj = db_alloc_tmp_uncompressed(tb, obj); - base = NULL; } - else base = HALFWORD_HEAP ? obj->tpl : NULL; - res = db_prog_match(c_p, bprog, make_tuple_rel(obj->tpl,base), base, NULL, 0, + res = db_prog_match(c_p, bprog, make_tuple(obj->tpl), NULL, 0, ERTS_PAM_COPY_RESULT|ERTS_PAM_CONTIGUOUS_TUPLE, &dummy); if (is_value(res) && hpp!=NULL) { @@ -5573,7 +5327,7 @@ void db_match_dis(Binary *bp) first = 0; else erts_printf(", "); -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) erts_printf("0x%016bex", rt->data.ui[ri]); #else erts_printf("0x%08bex", rt->data.ui[ri]); @@ -5597,7 +5351,7 @@ void db_match_dis(Binary *bp) first = 0; else erts_printf(", "); -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) erts_printf("0x%016bex", *et); #else erts_printf("0x%08bex", *et); @@ -5720,13 +5474,6 @@ void db_match_dis(Binary *bp) ++t; erts_printf("PushV\t%beu\n", n); break; - #if HALFWORD_HEAP - case matchPushVGuard: - n = (Uint) *++t; - ++t; - erts_printf("PushVGuard\t%beu\n", n); - break; - #endif case matchPushVResult: n = (Uint) *++t; ++t; diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h index 1ccdc0305b..c0966655cd 100644 --- a/erts/emulator/beam/erl_db_util.h +++ b/erts/emulator/beam/erl_db_util.h @@ -90,9 +90,6 @@ typedef struct { Uint new_size; int flags; void* lck; -#if HALFWORD_HEAP - unsigned char* abs_vec; /* [i] true if dbterm->tpl[i] is absolute Eterm */ -#endif } DbUpdateHandle; @@ -287,10 +284,10 @@ ERTS_GLB_INLINE Eterm db_copy_key(Process* p, DbTable* tb, DbTerm* obj) Eterm key = GETKEY(tb, obj->tpl); if IS_CONST(key) return key; else { - Uint size = size_object_rel(key, obj->tpl); + Uint size = size_object(key); Eterm* hp = HAlloc(p, size); - Eterm res = copy_struct_rel(key, size, &hp, &MSO(p), obj->tpl, NULL); - ASSERT(eq_rel(res,NULL,key,obj->tpl)); + Eterm res = copy_struct(key, size, &hp, &MSO(p)); + ASSERT(EQ(res,key)); return res; } } @@ -302,14 +299,14 @@ ERTS_GLB_INLINE Eterm db_copy_object_from_ets(DbTableCommon* tb, DbTerm* bp, return db_copy_from_comp(tb, bp, hpp, off_heap); } else { - return copy_shallow_rel(bp->tpl, bp->size, hpp, off_heap, bp->tpl); + return copy_shallow(bp->tpl, bp->size, hpp, off_heap); } } ERTS_GLB_INLINE int db_eq(DbTableCommon* tb, Eterm a, DbTerm* b) { if (!tb->compress) { - return eq_rel(a, NULL, make_tuple_rel(b->tpl,b->tpl), b->tpl); + return EQ(a, make_tuple(b->tpl)); } else { return db_eq_comp(tb, a, b); @@ -435,7 +432,7 @@ Binary *db_match_compile(Eterm *matchexpr, Eterm *guards, Eterm db_match_dbterm(DbTableCommon* tb, Process* c_p, Binary* bprog, int all, DbTerm* obj, Eterm** hpp, Uint extra); -Eterm db_prog_match(Process *p, Binary *prog, Eterm term, Eterm* base, +Eterm db_prog_match(Process *p, Binary *prog, Eterm term, Eterm *termp, int arity, enum erts_pam_run_flags in_flags, Uint32 *return_flags /* Zeroed on enter */); diff --git a/erts/emulator/beam/erl_debug.c b/erts/emulator/beam/erl_debug.c index 2dcfb79f00..fae38728e4 100644 --- a/erts/emulator/beam/erl_debug.c +++ b/erts/emulator/beam/erl_debug.c @@ -631,29 +631,4 @@ void print_memory_info(Process *p) } erts_printf("+-----------------%s-%s-%s-%s-+\n",dashes,dashes,dashes,dashes); } -#if !HEAP_ON_C_STACK && defined(DEBUG) -Eterm *erts_debug_allocate_tmp_heap(int size, Process *p) -{ - ErtsSchedulerData *sd = ((p == NULL) ? erts_get_scheduler_data() : ERTS_PROC_GET_SCHDATA(p)); - int offset = sd->num_tmp_heap_used; - - ASSERT(offset+size <= TMP_HEAP_SIZE); - return (sd->tmp_heap)+offset; -} -void erts_debug_use_tmp_heap(int size, Process *p) -{ - ErtsSchedulerData *sd = ((p == NULL) ? erts_get_scheduler_data() : ERTS_PROC_GET_SCHDATA(p)); - - sd->num_tmp_heap_used += size; - ASSERT(sd->num_tmp_heap_used <= TMP_HEAP_SIZE); -} -void erts_debug_unuse_tmp_heap(int size, Process *p) -{ - ErtsSchedulerData *sd = ((p == NULL) ? erts_get_scheduler_data() : ERTS_PROC_GET_SCHDATA(p)); - - sd->num_tmp_heap_used -= size; - ASSERT(sd->num_tmp_heap_used >= 0); -} #endif -#endif - diff --git a/erts/emulator/beam/erl_debug.h b/erts/emulator/beam/erl_debug.h index 4905e64f07..f4259e7dae 100644 --- a/erts/emulator/beam/erl_debug.h +++ b/erts/emulator/beam/erl_debug.h @@ -92,10 +92,4 @@ extern void print_tagged_memory(Eterm *start, Eterm *end); extern void print_untagged_memory(Eterm *start, Eterm *end); extern void print_memory(Process *p); extern void print_memory_info(Process *p); -#if defined(DEBUG) && !HEAP_ON_C_STACK -extern Eterm *erts_debug_allocate_tmp_heap(int, Process *); -extern void erts_debug_use_tmp_heap(int, Process *); -extern void erts_debug_unuse_tmp_heap(int, Process *); -#endif - #endif /* _ERL_DEBUG_H_ */ diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h index 6b406d069c..e71b87803b 100644 --- a/erts/emulator/beam/erl_driver.h +++ b/erts/emulator/beam/erl_driver.h @@ -57,10 +57,6 @@ # define SIZEOF_LONG_LONG_SAVED__ SIZEOF_LONG_LONG # undef SIZEOF_LONG_LONG #endif -#ifdef HALFWORD_HEAP_EMULATOR -# define HALFWORD_HEAP_EMULATOR_SAVED__ HALFWORD_HEAP_EMULATOR -# undef HALFWORD_HEAP_EMULATOR -#endif #include "erl_int_sizes_config.h" #if defined(SIZEOF_CHAR_SAVED__) && SIZEOF_CHAR_SAVED__ != SIZEOF_CHAR # error SIZEOF_CHAR mismatch @@ -78,11 +74,6 @@ # error SIZEOF_LONG_LONG mismatch #endif -/* This is OK to override by the NIF/driver implementor */ -#if defined(HALFWORD_HEAP_EMULATOR_SAVED__) && !defined(HALFWORD_HEAP_EMULATOR) -#define HALFWORD_HEAP_EMULATOR HALFWORD_HEAP_EMULATOR_SAVED__ -#endif - #include "erl_drv_nif.h" #include <stdlib.h> @@ -699,16 +690,6 @@ EXTERN char *driver_dl_error(void); EXTERN int erl_drv_putenv(char *key, char *value); EXTERN int erl_drv_getenv(char *key, char *value, size_t *value_size); -#ifdef __OSE__ -typedef ErlDrvUInt ErlDrvOseEventId; -EXTERN union SIGNAL *erl_drv_ose_get_signal(ErlDrvEvent ev); -EXTERN ErlDrvEvent erl_drv_ose_event_alloc(SIGSELECT sig, ErlDrvOseEventId handle, - ErlDrvOseEventId (*resolve_signal)(union SIGNAL *sig), void *extra); -EXTERN void erl_drv_ose_event_free(ErlDrvEvent ev); -EXTERN void erl_drv_ose_event_fetch(ErlDrvEvent ev, SIGSELECT *sig, - ErlDrvOseEventId *handle, void **extra); -#endif - #endif /* !ERL_DRIVER_TYPES_ONLY */ #ifdef WIN32_DYNAMIC_ERL_DRIVER diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index d2604f1595..29579f74e6 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -128,7 +128,7 @@ static void disallow_heap_frag_ref_in_old_heap(Process* p); static void disallow_heap_frag_ref(Process* p, Eterm* n_htop, Eterm* objv, int nobj); #endif -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) # define MAX_HEAP_SIZES 154 #else # define MAX_HEAP_SIZES 59 @@ -147,26 +147,10 @@ typedef struct { erts_smp_atomic32_t refc; } ErtsGCInfoReq; -#if !HALFWORD_HEAP ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(gcireq, - ErtsGCInfoReq, - 5, - ERTS_ALC_T_GC_INFO_REQ) -#else -static ERTS_INLINE ErtsGCInfoReq * -gcireq_alloc(void) -{ - return erts_alloc(ERTS_ALC_T_GC_INFO_REQ, - sizeof(ErtsGCInfoReq)); -} - -static ERTS_INLINE void -gcireq_free(ErtsGCInfoReq *ptr) -{ - erts_free(ERTS_ALC_T_GC_INFO_REQ, ptr); -} -#endif - + ErtsGCInfoReq, + 5, + ERTS_ALC_T_GC_INFO_REQ) /* * Initialize GC global data. */ @@ -208,7 +192,7 @@ erts_init_gc(void) } - /* for 32 bit we want max_heap_size to be MAX(32bit) / 4 [words] (and halfword) + /* for 32 bit we want max_heap_size to be MAX(32bit) / 4 [words] * for 64 bit we want max_heap_size to be MAX(52bit) / 8 [words] */ @@ -232,10 +216,7 @@ erts_init_gc(void) init_gc_info(&esdp->gc_info); } -#if !HALFWORD_HEAP init_gcireq_alloc(); -#endif - } /* @@ -867,7 +848,6 @@ minor_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl) if (OLD_HEAP(p) && ((mature <= OLD_HEND(p) - OLD_HTOP(p)) && - ((BIN_VHEAP_MATURE(p) < ( BIN_OLD_VHEAP_SZ(p) - BIN_OLD_VHEAP(p)))) && ((BIN_OLD_VHEAP_SZ(p) > BIN_OLD_VHEAP(p))) ) ) { ErlMessage *msgp; Uint size_after; @@ -1681,7 +1661,7 @@ disallow_heap_frag_ref_in_old_heap(Process* p) val = *hp++; switch (primary_tag(val)) { case TAG_PRIMARY_BOXED: - ptr = (Eterm *) EXPAND_POINTER(val); + ptr = (Eterm *) val; if (!in_area(ptr, old_heap, old_heap_size)) { if (in_area(ptr, new_heap, new_heap_size)) { abort(); @@ -1694,7 +1674,7 @@ disallow_heap_frag_ref_in_old_heap(Process* p) } break; case TAG_PRIMARY_LIST: - ptr = (Eterm *) EXPAND_POINTER(val); + ptr = (Eterm *) val; if (!in_area(ptr, old_heap, old_heap_size)) { if (in_area(ptr, new_heap, new_heap_size)) { abort(); @@ -2392,7 +2372,6 @@ sweep_off_heap(Process *p, int fullsweep) } BIN_VHEAP_SZ(p) = next_vheap_size(p, bin_vheap, BIN_VHEAP_SZ(p)); MSO(p).overhead = bin_vheap; - BIN_VHEAP_MATURE(p) = bin_vheap; /* * If we got any shrink candidates, check them out. diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index d9c3b0dcf4..5c209a4af2 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -91,11 +91,6 @@ const int etp_arch_bits = 32; #else # error "Not 64-bit, nor 32-bit arch" #endif -#if HALFWORD_HEAP -const int etp_halfword = 1; -#else -const int etp_halfword = 0; -#endif #ifdef HIPE const int etp_hipe = 1; #else diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c index 3b3b247020..84bee976ff 100644 --- a/erts/emulator/beam/erl_lock_check.c +++ b/erts/emulator/beam/erl_lock_check.c @@ -156,9 +156,6 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "instr", NULL }, { "alcu_allocator", "index" }, { "mseg", NULL }, -#if HALFWORD_HEAP - { "pmmap", NULL }, -#endif #ifdef ERTS_SMP { "port_task_pre_alloc_lock", "address" }, { "proclist_pre_alloc_lock", "address" }, diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c index ff2a355309..29b3024644 100644 --- a/erts/emulator/beam/erl_map.c +++ b/erts/emulator/beam/erl_map.c @@ -172,26 +172,22 @@ BIF_RETTYPE maps_to_list_1(BIF_ALIST_1) { */ const Eterm * -#if HALFWORD_HEAP -erts_maps_get_rel(Eterm key, Eterm map, Eterm *map_base) -#else erts_maps_get(Eterm key, Eterm map) -#endif { Uint32 hx; - if (is_flatmap_rel(map, map_base)) { + if (is_flatmap(map)) { Eterm *ks, *vs; flatmap_t *mp; Uint n, i; - mp = (flatmap_t *)flatmap_val_rel(map, map_base); + mp = (flatmap_t *)flatmap_val(map); n = flatmap_get_size(mp); if (n == 0) { return NULL; } - ks = (Eterm *)tuple_val_rel(mp->keys, map_base) + 1; + ks = (Eterm *)tuple_val(mp->keys) + 1; vs = flatmap_get_values(mp); if (is_immed(key)) { @@ -203,16 +199,16 @@ erts_maps_get(Eterm key, Eterm map) } for (i = 0; i < n; i++) { - if (eq_rel(ks[i], map_base, key, NULL)) { + if (EQ(ks[i], key)) { return &vs[i]; } } return NULL; } - ASSERT(is_hashmap_rel(map, map_base)); + ASSERT(is_hashmap(map)); hx = hashmap_make_hash(key); - return erts_hashmap_get_rel(hx, key, map, map_base); + return erts_hashmap_get(hx, key, map); } BIF_RETTYPE maps_find_2(BIF_ALIST_2) { @@ -1998,11 +1994,7 @@ Eterm* hashmap_iterator_prev(ErtsWStack* s) { } const Eterm * -#if HALFWORD_HEAP -erts_hashmap_get_rel(Uint32 hx, Eterm key, Eterm node, Eterm *map_base) -#else erts_hashmap_get(Uint32 hx, Eterm key, Eterm node) -#endif { Eterm *ptr, hdr, *res; Uint ix, lvl = 0; @@ -2011,7 +2003,7 @@ erts_hashmap_get(Uint32 hx, Eterm key, Eterm node) UseTmpHeapNoproc(2); ASSERT(is_boxed(node)); - ptr = boxed_val_rel(node, map_base); + ptr = boxed_val(node); hdr = *ptr; ASSERT(is_header(hdr)); ASSERT(is_hashmap_header_head(hdr)); @@ -2032,15 +2024,15 @@ erts_hashmap_get(Uint32 hx, Eterm key, Eterm node) node = ptr[ix+1]; if (is_list(node)) { /* LEAF NODE [K|V] */ - ptr = list_val_rel(node,map_base); - res = eq_rel(CAR(ptr), map_base, key, NULL) ? &(CDR(ptr)) : NULL; + ptr = list_val(node); + res = EQ(CAR(ptr), key) ? &(CDR(ptr)) : NULL; break; } hx = hashmap_shift_hash(th,hx,lvl,key); ASSERT(is_boxed(node)); - ptr = boxed_val_rel(node, map_base); + ptr = boxed_val(node); hdr = *ptr; ASSERT(is_header(hdr)); ASSERT(!is_hashmap_header_head(hdr)); diff --git a/erts/emulator/beam/erl_map.h b/erts/emulator/beam/erl_map.h index c391de3f11..be6f791a4e 100644 --- a/erts/emulator/beam/erl_map.h +++ b/erts/emulator/beam/erl_map.h @@ -57,7 +57,6 @@ typedef struct flatmap_s { #define hashmap_size(x) (((hashmap_head_t*) hashmap_val(x))->size) -#define hashmap_size_rel(RTERM, BASE) hashmap_size(rterm2wterm(RTERM, BASE)) #define hashmap_make_hash(Key) make_internal_hash(Key) #define hashmap_restore_hash(Heap,Lvl,Key) \ @@ -104,23 +103,9 @@ Eterm erts_hashmap_from_array(ErtsHeapFactory*, Eterm *leafs, Uint n, int rejec Eterm erts_hashmap_from_ks_and_vs_extra(Process *p, Eterm *ks, Eterm *vs, Uint n, Eterm k, Eterm v); -const Eterm * -#if HALFWORD_HEAP -erts_maps_get_rel(Eterm key, Eterm map, Eterm *map_base); -# define erts_maps_get(A, B) erts_maps_get_rel(A, B, NULL) -#else -erts_maps_get(Eterm key, Eterm map); -# define erts_maps_get_rel(A, B, B_BASE) erts_maps_get(A, B) -#endif +const Eterm *erts_maps_get(Eterm key, Eterm map); -const Eterm * -#if HALFWORD_HEAP -erts_hashmap_get_rel(Uint32 hx, Eterm key, Eterm node, Eterm *map_base); -# define erts_hashmap_get(Hx, K, M) erts_hashmap_get_rel(Hx, K, M, NULL) -#else -erts_hashmap_get(Uint32 hx, Eterm key, Eterm map); -# define erts_hashmap_get_rel(Hx, K, M, M_BASE) erts_hashmap_get(Hx, K, M) -#endif +const Eterm *erts_hashmap_get(Uint32 hx, Eterm key, Eterm map); /* hamt nodes v2.0 * diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h index fbdf3fb0e2..f37b430d27 100644 --- a/erts/emulator/beam/erl_message.h +++ b/erts/emulator/beam/erl_message.h @@ -32,9 +32,6 @@ struct external_thing_; struct erl_off_heap_header { Eterm thing_word; Uint size; -#if HALFWORD_HEAP - void* dummy_ptr_padding__; -#endif struct erl_off_heap_header* next; }; diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index 7d880126f8..5da6bb877a 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -86,10 +86,6 @@ # define SIZEOF_LONG_LONG_SAVED__ SIZEOF_LONG_LONG # undef SIZEOF_LONG_LONG #endif -#ifdef HALFWORD_HEAP_EMULATOR -# define HALFWORD_HEAP_EMULATOR_SAVED__ HALFWORD_HEAP_EMULATOR -# undef HALFWORD_HEAP_EMULATOR -#endif #include "erl_int_sizes_config.h" #ifdef __cplusplus @@ -109,16 +105,11 @@ typedef long long ErlNifSInt64; #error No 64-bit integer type #endif -#ifdef HALFWORD_HEAP_EMULATOR -# define ERL_NIF_VM_VARIANT "beam.halfword" -typedef unsigned int ERL_NIF_TERM; -#else -# define ERL_NIF_VM_VARIANT "beam.vanilla" -# if SIZEOF_LONG == SIZEOF_VOID_P +#define ERL_NIF_VM_VARIANT "beam.vanilla" +#if SIZEOF_LONG == SIZEOF_VOID_P typedef unsigned long ERL_NIF_TERM; -# elif SIZEOF_LONG_LONG == SIZEOF_VOID_P +#elif SIZEOF_LONG_LONG == SIZEOF_VOID_P typedef unsigned long long ERL_NIF_TERM; -# endif #endif typedef ERL_NIF_TERM ERL_NIF_UINT; diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h index f93152c921..2f2180e1aa 100644 --- a/erts/emulator/beam/erl_nif_api_funcs.h +++ b/erts/emulator/beam/erl_nif_api_funcs.h @@ -543,7 +543,7 @@ static ERL_NIF_INLINE ERL_NIF_TERM enif_make_list9(ErlNifEnv* env, #ifndef enif_make_pid -# define enif_make_pid(ENV, PID) ((const ERL_NIF_TERM)((PID)->pid)) +# define enif_make_pid(ENV, PID) ((void)(ENV),(const ERL_NIF_TERM)((PID)->pid)) #if SIZEOF_LONG == 8 # define enif_get_int64 enif_get_long diff --git a/erts/emulator/beam/erl_node_container_utils.h b/erts/emulator/beam/erl_node_container_utils.h index 211b1a0090..b6a3531e28 100644 --- a/erts/emulator/beam/erl_node_container_utils.h +++ b/erts/emulator/beam/erl_node_container_utils.h @@ -255,7 +255,7 @@ extern ErtsPTab erts_port; * Refs * \* */ -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) #define internal_ref_no_of_numbers(x) \ (internal_ref_data((x))[0]) @@ -328,8 +328,6 @@ extern ErtsPTab erts_port; : external_ref_channel_no((x))) #define is_ref(x) (is_internal_ref((x)) \ || is_external_ref((x))) -#define is_ref_rel(x,Base) (is_internal_ref_rel((x),Base) \ - || is_external_ref_rel((x),Base)) #define is_not_ref(x) (!is_ref(x)) #endif diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c index 2fb790b953..62a44f7129 100644 --- a/erts/emulator/beam/erl_node_tables.c +++ b/erts/emulator/beam/erl_node_tables.c @@ -1207,23 +1207,11 @@ insert_offheap(ErlOffHeap *oh, int type, Eterm id) break; } if (insert_bin) { -#if HALFWORD_HEAP - UWord val = (UWord) u.pb->val; - DeclareTmpHeapNoproc(id_heap,BIG_UINT_HEAP_SIZE*2); /* extra place allocated */ -#else DeclareTmpHeapNoproc(id_heap,BIG_UINT_HEAP_SIZE); -#endif Uint *hp = &id_heap[0]; InsertedBin *nib; -#if HALFWORD_HEAP - int actual_need = BIG_UWORD_HEAP_SIZE(val); - ASSERT(actual_need <= (BIG_UINT_HEAP_SIZE*2)); - UseTmpHeapNoproc(actual_need); - a.id = erts_bld_uword(&hp, NULL, (UWord) val); -#else UseTmpHeapNoproc(BIG_UINT_HEAP_SIZE); a.id = erts_bld_uint(&hp, NULL, (Uint) u.pb->val); -#endif erts_match_prog_foreach_offheap(u.pb->val, insert_offheap2, (void *) &a); @@ -1231,11 +1219,7 @@ insert_offheap(ErlOffHeap *oh, int type, Eterm id) nib->bin_val = u.pb->val; nib->next = inserted_bins; inserted_bins = nib; -#if HALFWORD_HEAP - UnUseTmpHeapNoproc(actual_need); -#else UnUseTmpHeapNoproc(BIG_UINT_HEAP_SIZE); -#endif } } break; diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h index 694ac84232..64278d2ea0 100644 --- a/erts/emulator/beam/erl_node_tables.h +++ b/erts/emulator/beam/erl_node_tables.h @@ -66,7 +66,7 @@ #define ERTS_DE_QFLGS_ALL (ERTS_DE_QFLG_BUSY \ | ERTS_DE_QFLG_EXIT) -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) #define ERTS_DIST_OUTPUT_BUF_DBG_PATTERN ((Uint) 0xf713f713f713f713UL) #else #define ERTS_DIST_OUTPUT_BUF_DBG_PATTERN ((Uint) 0xf713f713) diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index 5c38db1cbc..2c09834d19 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -1734,7 +1734,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) reds = ERTS_PORT_REDS_INPUT; ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0); DTRACE_DRIVER(driver_ready_input, pp); - /* NOTE some windows/ose drivers use ->ready_input + /* NOTE some windows drivers use ->ready_input for input and output */ (*pp->drv_ptr->ready_input)((ErlDrvData) pp->drv_data, ptp->u.alive.td.io.event); diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c index 2917d58932..45ba4371dc 100644 --- a/erts/emulator/beam/erl_printf_term.c +++ b/erts/emulator/beam/erl_printf_term.c @@ -117,13 +117,12 @@ do { \ /* return 0 if list is not a non-empty flat list of printable characters */ static int -is_printable_string(Eterm list, Eterm* base) -{ +is_printable_string(Eterm list) { int len = 0; int c; while(is_list(list)) { - Eterm* consp = list_val_rel(list, base); + Eterm* consp = list_val(list); Eterm hd = CAR(consp); if (!is_byte(hd)) @@ -260,9 +259,7 @@ static char *format_binary(Uint16 x, char *b) { #endif static int -print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, - Eterm* obj_base) /* ignored if !HALFWORD_HEAP */ -{ +print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount) { DECLARE_WSTACK(s); int res; int i; @@ -308,7 +305,7 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, obj = (Eterm) popped.word; L_print_one_cons: { - Eterm* cons = list_val_rel(obj, obj_base); + Eterm* cons = list_val(obj); Eterm tl; obj = CAR(cons); @@ -344,11 +341,7 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, PRINT_CHAR(res, fn, arg, '>'); goto L_done; } -#if HALFWORD_HEAP - wobj = is_immed(obj) ? (Wterm)obj : rterm2wterm(obj, obj_base); -#else wobj = (Wterm)obj; -#endif switch (tag_val_def(wobj)) { case NIL_DEF: PRINT_STRING(res, fn, arg, "[]"); @@ -424,10 +417,10 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, PRINT_CHAR(res, fn, arg, '>'); break; case LIST_DEF: - if (is_printable_string(obj, obj_base)) { + if (is_printable_string(obj)) { int c; PRINT_CHAR(res, fn, arg, '"'); - nobj = list_val_rel(obj, obj_base); + nobj = list_val(obj); while (1) { if ((*dcount)-- <= 0) goto L_done; @@ -441,7 +434,7 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, } if (is_not_list(*nobj)) break; - nobj = list_val_rel(*nobj, obj_base); + nobj = list_val(*nobj); } PRINT_CHAR(res, fn, arg, '"'); } else { @@ -469,11 +462,11 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, case BINARY_DEF: { byte* bytep; - Uint bytesize = binary_size_rel(obj,obj_base); + Uint bytesize = binary_size(obj); Uint bitoffs; Uint bitsize; byte octet; - ERTS_GET_BINARY_BYTES_REL(obj, bytep, bitoffs, bitsize, obj_base); + ERTS_GET_BINARY_BYTES(obj, bytep, bitoffs, bitsize); if (bitsize || !bytesize || !is_printable_ascii(bytep, bytesize, bitoffs)) { @@ -648,13 +641,11 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, int -erts_printf_term(fmtfn_t fn, void* arg, ErlPfEterm term, long precision, - ErlPfEterm* term_base) -{ +erts_printf_term(fmtfn_t fn, void* arg, ErlPfEterm term, long precision) { int res; ERTS_CT_ASSERT(sizeof(ErlPfEterm) == sizeof(Eterm)); - res = print_term(fn, arg, (Eterm)term, &precision, (Eterm*)term_base); + res = print_term(fn, arg, (Eterm)term, &precision); if (res < 0) return res; if (precision <= 0) diff --git a/erts/emulator/beam/erl_printf_term.h b/erts/emulator/beam/erl_printf_term.h index 87618a36d7..4618457f27 100644 --- a/erts/emulator/beam/erl_printf_term.h +++ b/erts/emulator/beam/erl_printf_term.h @@ -22,6 +22,5 @@ #define ERL_PRINTF_TERM_H__ #include "erl_printf_format.h" -int erts_printf_term(fmtfn_t fn, void* arg, ErlPfEterm term, long precision, - ErlPfEterm* term_base); +int erts_printf_term(fmtfn_t fn, void* arg, ErlPfEterm term, long precision); #endif diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 7135c0475e..15a6d5d651 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -58,11 +58,7 @@ #define ERTS_PROC_MIN_CONTEXT_SWITCH_REDS_COST (CONTEXT_REDS/10) -#ifndef ERTS_SCHED_MIN_SPIN #define ERTS_SCHED_SPIN_UNTIL_YIELD 100 -#else -#define ERTS_SCHED_SPIN_UNTIL_YIELD 1 -#endif #define ERTS_SCHED_SYS_SLEEP_SPINCOUNT_VERY_LONG 40 #define ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_VERY_LONG 1000 @@ -119,7 +115,7 @@ #define RUNQ_SET_RQ(X, RQ) erts_smp_atomic_set_nob((X), (erts_aint_t) (RQ)) #ifdef DEBUG -# if defined(ARCH_64) && !HALFWORD_HEAP +# if defined(ARCH_64) # define ERTS_DBG_SET_INVALID_RUNQP(RQP, N) \ (RUNQ_SET_RQ((RQP), (0xdeadbeefdead0003LL | ((N) << 4))) # define ERTS_DBG_VERIFY_VALID_RUNQP(RQP) \ @@ -152,12 +148,7 @@ extern BeamInstr beam_apply[]; extern BeamInstr beam_exit[]; extern BeamInstr beam_continue_exit[]; -#ifdef __OSE__ -/* Eager check I/O not supported on OSE yet. */ -int erts_eager_check_io = 0; -#else int erts_eager_check_io = 1; -#endif int erts_sched_compact_load; int erts_sched_balance_util = 0; Uint erts_no_schedulers; @@ -971,25 +962,10 @@ typedef struct { erts_smp_atomic32_t refc; } ErtsSchedWallTimeReq; -#if !HALFWORD_HEAP ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(swtreq, - ErtsSchedWallTimeReq, - 5, - ERTS_ALC_T_SCHED_WTIME_REQ) -#else -static ERTS_INLINE ErtsSchedWallTimeReq * -swtreq_alloc(void) -{ - return erts_alloc(ERTS_ALC_T_SCHED_WTIME_REQ, - sizeof(ErtsSchedWallTimeReq)); -} - -static ERTS_INLINE void -swtreq_free(ErtsSchedWallTimeReq *ptr) -{ - erts_free(ERTS_ALC_T_SCHED_WTIME_REQ, ptr); -} -#endif + ErtsSchedWallTimeReq, + 5, + ERTS_ALC_T_SCHED_WTIME_REQ) static void reply_sched_wall_time(void *vswtrp) @@ -2536,19 +2512,10 @@ try_set_sys_scheduling(void) #endif static ERTS_INLINE int -prepare_for_sys_schedule(ErtsSchedulerData *esdp, int non_blocking) +prepare_for_sys_schedule(int non_blocking) { if (non_blocking && erts_eager_check_io) { #ifdef ERTS_SMP -#ifdef ERTS_SCHED_ONLY_POLL_SCHED_1 - if (esdp->no != 1) { - /* If we are not scheduler 1 and ERTS_SCHED_ONLY_POLL_SCHED_1 is used - then we make sure to wake scheduler 1 */ - ErtsRunQueue *rq = ERTS_RUNQ_IX(0); - wake_scheduler(rq); - return 0; - } -#endif return try_set_sys_scheduling(); #else return 1; @@ -2558,16 +2525,6 @@ prepare_for_sys_schedule(ErtsSchedulerData *esdp, int non_blocking) #ifdef ERTS_SMP while (!erts_port_task_have_outstanding_io_tasks() && try_set_sys_scheduling()) { -#ifdef ERTS_SCHED_ONLY_POLL_SCHED_1 - if (esdp->no != 1) { - /* If we are not scheduler 1 and ERTS_SCHED_ONLY_POLL_SCHED_1 is used - then we make sure to wake scheduler 1 */ - ErtsRunQueue *rq = ERTS_RUNQ_IX(0); - clear_sys_scheduling(); - wake_scheduler(rq); - return 0; - } -#endif if (!erts_port_task_have_outstanding_io_tasks()) return 1; clear_sys_scheduling(); @@ -2891,8 +2848,6 @@ aux_thread(void *unused) erts_thr_progress_active(NULL, thr_prgr_active = 0); erts_thr_progress_prepare_wait(NULL); - ERTS_SCHED_FAIR_YIELD(); - flgs = sched_spin_wait(ssi, 0); if (flgs & ERTS_SSI_FLG_SLEEPING) { @@ -2960,7 +2915,7 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) * be waiting in erl_sys_schedule() */ - if (ERTS_SCHEDULER_IS_DIRTY(esdp) || !prepare_for_sys_schedule(esdp, 0)) { + if (ERTS_SCHEDULER_IS_DIRTY(esdp) || !prepare_for_sys_schedule(0)) { sched_waiting(esdp->no, rq); @@ -3025,8 +2980,6 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) erts_thr_progress_prepare_wait(esdp); } - ERTS_SCHED_FAIR_YIELD(); - flgs = sched_spin_wait(ssi, spincount); if (flgs & ERTS_SSI_FLG_SLEEPING) { ASSERT(flgs & ERTS_SSI_FLG_WAITING); @@ -3097,13 +3050,8 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) #ifdef ERTS_DIRTY_SCHEDULERS ASSERT(!ERTS_SCHEDULER_IS_DIRTY(esdp)); #endif - -#ifdef ERTS_SCHED_ONLY_POLL_SCHED_1 - ASSERT(esdp->no == 1); -#endif sched_waiting_sys(esdp->no, rq); - erts_smp_runq_unlock(rq); ASSERT(working); @@ -3173,7 +3121,7 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) * Got to check that we still got I/O tasks; otherwise * we have to continue checking for I/O... */ - if (!prepare_for_sys_schedule(esdp, 0)) { + if (!prepare_for_sys_schedule(0)) { spincount *= ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT; goto tse_wait; } @@ -3195,7 +3143,7 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) * Got to check that we still got I/O tasks; otherwise * we have to wait in erl_sys_schedule() after all... */ - if (!prepare_for_sys_schedule(esdp, 0)) { + if (!prepare_for_sys_schedule(0)) { /* * Not allowed to wait in erl_sys_schedule; * do tse wait instead... @@ -5316,17 +5264,11 @@ erts_early_init_scheduling(int no_schedulers) wakeup_other.threshold = ERTS_SCHED_WAKEUP_OTHER_THRESHOLD_MEDIUM; wakeup_other.type = ERTS_SCHED_WAKEUP_OTHER_TYPE_DEFAULT; #endif -#ifndef ERTS_SCHED_MIN_SPIN sched_busy_wait.sys_schedule = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_MEDIUM; sched_busy_wait.tse = (ERTS_SCHED_SYS_SLEEP_SPINCOUNT_MEDIUM * ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT); sched_busy_wait.aux_work = (ERTS_SCHED_SYS_SLEEP_SPINCOUNT_MEDIUM * ERTS_SCHED_AUX_WORK_SLEEP_SPINCOUNT_FACT_MEDIUM); -#else - sched_busy_wait.sys_schedule = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_NONE; - sched_busy_wait.tse = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_NONE; - sched_busy_wait.aux_work = ERTS_SCHED_SYS_SLEEP_SPINCOUNT_NONE; -#endif } int @@ -5510,9 +5452,6 @@ init_scheduler_data(ErtsSchedulerData* esdp, int num, esdp->f_reg_array = erts_alloc_permanent_cache_aligned(ERTS_ALC_T_BEAM_REGISTER, MAX_REG * sizeof(FloatDef)); -#if !HEAP_ON_C_STACK - esdp->num_tmp_heap_used = 0; -#endif #ifdef ERTS_DIRTY_SCHEDULERS if (ERTS_RUNQ_IX_IS_DIRTY(runq->ix)) { esdp->no = 0; @@ -5797,9 +5736,7 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online #endif init_misc_aux_work(); -#if !HALFWORD_HEAP init_swtreq_alloc(); -#endif erts_atomic32_init_nob(&debug_wait_completed_count, 0); /* debug only */ debug_wait_completed_flags = 0; @@ -7938,11 +7875,16 @@ sched_thread_func(void *vesdp) ErtsThrPrgrCallbacks callbacks; ErtsSchedulerData *esdp = vesdp; Uint no = esdp->no; +#ifdef ERTS_SMP + erts_tse_t *tse; +#endif erts_sched_init_time_sup(esdp); #ifdef ERTS_SMP - ERTS_SCHED_SLEEP_INFO_IX(no - 1)->event = erts_tse_fetch(); + tse = erts_tse_fetch(); + erts_tse_prepare_timed(tse); + ERTS_SCHED_SLEEP_INFO_IX(no - 1)->event = tse; callbacks.arg = (void *) esdp->ssi; callbacks.wakeup = thr_prgr_wakeup; callbacks.prepare_wait = thr_prgr_prep_wait; @@ -8204,18 +8146,12 @@ erts_start_schedulers(void) erts_snprintf(opts.name, 16, "%lu_scheduler", actual + 1); -#ifdef __OSE__ - /* This should be done in the bind strategy */ - opts.coreNo = (actual+1) % ose_num_cpus(); -#endif - res = ethr_thr_create(&esdp->tid, sched_thread_func, (void*)esdp, &opts); if (res != 0) { break; } } - erts_no_schedulers = actual; #ifdef ERTS_DIRTY_SCHEDULERS @@ -8244,10 +8180,6 @@ erts_start_schedulers(void) erts_snprintf(opts.name, 16, "aux"); -#ifdef __OSE__ - opts.coreNo = 0; -#endif /* __OSE__ */ - res = ethr_thr_create(&aux_tid, aux_thread, NULL, &opts); if (res != 0) erl_exit(1, "Failed to create aux thread\n"); @@ -8267,7 +8199,6 @@ erts_start_schedulers(void) actual, actual == 1 ? " was" : "s were"); erts_send_error_to_logger_nogl(dsbufp); } - } #endif /* ERTS_SMP */ @@ -8286,7 +8217,7 @@ add_pend_suspend(Process *suspendee, sizeof(ErtsPendingSuspend)); psp->next = NULL; #ifdef DEBUG -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) psp->end = (ErtsPendingSuspend *) 0xdeaddeaddeaddead; #else psp->end = (ErtsPendingSuspend *) 0xdeaddead; @@ -9412,12 +9343,10 @@ Process *schedule(Process *p, int calls) int leader_update = ERTS_SCHEDULER_IS_DIRTY(esdp) ? 0 : erts_thr_progress_update(esdp); aux_work = erts_atomic32_read_acqb(&esdp->ssi->aux_work); - if (aux_work | leader_update | ERTS_SCHED_FAIR) { + if (aux_work | leader_update) { erts_smp_runq_unlock(rq); if (leader_update) erts_thr_progress_leader_update(esdp); - else if (ERTS_SCHED_FAIR) - ERTS_SCHED_FAIR_YIELD(); if (aux_work) handle_aux_work(&esdp->aux_work_data, aux_work, 0); erts_smp_runq_lock(rq); @@ -9493,7 +9422,7 @@ Process *schedule(Process *p, int calls) } else if (!ERTS_SCHEDULER_IS_DIRTY(esdp) && (fcalls > input_reductions && - prepare_for_sys_schedule(esdp, !0))) { + prepare_for_sys_schedule(!0))) { ErtsMonotonicTime current_time; /* * Schedule system-level activities. @@ -10905,7 +10834,6 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). p->bin_vheap_sz = p->min_vheap_size; p->bin_old_vheap_sz = p->min_vheap_size; p->bin_old_vheap = 0; - p->bin_vheap_mature = 0; p->sys_task_qs = NULL; @@ -11125,7 +11053,6 @@ void erts_init_empty_process(Process *p) p->bin_old_vheap_sz = BIN_VH_MIN_SIZE; p->bin_old_vheap = 0; p->sys_task_qs = NULL; - p->bin_vheap_mature = 0; ERTS_PTMR_INIT(p); p->next = NULL; p->off_heap.first = NULL; @@ -12542,7 +12469,7 @@ stack_element_dump(int to, void *to_arg, Eterm* sp, int yreg) } if (is_CP(x)) { - erts_print(to, to_arg, "Return addr %p (", (Eterm *) EXPAND_POINTER(x)); + erts_print(to, to_arg, "Return addr %p (", (Eterm *) x); print_function_from_pc(to, to_arg, cp_val(x)); erts_print(to, to_arg, ")\n"); yreg = 0; diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 20ffe7ea7c..e7c5614b9c 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -632,12 +632,6 @@ struct ErtsSchedulerData_ { Process *free_process; ErtsThrPrgrData thr_progress_data; #endif -#if !HEAP_ON_C_STACK - Eterm tmp_heap[TMP_HEAP_SIZE]; - int num_tmp_heap_used; - Eterm beam_emu_tmp_heap[BEAM_EMU_TMP_HEAP_SIZE]; - Eterm erl_arith_tmp_heap[ERL_ARITH_TMP_HEAP_SIZE]; -#endif ErtsSchedulerSleepInfo *ssi; Process *current_process; Uint no; /* Scheduler number for normal schedulers */ @@ -691,13 +685,6 @@ extern ErtsAlignedSchedulerData *erts_aligned_dirty_io_scheduler_data; extern ErtsSchedulerData *erts_scheduler_data; #endif -#ifdef ERTS_SCHED_FAIR -#define ERTS_SCHED_FAIR_YIELD() ETHR_YIELD() -#else -#define ERTS_SCHED_FAIR 0 -#define ERTS_SCHED_FAIR_YIELD() -#endif - #if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK) int erts_smp_lc_runq_is_locked(ErtsRunQueue *); #endif @@ -911,7 +898,6 @@ struct ErtsPendingSuspend_ { # define MIN_VHEAP_SIZE(p) (p)->min_vheap_size # define BIN_VHEAP_SZ(p) (p)->bin_vheap_sz -# define BIN_VHEAP_MATURE(p) (p)->bin_vheap_mature # define BIN_OLD_VHEAP_SZ(p) (p)->bin_old_vheap_sz # define BIN_OLD_VHEAP(p) (p)->bin_old_vheap @@ -1030,7 +1016,6 @@ struct process { ErtsPSD *psd; /* Rarely used process specific data */ Uint64 bin_vheap_sz; /* Virtual heap block size for binaries */ - Uint64 bin_vheap_mature; /* Virtual heap block size for binaries */ Uint64 bin_old_vheap_sz; /* Virtual old heap block size for binaries */ Uint64 bin_old_vheap; /* Virtual old heap size for binaries */ diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c index 25f0b1ed38..3b8ae11e94 100644 --- a/erts/emulator/beam/erl_process_dump.c +++ b/erts/emulator/beam/erl_process_dump.c @@ -365,7 +365,7 @@ heap_dump(int to, void *to_arg, Eterm x) while (x != OUR_NIL) { if (is_CP(x)) { - next = (Eterm *) EXPAND_POINTER(x); + next = (Eterm *) x; } else if (is_list(x)) { ptr = list_val(x); if (ptr[0] != OUR_NIL) { @@ -378,7 +378,7 @@ heap_dump(int to, void *to_arg, Eterm x) ptr[1] = make_small(0); } x = ptr[0]; - ptr[0] = (Eterm) COMPRESS_POINTER(next); + ptr[0] = (Eterm) next; next = ptr + 1; continue; } @@ -408,7 +408,7 @@ heap_dump(int to, void *to_arg, Eterm x) ptr[0] = OUR_NIL; } else { x = ptr[arity]; - ptr[0] = (Eterm) COMPRESS_POINTER(next); + ptr[0] = (Eterm) next; next = ptr + arity - 1; continue; } diff --git a/erts/emulator/beam/erl_process_lock.h b/erts/emulator/beam/erl_process_lock.h index 788348e613..a64c993e8f 100644 --- a/erts/emulator/beam/erl_process_lock.h +++ b/erts/emulator/beam/erl_process_lock.h @@ -854,9 +854,6 @@ ERTS_GLB_INLINE void erts_proc_dec_refc(Process *p) #endif if (!referred) { ASSERT(ERTS_PROC_IS_EXITING(p)); - ASSERT(ERTS_AINT_NULL - == erts_ptab_pix2intptr_ddrb(&erts_proc, - internal_pid_index(p->common.id))); erts_free_proc(p); } } @@ -872,9 +869,6 @@ ERTS_GLB_INLINE void erts_proc_add_refc(Process *p, Sint add_refc) #endif if (!referred) { ASSERT(ERTS_PROC_IS_EXITING(p)); - ASSERT(ERTS_AINT_NULL - == erts_ptab_pix2intptr_ddrb(&erts_proc, - internal_pid_index(p->common.id))); erts_free_proc(p); } } diff --git a/erts/emulator/beam/erl_term.c b/erts/emulator/beam/erl_term.c index e5050bfaa5..ed302fa2fa 100644 --- a/erts/emulator/beam/erl_term.c +++ b/erts/emulator/beam/erl_term.c @@ -174,9 +174,7 @@ ET_DEFINE_CHECKED(Uint,external_thing_data_words,ExternalThing*,is_thing_ptr); ET_DEFINE_CHECKED(Eterm,make_cp,UWord *,_is_taggable_pointer); ET_DEFINE_CHECKED(UWord *,cp_val,Eterm,is_CP); ET_DEFINE_CHECKED(Uint,catch_val,Eterm,is_catch); -ET_DEFINE_CHECKED(Uint,x_reg_offset,Uint,_is_xreg); -ET_DEFINE_CHECKED(Uint,y_reg_offset,Uint,_is_yreg); -ET_DEFINE_CHECKED(Uint,x_reg_index,Uint,_is_xreg); -ET_DEFINE_CHECKED(Uint,y_reg_index,Uint,_is_yreg); +ET_DEFINE_CHECKED(Uint,loader_x_reg_index,Uint,_is_loader_x_reg); +ET_DEFINE_CHECKED(Uint,loader_y_reg_index,Uint,_is_loader_y_reg); #endif /* ET_DEBUG */ diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h index d5e91d80d9..01ef567dcd 100644 --- a/erts/emulator/beam/erl_term.h +++ b/erts/emulator/beam/erl_term.h @@ -21,34 +21,8 @@ #ifndef __ERL_TERM_H #define __ERL_TERM_H -#include "sys.h" /* defines HALFWORD_HEAP */ - typedef UWord Wterm; /* Full word terms */ -#if HALFWORD_HEAP -# define HEAP_ON_C_STACK 0 -# if HALFWORD_ASSERT -# ifdef ET_DEBUG -# undef ET_DEBUG -# endif -# define ET_DEBUG 1 -# endif -# if 1 -# define CHECK_POINTER_MASK 0xFFFFFFFF00000000UL -# define COMPRESS_POINTER(APointer) ((Eterm) (UWord) (APointer)) -# define EXPAND_POINTER(AnEterm) ((UWord) (AnEterm)) -# else -# define CHECK_POINTER_MASK 0x0UL -# define COMPRESS_POINTER(AnUint) (AnUint) -# define EXPAND_POINTER(APointer) (APointer) -# endif -#else -# define HEAP_ON_C_STACK 1 -# define CHECK_POINTER_MASK 0x0UL -# define COMPRESS_POINTER(AnUint) (AnUint) -# define EXPAND_POINTER(APointer) (APointer) -#endif - struct erl_node_; /* Declared in erl_node_tables.h */ /* @@ -190,15 +164,12 @@ struct erl_node_; /* Declared in erl_node_tables.h */ /* boxed object access methods */ -#if HALFWORD_HEAP -#define _is_taggable_pointer(x) (((UWord)(x) & (CHECK_POINTER_MASK | 0x3)) == 0) -#define _boxed_precond(x) (is_boxed(x)) -#else + #define _is_taggable_pointer(x) (((Uint)(x) & 0x3) == 0) #define _boxed_precond(x) (is_boxed(x)) -#endif + #define _is_aligned(x) (((Uint)(x) & 0x3) == 0) -#define _unchecked_make_boxed(x) ((Uint) COMPRESS_POINTER(x) + TAG_PRIMARY_BOXED) +#define _unchecked_make_boxed(x) ((Uint)(x) + TAG_PRIMARY_BOXED) _ET_DECLARE_CHECKED(Eterm,make_boxed,const Eterm*) #define make_boxed(x) _ET_APPLY(make_boxed,(x)) #if 1 @@ -209,12 +180,12 @@ _ET_DECLARE_CHECKED(int,is_boxed,Eterm) #else #define is_boxed(x) (((x) & _TAG_PRIMARY_MASK) == TAG_PRIMARY_BOXED) #endif -#define _unchecked_boxed_val(x) ((Eterm*) EXPAND_POINTER(((x) - TAG_PRIMARY_BOXED))) +#define _unchecked_boxed_val(x) ((Eterm*) ((x) - TAG_PRIMARY_BOXED)) _ET_DECLARE_CHECKED(Eterm*,boxed_val,Wterm) #define boxed_val(x) _ET_APPLY(boxed_val,(x)) /* cons cell ("list") access methods */ -#define _unchecked_make_list(x) ((Uint) COMPRESS_POINTER(x) + TAG_PRIMARY_LIST) +#define _unchecked_make_list(x) ((Uint)(x) + TAG_PRIMARY_LIST) _ET_DECLARE_CHECKED(Eterm,make_list,const Eterm*) #define make_list(x) _ET_APPLY(make_list,(x)) #if 1 @@ -226,12 +197,8 @@ _ET_DECLARE_CHECKED(int,is_not_list,Eterm) #define is_list(x) (((x) & _TAG_PRIMARY_MASK) == TAG_PRIMARY_LIST) #define is_not_list(x) (!is_list((x))) #endif -#if HALFWORD_HEAP #define _list_precond(x) (is_list(x)) -#else -#define _list_precond(x) (is_list(x)) -#endif -#define _unchecked_list_val(x) ((Eterm*) EXPAND_POINTER((x) - TAG_PRIMARY_LIST)) +#define _unchecked_list_val(x) ((Eterm*) ((x) - TAG_PRIMARY_LIST)) _ET_DECLARE_CHECKED(Eterm*,list_val,Wterm) #define list_val(x) _ET_APPLY(list_val,(x)) @@ -242,7 +209,7 @@ _ET_DECLARE_CHECKED(Eterm*,list_val,Wterm) #define CDR(x) ((x)[1]) /* generic tagged pointer (boxed or list) access methods */ -#define _unchecked_ptr_val(x) ((Eterm*) EXPAND_POINTER((x) & ~((Uint) 0x3))) +#define _unchecked_ptr_val(x) ((Eterm*) ((x) & ~((Uint) 0x3))) #define ptr_val(x) _unchecked_ptr_val((x)) /*XXX*/ #define _unchecked_offset_ptr(x,offs) ((x)+((offs)*sizeof(Eterm))) #define offset_ptr(x,offs) _unchecked_offset_ptr(x,offs) /*XXX*/ @@ -250,7 +217,7 @@ _ET_DECLARE_CHECKED(Eterm*,list_val,Wterm) #define byte_offset_ptr(x,offs) _unchecked_byte_offset_ptr(x,offs) /*XXX*/ /* fixnum ("small") access methods */ -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) #define SMALL_BITS (64-4) #define SMALL_DIGITS (17) #else @@ -396,11 +363,7 @@ _ET_DECLARE_CHECKED(Eterm*,fun_val,Wterm) _ET_DECLARE_CHECKED(Eterm*,export_val,Wterm) #define export_val(x) _ET_APPLY(export_val,(x)) #define is_export_header(x) ((x) == HEADER_EXPORT) -#if HALFWORD_HEAP -#define HEADER_EXPORT _make_header(2,_TAG_HEADER_EXPORT) -#else #define HEADER_EXPORT _make_header(1,_TAG_HEADER_EXPORT) -#endif /* bignum access methods */ #define make_pos_bignum_header(sz) _make_header((sz),_TAG_HEADER_POS_BIG) @@ -424,7 +387,7 @@ _ET_DECLARE_CHECKED(Eterm*,big_val,Wterm) #define big_val(x) _ET_APPLY(big_val,(x)) /* flonum ("float") access methods */ -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) #define HEADER_FLONUM _make_header(1,_TAG_HEADER_FLOAT) #else #define HEADER_FLONUM _make_header(2,_TAG_HEADER_FLOAT) @@ -445,12 +408,12 @@ typedef union float_def byte fb[sizeof(ieee754_8)]; Uint16 fs[sizeof(ieee754_8) / sizeof(Uint16)]; Uint32 fw[sizeof(ieee754_8) / sizeof(Uint32)]; -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) Uint fdw; #endif } FloatDef; -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) #define FLOAT_VAL_GET_DOUBLE(fval, f) (f).fdw = *((fval)+1) @@ -727,7 +690,7 @@ _ET_DECLARE_CHECKED(struct erl_node_*,internal_port_node,Eterm) #define ERTS_MAX_REF_NUMBERS 3 #define ERTS_REF_NUMBERS ERTS_MAX_REF_NUMBERS -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) # define ERTS_REF_WORDS (ERTS_REF_NUMBERS/2 + 1) # define ERTS_REF_32BIT_WORDS (ERTS_REF_NUMBERS+1) #else @@ -749,7 +712,7 @@ typedef struct { #define make_ref_thing_header(DW) \ _make_header((DW)+REF_THING_HEAD_SIZE-1,_TAG_HEADER_REF) -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) /* * Ref layout on a 64-bit little endian machine: @@ -1009,27 +972,20 @@ _ET_DECLARE_CHECKED(struct erl_node_*,external_ref_node,Eterm) #define MAP_HEADER_VAL(Hdr) (((Hdr) >> (_HEADER_ARITY_OFFS + MAP_HEADER_TAG_SZ + MAP_HEADER_ARITY_SZ)) & (0xffff)) #define make_hashmap(x) make_boxed((Eterm*)(x)) -#define make_hashmap_rel make_boxed_rel #define is_hashmap(x) (is_boxed((x)) && is_hashmap_header(*boxed_val((x)))) #define is_not_hashmap(x) (!is_hashmap(x)) -#define is_hashmap_rel(RTERM,BASE) is_hashmap(rterm2wterm(RTERM,BASE)) #define is_hashmap_header(x) (((x) & (_HEADER_MAP_HASHMAP_HEAD_MASK)) == HAMT_SUBTAG_HEAD_ARRAY) #define hashmap_val(x) _unchecked_boxed_val((x)) -#define hashmap_val_rel(RTERM, BASE) hashmap_val(rterm2wterm(RTERM, BASE)) #define make_flatmap(x) make_boxed((Eterm*)(x)) -#define make_flatmap_rel(x, BASE) make_boxed_rel((Eterm*)(x),(BASE)) #define is_flatmap(x) (is_boxed((x)) && is_flatmap_header(*boxed_val((x)))) -#define is_flatmap_rel(RTERM,BASE) is_flatmap(rterm2wterm(RTERM,BASE)) #define is_not_flatmap(x) (!is_flatmap((x))) #define is_flatmap_header(x) (((x) & (_HEADER_MAP_SUBTAG_MASK)) == HAMT_SUBTAG_HEAD_FLATMAP) #define flatmap_val(x) (_unchecked_boxed_val((x))) -#define flatmap_val_rel(RTERM, BASE) flatmap_val(rterm2wterm(RTERM, BASE)) #define is_map_header(x) (((x) & (_TAG_HEADER_MASK)) == _TAG_HEADER_MAP) #define is_map(x) (is_boxed((x)) && is_map_header(*boxed_val(x))) #define is_not_map(x) (!is_map(x)) -#define is_map_rel(RTERM,BASE) is_map(rterm2wterm(RTERM,BASE)) /* number tests */ @@ -1048,14 +1004,14 @@ _ET_DECLARE_CHECKED(struct erl_node_*,external_ref_node,Eterm) #error "fix yer arch, like" #endif -#define _unchecked_make_cp(x) ((Eterm) COMPRESS_POINTER(x)) +#define _unchecked_make_cp(x) ((Eterm)(x)) _ET_DECLARE_CHECKED(Eterm,make_cp,BeamInstr*) #define make_cp(x) _ET_APPLY(make_cp,(x)) #define is_not_CP(x) ((x) & _CPMASK) #define is_CP(x) (!is_not_CP(x)) -#define _unchecked_cp_val(x) ((BeamInstr*) EXPAND_POINTER(x)) +#define _unchecked_cp_val(x) ((BeamInstr*) (x)) _ET_DECLARE_CHECKED(BeamInstr*,cp_val,Eterm) #define cp_val(x) _ET_APPLY(cp_val,(x)) @@ -1071,44 +1027,40 @@ _ET_DECLARE_CHECKED(Uint,catch_val,Eterm) /* * Overloaded tags. * - * SMALL = 15 - * ATOM/NIL=7 + * In the loader, we want to tag a term in a way so that it can + * be any literal (atom/integer/float/tuple/list/binary) or a + * register. * - * Note that the two least significant bits in SMALL/ATOM/NIL always are 3; - * thus, we can distinguish register from literals by looking at only these - * two bits. + * We can achive that by overloading the PID and PORT tags to + * mean X and Y registers. That works because there are no + * pid or port literals. */ -#define X_REG_DEF 0 -#define Y_REG_DEF 1 -#define R_REG_DEF 2 - -#define beam_reg_tag(x) ((x) & 3) +#define _LOADER_TAG_XREG _TAG_IMMED1_PID +#define _LOADER_TAG_YREG _TAG_IMMED1_PORT +#define _LOADER_TAG_SIZE _TAG_IMMED1_SIZE +#define _LOADER_MASK _TAG_IMMED1_MASK -#define make_rreg() R_REG_DEF -#define make_xreg(ix) (((ix) * sizeof(Eterm)) | X_REG_DEF) -#define make_yreg(ix) (((ix) * sizeof(Eterm)) | Y_REG_DEF) +#define LOADER_X_REG _LOADER_TAG_XREG +#define LOADER_Y_REG _LOADER_TAG_YREG -#define _is_xreg(x) (beam_reg_tag(x) == X_REG_DEF) -#define _is_yreg(x) (beam_reg_tag(x) == Y_REG_DEF) +#define make_loader_x_reg(R) (((R) << _LOADER_TAG_SIZE) | _LOADER_TAG_XREG) +#define make_loader_y_reg(R) (((R) << _LOADER_TAG_SIZE) | _LOADER_TAG_YREG) -#define _unchecked_x_reg_offset(R) ((R) - X_REG_DEF) -_ET_DECLARE_CHECKED(Uint,x_reg_offset,Uint) -#define x_reg_offset(R) _ET_APPLY(x_reg_offset,(R)) +#define loader_reg_index(R) ((R) >> _LOADER_TAG_SIZE) -#define _unchecked_y_reg_offset(R) ((R) - Y_REG_DEF) -_ET_DECLARE_CHECKED(Uint,y_reg_offset,Uint) -#define y_reg_offset(R) _ET_APPLY(y_reg_offset,(R)) +#define loader_tag(T) ((T) & _LOADER_MASK) -#define reg_index(R) ((R) / sizeof(Eterm)) +#define _is_loader_x_reg(x) (loader_tag(x) == _LOADER_TAG_XREG) +#define _is_loader_y_reg(x) (loader_tag(x) == _LOADER_TAG_YREG) -#define _unchecked_x_reg_index(R) ((R) >> 2) -_ET_DECLARE_CHECKED(Uint,x_reg_index,Uint) -#define x_reg_index(R) _ET_APPLY(x_reg_index,(R)) +#define _unchecked_loader_x_reg_index(R) ((R) >> _LOADER_TAG_SIZE) +_ET_DECLARE_CHECKED(Uint,loader_x_reg_index,Uint) +#define loader_x_reg_index(R) _ET_APPLY(loader_x_reg_index,(R)) -#define _unchecked_y_reg_index(R) ((R) >> 2) -_ET_DECLARE_CHECKED(Uint,y_reg_index,Uint) -#define y_reg_index(R) _ET_APPLY(y_reg_index,(R)) +#define _unchecked_loader_y_reg_index(R) ((R) >> _LOADER_TAG_SIZE) +_ET_DECLARE_CHECKED(Uint,loader_y_reg_index,Uint) +#define loader_y_reg_index(R) _ET_APPLY(loader_y_reg_index,(R)) /* * Backwards compatibility definitions: @@ -1160,82 +1112,7 @@ extern unsigned tag_val_def(Wterm); #define FLOAT_BIG _NUMBER_CODE(FLOAT_DEF,BIG_DEF) #define FLOAT_FLOAT _NUMBER_CODE(FLOAT_DEF,FLOAT_DEF) -#if HALFWORD_HEAP -#define ptr2rel(PTR,BASE) ((Eterm*)((char*)(PTR) - (char*)(BASE))) -#define rterm2wterm(REL,BASE) ((Wterm)(REL) + (Wterm)(BASE)) - -#else /* HALFWORD_HEAP */ - -#define ptr2rel(PTR,BASE) (PTR) -#define rterm2wterm(REL,BASE) (REL) - -#endif /* !HALFWORD_HEAP */ - -#define make_list_rel(PTR, BASE) make_list(ptr2rel(PTR,BASE)) -#define make_boxed_rel(PTR, BASE) make_boxed(ptr2rel(PTR,BASE)) -#define make_fun_rel make_boxed_rel -#define make_binary_rel make_boxed_rel -#define make_tuple_rel make_boxed_rel -#define make_external_rel make_boxed_rel -#define make_internal_ref_rel make_boxed_rel -#define make_big_rel make_boxed_rel - -#define binary_val_rel(RTERM, BASE) binary_val(rterm2wterm(RTERM, BASE)) -#define list_val_rel(RTERM, BASE) list_val(rterm2wterm(RTERM, BASE)) -#define boxed_val_rel(RTERM, BASE) boxed_val(rterm2wterm(RTERM, BASE)) -#define tuple_val_rel(RTERM, BASE) tuple_val(rterm2wterm(RTERM, BASE)) -#define export_val_rel(RTERM, BASE) export_val(rterm2wterm(RTERM, BASE)) -#define fun_val_rel(RTERM, BASE) fun_val(rterm2wterm(RTERM, BASE)) -#define big_val_rel(RTERM,BASE) big_val(rterm2wterm(RTERM,BASE)) -#define float_val_rel(RTERM,BASE) float_val(rterm2wterm(RTERM,BASE)) -#define internal_ref_val_rel(RTERM,BASE) internal_ref_val(rterm2wterm(RTERM,BASE)) - -#define external_thing_ptr_rel(RTERM, BASE) external_thing_ptr(rterm2wterm(RTERM, BASE)) -#define external_data_words_rel(RTERM,BASE) external_data_words(rterm2wterm(RTERM,BASE)) - -#define external_port_node_rel(RTERM,BASE) external_port_node(rterm2wterm(RTERM,BASE)) -#define external_port_data_rel(RTERM,BASE) external_port_data(rterm2wterm(RTERM,BASE)) - -#define is_external_pid_rel(RTERM,BASE) is_external_pid(rterm2wterm(RTERM,BASE)) -#define external_pid_node_rel(RTERM,BASE) external_pid_node(rterm2wterm(RTERM,BASE)) -#define external_pid_data_rel(RTERM,BASE) external_pid_data(rterm2wterm(RTERM,BASE)) - -#define is_binary_rel(RTERM,BASE) is_binary(rterm2wterm(RTERM,BASE)) -#define is_float_rel(RTERM,BASE) is_float(rterm2wterm(RTERM,BASE)) -#define is_fun_rel(RTERM,BASE) is_fun(rterm2wterm(RTERM,BASE)) -#define is_big_rel(RTERM,BASE) is_big(rterm2wterm(RTERM,BASE)) -#define is_export_rel(RTERM,BASE) is_export(rterm2wterm(RTERM,BASE)) -#define is_tuple_rel(RTERM,BASE) is_tuple(rterm2wterm(RTERM,BASE)) - -#define GET_DOUBLE_REL(RTERM, f, BASE) GET_DOUBLE(rterm2wterm(RTERM,BASE), f) - -#define ref_thing_ptr_rel(RTERM,BASE) ref_thing_ptr(rterm2wterm(RTERM,BASE)) -#define is_internal_ref_rel(RTERM,BASE) is_internal_ref(rterm2wterm(RTERM,BASE)) -#define is_external_rel(RTERM,BASE) is_external(rterm2wterm(RTERM,BASE)) -#define is_external_port_rel(RTERM,BASE) is_external_port(rterm2wterm(RTERM,BASE)) -#define is_external_ref_rel(RTERM,BASE) is_external_ref(rterm2wterm(RTERM,BASE)) - -#define external_node_rel(RTERM,BASE) external_node(rterm2wterm(RTERM,BASE)) - - -#if HALFWORD_HEAP -ERTS_GLB_INLINE int is_same(Eterm a, Eterm* a_base, Eterm b, Eterm* b_base); - -#if ERTS_GLB_INLINE_INCL_FUNC_DEF -ERTS_GLB_INLINE int is_same(Eterm a, Eterm* a_base, Eterm b, Eterm* b_base) -{ - /* If bases differ, assume a and b are on different "heaps", - ie can only be same if immed */ - ASSERT(a_base == b_base || is_immed(a) || is_immed(b) - || rterm2wterm(a,a_base) != rterm2wterm(b,b_base)); - - return a == b && (a_base == b_base || is_immed(a)); -} -#endif - -#else /* !HALFWORD_HEAP */ -#define is_same(A,A_BASE,B,B_BASE) ((A)==(B)) -#endif +#define is_same(A,B) ((A)==(B)) #endif /* __ERL_TERM_H */ diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h index 5347979372..34f91e2ec8 100644 --- a/erts/emulator/beam/erl_threads.h +++ b/erts/emulator/beam/erl_threads.h @@ -649,6 +649,7 @@ ERTS_GLB_INLINE void erts_tsd_set(erts_tsd_key_t key, void *value); ERTS_GLB_INLINE void * erts_tsd_get(erts_tsd_key_t key); ERTS_GLB_INLINE erts_tse_t *erts_tse_fetch(void); ERTS_GLB_INLINE void erts_tse_return(erts_tse_t *ep); +ERTS_GLB_INLINE void erts_tse_prepare_timed(erts_tse_t *ep); ERTS_GLB_INLINE void erts_tse_set(erts_tse_t *ep); ERTS_GLB_INLINE void erts_tse_reset(erts_tse_t *ep); ERTS_GLB_INLINE int erts_tse_wait(erts_tse_t *ep); @@ -3461,6 +3462,15 @@ ERTS_GLB_INLINE void erts_tse_return(erts_tse_t *ep) #endif } +ERTS_GLB_INLINE void erts_tse_prepare_timed(erts_tse_t *ep) +{ +#ifdef USE_THREADS + int res = ethr_event_prepare_timed(&((ethr_ts_event *) ep)->event); + if (res != 0) + erts_thr_fatal_error(res, "prepare timed"); +#endif +} + ERTS_GLB_INLINE void erts_tse_set(erts_tse_t *ep) { #ifdef USE_THREADS diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index e1b03a057f..e9dd96efc4 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -1677,12 +1677,7 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, args = transformed_args; if (is_internal_port(*tracer_pid)) { -#if HEAP_ON_C_STACK Eterm local_heap[64+MAX_ARG]; -#else - Eterm *local_heap = erts_alloc(ERTS_ALC_T_TEMP_TERM, - sizeof(Eterm)*(64+MAX_ARG)); -#endif hp = local_heap; if (!erts_is_valid_tracer_port(*tracer_pid)) { @@ -1697,9 +1692,6 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, if (is_not_nil(tracee)) erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR); #endif -#if !HEAP_ON_C_STACK - erts_free(ERTS_ALC_T_TEMP_TERM,local_heap); -#endif UnUseTmpHeap(ERL_SUB_BIN_SIZE,p); return 0; } @@ -1727,9 +1719,6 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, ERTS_PAM_TMP_RESULT, &return_flags); if (is_non_value(pam_result)) { erts_match_set_release_result(p); -#if !HEAP_ON_C_STACK - erts_free(ERTS_ALC_T_TEMP_TERM,local_heap); -#endif UnUseTmpHeap(ERL_SUB_BIN_SIZE,p); return 0; } @@ -1738,9 +1727,6 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, /* Meta trace */ if (pam_result == am_false) { erts_match_set_release_result(p); -#if !HEAP_ON_C_STACK - erts_free(ERTS_ALC_T_TEMP_TERM,local_heap); -#endif UnUseTmpHeap(ERL_SUB_BIN_SIZE,p); return return_flags; } @@ -1748,17 +1734,11 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, /* Non-meta trace */ if (*tracee_flags & F_TRACE_SILENT) { erts_match_set_release_result(p); -#if !HEAP_ON_C_STACK - erts_free(ERTS_ALC_T_TEMP_TERM,local_heap); -#endif UnUseTmpHeap(ERL_SUB_BIN_SIZE,p); return 0; } if (pam_result == am_false) { erts_match_set_release_result(p); -#if !HEAP_ON_C_STACK - erts_free(ERTS_ALC_T_TEMP_TERM,local_heap); -#endif UnUseTmpHeap(ERL_SUB_BIN_SIZE,p); return return_flags; } @@ -1802,9 +1782,6 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, send_to_port(p, mess, tracer_pid, tracee_flags); erts_smp_mtx_unlock(&smq_mtx); erts_match_set_release_result(p); -#if !HEAP_ON_C_STACK - erts_free(ERTS_ALC_T_TEMP_TERM,local_heap); -#endif UnUseTmpHeap(ERL_SUB_BIN_SIZE,p); return *tracer_pid == NIL ? 0 : return_flags; @@ -1823,7 +1800,6 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec, #ifdef DEBUG Eterm* limit; #endif - ASSERT(is_internal_pid(*tracer_pid)); tracer = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN, @@ -3297,8 +3273,6 @@ sys_msg_dispatcher_func(void *unused) if (erts_thr_progress_update(NULL)) erts_thr_progress_leader_update(NULL); - ERTS_SCHED_FAIR_YIELD(); - #ifdef DEBUG_PRINTOUTS print_msg_type(smqp); #endif @@ -3453,9 +3427,6 @@ static void init_sys_msg_dispatcher(void) { erts_smp_thr_opts_t thr_opts = ERTS_SMP_THR_OPTS_DEFAULT_INITER; -#ifdef __OSE__ - thr_opts.coreNo = 0; -#endif thr_opts.detached = 1; thr_opts.name = "sys_msg_dispatcher"; init_smq_element_alloc(); @@ -3463,7 +3434,6 @@ init_sys_msg_dispatcher(void) sys_message_queue_end = NULL; erts_smp_cnd_init(&smq_cnd); erts_smp_mtx_init(&smq_mtx, "sys_msg_q"); - erts_smp_thr_create(&sys_msg_dispatcher_tid, sys_msg_dispatcher_func, NULL, diff --git a/erts/emulator/beam/erl_utils.h b/erts/emulator/beam/erl_utils.h index 6dab3bf297..4058d63eaf 100644 --- a/erts/emulator/beam/erl_utils.h +++ b/erts/emulator/beam/erl_utils.h @@ -157,32 +157,15 @@ void erts_init_utils_mem(void); erts_dsprintf_buf_t *erts_create_tmp_dsbuf(Uint); void erts_destroy_tmp_dsbuf(erts_dsprintf_buf_t *); -#if HALFWORD_HEAP -int eq_rel(Eterm a, Eterm* a_base, Eterm b, Eterm* b_base); -# define eq(A,B) eq_rel(A,NULL,B,NULL) -#else int eq(Eterm, Eterm); -# define eq_rel(A,A_BASE,B,B_BASE) eq(A,B) -#endif #define EQ(x,y) (((x) == (y)) || (is_not_both_immed((x),(y)) && eq((x),(y)))) -#if HALFWORD_HEAP -Sint erts_cmp_rel_opt(Eterm, Eterm*, Eterm, Eterm*, int, int); -#define cmp_rel(A,A_BASE,B,B_BASE) erts_cmp_rel_opt(A,A_BASE,B,B_BASE,0,0) -#define cmp_rel_term(A,A_BASE,B,B_BASE) erts_cmp_rel_opt(A,A_BASE,B,B_BASE,1,0) -#define CMP(A,B) erts_cmp_rel_opt(A,NULL,B,NULL,0,0) -#define CMP_TERM(A,B) erts_cmp_rel_opt(A,NULL,B,NULL,1,0) -#define CMP_EQ_ONLY(A,B) erts_cmp_rel_opt(A,NULL,B,NULL,0,1) -#else Sint erts_cmp(Eterm, Eterm, int, int); Sint cmp(Eterm a, Eterm b); -#define cmp_rel(A,A_BASE,B,B_BASE) erts_cmp(A,B,0,0) -#define cmp_rel_term(A,A_BASE,B,B_BASE) erts_cmp(A,B,1,0) #define CMP(A,B) erts_cmp(A,B,0,0) #define CMP_TERM(A,B) erts_cmp(A,B,1,0) #define CMP_EQ_ONLY(A,B) erts_cmp(A,B,0,1) -#endif #define cmp_lt(a,b) (CMP((a),(b)) < 0) #define cmp_le(a,b) (CMP((a),(b)) <= 0) diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h index 8948ca2ea9..98f27a1725 100644 --- a/erts/emulator/beam/erl_vm.h +++ b/erts/emulator/beam/erl_vm.h @@ -40,14 +40,6 @@ #define MAX_ARG 255 /* Max number of arguments allowed */ #define MAX_REG 1024 /* Max number of x(N) registers used */ -/* Scheduler stores data for temporary heaps if - !HEAP_ON_C_STACK. Macros (*TmpHeap*) in global.h selects if we put temporary - heap data on the C stack or if we use the buffers in the scheduler data. */ -#define TMP_HEAP_SIZE 128 /* Number of Eterm in the schedulers - small heap for transient heap data */ -#define ERL_ARITH_TMP_HEAP_SIZE 4 /* as does erl_arith... */ -#define BEAM_EMU_TMP_HEAP_SIZE 2 /* and beam_emu... */ - /* * The new arithmetic operations need some extra X registers in the register array. * so does the gc_bif's (i_gc_bif3 need 3 extra). @@ -117,12 +109,8 @@ #define HeapWordsLeft(p) (HEAP_LIMIT(p) - HEAP_TOP(p)) #if defined(DEBUG) || defined(CHECK_FOR_HOLES) -#if HALFWORD_HEAP -# define ERTS_HOLE_MARKER (0xdeadbeef) -#else # define ERTS_HOLE_MARKER (((0xdeadbeef << 24) << 8) | 0xdeadbeef) -#endif -#endif +#endif /* egil: 32-bit ? */ /* * Allocate heap memory on the ordinary heap, NEVER in a heap @@ -153,6 +141,7 @@ typedef struct op_entry { char* name; /* Name of instruction. */ Uint32 mask[3]; /* Signature mask. */ + unsigned involves_r; /* Needs special attention when matching. */ int sz; /* Number of loaded words. */ char* pack; /* Instructions for packing engine. */ char* sign; /* Signature string. */ diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index c6d7e3fcc5..c3e93d1ad2 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -2339,10 +2339,6 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Eterm val; FloatDef f; Sint r = 0; -#if HALFWORD_HEAP - UWord wobj; -#endif - if (ctx) { WSTACK_CHANGE_ALLOCATOR(s, ERTS_ALC_T_SAVED_ESTACK); @@ -2362,11 +2358,8 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, outer_loop: while (!WSTACK_ISEMPTY(s)) { -#if HALFWORD_HEAP - obj = (Eterm) (wobj = WSTACK_POP(s)); -#else obj = WSTACK_POP(s); -#endif + switch (val = WSTACK_POP(s)) { case ENC_TERM: break; @@ -2384,11 +2377,7 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, break; case ENC_PATCH_FUN_SIZE: { -#if HALFWORD_HEAP - byte* size_p = (byte *) wobj; -#else byte* size_p = (byte *) obj; -#endif put_int32(ep - size_p, size_p); } goto outer_loop; @@ -2435,21 +2424,13 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, case ENC_LAST_ARRAY_ELEMENT: /* obj is the tuple */ { -#if HALFWORD_HEAP - Eterm* ptr = (Eterm *) wobj; -#else Eterm* ptr = (Eterm *) obj; -#endif obj = *ptr; } break; default: /* ENC_LAST_ARRAY_ELEMENT+1 and upwards */ { -#if HALFWORD_HEAP - Eterm* ptr = (Eterm *) wobj; -#else Eterm* ptr = (Eterm *) obj; -#endif obj = *ptr++; WSTACK_PUSH2(s, val-1, (UWord)ptr); } @@ -2977,7 +2958,7 @@ dec_term(ErtsDistExternal *edep, case B2TDecodeList: objp = next - 2; while (n > 0) { - objp[0] = (Eterm) COMPRESS_POINTER(next); + objp[0] = (Eterm) next; objp[1] = make_list(next); next = objp; objp -= 2; @@ -2988,7 +2969,7 @@ dec_term(ErtsDistExternal *edep, case B2TDecodeTuple: objp = next - 1; while (n-- > 0) { - objp[0] = (Eterm) COMPRESS_POINTER(next); + objp[0] = (Eterm) next; next = objp; objp--; } @@ -3041,7 +3022,7 @@ dec_term(ErtsDistExternal *edep, while (next != NULL) { objp = next; - next = (Eterm *) EXPAND_POINTER(*objp); + next = (Eterm *) *objp; switch (*ep++) { case INTEGER_EXT: @@ -3049,7 +3030,7 @@ dec_term(ErtsDistExternal *edep, Sint sn = get_int32(ep); ep += 4; -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) *objp = make_small(sn); #else if (MY_IS_SSMALL(sn)) { @@ -3172,7 +3153,7 @@ dec_term_atom_common: reds -= n; } while (n-- > 0) { - objp[0] = (Eterm) COMPRESS_POINTER(next); + objp[0] = (Eterm) next; next = objp; objp--; } @@ -3190,8 +3171,8 @@ dec_term_atom_common: *objp = make_list(hp); hp += 2 * n; objp = hp - 2; - objp[0] = (Eterm) COMPRESS_POINTER((objp+1)); - objp[1] = (Eterm) COMPRESS_POINTER(next); + objp[0] = (Eterm) (objp+1); + objp[1] = (Eterm) next; next = objp; objp -= 2; n--; @@ -3204,7 +3185,7 @@ dec_term_atom_common: reds -= n; } while (n > 0) { - objp[0] = (Eterm) COMPRESS_POINTER(next); + objp[0] = (Eterm) next; objp[1] = make_list(next); next = objp; objp -= 2; @@ -3371,7 +3352,7 @@ dec_term_atom_common: RefThing *rtp = (RefThing *) hp; ref_num = (Uint32 *) (hp + REF_THING_HEAD_SIZE); -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) hp += REF_THING_HEAD_SIZE + ref_words/2 + 1; rtp->header = make_ref_thing_header(ref_words/2 + 1); #else @@ -3382,13 +3363,13 @@ dec_term_atom_common: } else { ExternalThing *etp = (ExternalThing *) hp; -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) hp += EXTERNAL_THING_HEAD_SIZE + ref_words/2 + 1; #else hp += EXTERNAL_THING_HEAD_SIZE + ref_words; #endif -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) etp->header = make_external_ref_header(ref_words/2 + 1); #else etp->header = make_external_ref_header(ref_words); @@ -3401,7 +3382,7 @@ dec_term_atom_common: ref_num = &(etp->data.ui32[0]); } -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) *(ref_num++) = ref_words /* 32-bit arity */; #endif ref_num[0] = r0; @@ -3409,7 +3390,7 @@ dec_term_atom_common: ref_num[i] = get_int32(ep); ep += 4; } -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) if ((1 + ref_words) % 2) ref_num[ref_words] = 0; #endif @@ -3561,12 +3542,7 @@ dec_term_atom_common: } *objp = make_export(hp); *hp++ = HEADER_EXPORT; -#if HALFWORD_HEAP - *((UWord *) (UWord) hp) = (UWord) erts_export_get_or_make_stub(mod, name, arity); - hp += 2; -#else *hp++ = (Eterm) erts_export_get_or_make_stub(mod, name, arity); -#endif break; } break; @@ -3600,7 +3576,7 @@ dec_term_atom_common: * The list of maps is for later validation. */ - mp->thing_word = (Eterm) COMPRESS_POINTER(maps_list); + mp->thing_word = (Eterm) maps_list; maps_list = (Eterm *) mp; mp->size = size; @@ -3608,8 +3584,8 @@ dec_term_atom_common: *objp = make_flatmap(mp); for (n = size; n; n--) { - *vptr = (Eterm) COMPRESS_POINTER(next); - *kptr = (Eterm) COMPRESS_POINTER(vptr); + *vptr = (Eterm) next; + *kptr = (Eterm) vptr; next = kptr; vptr--; kptr--; @@ -3623,8 +3599,8 @@ dec_term_atom_common: hamt->leaf_array = hp; for (n = size; n; n--) { - CDR(hp) = (Eterm) COMPRESS_POINTER(next); - CAR(hp) = (Eterm) COMPRESS_POINTER(&CDR(hp)); + CDR(hp) = (Eterm) next; + CAR(hp) = (Eterm) &CDR(hp); next = &CAR(hp); hp += 2; } @@ -3701,11 +3677,11 @@ dec_term_atom_common: /* Environment */ for (i = num_free-1; i >= 0; i--) { - funp->env[i] = (Eterm) COMPRESS_POINTER(next); + funp->env[i] = (Eterm) next; next = funp->env + i; } /* Creator */ - funp->creator = (Eterm) COMPRESS_POINTER(next); + funp->creator = (Eterm) next; next = &(funp->creator); break; } @@ -3774,7 +3750,7 @@ dec_term_atom_common: /* Environment */ for (i = num_free-1; i >= 0; i--) { - funp->env[i] = (Eterm) COMPRESS_POINTER(next); + funp->env[i] = (Eterm) next; next = funp->env + i; } break; @@ -3870,11 +3846,11 @@ dec_term_atom_common: */ while (maps_list) { - next = (Eterm *)(EXPAND_POINTER(*maps_list)); + next = (Eterm *) *maps_list; *maps_list = MAP_HEADER_FLATMAP; if (!erts_validate_and_sort_flatmap((flatmap_t*)maps_list)) goto error; - maps_list = next; + maps_list = next; } ASSERT(hp <= factory->hp_end @@ -3900,7 +3876,7 @@ dec_term_atom_common: PSTACK_DESTROY(hamt_array); } - ASSERT((Eterm*)EXPAND_POINTER(*dbg_resultp) != NULL); + ASSERT((Eterm*)*dbg_resultp != NULL); if (ctx) { ctx->state = B2TDone; @@ -4192,11 +4168,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, case EXPORT_DEF: { Export* ep = *((Export **) (export_val(obj) + 1)); -#if HALFWORD_HEAP - result += 2; -#else result += 1; -#endif result += encode_size_struct2(acmp, ep->code[0], dflags); result += encode_size_struct2(acmp, ep->code[1], dflags); result += encode_size_struct2(acmp, make_small(ep->code[2]), dflags); @@ -4311,7 +4283,7 @@ init_done: switch (tag) { case INTEGER_EXT: SKIP(4); -#if !defined(ARCH_64) || HALFWORD_HEAP +#if !defined(ARCH_64) heap_size += BIG_UINT_HEAP_SIZE; #endif break; @@ -4400,7 +4372,7 @@ init_done: ep += 2; atom_extra_skip = 1 + 4*id_words; /* In case it is an external ref */ -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) heap_size += EXTERNAL_THING_HEAD_SIZE + id_words/2 + 1; #else heap_size += EXTERNAL_THING_HEAD_SIZE + id_words; @@ -4486,11 +4458,7 @@ init_done: break; case EXPORT_EXT: terms += 3; -#if HALFWORD_HEAP - heap_size += 3; -#else heap_size += 2; -#endif break; case NEW_FUN_EXT: { diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index ec9296d034..b4d02dd1dd 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -310,9 +310,6 @@ typedef union { typedef struct proc_bin { Eterm thing_word; /* Subtag REFC_BINARY_SUBTAG. */ Uint size; /* Binary size in bytes. */ -#if HALFWORD_HEAP - void* dummy_ptr_padding__; -#endif struct erl_off_heap_header *next; Binary *val; /* Pointer to Binary structure. */ byte *bytes; /* Pointer to the actual data bytes. */ @@ -957,31 +954,12 @@ __decl_noreturn void __noreturn erl_exit_flush_async(int n, char*, ...); void erl_error(char*, va_list); /* copy.c */ -Eterm copy_object(Eterm, Process*); - -#if HALFWORD_HEAP -Uint size_object_rel(Eterm, Eterm*); -# define size_object(A) size_object_rel(A,NULL) - -Eterm copy_struct_rel(Eterm, Uint, Eterm**, ErlOffHeap*, Eterm* src_base, Eterm* dst_base); -# define copy_struct(OBJ,SZ,HPP,OH) copy_struct_rel(OBJ,SZ,HPP,OH, NULL,NULL) - -Eterm copy_shallow_rel(Eterm*, Uint, Eterm**, ErlOffHeap*, Eterm* src_base); -# define copy_shallow(A,B,C,D) copy_shallow_rel(A,B,C,D,NULL) - -#else /* !HALFWORD_HEAP */ +Eterm copy_object_x(Eterm, Process*, Uint); +#define copy_object(Term, Proc) copy_object_x(Term,Proc,0) Uint size_object(Eterm); -# define size_object_rel(A,B) size_object(A) - Eterm copy_struct(Eterm, Uint, Eterm**, ErlOffHeap*); -# define copy_struct_rel(OBJ,SZ,HPP,OH, SB,DB) copy_struct(OBJ,SZ,HPP,OH) - Eterm copy_shallow(Eterm*, Uint, Eterm**, ErlOffHeap*); -# define copy_shallow_rel(A,B,C,D, BASE) copy_shallow(A,B,C,D) - -#endif - void move_multi_frags(Eterm** hpp, ErlOffHeap*, ErlHeapFragment* first, Eterm* refs, unsigned nrefs); @@ -1180,7 +1158,7 @@ void bin_write(int, void*, byte*, size_t); int intlist_to_buf(Eterm, char*, int); /* most callers pass plain char*'s */ struct Sint_buf { -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) char s[22]; #else char s[12]; @@ -1466,69 +1444,16 @@ erts_alloc_message_heap(Uint size, #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */ -#if !HEAP_ON_C_STACK -# if defined(DEBUG) -# define DeclareTmpHeap(VariableName,Size,Process) \ - Eterm *VariableName = erts_debug_allocate_tmp_heap(Size,Process) -# define DeclareTypedTmpHeap(Type,VariableName,Process) \ - Type *VariableName = (Type *) erts_debug_allocate_tmp_heap(sizeof(Type)/sizeof(Eterm),Process) -# define DeclareTmpHeapNoproc(VariableName,Size) \ - Eterm *VariableName = erts_debug_allocate_tmp_heap(Size,NULL) -# define UseTmpHeap(Size,Proc) \ - do { \ - erts_debug_use_tmp_heap((Size),(Proc)); \ - } while (0) -# define UnUseTmpHeap(Size,Proc) \ - do { \ - erts_debug_unuse_tmp_heap((Size),(Proc)); \ - } while (0) -# define UseTmpHeapNoproc(Size) \ - do { \ - erts_debug_use_tmp_heap(Size,NULL); \ - } while (0) -# define UnUseTmpHeapNoproc(Size) \ - do { \ - erts_debug_unuse_tmp_heap(Size,NULL); \ - } while (0) -# else -# define DeclareTmpHeap(VariableName,Size,Process) \ - Eterm *VariableName = (ERTS_PROC_GET_SCHDATA(Process)->tmp_heap)+(ERTS_PROC_GET_SCHDATA(Process)->num_tmp_heap_used) -# define DeclareTypedTmpHeap(Type,VariableName,Process) \ - Type *VariableName = (Type *) (ERTS_PROC_GET_SCHDATA(Process)->tmp_heap)+(ERTS_PROC_GET_SCHDATA(Process)->num_tmp_heap_used) -# define DeclareTmpHeapNoproc(VariableName,Size) \ - Eterm *VariableName = (erts_get_scheduler_data()->tmp_heap)+(erts_get_scheduler_data()->num_tmp_heap_used) -# define UseTmpHeap(Size,Proc) \ - do { \ - ERTS_PROC_GET_SCHDATA(Proc)->num_tmp_heap_used += (Size); \ - } while (0) -# define UnUseTmpHeap(Size,Proc) \ - do { \ - ERTS_PROC_GET_SCHDATA(Proc)->num_tmp_heap_used -= (Size); \ - } while (0) -# define UseTmpHeapNoproc(Size) \ - do { \ - erts_get_scheduler_data()->num_tmp_heap_used += (Size); \ - } while (0) -# define UnUseTmpHeapNoproc(Size) \ - do { \ - erts_get_scheduler_data()->num_tmp_heap_used -= (Size); \ - } while (0) - - -# endif - -#else -# define DeclareTmpHeap(VariableName,Size,Process) \ +#define DeclareTmpHeap(VariableName,Size,Process) \ Eterm VariableName[Size] -# define DeclareTypedTmpHeap(Type,VariableName,Process) \ +#define DeclareTypedTmpHeap(Type,VariableName,Process) \ Type VariableName[1] -# define DeclareTmpHeapNoproc(VariableName,Size) \ +#define DeclareTmpHeapNoproc(VariableName,Size) \ Eterm VariableName[Size] -# define UseTmpHeap(Size,Proc) /* Nothing */ -# define UnUseTmpHeap(Size,Proc) /* Nothing */ -# define UseTmpHeapNoproc(Size) /* Nothing */ -# define UnUseTmpHeapNoproc(Size) /* Nothing */ -#endif /* HEAP_ON_C_STACK */ +#define UseTmpHeap(Size,Proc) /* Nothing */ +#define UnUseTmpHeap(Size,Proc) /* Nothing */ +#define UseTmpHeapNoproc(Size) /* Nothing */ +#define UnUseTmpHeapNoproc(Size) /* Nothing */ ERTS_GLB_INLINE void dtrace_pid_str(Eterm pid, char *process_buf); ERTS_GLB_INLINE void dtrace_proc_str(Process *process, char *process_buf); diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 900616c981..fdd26fcc4b 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -52,9 +52,7 @@ #include "erl_hl_timer.h" extern ErlDrvEntry fd_driver_entry; -#ifndef __OSE__ extern ErlDrvEntry vanilla_driver_entry; -#endif extern ErlDrvEntry spawn_driver_entry; extern ErlDrvEntry *driver_tab[]; /* table of static drivers, only used during initialization */ @@ -1105,7 +1103,7 @@ io_list_vec_len(Eterm obj, int* vsize, Uint* csize, Uint p_v_size = 0; Uint p_c_size = 0; Uint p_in_clist = 0; - Uint total; /* Uint due to halfword emulator */ + Uint total; goto L_jump_start; /* avoid a push */ @@ -2794,9 +2792,7 @@ void erts_init_io(int port_tab_size, erts_smp_rwmtx_rwlock(&erts_driver_list_lock); init_driver(&fd_driver, &fd_driver_entry, NULL); -#ifndef __OSE__ init_driver(&vanilla_driver, &vanilla_driver_entry, NULL); -#endif init_driver(&spawn_driver, &spawn_driver_entry, NULL); erts_init_static_drivers(); for (dp = driver_tab; *dp != NULL; dp++) @@ -4091,10 +4087,10 @@ erts_port_control(Process* c_p, binp = NULL; if (is_binary(data) && binary_bitoffset(data) == 0) { - Eterm *ebinp = binary_val_rel(data, NULL); + Eterm *ebinp = binary_val(data); ASSERT(!tmp_alloced); if (*ebinp == HEADER_SUB_BIN) - ebinp = binary_val_rel(((ErlSubBin *) ebinp)->orig, NULL); + ebinp = binary_val(((ErlSubBin *) ebinp)->orig); if (*ebinp != HEADER_PROC_BIN) copy = 1; else { @@ -5248,25 +5244,17 @@ driver_deliver_term(Eterm to, ErlDrvTermData* data, int len) break; case ERL_DRV_INT: /* signed int argument */ ERTS_DDT_CHK_ENOUGH_ARGS(1); -#if HALFWORD_HEAP - erts_bld_sint64(NULL, &need, (Sint64)ptr[0]); -#else /* check for bignum */ if (!IS_SSMALL((Sint)ptr[0])) need += BIG_UINT_HEAP_SIZE; /* use small_to_big */ -#endif ptr++; depth++; break; case ERL_DRV_UINT: /* unsigned int argument */ ERTS_DDT_CHK_ENOUGH_ARGS(1); -#if HALFWORD_HEAP - erts_bld_uint64(NULL, &need, (Uint64)ptr[0]); -#else /* check for bignum */ if (!IS_USMALL(0, (Uint)ptr[0])) need += BIG_UINT_HEAP_SIZE; /* use small_to_big */ -#endif ptr++; depth++; break; @@ -5465,10 +5453,6 @@ driver_deliver_term(Eterm to, ErlDrvTermData* data, int len) break; case ERL_DRV_INT: /* signed int argument */ -#if HALFWORD_HEAP - erts_reserve_heap(&factory, BIG_NEED_SIZE(2)); - mess = erts_bld_sint64(&factory.hp, NULL, (Sint64)ptr[0]); -#else erts_reserve_heap(&factory, BIG_UINT_HEAP_SIZE); if (IS_SSMALL((Sint)ptr[0])) mess = make_small((Sint)ptr[0]); @@ -5476,15 +5460,10 @@ driver_deliver_term(Eterm to, ErlDrvTermData* data, int len) mess = small_to_big((Sint)ptr[0], factory.hp); factory.hp += BIG_UINT_HEAP_SIZE; } -#endif ptr++; break; case ERL_DRV_UINT: /* unsigned int argument */ -#if HALFWORD_HEAP - erts_reserve_heap(&factory, BIG_NEED_FOR_BITS(64)); - mess = erts_bld_uint64(&factory.hp, NULL, (Uint64)ptr[0]); -#else erts_reserve_heap(&factory, BIG_UINT_HEAP_SIZE); if (IS_USMALL(0, (Uint)ptr[0])) mess = make_small((Uint)ptr[0]); @@ -5492,7 +5471,6 @@ driver_deliver_term(Eterm to, ErlDrvTermData* data, int len) mess = uint_to_big((Uint)ptr[0], factory.hp); factory.hp += BIG_UINT_HEAP_SIZE; } -#endif ptr++; break; @@ -6809,7 +6787,7 @@ int driver_monitor_process(ErlDrvPort drvport, { Port *prt; int ret; -#if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)) +#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK) ErtsSchedulerData *sched = erts_get_scheduler_data(); #endif @@ -6820,16 +6798,6 @@ int driver_monitor_process(ErlDrvPort drvport, /* Now (in SMP) we should have either the port lock (if we have a scheduler) or the port data lock (if we're a driver thread) */ ERTS_SMP_LC_ASSERT((sched != NULL || prt->port_data_lock)); - -#if !HEAP_ON_C_STACK - if (!sched) { - /* Need a separate allocation for the ref :( */ - Eterm *buf = erts_alloc(ERTS_ALC_T_TEMP_TERM, - sizeof(Eterm)*REF_THING_SIZE); - ret = do_driver_monitor_process(prt,buf,process,monitor); - erts_free(ERTS_ALC_T_TEMP_TERM,buf); - } else -#endif { DeclareTmpHeapNoproc(buf,REF_THING_SIZE); UseTmpHeapNoproc(REF_THING_SIZE); @@ -6882,7 +6850,7 @@ int driver_demonitor_process(ErlDrvPort drvport, { Port *prt; int ret; -#if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)) +#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK) ErtsSchedulerData *sched = erts_get_scheduler_data(); #endif @@ -6893,15 +6861,6 @@ int driver_demonitor_process(ErlDrvPort drvport, /* Now we should have either the port lock (if we have a scheduler) or the port data lock (if we're a driver thread) */ ERTS_SMP_LC_ASSERT((sched != NULL || prt->port_data_lock)); -#if !HEAP_ON_C_STACK - if (!sched) { - /* Need a separate allocation for the ref :( */ - Eterm *buf = erts_alloc(ERTS_ALC_T_TEMP_TERM, - sizeof(Eterm)*REF_THING_SIZE); - ret = do_driver_demonitor_process(prt,buf,monitor); - erts_free(ERTS_ALC_T_TEMP_TERM,buf); - } else -#endif { DeclareTmpHeapNoproc(buf,REF_THING_SIZE); UseTmpHeapNoproc(REF_THING_SIZE); @@ -6937,7 +6896,7 @@ ErlDrvTermData driver_get_monitored_process(ErlDrvPort drvport, { Port *prt; ErlDrvTermData ret; -#if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)) +#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK) ErtsSchedulerData *sched = erts_get_scheduler_data(); #endif @@ -6948,16 +6907,6 @@ ErlDrvTermData driver_get_monitored_process(ErlDrvPort drvport, /* Now we should have either the port lock (if we have a scheduler) or the port data lock (if we're a driver thread) */ ERTS_SMP_LC_ASSERT((sched != NULL || prt->port_data_lock)); - -#if !HEAP_ON_C_STACK - if (!sched) { - /* Need a separate allocation for the ref :( */ - Eterm *buf = erts_alloc(ERTS_ALC_T_TEMP_TERM, - sizeof(Eterm)*REF_THING_SIZE); - ret = do_driver_get_monitored_process(prt,buf,monitor); - erts_free(ERTS_ALC_T_TEMP_TERM,buf); - } else -#endif { DeclareTmpHeapNoproc(buf,REF_THING_SIZE); UseTmpHeapNoproc(REF_THING_SIZE); diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index 1d32e72247..46fefb88af 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -39,8 +39,8 @@ too_old_compiler | never() => # necessary.) Since the instructions don't work correctly in R12B, simply # refuse to load the module. -func_info M=a a==am_module_info A=u==0 | label L | move n r => too_old_compiler -func_info M=a a==am_module_info A=u==1 | label L | move n r => too_old_compiler +func_info M=a a==am_module_info A=u==0 | label L | move n x==0 => too_old_compiler +func_info M=a a==am_module_info A=u==1 | label L | move n x==0 => too_old_compiler # The undocumented and unsupported guard BIF is_constant/1 was removed # in R13. The is_constant/2 operation is marked as obsolete in genop.tab, @@ -76,17 +76,6 @@ return # with the following call instruction, we need to make sure that # there is no line/1 instruction between the move and the call. # - -move S r | line Loc | call_ext Ar Func => \ - line Loc | move S r | call_ext Ar Func -move S r | line Loc | call_ext_last Ar Func=u$is_bif D => \ - line Loc | move S r | call_ext_last Ar Func D -move S r | line Loc | call_ext_only Ar Func=u$is_bif => \ - line Loc | move S r | call_ext_only Ar Func -move S r | line Loc | call Ar Func => \ - line Loc | move S r | call Ar Func - -# # A tail-recursive call to an external function (non-BIF) will # never be saved on the stack, so there is no reason to keep # the line instruction. (The compiler did not remove the line @@ -94,10 +83,14 @@ move S r | line Loc | call Ar Func => \ # BIFs and ordinary Erlang functions.) # -line Loc | call_ext_last Ar Func=u$is_not_bif D => \ - call_ext_last Ar Func D -line Loc | call_ext_only Ar Func=u$is_not_bif => \ - call_ext_only Ar Func +move S X0=x==0 | line Loc | call_ext Ar Func => \ + line Loc | move S X0 | call_ext Ar Func +move S X0=x==0 | line Loc | call_ext_last Ar Func=u$is_not_bif D => \ + move S X0 | call_ext_last Ar Func D +move S X0=x==0 | line Loc | call_ext_only Ar Func=u$is_not_bif => \ + move S X0 | call_ext_only Ar Func +move S X0=x==0 | line Loc | call Ar Func => \ + line Loc | move S X0 | call Ar Func line Loc | func_info M F A => func_info M F A | line Loc @@ -167,31 +160,24 @@ is_tuple Fail=f S | select_tuple_arity S=d Fail=f Size=u Rest=* => \ select_tuple_arity S=d Fail=f Size=u Rest=* => \ gen_select_tuple_arity(S, Fail, Size, Rest) -i_select_val_bins r f I i_select_val_bins x f I i_select_val_bins y f I -i_select_val_lins r f I i_select_val_lins x f I i_select_val_lins y f I -i_select_val2 r f c c f f i_select_val2 x f c c f f i_select_val2 y f c c f f -i_select_tuple_arity r f I i_select_tuple_arity x f I i_select_tuple_arity y f I -i_select_tuple_arity2 r f A A f f i_select_tuple_arity2 x f A A f f i_select_tuple_arity2 y f A A f f -i_jump_on_val_zero r f I i_jump_on_val_zero x f I i_jump_on_val_zero y f I -i_jump_on_val r f I I i_jump_on_val x f I I i_jump_on_val y f I I @@ -203,30 +189,21 @@ is_ne_exact L1 S1 S2 | jump Fail | label L2 | same_label(L1, L2) => \ %macro: get_list GetList -pack get_list x x x get_list x x y -get_list x x r get_list x y x get_list x y y -get_list x y r -get_list x r x -get_list x r y get_list y x x get_list y x y -get_list y x r get_list y y x get_list y y y -get_list y y r -get_list y r x -get_list y r y +# The following get_list instructions using x(0) are frequently used. get_list r x x +get_list r r y +get_list x r x get_list r x y -get_list r x r -get_list r y x -get_list r y y get_list r y r -get_list r r x -get_list r r y +get_list r x r # Old-style catch. catch y f @@ -237,33 +214,31 @@ try Y F => catch Y F try_case Y => try_end Y try_end y -try_case_end Literal=q => move Literal x | try_case_end x try_case_end s # Destructive set tuple element -set_tuple_element Lit=q Tuple Pos => move Lit x | set_tuple_element x Tuple Pos set_tuple_element s d P # Get tuple element %macro: i_get_tuple_element GetTupleElement -pack i_get_tuple_element x P x -i_get_tuple_element r P x i_get_tuple_element y P x -i_get_tuple_element x P r -i_get_tuple_element y P r %cold -i_get_tuple_element r P r i_get_tuple_element x P y -i_get_tuple_element r P y i_get_tuple_element y P y %hot +%macro: i_get_tuple_element2 GetTupleElement2 -pack +i_get_tuple_element2 x P x + +%macro: i_get_tuple_element3 GetTupleElement3 -pack +i_get_tuple_element3 x P x + %macro: is_number IsNumber -fail_action %cold -is_number f r is_number f x is_number f y %hot @@ -273,16 +248,12 @@ is_number Fail Literal=q => move Literal x | is_number Fail x jump f -case_end Literal=cq => move Literal x | case_end x -badmatch Literal=cq => move Literal x | badmatch x +case_end NotInX=cy => move NotInX x | case_end x +badmatch NotInX=cy => move NotInX x | badmatch x -case_end r case_end x -case_end y -badmatch r badmatch x -badmatch y if_end raise s s @@ -291,7 +262,7 @@ raise s s badarg j system_limit j -move C=cxy r | jump Lbl => move_jump Lbl C +move C=cxy x==0 | jump Lbl => move_jump Lbl C %macro: move_jump MoveJump -nonext move_jump f n @@ -309,8 +280,6 @@ move_window/6 # x -> y -move S1=r S2=y | move X1=x Y1=y => move2 S1 S2 X1 Y1 - move X1=x Y1=y | move X2=x Y2=y | move X3=x Y3=y | succ(Y1,Y2) | succ(Y2,Y3) => \ move_window X1 X2 X3 Y1 Y3 @@ -323,24 +292,76 @@ move_window X1=x X2=x X3=x X4=x Y1=y Y4=y | move X5=x Y5=y | succ(Y4,Y5) => \ move_window X1=x X2=x X3=x Y1=y Y3=y => move_window3 X1 X2 X3 Y1 move_window X1=x X2=x X3=x X4=x Y1=y Y4=y => move_window4 X1 X2 X3 X4 Y1 +%macro: move_window3 MoveWindow3 -pack +%macro: move_window4 MoveWindow4 -pack +%macro: move_window5 MoveWindow5 -pack + move_window3 x x x y move_window4 x x x x y move_window5 x x x x x y -move X1=x Y1=y | move X2=x Y2=y => move2 X1 Y1 X2 Y2 -move Y1=y X1=x | move Y2=y X2=x => move2 Y1 X1 Y2 X2 -move X1=x X2=x | move X3=x X4=x => move2 X1 X2 X3 X4 +# Swap registers. +move R1=x Tmp=x | move R2=xy R1 | move Tmp R2 => swap_temp R1 R2 Tmp + +swap_temp R1 R2 Tmp | line Loc | apply Live | is_killed(Tmp, Live) => \ + swap R1 R2 | line Loc | apply Live + +swap_temp R1 R2 Tmp | line Loc | call Live Addr | is_killed(Tmp, Live) => \ + swap R1 R2 | line Loc | call Live Addr +swap_temp R1 R2 Tmp | call_only Live Addr | \ + is_killed(Tmp, Live) => swap R1 R2 | call_only Live Addr +swap_temp R1 R2 Tmp | call_last Live Addr D | \ + is_killed(Tmp, Live) => swap R1 R2 | call_last Live Addr D -move S1=x S2=r | move S3=x S4=x => move2 S1 S2 S3 S4 -move S1=x S2=r | move X1=x Y1=y => move2 S1 S2 X1 Y1 -move S1=y S2=r | move X1=x Y1=y => move2 S1 S2 X1 Y1 +swap_temp R1 R2 Tmp | line Loc | call_ext Live Addr | is_killed(Tmp, Live) => \ + swap R1 R2 | line Loc | call_ext Live Addr +swap_temp R1 R2 Tmp | line Loc | call_ext_only Live Addr | \ + is_killed(Tmp, Live) => swap R1 R2 | line Loc | call_ext_only Live Addr +swap_temp R1 R2 Tmp | line Loc | call_ext_last Live Addr D | \ + is_killed(Tmp, Live) => swap R1 R2 | line Loc | call_ext_last Live Addr D -move Y1=y X1=x | move S1=r D1=x => move2 Y1 X1 S1 D1 -move S1=r D1=x | move Y1=y X1=x => move2 S1 D1 Y1 X1 +%macro: swap_temp SwapTemp -pack +swap_temp x x x +swap_temp x y x -move2 X1=x Y1=y X2=x Y2=y | move X3=x Y3=y => move3 X1 Y1 X2 Y2 X3 Y3 -move2 Y1=y X1=x Y2=y X2=x | move Y3=y X3=x => move3 Y1 X1 Y2 X2 Y3 X3 -move2 X1=x X2=x X3=x X4=x | move X5=x X6=x => move3 X1 X2 X3 X4 X5 X6 +%macro: swap Swap -pack +swap x x +swap x y + +move Src=x D1=x | move Src=x D2=x => move_dup Src D1 D2 +move Src=x SD=x | move SD=x D=x => move_dup Src SD D +move Src=x D1=x | move Src=x D2=y => move_dup Src D1 D2 +move Src=y SD=x | move SD=x D=y => move_dup Src SD D +move Src=x SD=x | move SD=x D=y => move_dup Src SD D +move Src=y SD=x | move SD=x D=x => move_dup Src SD D + +move SD=x D=x | move Src=xy SD=x => move_shift Src SD D +move SD=y D=x | move Src=x SD=y => move_shift Src SD D +move SD=x D=y | move Src=x SD=x => move_shift Src SD D + +# The transformations above guarantee that the source for +# the second move is not the same as the destination for +# the first move. That means that we can do the moves in +# parallel (fetch both values, then store them) which could +# be faster. + +move X1=x Y1=y | move X2=x Y2=y => move2_par X1 Y1 X2 Y2 +move Y1=y X1=x | move Y2=y X2=x => move2_par Y1 X1 Y2 X2 + +move X1=x X2=x | move X3=x X4=x => move2_par X1 X2 X3 X4 + +move X1=x X2=x | move X3=x Y1=y => move2_par X1 X2 X3 Y1 + +move S1=x S2=x | move X1=x Y1=y => move2_par S1 S2 X1 Y1 + +move S1=y S2=x | move X1=x Y1=y => move2_par S1 S2 X1 Y1 + +move Y1=y X1=x | move S1=x D1=x => move2_par Y1 X1 S1 D1 +move S1=x D1=x | move Y1=y X1=x => move2_par S1 D1 Y1 X1 + +move2_par X1=x Y1=y X2=x Y2=y | move X3=x Y3=y => move3 X1 Y1 X2 Y2 X3 Y3 +move2_par Y1=y X1=x Y2=y X2=x | move Y3=y X3=x => move3 Y1 X1 Y2 X2 Y3 X3 +move2_par X1=x X2=x X3=x X4=x | move X5=x X6=x => move3 X1 X2 X3 X4 X5 X6 move C=aiq X=x==1 => move_x1 C move C=aiq X=x==2 => move_x2 C @@ -348,21 +369,32 @@ move C=aiq X=x==2 => move_x2 C move_x1 c move_x2 c -%macro: move2 Move2 -pack -move2 x y x y -move2 y x y x -move2 x x x x +%macro: move_shift MoveShift -pack +move_shift x x x +move_shift y x x +move_shift x y x +move_shift x x y + +%macro: move_dup MoveDup -pack +move_dup x x x +move_dup x x y +move_dup y x x +move_dup y x y -move2 x r x x +%macro: move2_par Move2Par -pack -move2 x r x y -move2 r y x y -move2 y r x y +move2_par x y x y +move2_par y x y x +move2_par x x x x -move2 r x y x -move2 y x r x +move2_par x x x y -%macro: move3 Move3 +move2_par y x x y + +move2_par x x y x +move2_par y x x x + +%macro: move3 Move3 -pack move3 x y x y x y move3 y x y x y x move3 x x x x x x @@ -375,20 +407,22 @@ move S=c D=y => move S x | move x D %macro:move Move -pack -gen_dest move x x move x y -move x r move y x -move y r -move r x -move r y -move c r move c x move n x -move n r move y y +# The following move instructions using x(0) are frequently used. + +move x r +move r x +move y r +move c r +move r y + # Receive operations. -loop_rec Fail Src | smp_mark_target_label(Fail) => i_loop_rec Fail Src +loop_rec Fail x==0 | smp_mark_target_label(Fail) => i_loop_rec Fail label L | wait_timeout Fail Src | smp_already_locked(L) => label L | i_wait_timeout_locked Fail Src wait_timeout Fail Src => i_wait_timeout Fail Src @@ -403,7 +437,7 @@ label L | timeout | smp_already_locked(L) => label L | timeout_locked remove_message timeout timeout_locked -i_loop_rec f r +i_loop_rec f loop_rec_end f wait f wait_locked f @@ -421,93 +455,57 @@ send # Optimized comparisons with one immediate/literal operand. # -is_eq_exact Lbl R=rxy C=ian => i_is_eq_exact_immed Lbl R C -is_eq_exact Lbl R=rxy C=q => i_is_eq_exact_literal R Lbl C +is_eq_exact Lbl R=xy C=ian => i_is_eq_exact_immed Lbl R C +is_eq_exact Lbl R=xy C=q => i_is_eq_exact_literal Lbl R C -is_ne_exact Lbl R=rxy C=ian => i_is_ne_exact_immed Lbl R C -is_ne_exact Lbl R=rxy C=q => i_is_ne_exact_literal R Lbl C +is_ne_exact Lbl R=xy C=ian => i_is_ne_exact_immed Lbl R C +is_ne_exact Lbl R=xy C=q => i_is_ne_exact_literal Lbl R C %macro: i_is_eq_exact_immed EqualImmed -fail_action i_is_eq_exact_immed f r c i_is_eq_exact_immed f x c i_is_eq_exact_immed f y c -i_is_eq_exact_literal r f c -i_is_eq_exact_literal x f c -i_is_eq_exact_literal y f c +i_is_eq_exact_literal f x c +i_is_eq_exact_literal f y c %macro: i_is_ne_exact_immed NotEqualImmed -fail_action -i_is_ne_exact_immed f r c i_is_ne_exact_immed f x c i_is_ne_exact_immed f y c -i_is_ne_exact_literal r f c -i_is_ne_exact_literal x f c -i_is_ne_exact_literal y f c - -# -# Common Compare Specializations -# We don't do all of them since we want -# to keep the instruction set small-ish -# - -is_eq_exact Lbl S1=xy S2=r => is_eq_exact Lbl S2 S1 -is_eq_exact Lbl S1=rx S2=xy => i_is_eq_exact_spec Lbl S1 S2 -%macro: i_is_eq_exact_spec EqualExact -fail_action - -i_is_eq_exact_spec f x x -i_is_eq_exact_spec f x y -i_is_eq_exact_spec f r x -i_is_eq_exact_spec f r y -%cold -i_is_eq_exact_spec f r r -%hot +i_is_ne_exact_literal f x c +i_is_ne_exact_literal f y c -is_lt Lbl S1=rxc S2=rxc => i_is_lt_spec Lbl S1 S2 +is_eq_exact Lbl Y=y X=x => is_eq_exact Lbl X Y +%macro: is_eq_exact EqualExact -fail_action -pack +is_eq_exact f x x +is_eq_exact f x y +is_eq_exact f s s -%macro: i_is_lt_spec IsLessThan -fail_action - -i_is_lt_spec f x x -i_is_lt_spec f x r -i_is_lt_spec f x c -i_is_lt_spec f r x -i_is_lt_spec f r c -i_is_lt_spec f c x -i_is_lt_spec f c r +%macro: is_lt IsLessThan -fail_action +is_lt f x x +is_lt f x c +is_lt f c x %cold -i_is_lt_spec f r r -i_is_lt_spec f c c +is_lt f s s %hot -is_ge Lbl S1=xc S2=xc => i_is_ge_spec Lbl S1 S2 - -%macro: i_is_ge_spec IsGreaterEqual -fail_action - -i_is_ge_spec f x x -i_is_ge_spec f x c -i_is_ge_spec f c x +%macro: is_ge IsGreaterEqual -fail_action +is_ge f x x +is_ge f x c +is_ge f c x %cold -i_is_ge_spec f c c +is_ge f s s %hot -# -# All other comparisons. -# +%macro: is_ne_exact NotEqualExact -fail_action +is_ne_exact f s s -is_eq_exact Lbl S1 S2 => i_fetch S1 S2 | i_is_eq_exact Lbl -is_ne_exact Lbl S1 S2 => i_fetch S1 S2 | i_is_ne_exact Lbl +%macro: is_eq Equal -fail_action +is_eq f s s -is_lt Lbl S1 S2 => i_fetch S1 S2 | i_is_lt Lbl -is_ge Lbl S1 S2 => i_fetch S1 S2 | i_is_ge Lbl -is_eq Lbl S1 S2 => i_fetch S1 S2 | i_is_eq Lbl -is_ne Lbl S1 S2 => i_fetch S1 S2 | i_is_ne Lbl - -i_is_eq_exact f -i_is_ne_exact f -i_is_lt f -i_is_ge f -i_is_eq f -i_is_ne f +%macro: is_ne NotEqual -fail_action +is_ne f s s # # Putting things. @@ -525,7 +523,6 @@ i_put_tuple Dst Arity Puts=* | put S => \ i_put_tuple/2 %macro:i_put_tuple PutTuple -pack -goto:do_put_tuple -i_put_tuple r I i_put_tuple x I i_put_tuple y I @@ -542,74 +539,36 @@ put_list x n x put_list y n x put_list x x x put_list y x x -put_list x x r -put_list y r r put_list y y x put_list x y x -put_list r x x -put_list r y x -put_list r x r -put_list y y r -put_list y r x -put_list r n x -put_list x r x -put_list x y r -put_list y x r put_list y x x -put_list x r r - # put_list SrcReg Constant Dst -put_list r c r -put_list r c x -put_list r c y -put_list x c r put_list x c x put_list x c y -put_list y c r put_list y c x -put_list y c y # put_list Constant SrcReg Dst -put_list c r r -put_list c r x -put_list c r y -put_list c x r put_list c x x -put_list c x y - -put_list c y r put_list c y x -put_list c y y -%cold -put_list s s d -%hot +# The following put_list instructions using x(0) are frequently used. -%macro: i_fetch FetchArgs -pack -i_fetch c r -i_fetch c x -i_fetch c y -i_fetch r c -i_fetch r x -i_fetch r y -i_fetch x c -i_fetch x r -i_fetch x x -i_fetch x y -i_fetch y c -i_fetch y r -i_fetch y x -i_fetch y y +put_list y r r +put_list x r r +put_list r n r +put_list r n x +put_list r x x +put_list r x r +put_list x x r %cold -i_fetch c c -i_fetch s s +put_list s s d %hot # @@ -631,27 +590,27 @@ return_trace # Note: There is no 'move_return y r', since there never are any y registers # when we do move_return (if we have y registers, we must do move_deallocate_return). -move S r | return => move_return S r +move S x==0 | return => move_return S %macro: move_return MoveReturn -nonext -move_return x r -move_return c r -move_return n r +move_return x +move_return c +move_return n -move S r | deallocate D | return => move_deallocate_return S r D +move S x==0 | deallocate D | return => move_deallocate_return S D %macro: move_deallocate_return MoveDeallocateReturn -pack -nonext -move_deallocate_return x r Q -move_deallocate_return y r Q -move_deallocate_return c r Q -move_deallocate_return n r Q +move_deallocate_return x Q +move_deallocate_return y Q +move_deallocate_return c Q +move_deallocate_return n Q deallocate D | return => deallocate_return D %macro: deallocate_return DeallocateReturn -nonext deallocate_return Q -test_heap Need u==1 | put_list Y=y r r => test_heap_1_put_list Need Y +test_heap Need u==1 | put_list Y=y x==0 x==0 => test_heap_1_put_list Need Y %macro: test_heap_1_put_list TestHeapPutList -pack test_heap_1_put_list I y @@ -660,18 +619,18 @@ test_heap_1_put_list I y is_tuple Fail Literal=q => move Literal x | is_tuple Fail x is_tuple Fail=f c => jump Fail -is_tuple Fail=f S=rxy | test_arity Fail=f S=rxy Arity => is_tuple_of_arity Fail S Arity +is_tuple Fail=f S=xy | test_arity Fail=f S=xy Arity => is_tuple_of_arity Fail S Arity %macro:is_tuple_of_arity IsTupleOfArity -fail_action +is_tuple_of_arity f r A is_tuple_of_arity f x A is_tuple_of_arity f y A -is_tuple_of_arity f r A %macro: is_tuple IsTuple -fail_action +is_tuple f r is_tuple f x is_tuple f y -is_tuple f r test_arity Fail Literal=q Arity => move Literal x | test_arity Fail x Arity test_arity Fail=f c Arity => jump Fail @@ -679,95 +638,63 @@ test_arity Fail=f c Arity => jump Fail %macro: test_arity IsArity -fail_action test_arity f x A test_arity f y A -test_arity f r A - -is_tuple_of_arity Fail=f Reg Arity | get_tuple_element Reg P=u==0 Dst=xy => \ - is_tuple_of_arity Fail Reg Arity | extract_next_element Dst | original_reg Reg P - -test_arity Fail Reg Arity | get_tuple_element Reg P=u==0 Dst=xy => \ - test_arity Fail Reg Arity | extract_next_element Dst | original_reg Reg P - -original_reg Reg P1 | get_tuple_element Reg P2 Dst=xy | succ(P1, P2) => \ - extract_next_element Dst | original_reg Reg P2 - -get_tuple_element Reg P Dst => i_get_tuple_element Reg P Dst | original_reg Reg P - -original_reg Reg Pos => - -original_reg/2 - -extract_next_element D1=xy | original_reg Reg P1 | get_tuple_element Reg P2 D2=xy | \ -succ(P1, P2) | succ(D1, D2) => \ - extract_next_element2 D1 | original_reg Reg P2 - -extract_next_element2 D1=xy | original_reg Reg P1 | get_tuple_element Reg P2 D2=xy | \ -succ(P1, P2) | succ2(D1, D2) => \ - extract_next_element3 D1 | original_reg Reg P2 - -#extract_next_element3 D1=xy | original_reg Reg P1 | get_tuple_element Reg P2 D2=xy | \ -#succ(P1, P2) | succ3(D1, D2) => \ -# extract_next_element4 D1 | original_reg Reg P2 - -%macro: extract_next_element ExtractNextElement -pack -extract_next_element x -extract_next_element y -%macro: extract_next_element2 ExtractNextElement2 -pack -extract_next_element2 x -extract_next_element2 y +get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \ + get_tuple_element Reg=x P3 D3=x | \ + succ(P1, P2) | succ(P2, P3) | \ + succ(D1, D2) | succ(D2, D3) => i_get_tuple_element3 Reg P1 D1 -%macro: extract_next_element3 ExtractNextElement3 -pack -extract_next_element3 x -extract_next_element3 y +get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \ + succ(P1, P2) | succ(D1, D2) => i_get_tuple_element2 Reg P1 D1 -#%macro: extract_next_element4 ExtractNextElement4 -pack -#extract_next_element4 x -#extract_next_element4 y +get_tuple_element Reg P Dst => i_get_tuple_element Reg P Dst is_integer Fail=f i => is_integer Fail=f an => jump Fail is_integer Fail Literal=q => move Literal x | is_integer Fail x -is_integer Fail=f S=rx | allocate Need Regs => is_integer_allocate Fail S Need Regs +is_integer Fail=f S=x | allocate Need Regs => is_integer_allocate Fail S Need Regs %macro: is_integer_allocate IsIntegerAllocate -fail_action is_integer_allocate f x I I -is_integer_allocate f r I I %macro: is_integer IsInteger -fail_action is_integer f x is_integer f y -is_integer f r is_list Fail=f n => is_list Fail Literal=q => move Literal x | is_list Fail x is_list Fail=f c => jump Fail %macro: is_list IsList -fail_action -is_list f r is_list f x %cold is_list f y %hot -is_nonempty_list Fail=f S=rx | allocate Need Rs => is_nonempty_list_allocate Fail S Need Rs +is_nonempty_list Fail=f S=x | allocate Need Rs => is_nonempty_list_allocate Fail S Need Rs %macro:is_nonempty_list_allocate IsNonemptyListAllocate -fail_action -pack -is_nonempty_list_allocate f x I t is_nonempty_list_allocate f r I t +is_nonempty_list_allocate f x I t -is_nonempty_list F=f r | test_heap I1 I2 => is_non_empty_list_test_heap F r I1 I2 +is_nonempty_list F=f x==0 | test_heap I1 I2 => is_non_empty_list_test_heap F I1 I2 %macro: is_non_empty_list_test_heap IsNonemptyListTestHeap -fail_action -pack -is_non_empty_list_test_heap f r I t +is_non_empty_list_test_heap f I t + +is_nonempty_list Fail=f S=x | get_list S D1=x D2=x => \ + is_nonempty_list_get_list Fail S D1 D2 + +%macro: is_nonempty_list_get_list IsNonemptyListGetList -fail_action -pack +is_nonempty_list_get_list f r x x +is_nonempty_list_get_list f x x x %macro: is_nonempty_list IsNonemptyList -fail_action is_nonempty_list f x is_nonempty_list f y -is_nonempty_list f r %macro: is_atom IsAtom -fail_action is_atom f x -is_atom f r %cold is_atom f y %hot @@ -775,7 +702,6 @@ is_atom Fail=f a => is_atom Fail=f niq => jump Fail %macro: is_float IsFloat -fail_action -is_float f r is_float f x %cold is_float f y @@ -789,12 +715,10 @@ is_nil Fail=f qia => jump Fail %macro: is_nil IsNil -fail_action is_nil f x is_nil f y -is_nil f r is_binary Fail Literal=q => move Literal x | is_binary Fail x is_binary Fail=f c => jump Fail %macro: is_binary IsBinary -fail_action -is_binary f r is_binary f x %cold is_binary f y @@ -806,7 +730,6 @@ is_bitstr Fail Term => is_bitstring Fail Term is_bitstring Fail Literal=q => move Literal x | is_bitstring Fail x is_bitstring Fail=f c => jump Fail %macro: is_bitstring IsBitstring -fail_action -is_bitstring f r is_bitstring f x %cold is_bitstring f y @@ -814,7 +737,6 @@ is_bitstring f y is_reference Fail=f cq => jump Fail %macro: is_reference IsRef -fail_action -is_reference f r is_reference f x %cold is_reference f y @@ -822,7 +744,6 @@ is_reference f y is_pid Fail=f cq => jump Fail %macro: is_pid IsPid -fail_action -is_pid f r is_pid f x %cold is_pid f y @@ -830,7 +751,6 @@ is_pid f y is_port Fail=f cq => jump Fail %macro: is_port IsPort -fail_action -is_port f r is_port f x %cold is_port f y @@ -842,14 +762,12 @@ is_boolean Fail=f ac => jump Fail %cold %macro: is_boolean IsBoolean -fail_action -is_boolean f r is_boolean f x is_boolean f y %hot is_function2 Fail=f acq Arity => jump Fail is_function2 Fail=f Fun a => jump Fail -is_function2 Fail Fun Literal=q => move Literal x | is_function2 Fail Fun x is_function2 f s s %macro: is_function2 IsFunction2 -fail_action @@ -989,76 +907,76 @@ call_ext_only u==3 u$func:erlang:hibernate/3 => i_hibernate %unless USE_VM_PROBES call_ext Arity u$func:erlang:dt_get_tag/0 => \ - move a=am_undefined r + move a=am_undefined x=0 call_ext_last Arity u$func:erlang:dt_get_tag/0 D => \ - move a=am_undefined r | deallocate D | return + move a=am_undefined x=0 | deallocate D | return call_ext_only Arity u$func:erlang:dt_get_tag/0 => \ - move a=am_undefined r | return - -move Any r | call_ext Arity u$func:erlang:dt_put_tag/1 => \ - move a=am_undefined r -move Any r | call_ext_last Arity u$func:erlang:dt_put_tag/1 D => \ - move a=am_undefined r | deallocate D | return -move Any r | call_ext_only Arity u$func:erlang:dt_put_tag/1 => \ - move a=am_undefined r | return + move a=am_undefined x=0 | return + +move Any x==0 | call_ext Arity u$func:erlang:dt_put_tag/1 => \ + move a=am_undefined x=0 +move Any x==0 | call_ext_last Arity u$func:erlang:dt_put_tag/1 D => \ + move a=am_undefined x=0 | deallocate D | return +move Any x==0 | call_ext_only Arity u$func:erlang:dt_put_tag/1 => \ + move a=am_undefined x=0 | return call_ext Arity u$func:erlang:dt_put_tag/1 => \ - move a=am_undefined r + move a=am_undefined x=0 call_ext_last Arity u$func:erlang:dt_put_tag/1 D => \ - move a=am_undefined r | deallocate D | return + move a=am_undefined x=0 | deallocate D | return call_ext_only Arity u$func:erlang:dt_put_tag/1 => \ - move a=am_undefined r | return + move a=am_undefined x=0 | return call_ext Arity u$func:erlang:dt_get_tag_data/0 => \ - move a=am_undefined r + move a=am_undefined x=0 call_ext_last Arity u$func:erlang:dt_get_tag_data/0 D => \ - move a=am_undefined r | deallocate D | return + move a=am_undefined x=0 | deallocate D | return call_ext_only Arity u$func:erlang:dt_get_tag_data/0 => \ - move a=am_undefined r | return - -move Any r | call_ext Arity u$func:erlang:dt_spread_tag/1 => \ - move a=am_true r -move Any r | call_ext_last Arity u$func:erlang:dt_spread_tag/1 D => \ - move a=am_true r | deallocate D | return -move Any r | call_ext_only Arity u$func:erlang:dt_spread_tag/1 => \ - move a=am_true r | return + move a=am_undefined x=0 | return + +move Any x==0 | call_ext Arity u$func:erlang:dt_spread_tag/1 => \ + move a=am_true x=0 +move Any x==0 | call_ext_last Arity u$func:erlang:dt_spread_tag/1 D => \ + move a=am_true x=0 | deallocate D | return +move Any x==0 | call_ext_only Arity u$func:erlang:dt_spread_tag/1 => \ + move a=am_true x=0 | return call_ext Arity u$func:erlang:dt_spread_tag/1 => \ - move a=am_true r + move a=am_true x=0 call_ext_last Arity u$func:erlang:dt_spread_tag/1 D => \ - move a=am_true r | deallocate D | return + move a=am_true x=0 | deallocate D | return call_ext_only Arity u$func:erlang:dt_spread_tag/1 => \ - move a=am_true r | return - -move Any r | call_ext Arity u$func:erlang:dt_restore_tag/1 => \ - move a=am_true r -move Any r | call_ext_last Arity u$func:erlang:dt_restore_tag/1 D => \ - move a=am_true r | deallocate D | return -move Any r | call_ext_only Arity u$func:erlang:dt_restore_tag/1 => \ - move a=am_true r | return + move a=am_true x=0 | return + +move Any x==0 | call_ext Arity u$func:erlang:dt_restore_tag/1 => \ + move a=am_true x=0 +move Any x==0 | call_ext_last Arity u$func:erlang:dt_restore_tag/1 D => \ + move a=am_true x=0 | deallocate D | return +move Any x==0 | call_ext_only Arity u$func:erlang:dt_restore_tag/1 => \ + move a=am_true x=0 | return call_ext Arity u$func:erlang:dt_restore_tag/1 => \ - move a=am_true r + move a=am_true x=0 call_ext_last Arity u$func:erlang:dt_restore_tag/1 D => \ - move a=am_true r | deallocate D | return + move a=am_true x=0 | deallocate D | return call_ext_only Arity u$func:erlang:dt_restore_tag/1 => \ - move a=am_true r | return - -move Any r | call_ext Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \ - move Any r -move Any r | call_ext_last Arity u$func:erlang:dt_prepend_vm_tag_data/1 D => \ - move Any r | deallocate D | return -move Any r | call_ext_only Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \ - move Any r | return + move a=am_true x=0 | return + +move Any x==0 | call_ext Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \ + move Any x=0 +move Any x==0 | call_ext_last Arity u$func:erlang:dt_prepend_vm_tag_data/1 D => \ + move Any x=0 | deallocate D | return +move Any x==0 | call_ext_only Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \ + move Any x=0 | return call_ext Arity u$func:erlang:dt_prepend_vm_tag_data/1 => call_ext_last Arity u$func:erlang:dt_prepend_vm_tag_data/1 D => \ deallocate D | return call_ext_only Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \ return -move Any r | call_ext Arity u$func:erlang:dt_append_vm_tag_data/1 => \ - move Any r -move Any r | call_ext_last Arity u$func:erlang:dt_append_vm_tag_data/1 D => \ - move Any r | deallocate D | return -move Any r | call_ext_only Arity u$func:erlang:dt_append_vm_tag_data/1 => \ - move Any r | return +move Any x==0 | call_ext Arity u$func:erlang:dt_append_vm_tag_data/1 => \ + move Any x=0 +move Any x==0 | call_ext_last Arity u$func:erlang:dt_append_vm_tag_data/1 D => \ + move Any x=0 | deallocate D | return +move Any x==0 | call_ext_only Arity u$func:erlang:dt_append_vm_tag_data/1 => \ + move Any x=0 | return call_ext Arity u$func:erlang:dt_append_vm_tag_data/1 => call_ext_last Arity u$func:erlang:dt_append_vm_tag_data/1 D => \ deallocate D | return @@ -1066,7 +984,7 @@ call_ext_only Arity u$func:erlang:dt_append_vm_tag_data/1 => \ return # Can happen after one of the transformations above. -move Discarded r | move Something r => move Something r +move Discarded x==0 | move Something x==0 => move Something x=0 %endif @@ -1091,9 +1009,9 @@ call_ext_only Ar=u Bif=u$is_bif => \ # with call instructions. # -move S=c r | call_ext Ar=u Func=u$is_not_bif => i_move_call_ext S r Func -move S=c r | call_ext_last Ar=u Func=u$is_not_bif D => i_move_call_ext_last Func D S r -move S=c r | call_ext_only Ar=u Func=u$is_not_bif => i_move_call_ext_only Func S r +move S=c x==0 | call_ext Ar=u Func=u$is_not_bif => i_move_call_ext S Func +move S=c x==0 | call_ext_last Ar=u Func=u$is_not_bif D => i_move_call_ext_last Func D S +move S=c x==0 | call_ext_only Ar=u Func=u$is_not_bif => i_move_call_ext_only Func S call_ext Ar Func => i_call_ext Func call_ext_last Ar Func D => i_call_ext_last Func D @@ -1120,78 +1038,71 @@ bif0 u$bif:erlang:node/0 Dst=d => node Dst bif1 Fail Bif=u$bif:erlang:get/1 Src=s Dst=d => i_get Src Dst -bif2 Jump=j u$bif:erlang:element/2 S1=s S2=rxy Dst=d => gen_element(Jump, S1, S2, Dst) +bif2 Jump=j u$bif:erlang:element/2 S1=s S2=xy Dst=d => gen_element(Jump, S1, S2, Dst) -bif1 Fail Bif Literal=q Dst => move Literal x | bif1 Fail Bif x Dst bif1 p Bif S1 Dst => bif1_body Bif S1 Dst -bif1_body Bif Literal=q Dst => move Literal x | bif1_body Bif x Dst - -bif2 p Bif S1 S2 Dst => i_fetch S1 S2 | i_bif2_body Bif Dst -bif2 Fail Bif S1 S2 Dst => i_fetch S1 S2 | i_bif2 Fail Bif Dst +bif2 p Bif S1 S2 Dst => i_bif2_body Bif S1 S2 Dst +bif2 Fail Bif S1 S2 Dst => i_bif2 Fail Bif S1 S2 Dst i_get s d %macro: self Self -self r self x self y %macro: node Node -node r node x %cold node y %hot -i_fast_element r j I d -i_fast_element x j I d -i_fast_element y j I d +i_fast_element j x I d +i_fast_element j y I d -i_element r j s d -i_element x j s d -i_element y j s d +i_element j x s d +i_element j y s d bif1 f b s d bif1_body b s d -i_bif2 f b d -i_bif2_body b d +i_bif2 f b s s d +i_bif2_body b s s d # # Internal calls. # -move S=c r | call Ar P=f => i_move_call S r P -move S=s r | call Ar P=f => move_call S r P +move S=c x==0 | call Ar P=f => i_move_call S P +move S=s x==0 | call Ar P=f => move_call S P -i_move_call c r f +i_move_call c f %macro:move_call MoveCall -arg_f -size -nonext -move_call/3 +move_call/2 -move_call x r f -move_call y r f +move_call x f +move_call y f -move S=c r | call_last Ar P=f D => i_move_call_last P D S r -move S r | call_last Ar P=f D => move_call_last S r P D +move S=c x==0 | call_last Ar P=f D => i_move_call_last P D S +move S x==0 | call_last Ar P=f D => move_call_last S P D -i_move_call_last f P c r +i_move_call_last f P c %macro:move_call_last MoveCallLast -arg_f -nonext -pack -move_call_last/4 -move_call_last x r f Q -move_call_last y r f Q +move_call_last/3 +move_call_last x f Q +move_call_last y f Q -move S=c r | call_only Ar P=f => i_move_call_only P S r -move S=x r | call_only Ar P=f => move_call_only S r P +move S=c x==0 | call_only Ar P=f => i_move_call_only P S +move S=x x==0 | call_only Ar P=f => move_call_only S P -i_move_call_only f c r +i_move_call_only f c %macro:move_call_only MoveCallOnly -arg_f -nonext -move_call_only/3 +move_call_only/2 -move_call_only x r f +move_call_only x f call Ar Func => i_call Func call_last Ar Func D => i_call_last Func D @@ -1205,9 +1116,9 @@ i_call_ext e i_call_ext_last e P i_call_ext_only e -i_move_call_ext c r e -i_move_call_ext_last e P c r -i_move_call_ext_only e c r +i_move_call_ext c e +i_move_call_ext_last e P c +i_move_call_ext_only e c # Fun calls. @@ -1227,7 +1138,6 @@ i_make_fun I t %macro: is_function IsFunction -fail_action is_function f x is_function f y -is_function f r is_function Fail=f c => jump Fail func_info M F A => i_func_info u M F A @@ -1239,131 +1149,105 @@ func_info M F A => i_func_info u M F A %cold bs_start_match2 Fail=f ica X Y D => jump Fail bs_start_match2 Fail Bin X Y D => i_bs_start_match2 Bin Fail X Y D -i_bs_start_match2 r f I I d i_bs_start_match2 x f I I d i_bs_start_match2 y f I I d bs_save2 Reg Index => gen_bs_save(Reg, Index) -i_bs_save2 r I i_bs_save2 x I bs_restore2 Reg Index => gen_bs_restore(Reg, Index) -i_bs_restore2 r I i_bs_restore2 x I # Matching integers bs_match_string Fail Ms Bits Val => i_bs_match_string Ms Fail Bits Val -i_bs_match_string r f I I i_bs_match_string x f I I # Fetching integers from binaries. -bs_get_integer2 Fail=f Ms=rx Live=u Sz=sq Unit=u Flags=u Dst=d => \ +bs_get_integer2 Fail=f Ms=x Live=u Sz=sq Unit=u Flags=u Dst=d => \ gen_get_integer2(Fail, Ms, Live, Sz, Unit, Flags, Dst) -i_bs_get_integer_small_imm r I f I d i_bs_get_integer_small_imm x I f I d -i_bs_get_integer_imm r I I f I d i_bs_get_integer_imm x I I f I d -i_bs_get_integer f I I d -i_bs_get_integer_8 r f d +i_bs_get_integer f I I s s d i_bs_get_integer_8 x f d -i_bs_get_integer_16 r f d i_bs_get_integer_16 x f d -i_bs_get_integer_32 r f I d i_bs_get_integer_32 x f I d # Fetching binaries from binaries. -bs_get_binary2 Fail=f Ms=rx Live=u Sz=sq Unit=u Flags=u Dst=d => \ +bs_get_binary2 Fail=f Ms=x Live=u Sz=sq Unit=u Flags=u Dst=d => \ gen_get_binary2(Fail, Ms, Live, Sz, Unit, Flags, Dst) %macro: i_bs_get_binary_imm2 BsGetBinaryImm_2 -fail_action -gen_dest %macro: i_bs_get_binary2 BsGetBinary_2 -fail_action -gen_dest %macro: i_bs_get_binary_all2 BsGetBinaryAll_2 -fail_action -gen_dest -i_bs_get_binary_imm2 f r I I I d i_bs_get_binary_imm2 f x I I I d -i_bs_get_binary2 f r I s I d i_bs_get_binary2 f x I s I d -i_bs_get_binary_all2 f r I I d i_bs_get_binary_all2 f x I I d -i_bs_get_binary_all_reuse r f I i_bs_get_binary_all_reuse x f I # Fetching float from binaries. -bs_get_float2 Fail=f Ms=rx Live=u Sz=s Unit=u Flags=u Dst=d => \ +bs_get_float2 Fail=f Ms=x Live=u Sz=s Unit=u Flags=u Dst=d => \ gen_get_float2(Fail, Ms, Live, Sz, Unit, Flags, Dst) -bs_get_float2 Fail=f Ms=rx Live=u Sz=q Unit=u Flags=u Dst=d => jump Fail +bs_get_float2 Fail=f Ms=x Live=u Sz=q Unit=u Flags=u Dst=d => jump Fail %macro: i_bs_get_float2 BsGetFloat2 -fail_action -gen_dest -i_bs_get_float2 f r I s I d i_bs_get_float2 f x I s I d # Miscellanous -bs_skip_bits2 Fail=f Ms=rx Sz=s Unit=u Flags=u => \ - gen_skip_bits2(Fail, Ms, Sz, Unit, Flags) -bs_skip_bits2 Fail=f Ms=rx Sz=q Unit=u Flags=u => \ +bs_skip_bits2 Fail=f Ms=x Sz=sq Unit=u Flags=u => \ gen_skip_bits2(Fail, Ms, Sz, Unit, Flags) %macro: i_bs_skip_bits_imm2 BsSkipBitsImm2 -fail_action -i_bs_skip_bits_imm2 f r I i_bs_skip_bits_imm2 f x I %macro: i_bs_skip_bits2 BsSkipBits2 -fail_action -i_bs_skip_bits2 f r x I -i_bs_skip_bits2 f r y I i_bs_skip_bits2 f x x I -i_bs_skip_bits2 f x r I i_bs_skip_bits2 f x y I %macro: i_bs_skip_bits_all2 BsSkipBitsAll2 -fail_action -i_bs_skip_bits_all2 f r I i_bs_skip_bits_all2 f x I -bs_test_tail2 Fail=f Ms=rx Bits=u==0 => bs_test_zero_tail2 Fail Ms -bs_test_tail2 Fail=f Ms=rx Bits=u => bs_test_tail_imm2 Fail Ms Bits -bs_test_zero_tail2 f r +bs_test_tail2 Fail=f Ms=x Bits=u==0 => bs_test_zero_tail2 Fail Ms +bs_test_tail2 Fail=f Ms=x Bits=u => bs_test_tail_imm2 Fail Ms Bits bs_test_zero_tail2 f x -bs_test_tail_imm2 f r I bs_test_tail_imm2 f x I bs_test_unit F Ms Unit=u==8 => bs_test_unit8 F Ms -bs_test_unit f r I bs_test_unit f x I -bs_test_unit8 f r bs_test_unit8 f x -bs_context_to_binary r +# An y register operand for bs_context_to_binary is rare, +# but can happen because of inlining. + +bs_context_to_binary Y=y => move Y x | bs_context_to_binary x + bs_context_to_binary x -bs_context_to_binary y # # Utf8/utf16/utf32 support. (R12B-5) # -bs_get_utf8 Fail=f Ms=rx u u Dst=d => i_bs_get_utf8 Ms Fail Dst -i_bs_get_utf8 r f d +bs_get_utf8 Fail=f Ms=x u u Dst=d => i_bs_get_utf8 Ms Fail Dst i_bs_get_utf8 x f d -bs_skip_utf8 Fail=f Ms=rx u u => i_bs_get_utf8 Ms Fail x +bs_skip_utf8 Fail=f Ms=x u u => i_bs_get_utf8 Ms Fail x -bs_get_utf16 Fail=f Ms=rx u Flags=u Dst=d => i_bs_get_utf16 Ms Fail Flags Dst -bs_skip_utf16 Fail=f Ms=rx u Flags=u => i_bs_get_utf16 Ms Fail Flags x +bs_get_utf16 Fail=f Ms=x u Flags=u Dst=d => i_bs_get_utf16 Ms Fail Flags Dst +bs_skip_utf16 Fail=f Ms=x u Flags=u => i_bs_get_utf16 Ms Fail Flags x -i_bs_get_utf16 r f I d i_bs_get_utf16 x f I d -bs_get_utf32 Fail=f Ms=rx Live=u Flags=u Dst=d => \ +bs_get_utf32 Fail=f Ms=x Live=u Flags=u Dst=d => \ bs_get_integer2 Fail Ms Live i=32 u=1 Flags Dst | \ - i_fetch Dst Ms | \ - i_bs_validate_unicode_retract Fail -bs_skip_utf32 Fail=f Ms=rx Live=u Flags=u => \ + i_bs_validate_unicode_retract Fail Dst Ms +bs_skip_utf32 Fail=f Ms=x Live=u Flags=u => \ bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | \ - i_fetch x Ms | \ - i_bs_validate_unicode_retract Fail + i_bs_validate_unicode_retract Fail x Ms -i_bs_validate_unicode_retract j +i_bs_validate_unicode_retract j s s %hot # @@ -1385,13 +1269,12 @@ bs_init2 Fail Sz=u Words Regs Flags Dst => \ bs_init2 Fail Sz Words=u==0 Regs Flags Dst => \ i_bs_init_fail Sz Fail Regs Dst bs_init2 Fail Sz Words Regs Flags Dst => \ - i_fetch Sz r | i_bs_init_fail_heap Words Fail Regs Dst + i_bs_init_fail_heap Sz Words Fail Regs Dst -i_bs_init_fail r j I d i_bs_init_fail x j I d i_bs_init_fail y j I d -i_bs_init_fail_heap I j I d +i_bs_init_fail_heap s I j I d i_bs_init I I d i_bs_init_heap_bin I I d @@ -1408,39 +1291,35 @@ bs_init_bits Fail Sz=u Words Regs Flags Dst => i_bs_init_bits_heap Sz Words Reg bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => \ i_bs_init_bits_fail Sz Fail Regs Dst bs_init_bits Fail Sz Words Regs Flags Dst => \ - i_fetch Sz r | i_bs_init_bits_fail_heap Words Fail Regs Dst + i_bs_init_bits_fail_heap Sz Words Fail Regs Dst -i_bs_init_bits_fail r j I d i_bs_init_bits_fail x j I d i_bs_init_bits_fail y j I d -i_bs_init_bits_fail_heap I j I d +i_bs_init_bits_fail_heap s I j I d i_bs_init_bits I I d i_bs_init_bits_heap I I I d bs_add Fail S1=i==0 S2 Unit=u==1 D => move S2 D -bs_add Fail S1 S2 Unit D => i_fetch S1 S2 | i_bs_add Fail Unit D -i_bs_add j I d +bs_add j s s I d bs_append Fail Size Extra Live Unit Bin Flags Dst => \ - i_fetch Size Bin | i_bs_append Fail Extra Live Unit Dst + move Bin x | i_bs_append Fail Extra Live Unit Size Dst bs_private_append Fail Size Unit Bin Flags Dst => \ - i_fetch Size Bin | i_bs_private_append Fail Unit Dst + i_bs_private_append Fail Unit Size Bin Dst bs_init_writable -i_bs_append j I I I d -i_bs_private_append j I d +i_bs_append j I I I s d +i_bs_private_append j I s s d # # Storing integers into binaries. # -bs_put_integer Fail=j Sz=s Unit=u Flags=u Literal=q => \ - move Literal x | bs_put_integer Fail Sz Unit Flags x bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => \ gen_put_integer(Fail, Sz, Unit, Flags, Src) @@ -1454,32 +1333,22 @@ i_new_bs_put_integer_imm j I I s # Utf8/utf16/utf32 support. (R12B-5) # -bs_utf8_size Fail Literal=q Dst=d => \ - move Literal x | bs_utf8_size Fail x Dst bs_utf8_size j Src=s Dst=d => i_bs_utf8_size Src Dst i_bs_utf8_size s d -bs_utf16_size Fail Literal=q Dst=d => \ - move Literal x | bs_utf16_size Fail x Dst bs_utf16_size j Src=s Dst=d => i_bs_utf16_size Src Dst i_bs_utf16_size s d -bs_put_utf8 Fail=j Flags=u Literal=q => \ - move Literal x | bs_put_utf8 Fail Flags x bs_put_utf8 Fail u Src=s => i_bs_put_utf8 Fail Src i_bs_put_utf8 j s -bs_put_utf16 Fail=j Flags=u Literal=q => \ - move Literal x | bs_put_utf16 Fail Flags x bs_put_utf16 Fail Flags=u Src=s => i_bs_put_utf16 Fail Flags Src i_bs_put_utf16 j I s -bs_put_utf32 Fail=j Flags=u Literal=q => \ - move Literal x | bs_put_utf32 Fail Flags x bs_put_utf32 Fail=j Flags=u Src=s => \ i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src @@ -1490,9 +1359,6 @@ i_bs_validate_unicode j s # bs_put_float Fail Sz=q Unit Flags Val => badarg Fail -bs_put_float Fail=j Sz Unit=u Flags=u Literal=q => \ - move Literal x | bs_put_float Fail Sz Unit Flags x - bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => \ gen_put_float(Fail, Sz, Unit, Flags, Src) @@ -1506,8 +1372,6 @@ i_new_bs_put_float_imm j I I s # Storing binaries into binaries. # -bs_put_binary Fail Sz Unit Flags Literal=q => \ - move Literal x | bs_put_binary Fail Sz Unit Flags x bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => \ gen_put_binary(Fail, Sz, Unit, Flags, Src) @@ -1600,7 +1464,6 @@ is_map Fail Lit=q | literal_is_map(Lit) => is_map Fail cq => jump Fail %macro: is_map IsMap -fail_action -is_map f r is_map f x is_map f y @@ -1611,101 +1474,120 @@ has_map_fields Fail Src Size Rest=* => \ ## Transform get_map_elements(s) #{ K1 := V1, K2 := V2 } -get_map_elements Fail Src=rxy Size=u==2 Rest=* => \ +get_map_elements Fail Src=xy Size=u==2 Rest=* => \ gen_get_map_element(Fail, Src, Size, Rest) get_map_elements Fail Src Size Rest=* | map_key_sort(Size, Rest) => \ gen_get_map_elements(Fail, Src, Size, Rest) i_get_map_elements f s I -i_get_map_element Fail Src=rxy Key=ry Dst => \ +i_get_map_element Fail Src=xy Key=y Dst => \ move Key x | i_get_map_element Fail Src x Dst %macro: i_get_map_element_hash GetMapElementHash -fail_action -i_get_map_element_hash f r c I r -i_get_map_element_hash f x c I r -i_get_map_element_hash f y c I r -i_get_map_element_hash f r c I x i_get_map_element_hash f x c I x i_get_map_element_hash f y c I x -i_get_map_element_hash f r c I y i_get_map_element_hash f x c I y i_get_map_element_hash f y c I y %macro: i_get_map_element GetMapElement -fail_action -i_get_map_element f r x r -i_get_map_element f x x r -i_get_map_element f y x r -i_get_map_element f r x x i_get_map_element f x x x i_get_map_element f y x x -i_get_map_element f r x y i_get_map_element f x x y i_get_map_element f y x y # +# Convert the plus operations to a generic plus instruction. +# +gen_plus/5 +gen_minus/5 + +gc_bif1 Fail Live u$bif:erlang:splus/1 Src Dst => \ + gen_plus Fail Live Src i Dst +gc_bif2 Fail Live u$bif:erlang:splus/2 S1 S2 Dst => \ + gen_plus Fail Live S1 S2 Dst + +gc_bif1 Fail Live u$bif:erlang:sminus/1 Src Dst => \ + gen_minus Fail Live i Src Dst +gc_bif2 Fail Live u$bif:erlang:sminus/2 S1 S2 Dst => \ + gen_minus Fail Live S1 S2 Dst + +# # Optimize addition and subtraction of small literals using # the i_increment/4 instruction (in bodies, not in guards). # -gc_bif2 p Live u$bif:erlang:splus/2 Int=i Reg=d Dst => \ +gen_plus p Live Int=i Reg=d Dst => \ gen_increment(Reg, Int, Live, Dst) -gc_bif2 p Live u$bif:erlang:splus/2 Reg=d Int=i Dst => \ +gen_plus p Live Reg=d Int=i Dst => \ gen_increment(Reg, Int, Live, Dst) -gc_bif2 p Live u$bif:erlang:sminus/2 Reg=d Int=i Dst | \ - negation_is_small(Int) => \ +gen_minus p Live Reg=d Int=i Dst | negation_is_small(Int) => \ gen_increment_from_minus(Reg, Int, Live, Dst) # # GCing arithmetic instructions. # -gc_bif2 Fail I u$bif:erlang:splus/2 S1=x S2=x Dst=d => i_plus Fail I S1 S2 Dst -gc_bif2 Fail I u$bif:erlang:splus/2 S1 S2 Dst=d => i_fetch S1 S2 | i_plus Fail I Dst -gc_bif2 Fail I u$bif:erlang:sminus/2 S1=x S2=x Dst=d => i_minus Fail I S1 S2 Dst -gc_bif2 Fail I u$bif:erlang:sminus/2 S1 S2 Dst=d => i_fetch S1 S2 | i_minus Fail I Dst -gc_bif2 Fail I u$bif:erlang:stimes/2 S1 S2 Dst=d => i_fetch S1 S2 | i_times Fail I Dst -gc_bif2 Fail I u$bif:erlang:div/2 S1 S2 Dst=d => i_fetch S1 S2 | i_m_div Fail I Dst +gen_plus Fail Live Y=y X=x Dst => i_plus Fail Live X Y Dst +gen_plus Fail Live S1 S2 Dst => i_plus Fail Live S1 S2 Dst -gc_bif2 Fail I u$bif:erlang:intdiv/2 S1 S2 Dst=d => i_fetch S1 S2 | i_int_div Fail I Dst -gc_bif2 Fail I u$bif:erlang:rem/2 S1=x S2=x Dst=d => i_rem Fail I S1 S2 Dst -gc_bif2 Fail I u$bif:erlang:rem/2 S1 S2 Dst=d => i_fetch S1 S2 | i_rem Fail I Dst +gen_minus Fail Live S1 S2 Dst => i_minus Fail Live S1 S2 Dst -gc_bif2 Fail I u$bif:erlang:bsl/2 S1 S2 Dst=d => i_fetch S1 S2 | i_bsl Fail I Dst -gc_bif2 Fail I u$bif:erlang:bsr/2 S1 S2 Dst=d => i_fetch S1 S2 | i_bsr Fail I Dst +gc_bif2 Fail Live u$bif:erlang:stimes/2 S1 S2 Dst => \ + i_times Fail Live S1 S2 Dst -gc_bif2 Fail I u$bif:erlang:band/2 S1=x S2=c Dst=d => i_band Fail I S1 S2 Dst -gc_bif2 Fail I u$bif:erlang:band/2 S1 S2 Dst=d => i_fetch S1 S2 | i_band Fail I Dst -gc_bif2 Fail I u$bif:erlang:bor/2 S1 S2 Dst=d => i_fetch S1 S2 | i_bor Fail I Dst -gc_bif2 Fail I u$bif:erlang:bxor/2 S1 S2 Dst=d => i_fetch S1 S2 | i_bxor Fail I Dst +gc_bif2 Fail Live u$bif:erlang:div/2 S1 S2 Dst => \ + i_m_div Fail Live S1 S2 Dst +gc_bif2 Fail Live u$bif:erlang:intdiv/2 S1 S2 Dst => \ + i_int_div Fail Live S1 S2 Dst -gc_bif1 Fail I u$bif:erlang:bnot/1 Src Dst=d => i_int_bnot Fail Src I Dst +gc_bif2 Fail Live u$bif:erlang:rem/2 S1 S2 Dst => \ + i_rem Fail Live S1 S2 Dst + +gc_bif2 Fail Live u$bif:erlang:bsl/2 S1 S2 Dst => \ + i_bsl Fail Live S1 S2 Dst +gc_bif2 Fail Live u$bif:erlang:bsr/2 S1 S2 Dst => \ + i_bsr Fail Live S1 S2 Dst + +gc_bif2 Fail Live u$bif:erlang:band/2 S1 S2 Dst => \ + i_band Fail Live S1 S2 Dst + +gc_bif2 Fail Live u$bif:erlang:bor/2 S1 S2 Dst => \ + i_bor Fail Live S1 S2 Dst -gc_bif1 Fail I u$bif:erlang:sminus/1 Src Dst=d => i_fetch i Src | i_minus Fail I Dst -gc_bif1 Fail I u$bif:erlang:splus/1 Src Dst=d => i_fetch i Src | i_plus Fail I Dst +gc_bif2 Fail Live u$bif:erlang:bxor/2 S1 S2 Dst => \ + i_bxor Fail Live S1 S2 Dst + +gc_bif1 Fail I u$bif:erlang:bnot/1 Src Dst=d => i_int_bnot Fail Src I Dst i_increment r I I d i_increment x I I d i_increment y I I d i_plus j I x x d -i_plus j I d +i_plus j I x y d +i_plus j I s s d + i_minus j I x x d -i_minus j I d -i_times j I d -i_m_div j I d -i_int_div j I d +i_minus j I s s d + +i_times j I s s d + +i_m_div j I s s d +i_int_div j I s s d + i_rem j I x x d -i_rem j I d +i_rem j I s s d -i_bsl j I d -i_bsr j I d +i_bsl j I s s d +i_bsr j I s s d i_band j I x c d -i_band j I d -i_bor j I d -i_bxor j I d +i_band j I s s d + +i_bor j I s s d +i_bxor j I s s d i_int_bnot j s I d @@ -1731,21 +1613,18 @@ gc_bif2 Fail I Bif S1 S2 Dst => \ gc_bif3 Fail I Bif S1 S2 S3 Dst => \ gen_guard_bif3(Fail, I, Bif, S1, S2, S3, Dst) -i_gc_bif1 Fail Bif V=q Live D => move V x | i_gc_bif1 Fail Bif x Live D - i_gc_bif1 j I s I d -ii_gc_bif2/6 - -ii_gc_bif2 Fail Bif S1 S2 Live D => i_fetch S1 S2 | i_gc_bif2 Fail Bif Live D - -i_gc_bif2 j I I d +i_gc_bif2 j I I s s d ii_gc_bif3/7 -ii_gc_bif3 Fail Bif S1 S2 S3 Live D => move S1 x | i_fetch S2 S3 | i_gc_bif3 Fail Bif x Live D +# A specific instruction can only have 6 operands, so we must +# pass one of the arguments in an x register. +ii_gc_bif3 Fail Bif Live S1 S2 S3 Dst => \ + move S1 x | i_gc_bif3 Fail Bif Live S2 S3 Dst -i_gc_bif3 j I s I d +i_gc_bif3 j I I s s d # # The following instruction is specially handled in beam_load.c diff --git a/erts/emulator/beam/packet_parser.c b/erts/emulator/beam/packet_parser.c index 2dd421a9e9..a737a86f14 100644 --- a/erts/emulator/beam/packet_parser.c +++ b/erts/emulator/beam/packet_parser.c @@ -256,6 +256,7 @@ int packet_get_length(enum PacketParseType htype, const char* ptr, unsigned n, /* Bytes read so far */ unsigned max_plen, /* Max packet length, 0=no limit */ unsigned trunc_len, /* Truncate (lines) if longer, 0=no limit */ + char delimiter, /* Line delimiting character */ int* statep) /* Protocol specific state */ { unsigned hlen, plen; @@ -299,9 +300,9 @@ int packet_get_length(enum PacketParseType htype, goto remain; case TCP_PB_LINE_LF: { - /* TCP_PB_LINE_LF: [Data ... \n] */ + /* TCP_PB_LINE_LF: [Data ... Delimiter] */ const char* ptr2; - if ((ptr2 = memchr(ptr, '\n', n)) == NULL) { + if ((ptr2 = memchr(ptr, delimiter, n)) == NULL) { if (n > max_plen && max_plen != 0) { /* packet full */ DEBUGF((" => packet full (no NL)=%d\r\n", n)); goto error; diff --git a/erts/emulator/beam/packet_parser.h b/erts/emulator/beam/packet_parser.h index ff158ff8b8..717d905fad 100644 --- a/erts/emulator/beam/packet_parser.h +++ b/erts/emulator/beam/packet_parser.h @@ -105,7 +105,8 @@ int packet_get_length(enum PacketParseType htype, const char* ptr, unsigned n, /* Bytes read so far */ unsigned max_plen, /* Packet max length, 0=no limit */ unsigned trunc_len, /* Truncate (lines) if longer, 0=no limit */ - int* statep); /* Internal protocol state */ + char delimiter, /* Line delimiting character */ + int* statep); /* Internal protocol state */ ERTS_GLB_INLINE void packet_get_body(enum PacketParseType htype, diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index bb871b05ba..34011147d9 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -74,9 +74,7 @@ #if defined (__WIN32__) # include "erl_win_sys.h" -#elif defined (__OSE__) -# include "erl_ose_sys.h" -#else +#else # include "erl_unix_sys.h" #ifndef UNIX # define UNIX 1 @@ -285,62 +283,11 @@ __decl_noreturn void __noreturn erl_assert_error(const char* expr, const char *f #else #error Neither 32 nor 64 bit architecture #endif -#if defined(ARCH_64) && defined(HALFWORD_HEAP_EMULATOR) -# define HALFWORD_HEAP 1 -# define HALFWORD_ASSERT 0 -# define ASSERT_HALFWORD(COND) ASSERT(COND) -# undef ERTS_SIZEOF_TERM -# define ERTS_SIZEOF_TERM 4 -#else -# define HALFWORD_HEAP 0 -# define HALFWORD_ASSERT 0 -# define ASSERT_HALFWORD(COND) -#endif #if SIZEOF_VOID_P != SIZEOF_SIZE_T #error sizeof(void*) != sizeof(size_t) #endif -#if HALFWORD_HEAP - -#if SIZEOF_INT == 4 -typedef unsigned int Eterm; -typedef unsigned int Uint; -typedef int Sint; -#define ERTS_UINT_MAX UINT_MAX -#define ERTS_SIZEOF_ETERM SIZEOF_INT -#define ErtsStrToSint strtol -#else -#error Found no appropriate type to use for 'Eterm', 'Uint' and 'Sint' -#endif - -#if SIZEOF_VOID_P == SIZEOF_LONG -typedef unsigned long UWord; -typedef long SWord; -#define SWORD_CONSTANT(Const) Const##L -#define UWORD_CONSTANT(Const) Const##UL -#define ERTS_UWORD_MAX ULONG_MAX -#define ERTS_SWORD_MAX LONG_MAX -#elif SIZEOF_VOID_P == SIZEOF_INT -typedef unsigned int UWord; -typedef int SWord; -#define SWORD_CONSTANT(Const) Const -#define UWORD_CONSTANT(Const) Const##U -#define ERTS_UWORD_MAX UINT_MAX -#define ERTS_SWORD_MAX INT_MAX -#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG -typedef unsigned long long UWord; -typedef long long SWord; -#define SWORD_CONSTANT(Const) Const##LL -#define UWORD_CONSTANT(Const) Const##ULL -#define ERTS_UWORD_MAX ULLONG_MAX -#define ERTS_SWORD_MAX LLONG_MAX -#else -#error Found no appropriate type to use for 'Eterm', 'Uint' and 'Sint' -#endif - -#else /* !HALFWORD_HEAP */ - #if SIZEOF_VOID_P == SIZEOF_LONG typedef unsigned long Eterm; typedef unsigned long Uint; @@ -383,8 +330,6 @@ typedef Uint UWord; typedef Sint SWord; #define ERTS_UINT_MAX ERTS_UWORD_MAX -#endif /* HALFWORD_HEAP */ - typedef UWord BeamInstr; #ifndef HAVE_INT64 diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index e9d7c91ac9..5fe4091adc 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -897,7 +897,7 @@ tail_recur: Uint y2 = y1 < 0 ? -(Uint)y1 : y1; UINT32_HASH_STEP(y2, FUNNY_NUMBER2); -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) if (y2 >> 32) UINT32_HASH_STEP(y2 >> 32, FUNNY_NUMBER2); #endif @@ -1018,7 +1018,7 @@ tail_recur: } d = BIG_DIGIT(ptr, k); k = sizeof(ErtsDigit); -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) if (!(d >> 32)) k /= 2; #endif @@ -1988,7 +1988,7 @@ tail_recur: (atom_tab(atom_val(term))->slot.bucket.hvalue); break; case SMALL_DEF: -#if defined(ARCH_64) && !HALFWORD_HEAP +#if defined(ARCH_64) { Sint y1 = signed_val(term); Uint y2 = y1 < 0 ? -(Uint)y1 : y1; @@ -2597,11 +2597,7 @@ erts_destroy_tmp_dsbuf(erts_dsprintf_buf_t *dsbufp) * Test for equality of two terms. * Returns 0 if not equal, or a non-zero value otherwise. */ -#if HALFWORD_HEAP -int eq_rel(Eterm a, Eterm* a_base, Eterm b, Eterm* b_base) -#else int eq(Eterm a, Eterm b) -#endif { DECLARE_WSTACK(stack); Sint sz; @@ -2609,18 +2605,18 @@ int eq(Eterm a, Eterm b) Eterm* bb; tailrecur: - if (is_same(a, a_base, b, b_base)) goto pop_next; + if (is_same(a, b)) goto pop_next; tailrecur_ne: switch (primary_tag(a)) { case TAG_PRIMARY_LIST: if (is_list(b)) { - Eterm* aval = list_val_rel(a, a_base); - Eterm* bval = list_val_rel(b, b_base); + Eterm* aval = list_val(a); + Eterm* bval = list_val(b); while (1) { Eterm atmp = CAR(aval); Eterm btmp = CAR(bval); - if (!is_same(atmp,a_base,btmp,b_base)) { + if (!is_same(atmp,btmp)) { WSTACK_PUSH2(stack,(UWord) CDR(bval),(UWord) CDR(aval)); a = atmp; b = btmp; @@ -2628,7 +2624,7 @@ tailrecur_ne: } atmp = CDR(aval); btmp = CDR(bval); - if (is_same(atmp,a_base,btmp,b_base)) { + if (is_same(atmp,btmp)) { goto pop_next; } if (is_not_list(atmp) || is_not_list(btmp)) { @@ -2636,22 +2632,22 @@ tailrecur_ne: b = btmp; goto tailrecur_ne; } - aval = list_val_rel(atmp, a_base); - bval = list_val_rel(btmp, b_base); + aval = list_val(atmp); + bval = list_val(btmp); } } break; /* not equal */ case TAG_PRIMARY_BOXED: { - Eterm hdr = *boxed_val_rel(a,a_base); + Eterm hdr = *boxed_val(a); switch (hdr & _TAG_HEADER_MASK) { case ARITYVAL_SUBTAG: { - aa = tuple_val_rel(a, a_base); - if (!is_boxed(b) || *boxed_val_rel(b,b_base) != *aa) + aa = tuple_val(a); + if (!is_boxed(b) || *boxed_val(b) != *aa) goto not_equal; - bb = tuple_val_rel(b,b_base); + bb = tuple_val(b); if ((sz = arityval(*aa)) == 0) goto pop_next; ++aa; ++bb; @@ -2670,16 +2666,16 @@ tailrecur_ne: Uint a_bitoffs; Uint b_bitoffs; - if (!is_binary_rel(b,b_base)) { + if (!is_binary(b)) { goto not_equal; } - a_size = binary_size_rel(a,a_base); - b_size = binary_size_rel(b,b_base); + a_size = binary_size(a); + b_size = binary_size(b); if (a_size != b_size) { goto not_equal; } - ERTS_GET_BINARY_BYTES_REL(a, a_ptr, a_bitoffs, a_bitsize, a_base); - ERTS_GET_BINARY_BYTES_REL(b, b_ptr, b_bitoffs, b_bitsize, b_base); + ERTS_GET_BINARY_BYTES(a, a_ptr, a_bitoffs, a_bitsize); + ERTS_GET_BINARY_BYTES(b, b_ptr, b_bitoffs, b_bitsize); if ((a_bitsize | b_bitsize | a_bitoffs | b_bitoffs) == 0) { if (sys_memcmp(a_ptr, b_ptr, a_size) == 0) goto pop_next; } else if (a_bitsize == b_bitsize) { @@ -2690,9 +2686,9 @@ tailrecur_ne: } case EXPORT_SUBTAG: { - if (is_export_rel(b,b_base)) { - Export* a_exp = *((Export **) (export_val_rel(a,a_base) + 1)); - Export* b_exp = *((Export **) (export_val_rel(b,b_base) + 1)); + if (is_export(b)) { + Export* a_exp = *((Export **) (export_val(a) + 1)); + Export* b_exp = *((Export **) (export_val(b) + 1)); if (a_exp == b_exp) goto pop_next; } break; /* not equal */ @@ -2702,10 +2698,10 @@ tailrecur_ne: ErlFunThing* f1; ErlFunThing* f2; - if (!is_fun_rel(b,b_base)) + if (!is_fun(b)) goto not_equal; - f1 = (ErlFunThing *) fun_val_rel(a,a_base); - f2 = (ErlFunThing *) fun_val_rel(b,b_base); + f1 = (ErlFunThing *) fun_val(a); + f2 = (ErlFunThing *) fun_val(b); if (f1->fe->module != f2->fe->module || f1->fe->old_index != f2->fe->old_index || f1->fe->old_uniq != f2->fe->old_uniq || @@ -2723,15 +2719,15 @@ tailrecur_ne: ExternalThing *ap; ExternalThing *bp; - if(!is_external_rel(b,b_base)) + if(!is_external(b)) goto not_equal; - ap = external_thing_ptr_rel(a,a_base); - bp = external_thing_ptr_rel(b,b_base); + ap = external_thing_ptr(a); + bp = external_thing_ptr(b); if(ap->header == bp->header && ap->node == bp->node) { - ASSERT(1 == external_data_words_rel(a,a_base)); - ASSERT(1 == external_data_words_rel(b,b_base)); + ASSERT(1 == external_data_words(a)); + ASSERT(1 == external_data_words(b)); if (ap->data.ui[0] == bp->data.ui[0]) goto pop_next; } @@ -2752,11 +2748,11 @@ tailrecur_ne: ExternalThing* athing; ExternalThing* bthing; - if(!is_external_ref_rel(b,b_base)) + if(!is_external_ref(b)) goto not_equal; - athing = external_thing_ptr_rel(a,a_base); - bthing = external_thing_ptr_rel(b,b_base); + athing = external_thing_ptr(a); + bthing = external_thing_ptr(b); if(athing->node != bthing->node) goto not_equal; @@ -2768,12 +2764,12 @@ tailrecur_ne: goto ref_common; case REF_SUBTAG: - if (!is_internal_ref_rel(b,b_base)) + if (!is_internal_ref(b)) goto not_equal; { - RefThing* athing = ref_thing_ptr_rel(a,a_base); - RefThing* bthing = ref_thing_ptr_rel(b,b_base); + RefThing* athing = ref_thing_ptr(a); + RefThing* bthing = ref_thing_ptr(b); alen = internal_thing_ref_no_of_numbers(athing); blen = internal_thing_ref_no_of_numbers(bthing); anum = internal_thing_ref_numbers(athing); @@ -2823,10 +2819,10 @@ tailrecur_ne: { int i; - if (!is_big_rel(b,b_base)) + if (!is_big(b)) goto not_equal; - aa = big_val_rel(a,a_base); - bb = big_val_rel(b,b_base); + aa = big_val(a); + bb = big_val(b); if (*aa != *bb) goto not_equal; i = BIG_ARITY(aa); @@ -2841,19 +2837,19 @@ tailrecur_ne: FloatDef af; FloatDef bf; - if (is_float_rel(b,b_base)) { - GET_DOUBLE_REL(a, af, a_base); - GET_DOUBLE_REL(b, bf, b_base); + if (is_float(b)) { + GET_DOUBLE(a, af); + GET_DOUBLE(b, bf); if (af.fd == bf.fd) goto pop_next; } break; /* not equal */ } case MAP_SUBTAG: - if (is_flatmap_rel(a, a_base)) { - aa = flatmap_val_rel(a, a_base); - if (!is_boxed(b) || *boxed_val_rel(b,b_base) != *aa) + if (is_flatmap(a)) { + aa = flatmap_val(a); + if (!is_boxed(b) || *boxed_val(b) != *aa) goto not_equal; - bb = flatmap_val_rel(b,b_base); + bb = flatmap_val(b); sz = flatmap_get_size((flatmap_t*)aa); if (sz != flatmap_get_size((flatmap_t*)bb)) goto not_equal; @@ -2865,11 +2861,11 @@ tailrecur_ne: goto term_array; } else { - if (!is_boxed(b) || *boxed_val_rel(b,b_base) != hdr) + if (!is_boxed(b) || *boxed_val(b) != hdr) goto not_equal; - aa = hashmap_val_rel(a, a_base) + 1; - bb = hashmap_val_rel(b, b_base) + 1; + aa = hashmap_val(a) + 1; + bb = hashmap_val(b) + 1; switch (hdr & _HEADER_MAP_SUBTAG_MASK) { case HAMT_SUBTAG_HEAD_ARRAY: aa++; bb++; @@ -2902,7 +2898,7 @@ term_array: /* arrays in 'aa' and 'bb', length in 'sz' */ Eterm* bp = bb; Sint i = sz; for (;;) { - if (!is_same(*ap,a_base,*bp,b_base)) break; + if (!is_same(*ap,*bp)) break; if (--i == 0) goto pop_next; ++ap; ++bp; @@ -2991,7 +2987,6 @@ static int cmp_atoms(Eterm a, Eterm b) bb->name+3, bb->len-3); } -#if !HALFWORD_HEAP /* cmp(Eterm a, Eterm b) * For compatibility with HiPE - arith-based compare. */ @@ -2999,39 +2994,22 @@ Sint cmp(Eterm a, Eterm b) { return erts_cmp(a, b, 0, 0); } -#endif -#if HALFWORD_HEAP -static Sint erts_cmp_compound_rel_opt(Eterm a, Eterm* a_base, - Eterm b, Eterm* b_base, - int exact, int eq_only); -#else static Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only); -#endif -#if HALFWORD_HEAP -Sint erts_cmp_rel_opt(Eterm a, Eterm* a_base, - Eterm b, Eterm* b_base, - int exact, int eq_only) -#else Sint erts_cmp(Eterm a, Eterm b, int exact, int eq_only) -#endif { if (is_atom(a) && is_atom(b)) { return cmp_atoms(a, b); } else if (is_both_small(a, b)) { return (signed_val(a) - signed_val(b)); - } else if (is_float_rel(a, a_base) && is_float_rel(b, b_base)) { + } else if (is_float(a) && is_float(b)) { FloatDef af, bf; - GET_DOUBLE_REL(a, af, a_base); - GET_DOUBLE_REL(b, bf, b_base); + GET_DOUBLE(a, af); + GET_DOUBLE(b, bf); return float_comp(af.fd, bf.fd); } -#if HALFWORD_HEAP - return erts_cmp_compound_rel_opt(a,a_base,b,b_base,exact,eq_only); -#else return erts_cmp_compound(a,b,exact,eq_only); -#endif } @@ -3039,13 +3017,7 @@ Sint erts_cmp(Eterm a, Eterm b, int exact, int eq_only) * exact = 1 -> term-based compare * exact = 0 -> arith-based compare */ -#if HALFWORD_HEAP -static Sint erts_cmp_compound_rel_opt(Eterm a, Eterm* a_base, - Eterm b, Eterm* b_base, - int exact, int eq_only) -#else static Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) -#endif { #define PSTACK_TYPE struct erts_cmp_hashmap_state struct erts_cmp_hashmap_state { @@ -3112,7 +3084,7 @@ static Sint erts_cmp_compound(Eterm a, Eterm b, int exact, int eq_only) bodyrecur: j = 0; tailrecur: - if (is_same(a,a_base,b,b_base)) { /* Equal values or pointers. */ + if (is_same(a,b)) { /* Equal values or pointers. */ goto pop_next; } tailrecur_ne: @@ -3138,9 +3110,9 @@ tailrecur_ne: if (is_internal_port(b)) { bnode = erts_this_node; bdata = internal_port_data(b); - } else if (is_external_port_rel(b,b_base)) { - bnode = external_port_node_rel(b,b_base); - bdata = external_port_data_rel(b,b_base); + } else if (is_external_port(b)) { + bnode = external_port_node(b); + bdata = external_port_data(b); } else { a_tag = PORT_DEF; goto mixed_types; @@ -3156,9 +3128,9 @@ tailrecur_ne: if (is_internal_pid(b)) { bnode = erts_this_node; bdata = internal_pid_data(b); - } else if (is_external_pid_rel(b,b_base)) { - bnode = external_pid_node_rel(b,b_base); - bdata = external_pid_data_rel(b,b_base); + } else if (is_external_pid(b)) { + bnode = external_pid_node(b); + bdata = external_pid_data(b); } else { a_tag = PID_DEF; goto mixed_types; @@ -3191,12 +3163,12 @@ tailrecur_ne: a_tag = LIST_DEF; goto mixed_types; } - aa = list_val_rel(a,a_base); - bb = list_val_rel(b,b_base); + aa = list_val(a); + bb = list_val(b); while (1) { Eterm atmp = CAR(aa); Eterm btmp = CAR(bb); - if (!is_same(atmp,a_base,btmp,b_base)) { + if (!is_same(atmp,btmp)) { WSTACK_PUSH2(stack,(UWord) CDR(bb),(UWord) CDR(aa)); a = atmp; b = btmp; @@ -3204,7 +3176,7 @@ tailrecur_ne: } atmp = CDR(aa); btmp = CDR(bb); - if (is_same(atmp,a_base,btmp,b_base)) { + if (is_same(atmp,btmp)) { goto pop_next; } if (is_not_list(atmp) || is_not_list(btmp)) { @@ -3212,20 +3184,20 @@ tailrecur_ne: b = btmp; goto tailrecur_ne; } - aa = list_val_rel(atmp,a_base); - bb = list_val_rel(btmp,b_base); + aa = list_val(atmp); + bb = list_val(btmp); } case TAG_PRIMARY_BOXED: { - Eterm ahdr = *boxed_val_rel(a,a_base); + Eterm ahdr = *boxed_val(a); switch ((ahdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) { case (_TAG_HEADER_ARITYVAL >> _TAG_PRIMARY_SIZE): - if (!is_tuple_rel(b,b_base)) { + if (!is_tuple(b)) { a_tag = TUPLE_DEF; goto mixed_types; } - aa = tuple_val_rel(a,a_base); - bb = tuple_val_rel(b,b_base); + aa = tuple_val(a); + bb = tuple_val(b); /* compare the arities */ i = arityval(ahdr); /* get the arity*/ if (i != arityval(*bb)) { @@ -3241,18 +3213,18 @@ tailrecur_ne: { struct erts_cmp_hashmap_state* sp; if (is_flatmap_header(ahdr)) { - if (!is_flatmap_rel(b,b_base)) { - if (is_hashmap_rel(b,b_base)) { - aa = (Eterm *)flatmap_val_rel(a,a_base); - i = flatmap_get_size((flatmap_t*)aa) - hashmap_size_rel(b,b_base); + if (!is_flatmap(b)) { + if (is_hashmap(b)) { + aa = (Eterm *)flatmap_val(a); + i = flatmap_get_size((flatmap_t*)aa) - hashmap_size(b); ASSERT(i != 0); RETURN_NEQ(i); } a_tag = MAP_DEF; goto mixed_types; } - aa = (Eterm *)flatmap_val_rel(a,a_base); - bb = (Eterm *)flatmap_val_rel(b,b_base); + aa = (Eterm *)flatmap_val(a); + bb = (Eterm *)flatmap_val(b); i = flatmap_get_size((flatmap_t*)aa); if (i != flatmap_get_size((flatmap_t*)bb)) { @@ -3279,21 +3251,21 @@ tailrecur_ne: goto bodyrecur; } } - if (!is_hashmap_rel(b,b_base)) { - if (is_flatmap_rel(b,b_base)) { - bb = (Eterm *)flatmap_val_rel(b,b_base); - i = hashmap_size_rel(a,a_base) - flatmap_get_size((flatmap_t*)bb); + if (!is_hashmap(b)) { + if (is_flatmap(b)) { + bb = (Eterm *)flatmap_val(b); + i = hashmap_size(a) - flatmap_get_size((flatmap_t*)bb); ASSERT(i != 0); RETURN_NEQ(i); } a_tag = MAP_DEF; goto mixed_types; } - i = hashmap_size_rel(a,a_base) - hashmap_size_rel(b,b_base); + i = hashmap_size(a) - hashmap_size(b); if (i) { RETURN_NEQ(i); } - if (hashmap_size_rel(a,a_base) == 0) { + if (hashmap_size(a) == 0) { goto pop_next; } @@ -3328,31 +3300,31 @@ tailrecur_ne: goto bodyrecur; } case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): - if (!is_float_rel(b,b_base)) { + if (!is_float(b)) { a_tag = FLOAT_DEF; goto mixed_types; } else { FloatDef af; FloatDef bf; - GET_DOUBLE_REL(a, af, a_base); - GET_DOUBLE_REL(b, bf, b_base); + GET_DOUBLE(a, af); + GET_DOUBLE(b, bf); ON_CMP_GOTO(float_comp(af.fd, bf.fd)); } case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): - if (!is_big_rel(b,b_base)) { + if (!is_big(b)) { a_tag = BIG_DEF; goto mixed_types; } - ON_CMP_GOTO(big_comp(rterm2wterm(a,a_base), rterm2wterm(b,b_base))); + ON_CMP_GOTO(big_comp(a, b)); case (_TAG_HEADER_EXPORT >> _TAG_PRIMARY_SIZE): - if (!is_export_rel(b,b_base)) { + if (!is_export(b)) { a_tag = EXPORT_DEF; goto mixed_types; } else { - Export* a_exp = *((Export **) (export_val_rel(a,a_base) + 1)); - Export* b_exp = *((Export **) (export_val_rel(b,b_base) + 1)); + Export* a_exp = *((Export **) (export_val(a) + 1)); + Export* b_exp = *((Export **) (export_val(b) + 1)); if ((j = cmp_atoms(a_exp->code[0], b_exp->code[0])) != 0) { RETURN_NEQ(j); @@ -3364,12 +3336,12 @@ tailrecur_ne: } break; case (_TAG_HEADER_FUN >> _TAG_PRIMARY_SIZE): - if (!is_fun_rel(b,b_base)) { + if (!is_fun(b)) { a_tag = FUN_DEF; goto mixed_types; } else { - ErlFunThing* f1 = (ErlFunThing *) fun_val_rel(a,a_base); - ErlFunThing* f2 = (ErlFunThing *) fun_val_rel(b,b_base); + ErlFunThing* f1 = (ErlFunThing *) fun_val(a); + ErlFunThing* f2 = (ErlFunThing *) fun_val(b); Sint diff; diff = cmpbytes(atom_tab(atom_val(f1->fe->module))->name, @@ -3401,29 +3373,29 @@ tailrecur_ne: if (is_internal_pid(b)) { bnode = erts_this_node; bdata = internal_pid_data(b); - } else if (is_external_pid_rel(b,b_base)) { - bnode = external_pid_node_rel(b,b_base); - bdata = external_pid_data_rel(b,b_base); + } else if (is_external_pid(b)) { + bnode = external_pid_node(b); + bdata = external_pid_data(b); } else { a_tag = EXTERNAL_PID_DEF; goto mixed_types; } - anode = external_pid_node_rel(a,a_base); - adata = external_pid_data_rel(a,a_base); + anode = external_pid_node(a); + adata = external_pid_data(a); goto pid_common; case (_TAG_HEADER_EXTERNAL_PORT >> _TAG_PRIMARY_SIZE): if (is_internal_port(b)) { bnode = erts_this_node; bdata = internal_port_data(b); - } else if (is_external_port_rel(b,b_base)) { - bnode = external_port_node_rel(b,b_base); - bdata = external_port_data_rel(b,b_base); + } else if (is_external_port(b)) { + bnode = external_port_node(b); + bdata = external_port_data(b); } else { a_tag = EXTERNAL_PORT_DEF; goto mixed_types; } - anode = external_port_node_rel(a,a_base); - adata = external_port_data_rel(a,a_base); + anode = external_port_node(a); + adata = external_port_data(a); goto port_common; case (_TAG_HEADER_REF >> _TAG_PRIMARY_SIZE): /* @@ -3431,14 +3403,13 @@ tailrecur_ne: * (32-bit words), *not* ref data words. */ - - if (is_internal_ref_rel(b,b_base)) { - RefThing* bthing = ref_thing_ptr_rel(b,b_base); + if (is_internal_ref(b)) { + RefThing* bthing = ref_thing_ptr(b); bnode = erts_this_node; bnum = internal_thing_ref_numbers(bthing); blen = internal_thing_ref_no_of_numbers(bthing); - } else if(is_external_ref_rel(b,b_base)) { - ExternalThing* bthing = external_thing_ptr_rel(b,b_base); + } else if(is_external_ref(b)) { + ExternalThing* bthing = external_thing_ptr(b); bnode = bthing->node; bnum = external_thing_ref_numbers(bthing); blen = external_thing_ref_no_of_numbers(bthing); @@ -3447,7 +3418,7 @@ tailrecur_ne: goto mixed_types; } { - RefThing* athing = ref_thing_ptr_rel(a,a_base); + RefThing* athing = ref_thing_ptr(a); anode = erts_this_node; anum = internal_thing_ref_numbers(athing); alen = internal_thing_ref_no_of_numbers(athing); @@ -3480,13 +3451,13 @@ tailrecur_ne: RETURN_NEQ((Sint32) (anum[i] - bnum[i])); goto pop_next; case (_TAG_HEADER_EXTERNAL_REF >> _TAG_PRIMARY_SIZE): - if (is_internal_ref_rel(b,b_base)) { - RefThing* bthing = ref_thing_ptr_rel(b,b_base); + if (is_internal_ref(b)) { + RefThing* bthing = ref_thing_ptr(b); bnode = erts_this_node; bnum = internal_thing_ref_numbers(bthing); blen = internal_thing_ref_no_of_numbers(bthing); - } else if (is_external_ref_rel(b,b_base)) { - ExternalThing* bthing = external_thing_ptr_rel(b,b_base); + } else if (is_external_ref(b)) { + ExternalThing* bthing = external_thing_ptr(b); bnode = bthing->node; bnum = external_thing_ref_numbers(bthing); blen = external_thing_ref_no_of_numbers(bthing); @@ -3495,7 +3466,7 @@ tailrecur_ne: goto mixed_types; } { - ExternalThing* athing = external_thing_ptr_rel(a,a_base); + ExternalThing* athing = external_thing_ptr(a); anode = athing->node; anum = external_thing_ref_numbers(athing); alen = external_thing_ref_no_of_numbers(athing); @@ -3503,13 +3474,13 @@ tailrecur_ne: goto ref_common; default: /* Must be a binary */ - ASSERT(is_binary_rel(a,a_base)); - if (!is_binary_rel(b,b_base)) { + ASSERT(is_binary(a)); + if (!is_binary(b)) { a_tag = BINARY_DEF; goto mixed_types; } else { - Uint a_size = binary_size_rel(a,a_base); - Uint b_size = binary_size_rel(b,b_base); + Uint a_size = binary_size(a); + Uint b_size = binary_size(b); Uint a_bitsize; Uint b_bitsize; Uint a_bitoffs; @@ -3518,8 +3489,8 @@ tailrecur_ne: int cmp; byte* a_ptr; byte* b_ptr; - ERTS_GET_BINARY_BYTES_REL(a, a_ptr, a_bitoffs, a_bitsize, a_base); - ERTS_GET_BINARY_BYTES_REL(b, b_ptr, b_bitoffs, b_bitsize, b_base); + ERTS_GET_BINARY_BYTES(a, a_ptr, a_bitoffs, a_bitsize); + ERTS_GET_BINARY_BYTES(b, b_ptr, b_bitoffs, b_bitsize); if ((a_bitsize | b_bitsize | a_bitoffs | b_bitoffs) == 0) { min_size = (a_size < b_size) ? a_size : b_size; if ((cmp = sys_memcmp(a_ptr, b_ptr, min_size)) != 0) { @@ -3550,13 +3521,8 @@ tailrecur_ne: { FloatDef f1, f2; Eterm big; -#if HALFWORD_HEAP - Wterm aw = is_immed(a) ? a : rterm2wterm(a,a_base); - Wterm bw = is_immed(b) ? b : rterm2wterm(b,b_base); -#else Eterm aw = a; Eterm bw = b; -#endif #define MAX_LOSSLESS_FLOAT ((double)((1LL << 53) - 2)) #define MIN_LOSSLESS_FLOAT ((double)(((1LL << 53) - 2)*-1)) #define BIG_ARITY_FLOAT_MAX (1024 / D_EXP) /* arity of max float as a bignum */ @@ -3628,7 +3594,7 @@ tailrecur_ne: } } else { big = double_to_big(f2.fd, big_buf, sizeof(big_buf)/sizeof(Eterm)); - j = big_comp(aw, rterm2wterm(big,big_buf)); + j = big_comp(aw, big); } if (_NUMBER_CODE(a_tag, b_tag) == FLOAT_BIG) { j = -j; @@ -3676,7 +3642,7 @@ term_array: /* arrays in 'aa' and 'bb', length in 'i' */ while (--i) { a = *aa++; b = *bb++; - if (!is_same(a,a_base, b,b_base)) { + if (!is_same(a, b)) { if (is_atom(a) && is_atom(b)) { if ((j = cmp_atoms(a, b)) != 0) { goto not_equal; @@ -4368,7 +4334,7 @@ iolist_size(const int yield_support, ErtsIOListState *state, Eterm obj, ErlDrvSi { int res, init_yield_count, yield_count; Eterm* objp; - Uint size = (Uint) *sizep; /* Intentionally Uint due to halfword heap */ + Uint size = (Uint) *sizep; DECLARE_ESTACK(s); if (!yield_support) diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 8aff6c1865..2cb4662fc3 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -101,15 +101,9 @@ # include "config.h" #endif -#ifndef __OSE__ #include <ctype.h> #include <sys/types.h> #include <stdlib.h> -#else -#include "ctype.h" -#include "sys/types.h" -#include "stdlib.h" -#endif /* Need (NON)BLOCKING macros for sendfile */ #ifndef WANT_NONBLOCKING @@ -895,7 +889,7 @@ static void reply_Uint_posix_error(file_descriptor *desc, Uint num, TRACE_C('N'); response[0] = FILE_RESP_NUMERR; -#if SIZEOF_VOID_P == 4 || HALFWORD_HEAP +#if SIZEOF_VOID_P == 4 put_int32(0, response+1); #else put_int32(num>>32, response+1); @@ -964,7 +958,7 @@ static int reply_Uint(file_descriptor *desc, Uint result) { TRACE_C('R'); tmp[0] = FILE_RESP_NUMBER; -#if SIZEOF_VOID_P == 4 || HALFWORD_HEAP +#if SIZEOF_VOID_P == 4 put_int32(0, tmp+1); #else put_int32(result>>32, tmp+1); diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 549de6503c..1e3360c2b1 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -94,10 +94,6 @@ typedef unsigned long long llu_t; #define INT16_MAX (32767) #endif -#ifdef __OSE__ -#include "inet.h" -#endif - #ifdef __WIN32__ #define STRNCASECMP strncasecmp @@ -298,139 +294,7 @@ static unsigned long one_value = 1; #define TCP_SHUT_RD SD_RECEIVE #define TCP_SHUT_RDWR SD_BOTH -#elif defined (__OSE__) - -/* - * Some notes about how inet (currently only tcp) works on OSE. - * The driver uses OSE signals to communicate with the one_inet - * process. Because of the difference in how signals and file descriptors - * work the whole select/deselect mechanic is very different. - * In ose when a sock_select is done a function is called. That function - * notes the changes that the driver want to do, but does not act on it. - * later when the function returns the new desired state is compared - * to the previous state and the apprioriate actions are taken. The action - * is usually to either request more data from the stack or stop requesting - * data. - * - * One thing to note is that the driver never does select/deselect. It always - * listens for the signals. Flow of data is regulated by sending or not sending - * signals to the ose inet process. - * - * The interesting functions to look at are: - * * inet_driver_select : called when sock_select is called - * * tcp_inet_ose_dispatch_signal : checks state changes and sends new signals - * * tcp_inet_drv_output_ose : ready output callback, reads signals and calls - * dispatch_signal - * * tcp_inet_drv_input_ose : ready input callback. - */ - -#include "efs.h" -#include "sys/socket.h" -#include "sys/uio.h" -#include "sfk/sys/sfk_uio.h" -#include "netinet/in.h" -#include "netinet/tcp.h" -#include "netdb.h" -#include "ose_spi/socket.sig" - - -static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int max_sz); - -#define INVALID_SOCKET -1 -#define INVALID_EVENT -1 -#define SOCKET_ERROR -1 - -#define SOCKET int -#define HANDLE int -#define FD_READ ERL_DRV_READ -#define FD_WRITE ERL_DRV_WRITE -#define FD_CLOSE 0 -#define FD_CONNECT (1<<4) -#define FD_ACCEPT (1<<5) -#define SOCK_FD_ERROR (1<<6) - -#define sock_connect(s, addr, len) connect((s), (addr), (len)) -#define sock_listen(s, b) listen((s), (b)) -#define sock_bind(s, addr, len) bind((s), (addr), (len)) -#define sock_getopt(s,t,n,v,l) getsockopt((s),(t),(n),(v),(l)) -#define sock_setopt(s,t,n,v,l) setsockopt((s),(t),(n),(v),(l)) -#define sock_name(s, addr, len) getsockname((s), (addr), (len)) -#define sock_peer(s, addr, len) getpeername((s), (addr), (len)) -#define sock_ntohs(x) ntohs((x)) -#define sock_ntohl(x) ntohl((x)) -#define sock_htons(x) htons((x)) -#define sock_htonl(x) htonl((x)) - -#define sock_accept(s, addr, len) accept((s), (addr), (len)) -#define sock_send(s,buf,len,flag) inet_send((s),(buf),(len),(flag)) -#define sock_sendto(s,buf,blen,flag,addr,alen) \ - sendto((s),(buf),(blen),(flag),(addr),(alen)) -#define sock_sendv(s, vec, size, np, flag) \ - (*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np)))) -#define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) - -#define sock_open(af, type, proto) socket((af), (type), (proto)) -#define sock_close(s) close((s)) -#define sock_dup(s) dup((s)) -#define sock_shutdown(s, how) shutdown((s), (how)) - -#define sock_hostname(buf, len) gethostname((buf), (len)) -#define sock_getservbyname(name,proto) getservbyname((name), (proto)) -#define sock_getservbyport(port,proto) getservbyport((port), (proto)) - -#define sock_recv(s,buf,len,flag) recv((s),(buf),(len),(flag)) -#define sock_recvfrom(s,buf,blen,flag,addr,alen) \ - recvfrom((s),(buf),(blen),(flag),(addr),(alen)) -#define sock_recvmsg(s,msghdr,flag) recvmsg((s),(msghdr),(flag)) - -#define sock_errno() errno -#define sock_create_event(d) ((d)->s) /* return file descriptor */ -#define sock_close_event(e) /* do nothing */ - -#ifndef WANT_NONBLOCKING -#define WANT_NONBLOCKING -#endif -#include "sys.h" - -typedef unsigned long u_long; -#define IN_CLASSA(a) ((((in_addr_t)(a)) & 0x80000000) == 0) -#define IN_CLASSA_NET 0xff000000 -#define IN_CLASSA_NSHIFT 24 -#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) -#define IN_CLASSA_MAX 128 - -#define IN_CLASSB(a) ((((in_addr_t)(a)) & 0xc0000000) == 0x80000000) -#define IN_CLASSB_NET 0xffff0000 -#define IN_CLASSB_NSHIFT 16 -#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) -#define IN_CLASSB_MAX 65536 - -#define IN_CLASSC(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xc0000000) -#define IN_CLASSC_NET 0xffffff00 -#define IN_CLASSC_NSHIFT 8 -#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) - -#define IN_CLASSD(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xe0000000) -#define IN_MULTICAST(a) IN_CLASSD(a) - -#define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000) -#define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000) - -#define sock_select(d, flags, onoff) do { \ - ASSERT(!(d)->is_ignored); \ - (d)->event_mask = (onoff) ? \ - ((d)->event_mask | (flags)) : \ - ((d)->event_mask & ~(flags)); \ - DEBUGF(("(%s / %d) sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX, s=%d\r\n", \ - __FILE__, __LINE__, (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask, (d)->s)); \ - inet_driver_select((d), (flags), (onoff)); \ - } while(0) - -#define TCP_SHUT_WR SHUT_WR -#define TCP_SHUT_RD SHUT_RD -#define TCP_SHUT_RDWR SHUT_RDWR - -#else /* !__OSE__ && !__WIN32__ */ +#else /* !__WIN32__ */ #include <sys/time.h> #ifdef NETDB_H_NEEDS_IN_H @@ -704,7 +568,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define TCP_SHUT_RD SHUT_RD #define TCP_SHUT_RDWR SHUT_RDWR -#endif /* !__WIN32__ && !__OSE__ */ +#endif /* !__WIN32__ */ #ifdef HAVE_SOCKLEN_T # define SOCKLEN_T socklen_t @@ -885,6 +749,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_LOPT_MSGQ_LOWTRMRK 37 /* set local msgq low watermark */ #define INET_LOPT_NETNS 38 /* Network namespace pathname */ #define INET_LOPT_TCP_SHOW_ECONNRESET 39 /* tell user about incoming RST */ +#define INET_LOPT_LINE_DELIM 40 /* Line delimiting char */ /* SCTP options: a separate range, from 100: */ #define SCTP_OPT_RTOINFO 100 #define SCTP_OPT_ASSOCINFO 101 @@ -1154,6 +1019,7 @@ typedef struct { #else Uint32 send_oct[2]; /* number of octets sent, 64 bits */ #endif + char delimiter; /* Line delimiting character (def: '\n') */ unsigned long send_cnt; /* number of packets sent */ unsigned long send_max; /* maximum packet send */ double send_avg; /* average packet size sent */ @@ -1166,13 +1032,6 @@ typedef struct { char *netns; /* Socket network namespace name as full file path */ #endif -#ifdef __OSE__ - int select_state; /* state to keep track of whether we - should trigger another read/write - request at end of ready_input/output */ - ErlDrvEvent events[6]; -#endif - } inet_descriptor; @@ -1188,10 +1047,8 @@ static void tcp_inet_stop(ErlDrvData); static void tcp_inet_command(ErlDrvData, char*, ErlDrvSizeT); static void tcp_inet_commandv(ErlDrvData, ErlIOVec*); static void tcp_inet_flush(ErlDrvData drv_data); -#ifndef __OSE__ static void tcp_inet_drv_input(ErlDrvData, ErlDrvEvent); static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event); -#endif static ErlDrvData tcp_inet_start(ErlDrvPort, char* command); static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData, unsigned int, char*, ErlDrvSizeT, char**, ErlDrvSizeT); @@ -1204,71 +1061,6 @@ static void tcp_inet_event(ErlDrvData, ErlDrvEvent); static void find_dynamic_functions(void); #endif -#ifdef __OSE__ -/* The structure of the signal used for requesting asynchronous - * notification from the stack. Under normal circumstances the network stack - * shouldn't overwrite the value set in the fd field by the sender - * of the request */ -struct OseAsyncSig { - struct FmEvent event; - int fd; -}; - -union SIGNAL { - SIGSELECT signo; - struct OseAsyncSig async; -}; - -static ErlDrvSSizeT tcp_inet_ctl_ose(ErlDrvData e, unsigned int cmd, - char* buf, ErlDrvSizeT len, - char** rbuf, ErlDrvSizeT rsize); -static void tcp_inet_commandv_ose(ErlDrvData e, ErlIOVec* ev); -static void tcp_inet_drv_output_ose(ErlDrvData data, ErlDrvEvent event); -static void tcp_inet_drv_input_ose(ErlDrvData data, ErlDrvEvent event); -static ErlDrvOseEventId inet_resolve_signal(union SIGNAL *sig); - -#ifdef INET_DRV_DEBUG - -static char *read_req = "SO_EVENT_READ_REQUEST"; -static char *read_rep = "SO_EVENT_READ_REPLY"; -static char *write_req = "SO_EVENT_WRITE_REQUEST"; -static char *write_rep = "SO_EVENT_WRITE_REPLY"; -static char *eof_req = "SO_EVENT_EOF_REQUEST"; -static char *eof_rep = "SO_EVENT_EOF_REPLY"; -static char *accept_req = "SO_EVENT_ACCEPT_REQUEST"; -static char *accept_rep = "SO_EVENT_ACCEPT_REPLY"; -static char *connect_req = "SO_EVENT_CONNECT_REQUEST"; -static char *connect_rep = "SO_EVENT_CONNECT_REPLY"; -static char *error_req = "SO_EVENT_ERROR_REQUEST"; -static char *error_rep = "SO_EVENT_ERROR_REPLY"; -static char signo_tmp[32]; - -static char *signo_to_string(SIGSELECT signo) { - switch (signo) { - case SO_EVENT_READ_REQUEST: { return read_req; } - case SO_EVENT_READ_REPLY: { return read_rep; } - case SO_EVENT_WRITE_REQUEST: { return write_req; } - case SO_EVENT_WRITE_REPLY: { return write_rep; } - case SO_EVENT_EOF_REQUEST: { return eof_req; } - case SO_EVENT_EOF_REPLY: { return eof_rep; } - case SO_EVENT_ACCEPT_REQUEST: { return accept_req; } - case SO_EVENT_ACCEPT_REPLY: { return accept_rep; } - case SO_EVENT_CONNECT_REQUEST: { return connect_req; } - case SO_EVENT_CONNECT_REPLY: { return connect_rep; } - case SO_EVENT_ERROR_REQUEST: { return error_req; } - case SO_EVENT_ERROR_REPLY: { return error_rep; } - } - - snprintf(signo_tmp,32,"0x%x",signo); - - return signo_tmp; -} - -#endif - -#endif /* __OSE__ */ - - static struct erl_drv_entry tcp_inet_driver_entry = { tcp_inet_init, /* inet_init will add this driver !! */ @@ -1278,9 +1070,6 @@ static struct erl_drv_entry tcp_inet_driver_entry = #ifdef __WIN32__ tcp_inet_event, NULL, -#elif defined(__OSE__) - tcp_inet_drv_input_ose, /*ready_input*/ - tcp_inet_drv_output_ose, /*ready_output*/ #else tcp_inet_drv_input, tcp_inet_drv_output, @@ -1288,17 +1077,9 @@ static struct erl_drv_entry tcp_inet_driver_entry = "tcp_inet", NULL, NULL, -#ifdef __OSE__ - tcp_inet_ctl_ose, -#else tcp_inet_ctl, -#endif tcp_inet_timeout, -#ifdef __OSE__ - tcp_inet_commandv_ose, -#else tcp_inet_commandv, -#endif NULL, tcp_inet_flush, NULL, @@ -1450,14 +1231,6 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event); /* convert descriptor pointer to inet_descriptor pointer */ #define INETP(d) (&(d)->inet) -#ifdef __OSE__ -static void inet_driver_select(inet_descriptor* desc, - int flags, int onoff); -static void tcp_inet_ose_dispatch_signals(tcp_descriptor *desc, - int prev_select_state, - union SIGNAL *sig); -#endif - static int async_ref = 0; /* async reference id generator */ #define NEW_ASYNC_ID() ((async_ref++) & 0xffff) @@ -2749,7 +2522,7 @@ int ssl_tls_inetdrv(void* arg, unsigned type, unsigned major, unsigned minor, { tcp_descriptor* desc = (tcp_descriptor*) arg; int i = 0; - ErlDrvTermData spec[28]; + ErlDrvTermData spec[30]; ErlDrvTermData caller = ERL_DRV_NIL; ErlDrvBinary* bin; int ret; @@ -2790,11 +2563,11 @@ int ssl_tls_inetdrv(void* arg, unsigned type, unsigned major, unsigned minor, if (desc->inet.active == INET_PASSIVE) { i = LOAD_TUPLE(spec, i, 2); i = LOAD_TUPLE(spec, i, 4); - ASSERT(i <= 28); + ASSERT(i <= sizeof(spec)/sizeof(*spec)); ret = erl_drv_send_term(desc->inet.dport, caller, spec, i); } else { - ASSERT(i <= 28); + ASSERT(i <= sizeof(spec)/sizeof(*spec)); ret = erl_drv_output_term(desc->inet.dport, spec, i); } done: @@ -4353,16 +4126,6 @@ static void desc_close(inet_descriptor* desc) desc->forced_events = 0; desc->send_would_block = 0; #endif -#ifdef __OSE__ - if (desc->events[0]) { - driver_select(desc->port,desc->events[0],FD_READ|FD_WRITE|ERL_DRV_USE,0); - driver_select(desc->port,desc->events[1],FD_READ|FD_WRITE|ERL_DRV_USE,0); - driver_select(desc->port,desc->events[2],FD_READ|FD_WRITE|ERL_DRV_USE,0); - driver_select(desc->port,desc->events[3],FD_READ|FD_WRITE|ERL_DRV_USE,0); - driver_select(desc->port,desc->events[4],FD_READ|FD_WRITE|ERL_DRV_USE,0); - driver_select(desc->port,desc->events[5],FD_READ|FD_WRITE|ERL_DRV_USE,0); - } -#else /* * We should close the fd here, but the other driver might still * be selecting on it. @@ -4372,7 +4135,6 @@ static void desc_close(inet_descriptor* desc) ERL_DRV_USE, 0); else inet_stop_select((ErlDrvEvent)(long)desc->event,NULL); -#endif desc->event = INVALID_EVENT; /* closed by stop_select callback */ desc->s = INVALID_SOCKET; desc->event_mask = 0; @@ -4414,65 +4176,6 @@ static int erl_inet_close(inet_descriptor* desc) return 0; } -#ifdef __OSE__ -static void inet_select_init(inet_descriptor* desc) -{ - desc->events[0] = - erl_drv_ose_event_alloc(SO_EVENT_READ_REPLY, - desc->s, - inet_resolve_signal, - NULL); - driver_select(desc->port, desc->events[0], - ERL_DRV_READ|ERL_DRV_USE, 1); - - desc->events[1] = - erl_drv_ose_event_alloc(SO_EVENT_EOF_REPLY, - desc->s, - inet_resolve_signal, - NULL); - driver_select(desc->port, desc->events[1], - ERL_DRV_READ|ERL_DRV_USE, 1); - - desc->events[2] = - erl_drv_ose_event_alloc(SO_EVENT_ACCEPT_REPLY, - desc->s, - inet_resolve_signal, - NULL); - driver_select(desc->port, desc->events[2], - ERL_DRV_READ|ERL_DRV_USE, 1); - - /* trigger tcp_inet_input */ - desc->events[3] = - erl_drv_ose_event_alloc(SO_EVENT_WRITE_REPLY, - desc->s, - inet_resolve_signal, - NULL); - driver_select(desc->port, desc->events[3], - ERL_DRV_WRITE|ERL_DRV_USE, 1); - - desc->events[4] = - erl_drv_ose_event_alloc(SO_EVENT_CONNECT_REPLY, - desc->s, - inet_resolve_signal, - NULL); - driver_select(desc->port, desc->events[4], - ERL_DRV_WRITE|ERL_DRV_USE, 1); - - desc->events[5] = - erl_drv_ose_event_alloc(SO_EVENT_ERROR_REPLY, - desc->s, - inet_resolve_signal, - NULL); - driver_select(desc->port, desc->events[5], - ERL_DRV_WRITE|ERL_DRV_USE, 1); - - /* Issue a select on error event before any other select to be sure we are - prepared to receive error notifications from the stack, even in the - situations when select isn't issued */ - sock_select(desc, SOCK_FD_ERROR, 1); -} -#endif - static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, char** rbuf, ErlDrvSizeT rsize) { @@ -4555,9 +4258,6 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, #ifdef __WIN32__ driver_select(desc->port, desc->event, ERL_DRV_READ, 1); #endif -#ifdef __OSE__ - inet_select_init(desc); -#endif desc->state = INET_STATE_OPEN; desc->stype = type; @@ -4581,13 +4281,7 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, if (name.sa.sa_family != domain) return ctl_error(EINVAL, rbuf, rsize); } -#ifdef __OSE__ - /* for fdopen duplicating the sd will allow to uniquely identify - the signal from OSE with erlang port */ - desc->s = sock_dup(s); -#else desc->s = s; -#endif if ((desc->event = sock_create_event(desc)) == INVALID_EVENT) return ctl_error(sock_errno(), rbuf, rsize); @@ -4605,12 +4299,6 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, sz = sizeof(name); if (!IS_SOCKET_ERROR(sock_peer(s, (struct sockaddr*) &name, &sz))) { desc->state = INET_STATE_CONNECTED; -#ifdef __OSE__ - /* since we are dealing with different descriptors (i.e. inet and - socket) the select part should be initialized with the right - values */ - inet_select_init(desc); -#endif } } @@ -6276,6 +5964,12 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) } continue; + case INET_LOPT_LINE_DELIM: + DEBUGF(("inet_set_opts(%ld): s=%d, LINE_DELIM=%d\r\n", + (long)desc->port, desc->s, ival)); + desc->delimiter = (char)ival; + continue; + case INET_OPT_REUSEADDR: #ifdef __WIN32__ continue; /* Bjorn says */ @@ -8371,6 +8065,7 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) desc->deliver = INET_DELIVER_TERM; /* standard term format */ desc->active = INET_PASSIVE; /* start passive */ desc->active_count = 0; + desc->delimiter = '\n'; /* line delimiting char */ desc->oph = NULL; desc->opt = NULL; @@ -8404,15 +8099,6 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) #ifdef HAVE_SETNS desc->netns = NULL; #endif -#ifdef __OSE__ - desc->select_state = 0; - desc->events[0] = NULL; - desc->events[1] = NULL; - desc->events[2] = NULL; - desc->events[3] = NULL; - desc->events[4] = NULL; - desc->events[5] = NULL; -#endif return (ErlDrvData)desc; } @@ -9139,10 +8825,6 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s, copy_desc->inet.port = port; copy_desc->inet.dport = driver_mk_port(port); -#ifdef __OSE__ - inet_select_init(©_desc->inet); -#endif - *err = 0; return copy_desc; } @@ -9204,23 +8886,6 @@ static void tcp_inet_stop(ErlDrvData e) inet_stop(INETP(desc)); } -#ifdef __OSE__ - -static ErlDrvSSizeT tcp_inet_ctl_ose(ErlDrvData e, unsigned int cmd, - char* buf, ErlDrvSizeT len, - char** rbuf, ErlDrvSizeT rsize) { - - tcp_descriptor* desc = (tcp_descriptor*)e; - int prev_select_state = INETP(desc)->select_state; - - ErlDrvSSizeT res = tcp_inet_ctl(e,cmd,buf,len,rbuf,rsize); - - tcp_inet_ose_dispatch_signals((tcp_descriptor*)e,prev_select_state,NULL); - - return res; -} -#endif - /* TCP requests from Erlang */ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, ErlDrvSizeT len, @@ -9662,17 +9327,6 @@ static void tcp_inet_command(ErlDrvData e, char *buf, ErlDrvSizeT len) DEBUGF(("tcp_inet_command(%ld) }\r\n", (long)desc->inet.port)); } -#ifdef __OSE__ - -static void tcp_inet_commandv_ose(ErlDrvData e, ErlIOVec* ev) { - int prev_select_state = INETP((tcp_descriptor*)e)->select_state; - tcp_inet_commandv(e, ev); - tcp_inet_ose_dispatch_signals((tcp_descriptor*)e,prev_select_state,NULL); -} - -#endif - - static void tcp_inet_commandv(ErlDrvData e, ErlIOVec* ev) { tcp_descriptor* desc = (tcp_descriptor*)e; @@ -9745,22 +9399,6 @@ static void inet_stop_select(ErlDrvEvent event, void* _) { #ifdef __WIN32__ WSACloseEvent((HANDLE)event); -#elif defined(__OSE__) - ErlDrvOseEventId id; - union SIGNAL *sig; - erl_drv_ose_event_fetch(event, NULL, &id,NULL); - DEBUGF(("inet_stop_select(?#?) {s=%d\n",id)); - sock_close((int)id); - /* On socket close all the signals waiting to be processed as part of the - select should be deallocated */ - while((sig = erl_drv_ose_get_signal(event))) { - DEBUGF(("inet_stop_select(?#?): Freeing signal %s\n", - signo_to_string(sig->signo))); - free_buf(&sig); - } - erl_drv_ose_event_free(event); - DEBUGF(("inet_stop_select(?#?) }\n")); - #else sock_close((SOCKET)(long)event); #endif @@ -9882,7 +9520,7 @@ static int tcp_remain(tcp_descriptor* desc, int* len) tlen = packet_get_length(desc->inet.htype, ptr, n, desc->inet.psize, desc->i_bufsz, - &desc->http_state); + desc->inet.delimiter, &desc->http_state); DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d, tlen %d\r\n", (long)desc->inet.port, desc->inet.s, n, nfill, nsz, tlen)); @@ -10309,146 +9947,7 @@ static void tcp_inet_event(ErlDrvData e, ErlDrvEvent event) return; } -#elif defined(__OSE__) /* !__WIN32__ */ -/* The specific resolve signal function. It will return the socket descriptor - for which the select was issued */ -static ErlDrvOseEventId inet_resolve_signal(union SIGNAL *sig) { - DEBUGF(("%s(?#?): s=%d got signal %s, status = %d, extra = %d, sender = 0x%x\n", - __FUNCTION__,sig->async.fd,signo_to_string(sig->signo), - sig->async.event.status, - sig->async.event.extra,sender(&sig))); - if (sig->signo == SO_EVENT_READ_REPLY || - sig->signo == SO_EVENT_ACCEPT_REPLY || - sig->signo == SO_EVENT_EOF_REPLY || - sig->signo == SO_EVENT_WRITE_REPLY || - sig->signo == SO_EVENT_ERROR_REPLY || - sig->signo == SO_EVENT_CONNECT_REPLY ) { - return sig->async.fd; - } - - return -1; -} - -static void inet_driver_select(inet_descriptor* desc, - int flags, int onoff) { - ASSERT(!desc->is_ignored); - - if(onoff) { - desc->select_state |= flags; - } else { - desc->select_state &= ~flags; - } -} - -static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int max_sz) -{ - size_t data_len = 0; - size_t sent = 0; - ssize_t n; - int i; - - for(i = 0; i < iovcnt; i++) - { - data_len = iov[i].iov_len; -tryagain: - n = sock_send(fd, iov[i].iov_base, data_len, 0); - if (IS_SOCKET_ERROR(n)) { - /* If buffer length is greater than the amount stack is able to - * send out then try to send at least max_sz (this comes with - * SO_EVENT_WRITE_REPLY signal*/ - if ((errno == EMSGSIZE) && (max_sz > 0) && (data_len > max_sz)) { - data_len = max_sz; - goto tryagain; - } - break; - } - sent += n; - } - return sent; -} - -#define OSE_EVENT_REQ(TCP_DESC,EVENT) do { \ - union SIGNAL *sig = alloc(sizeof(struct OseAsyncSig), EVENT); \ - sig->async.fd = INETP(TCP_DESC)->s; \ - ose_request_event(INETP(TCP_DESC)->s, &sig, 1); \ - DEBUGF(("%s(%ld): s=%d sent %s\r\n",__FUNCTION__, \ - INETP(TCP_DESC)->port,INETP(TCP_DESC)->s,signo_to_string(EVENT))); \ - } while(0) - -static void tcp_inet_ose_dispatch_signals(tcp_descriptor *desc, - int prev_select_state, - union SIGNAL *sig) { - if (sig) { - DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) {s=%d resend\r\n", - (long)INETP(desc)->port,INETP(desc)->s)); - /* We are reacting to a signal, which means that if - the select_state for that signal is still activated - we should send a new signal */ - switch (sig->signo) { - case SO_EVENT_READ_REPLY: { - if (INETP(desc)->select_state & FD_READ) - OSE_EVENT_REQ(desc,SO_EVENT_READ_REQUEST); - break; - } - case SO_EVENT_WRITE_REPLY: { - if (INETP(desc)->select_state & FD_WRITE) - OSE_EVENT_REQ(desc,SO_EVENT_WRITE_REQUEST); - break; - } - case SO_EVENT_CONNECT_REPLY: { - if (INETP(desc)->select_state & FD_CONNECT) - OSE_EVENT_REQ(desc,SO_EVENT_CONNECT_REQUEST); - break; - } - case SO_EVENT_ACCEPT_REPLY: { - if (INETP(desc)->select_state & FD_ACCEPT) - OSE_EVENT_REQ(desc,SO_EVENT_ACCEPT_REQUEST); - break; - } - case SO_EVENT_ERROR_REPLY: { - if (INETP(desc)->select_state & SOCK_FD_ERROR) - OSE_EVENT_REQ(desc,SO_EVENT_ERROR_REQUEST); - break; - } - - } - DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) }\r\n", - (long)INETP(desc)->port)); - } - - if (INETP(desc)->select_state != prev_select_state) { - /* If the select state has changed we have to issue signals for - the state parts that have changed. */ - int xor_select_state = INETP(desc)->select_state ^ prev_select_state; - DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) {s=%d select change\r\n", - (long)INETP(desc)->port,INETP(desc)->s)); - if ((xor_select_state & FD_READ) && - (INETP(desc)->select_state & FD_READ)) { - OSE_EVENT_REQ(desc,SO_EVENT_READ_REQUEST); - } - if ((xor_select_state & FD_WRITE) && - (INETP(desc)->select_state & FD_WRITE)) { - OSE_EVENT_REQ(desc,SO_EVENT_WRITE_REQUEST); - } - if ((xor_select_state & FD_CONNECT) && - (INETP(desc)->select_state & FD_CONNECT)) { - OSE_EVENT_REQ(desc,SO_EVENT_CONNECT_REQUEST); - } - if ((xor_select_state & FD_ACCEPT) && - (INETP(desc)->select_state & FD_ACCEPT)) { - OSE_EVENT_REQ(desc,SO_EVENT_ACCEPT_REQUEST); - } - if ((xor_select_state & SOCK_FD_ERROR) && - (INETP(desc)->select_state & SOCK_FD_ERROR)) { - OSE_EVENT_REQ(desc,SO_EVENT_ERROR_REQUEST); - } - - DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) }\r\n", - (long)INETP(desc)->port)); - } -} - -#endif /* __OSE__ */ +#endif /* __WIN32__ */ /* socket has input: @@ -10935,49 +10434,6 @@ static void tcp_shutdown_async(tcp_descriptor* desc) desc->tcp_add_flags |= TCP_ADDF_SHUTDOWN_WR_DONE; } -#ifdef __OSE__ - -static void tcp_inet_drv_output_ose(ErlDrvData data, ErlDrvEvent event) -{ - union SIGNAL *event_sig = erl_drv_ose_get_signal(event); - - while (event_sig) { - int prev_select_state = INETP((tcp_descriptor*)data)->select_state; - int res = tcp_inet_output((tcp_descriptor*)data, (HANDLE)event_sig); - if (res != -1) { - tcp_inet_ose_dispatch_signals((tcp_descriptor*)data, - prev_select_state,event_sig); - free_buf(&event_sig); - event_sig = erl_drv_ose_get_signal(event); - } else { - /* NOTE: here the event object could have been deallocated!!!! - inet_stop_select is called when doing driver_select(ERL_DRV_USE,0) - */ - free_buf(&event_sig); - return; - } - } -} - -static void tcp_inet_drv_input_ose(ErlDrvData data, ErlDrvEvent event) -{ - union SIGNAL *event_sig = erl_drv_ose_get_signal(event); - - while (event_sig) { - int prev_select_state = INETP((tcp_descriptor*)data)->select_state; - int res = tcp_inet_input((tcp_descriptor*)data, (HANDLE)event); - if (res != -1) { - tcp_inet_ose_dispatch_signals((tcp_descriptor*)data, prev_select_state, - event_sig); - free_buf(&event_sig); - event_sig = erl_drv_ose_get_signal(event); - } else { - free_buf(&event_sig); - return; - } - } -} -#else static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event) { (void)tcp_inet_output((tcp_descriptor*)data, (HANDLE)event); @@ -10987,7 +10443,6 @@ static void tcp_inet_drv_input(ErlDrvData data, ErlDrvEvent event) { (void)tcp_inet_input((tcp_descriptor*)data, (HANDLE)event); } -#endif /* socket ready for ouput: ** 1. INET_STATE_CONNECTING => non block connect ? @@ -11053,13 +10508,6 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) ssize_t n; SysIOVec* iov; -#ifdef __OSE__ - /* For large size buffers case the amount of data that the stack is - able to send out (received in the .extra field) should be passed - down to writev_fallback */ - n = event ? ((union SIGNAL*)event)->async.event.extra : 0; -#endif - if ((iov = driver_peekq(ix, &vsize)) == NULL) { sock_select(INETP(desc), FD_WRITE, 0); send_empty_out_q_msgs(INETP(desc)); @@ -11087,12 +10535,6 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) sizes > (max 32 bit signed int) */ size_t howmuch = 0x7FFFFFFF; /* max signed 32 bit */ int x; -#ifdef __OSE__ - /* For EWOULDBLOCK sock_sendv returns 0 so we have to be sure it - wasn't the case */ - if(sock_errno() == ERRNO_BLOCK) - goto done; -#endif for(x = 0; x < vsize && iov[x].iov_len == 0; ++x) ; if (x < vsize) { diff --git a/erts/emulator/drivers/ose/ose_efile.c b/erts/emulator/drivers/ose/ose_efile.c deleted file mode 100644 index c8337a95d5..0000000000 --- a/erts/emulator/drivers/ose/ose_efile.c +++ /dev/null @@ -1,1125 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2012. 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% - */ -/* - * Purpose: Provides file and directory operations for OSE. - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#if defined(HAVE_POSIX_FALLOCATE) && !defined(__sun) && !defined(__sun__) -#define _XOPEN_SOURCE 600 -#endif -#if !defined(_GNU_SOURCE) && defined(HAVE_LINUX_FALLOC_H) -#define _GNU_SOURCE -#endif -#include "sys.h" -#include "erl_driver.h" -#include "erl_efile.h" -#if defined(DARWIN) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) -#include "fcntl.h" -#endif -#include "ose.h" -#include "unistd.h" -#include "sys/stat.h" -#include "dirent.h" -#include "sys/time.h" -#include "time.h" -#include "assert.h" - -/* Find a definition of MAXIOV, that is used in the code later. */ -#if defined IOV_MAX -#define MAXIOV IOV_MAX -#elif defined UIO_MAXIOV -#define MAXIOV UIO_MAXIOV -#else -#define MAXIOV 16 -#endif - -/* - * Macros for testing file types. - */ - -#define ISDIR(st) (((st).st_mode & S_IFMT) == S_IFDIR) -#define ISREG(st) (((st).st_mode & S_IFMT) == S_IFREG) -#define ISDEV(st) \ - (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK) -#define ISLNK(st) (((st).st_mode & S_IFLNK) == S_IFLNK) -#ifdef NO_UMASK -#define FILE_MODE 0644 -#define DIR_MODE 0755 -#else -#define FILE_MODE 0666 -#define DIR_MODE 0777 -#endif - -#define IS_DOT_OR_DOTDOT(s) \ - (s[0] == '.' && (s[1] == '\0' || (s[1] == '.' && s[2] == '\0'))) - -/* - * Macros for handling local file descriptors - * and mutexes. - * - * Handling of files like this is necessary because OSE - * does not allow seeking after the end of a file. So - * what we do it emulate this by keeping track of the size - * of the file and where the file's positions is. If a - * write happens after eof then we pad it. - * - * Given time this should be rewritten to get rid of the - * mutex and use the port lock to protect the data. This - * could be done be done by adapting the efile api for some - * calls to allow some meta-data to be associated with the - * open file. - */ - -#define L_FD_IS_VALID(fd_data) ((fd_data)->beyond_eof > 0) -#define L_FD_INVALIDATE(fd_data) (fd_data)->beyond_eof = 0 -#define L_FD_CUR(fd_data) (fd_data)->pos -#define L_FD_OFFS_BEYOND_EOF(fd_data, offs) \ - (((fd_data)->size > offs) ? 0 : 1) - -#define L_FD_FAIL -1 -#define L_FD_SUCCESS 1 -#define L_FD_PAD_SIZE 255 - -struct fd_meta { - ErlDrvMutex *meta_mtx; - struct fd_data *fd_data_list; -}; - -struct fd_data { - int fd; - struct fd_data *next; - struct fd_data *prev; - int pos; - int beyond_eof; - size_t size; -#ifdef DEBUG - PROCESS owner; -#endif -}; - -static int l_invalidate_local_fd(int fd); -static int l_pad_file(struct fd_data *fd_data, off_t offset); -static int check_error(int result, Efile_error* errInfo); -static struct fd_data* l_new_fd(void); -static int l_remove_local_fd(int fd); -static struct fd_data* l_find_local_fd(int fd); -static int l_update_local_fd(int fd, int pos, int size); - -static struct fd_meta* fdm = NULL; - - -/***************************************************************************/ - -static int -l_remove_local_fd(int fd) -{ - struct fd_data *fd_data; - fd_data = l_find_local_fd(fd); - - if (fd_data == NULL) { - return L_FD_FAIL; - } -#ifdef DEBUG - assert(fd_data->owner == current_process()); -#endif - erl_drv_mutex_lock(fdm->meta_mtx); - /* head ? */ - if (fd_data == fdm->fd_data_list) { - if (fd_data->next != NULL) { - /* remove link to head */ - fd_data->next->prev = NULL; - /* set new head */ - fdm->fd_data_list = fd_data->next; - } - else { - /* head is lonely */ - fdm->fd_data_list = NULL; - } - } - else { /* not head */ - if (fd_data->prev == NULL) { - erl_drv_mutex_unlock(fdm->meta_mtx); - return L_FD_FAIL; - } - else { - if (fd_data->next != NULL) { - fd_data->next->prev = fd_data->prev; - fd_data->prev->next = fd_data->next; - } - else { - fd_data->prev->next = NULL; - } - } - } - - /* scramble values */ - fd_data->beyond_eof = -1; - fd_data->next = NULL; - fd_data->prev = NULL; - fd_data->fd = -1; - - /* unlock and clean */ - driver_free(fd_data); - erl_drv_mutex_unlock(fdm->meta_mtx); - - return L_FD_SUCCESS; -} - -/***************************************************************************/ - -static int -l_invalidate_local_fd(int fd) { - struct fd_data *fd_data; - - if ((fd_data = l_find_local_fd(fd)) == NULL) { - return L_FD_FAIL; - } - - fd_data->beyond_eof = 0; - return L_FD_SUCCESS; -} - -/****************************************************************************/ - -static struct fd_data* -l_find_local_fd(int fd) { - struct fd_data *fd_data; - - fd_data = NULL; - erl_drv_mutex_lock(fdm->meta_mtx); - for (fd_data = fdm->fd_data_list; fd_data != NULL; ) { - if (fd_data->fd == fd) { -#ifdef DEBUG - assert(fd_data->owner == current_process()); -#endif - break; - } - fd_data = fd_data->next; - } - erl_drv_mutex_unlock(fdm->meta_mtx); - return fd_data; -} - -/***************************************************************************/ - -static struct fd_data* -l_new_fd(void) { - struct fd_data *fd_data; - - fd_data = driver_alloc(sizeof(struct fd_data)); - if (fd_data == NULL) { - return NULL; - } - erl_drv_mutex_lock(fdm->meta_mtx); - if (fdm->fd_data_list == NULL) { - fdm->fd_data_list = fd_data; - fdm->fd_data_list->prev = NULL; - fdm->fd_data_list->next = NULL; - } - else { - fd_data->next = fdm->fd_data_list; - fdm->fd_data_list = fd_data; - fdm->fd_data_list->prev = NULL; - } -#ifdef DEBUG - fd_data->owner = current_process(); -#endif - erl_drv_mutex_unlock(fdm->meta_mtx); - return fd_data; -} - -/***************************************************************************/ - -static int -l_update_local_fd(int fd, int pos, int size) { - struct fd_data *fd_data = NULL; - - fd_data = l_find_local_fd(fd); - /* new fd to handle? */ - if (fd_data == NULL) { - fd_data = l_new_fd(); - if (fd_data == NULL) { - /* out of memory */ - return L_FD_FAIL; - } - } - fd_data->size = size; - fd_data->pos = pos; - fd_data->fd = fd; - fd_data->beyond_eof = 1; - - return L_FD_SUCCESS; -} - -/***************************************************************************/ - -static int -l_pad_file(struct fd_data *fd_data, off_t offset) { - int size_dif; - int written = 0; - int ret_val = L_FD_SUCCESS; - char padding[L_FD_PAD_SIZE]; - - size_dif = (offset - fd_data->size); - memset(&padding, '\0', L_FD_PAD_SIZE); - - while (size_dif > 0) { - written = write(fd_data->fd, padding, - (size_dif < L_FD_PAD_SIZE) ? - size_dif : L_FD_PAD_SIZE); - if (written < 0 && errno != EINTR && errno != EAGAIN) { - ret_val = -1; - break; - } - size_dif -= written; - } - L_FD_INVALIDATE(fd_data); - return ret_val; -} - -/***************************************************************************/ - -static int -check_error(int result, Efile_error *errInfo) { - if (result < 0) { - errInfo->posix_errno = errInfo->os_errno = errno; - return 0; - } - return 1; -} - -/***************************************************************************/ - -int -efile_init() { - fdm = driver_alloc(sizeof(struct fd_meta)); - if (fdm == NULL) { - return L_FD_FAIL; - } - fdm->meta_mtx = erl_drv_mutex_create("ose_efile local fd mutex\n"); - erl_drv_mutex_lock(fdm->meta_mtx); - fdm->fd_data_list = NULL; - erl_drv_mutex_unlock(fdm->meta_mtx); - return L_FD_SUCCESS; -} - -/***************************************************************************/ - -int -efile_mkdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of directory to create. */ -{ -#ifdef NO_MKDIR_MODE - return check_error(mkdir(name), errInfo); -#else - int res = mkdir(name, DIR_MODE); - if (res < 0 && errno == EINVAL) { - errno = ENOENT; - } - return check_error(res, errInfo); -#endif -} - -/***************************************************************************/ - -int -efile_rmdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of directory to delete. */ -{ - if (rmdir(name) == 0) { - return 1; - } - if (errno == ENOTEMPTY) { - errno = EEXIST; - } - if (errno == EEXIST || errno == EINVAL) { - int saved_errno = errno; - struct stat file_stat; - struct stat cwd_stat; - - if(stat(name, &file_stat) != 0) { - errno = ENOENT; - return check_error(-1, errInfo); - } - /* - * The error code might be wrong if this is the current directory. - */ - if (stat(name, &file_stat) == 0 && stat(".", &cwd_stat) == 0 && - file_stat.st_ino == cwd_stat.st_ino && - file_stat.st_dev == cwd_stat.st_dev) { - saved_errno = EACCES; - } - errno = saved_errno; - } - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_delete_file(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of file to delete. */ -{ - struct stat statbuf; - - if (stat(name, &statbuf) >= 0) { - /* Do not let unlink() remove directories */ - if (ISDIR(statbuf)) { - errno = EPERM; - return check_error(-1, errInfo); - } - - if (unlink(name) == 0) { - return 1; - } - - if (errno == EISDIR) { - errno = EPERM; - return check_error(-1, errInfo); - } - } - else { - if (errno == EINVAL) { - errno = ENOENT; - return check_error(-1, errInfo); - } - } - return check_error(-1, errInfo); -} - -/* - *--------------------------------------------------------------------------- - * - * Changes the name of an existing file or directory, from src to dst. - * If src and dst refer to the same file or directory, does nothing - * and returns success. Otherwise if dst already exists, it will be - * deleted and replaced by src subject to the following conditions: - * If src is a directory, dst may be an empty directory. - * If src is a file, dst may be a file. - * In any other situation where dst already exists, the rename will - * fail. - * - * Results: - * If the directory was successfully created, returns 1. - * Otherwise the return value is 0 and errno is set to - * indicate the error. Some possible values for errno are: - * - * EACCES: src or dst parent directory can't be read and/or written. - * EEXIST: dst is a non-empty directory. - * EINVAL: src is a root directory or dst is a subdirectory of src. - * EISDIR: dst is a directory, but src is not. - * ENOENT: src doesn't exist, or src or dst is "". - * ENOTDIR: src is a directory, but dst is not. - * EXDEV: src and dst are on different filesystems. - * - * Side effects: - * The implementation of rename may allow cross-filesystem renames, - * but the caller should be prepared to emulate it with copy and - * delete if errno is EXDEV. - * - *--------------------------------------------------------------------------- - */ - -int -efile_rename(Efile_error* errInfo, /* Where to return error codes. */ - char* src, /* Original name. */ - char* dst) /* New name. */ -{ - - /* temporary fix AFM does not recognize ./<file name> - * in destination remove pending on adaption of AFM fix - */ - - char *dot_str; - if (dst != NULL) { - dot_str = strchr(dst, '.'); - if (dot_str && dot_str == dst && dot_str[1] == '/') { - dst = dst+2; - } - } - - if (rename(src, dst) == 0) { - return 1; - } - if (errno == ENOTEMPTY) { - errno = EEXIST; - } - if (errno == EINVAL) { - struct stat file_stat; - - if (stat(dst, &file_stat)== 0) { - if (ISDIR(file_stat)) { - errno = EISDIR; - } - else if (ISREG(file_stat)) { - errno = ENOTDIR; - } - else { - errno = EINVAL; - } - } - else { - errno = EINVAL; - } - } - - if (strcmp(src, "/") == 0) { - errno = EINVAL; - } - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_chdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name) /* Name of directory to make current. */ -{ - return check_error(chdir(name), errInfo); -} - -/***************************************************************************/ - -int -efile_getdcwd(Efile_error* errInfo, /* Where to return error codes. */ - int drive, /* 0 - current, 1 - A, 2 - B etc. */ - char* buffer, /* Where to return the current - directory. */ - size_t size) /* Size of buffer. */ -{ - if (drive == 0) { - if (getcwd(buffer, size) == NULL) - return check_error(-1, errInfo); - - return 1; - } - - /* - * Drives other than 0 is not supported on Unix. - */ - - errno = ENOTSUP; - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_readdir(Efile_error* errInfo, /* Where to return error codes. */ - char* name, /* Name of directory to open. */ - EFILE_DIR_HANDLE* p_dir_handle, /* Pointer to directory - handle of - open directory.*/ - char* buffer, /* Pointer to buffer for - one filename. */ - size_t *size) /* in-out Size of buffer, length - of name. */ -{ - DIR *dp; /* Pointer to directory structure. */ - struct dirent* dirp; /* Pointer to directory entry. */ - - /* - * If this is the first call, we must open the directory. - */ - - if (*p_dir_handle == NULL) { - dp = opendir(name); - if (dp == NULL) - return check_error(-1, errInfo); - *p_dir_handle = (EFILE_DIR_HANDLE) dp; - } - - /* - * Retrieve the name of the next file using the directory handle. - */ - - dp = *((DIR **)((void *)p_dir_handle)); - for (;;) { - dirp = readdir(dp); - if (dirp == NULL) { - closedir(dp); - return 0; - } - if (IS_DOT_OR_DOTDOT(dirp->d_name)) - continue; - buffer[0] = '\0'; - strncat(buffer, dirp->d_name, (*size)-1); - *size = strlen(dirp->d_name); - return 1; - } -} - -/***************************************************************************/ - -int -efile_openfile(Efile_error* errInfo, /* Where to return error codes. */ - char* name, /* Name of directory to open. */ - int flags, /* Flags to user for opening. */ - int* pfd, /* Where to store the file - descriptor. */ - Sint64 *pSize) /* Where to store the size of the - file. */ -{ - struct stat statbuf; - int fd; - int mode; /* Open mode. */ - - if (stat(name, &statbuf) >= 0 && !ISREG(statbuf)) { - errno = EISDIR; - return check_error(-1, errInfo); - } - - switch (flags & (EFILE_MODE_READ|EFILE_MODE_WRITE)) { - case EFILE_MODE_READ: - mode = O_RDONLY; - break; - case EFILE_MODE_WRITE: - if (flags & EFILE_NO_TRUNCATE) - mode = O_WRONLY | O_CREAT; - else - mode = O_WRONLY | O_CREAT | O_TRUNC; - break; - case EFILE_MODE_READ_WRITE: - mode = O_RDWR | O_CREAT; - break; - default: - errno = EINVAL; - return check_error(-1, errInfo); - } - - - if (flags & EFILE_MODE_APPEND) { - mode &= ~O_TRUNC; - mode |= O_APPEND; - } - - if (flags & EFILE_MODE_EXCL) { - mode |= O_EXCL; - } - - fd = open(name, mode, FILE_MODE); - - if (!check_error(fd, errInfo)) - return 0; - - *pfd = fd; - if (pSize) { - *pSize = statbuf.st_size; - } - return 1; -} - -/***************************************************************************/ - -int -efile_may_openfile(Efile_error* errInfo, char *name) { - struct stat statbuf; /* Information about the file */ - int result; - - result = stat(name, &statbuf); - if (!check_error(result, errInfo)) - return 0; - if (!ISREG(statbuf)) { - errno = EISDIR; - return check_error(-1, errInfo); - } - return 1; -} - -/***************************************************************************/ - -void -efile_closefile(int fd) -{ - if (l_find_local_fd(fd) != NULL) { - l_remove_local_fd(fd); - } - close(fd); -} - -/***************************************************************************/ - -int -efile_fdatasync(Efile_error *errInfo, /* Where to return error codes. */ - int fd) /* File descriptor for file to sync data. */ -{ - return efile_fsync(errInfo, fd); -} - -/***************************************************************************/ - -int -efile_fsync(Efile_error *errInfo, /* Where to return error codes. */ - int fd) /* File descriptor for file to sync. */ -{ - return check_error(fsync(fd), errInfo); -} - -/***************************************************************************/ - -int -efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, - char* name, int info_for_link) -{ - struct stat statbuf; /* Information about the file */ - int result; - - result = stat(name, &statbuf); - if (!check_error(result, errInfo)) { - return 0; - } - -#if SIZEOF_OFF_T == 4 - pInfo->size_high = 0; -#else - pInfo->size_high = (Uint32)(statbuf.st_size >> 32); -#endif - pInfo->size_low = (Uint32)statbuf.st_size; - -#ifdef NO_ACCESS - /* Just look at read/write access for owner. */ - - pInfo->access = ((statbuf.st_mode >> 6) & 07) >> 1; - -#else - pInfo->access = FA_NONE; - if (access(name, R_OK) == 0) - pInfo->access |= FA_READ; - if (access(name, W_OK) == 0) - pInfo->access |= FA_WRITE; - -#endif - - if (ISDEV(statbuf)) - pInfo->type = FT_DEVICE; - else if (ISDIR(statbuf)) - pInfo->type = FT_DIRECTORY; - else if (ISREG(statbuf)) - pInfo->type = FT_REGULAR; - else if (ISLNK(statbuf)) - pInfo->type = FT_SYMLINK; - else - pInfo->type = FT_OTHER; - - pInfo->accessTime = statbuf.st_atime; - pInfo->modifyTime = statbuf.st_mtime; - pInfo->cTime = statbuf.st_ctime; - - pInfo->mode = statbuf.st_mode; - pInfo->links = statbuf.st_nlink; - pInfo->major_device = statbuf.st_dev; - pInfo->inode = statbuf.st_ino; - pInfo->uid = statbuf.st_uid; - pInfo->gid = statbuf.st_gid; - - return 1; -} - -/***************************************************************************/ - -int -efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) -{ - /* - * On some systems chown will always fail for a non-root user unless - * POSIX_CHOWN_RESTRICTED is not set. Others will succeed as long as - * you don't try to chown a file to someone besides youself. - */ - if (pInfo->mode != -1) { - mode_t newMode = pInfo->mode & (S_ISUID | S_ISGID | - S_IRWXU | S_IRWXG | S_IRWXO); - if (chmod(name, newMode)) { - newMode &= ~(S_ISUID | S_ISGID); - if (chmod(name, newMode)) { - return check_error(-1, errInfo); - } - } - } - - return 1; -} - -/***************************************************************************/ - -int -efile_write(Efile_error* errInfo, /* Where to return error codes. */ - int flags, /* Flags given when file was - opened. */ - int fd, /* File descriptor to write to. */ - char* buf, /* Buffer to write. */ - size_t count) /* Number of bytes to write. */ -{ - ssize_t written; /* Bytes written in last operation. */ - struct fd_data *fd_data; - - if ((fd_data = l_find_local_fd(fd)) != NULL) { - if (L_FD_IS_VALID(fd_data)) { - /* we are beyond eof and need to pad*/ - if (l_pad_file(fd_data, L_FD_CUR(fd_data)) < 0) { - return check_error(-1, errInfo); - } - } - } - - while (count > 0) { - if ((written = write(fd, buf, count)) < 0) { - if (errno != EINTR) { - return check_error(-1, errInfo); - } - else { - written = 0; - } - } - ASSERT(written <= count); - buf += written; - count -= written; - } - return 1; -} - -/***************************************************************************/ - -int -efile_writev(Efile_error* errInfo, /* Where to return error codes */ - int flags, /* Flags given when file was - * opened */ - int fd, /* File descriptor to write to */ - SysIOVec* iov, /* Vector of buffer structs. - * The structs may be changed i.e. - * due to incomplete writes */ - int iovcnt) /* Number of structs in vector */ -{ - struct fd_data *fd_data; - int cnt = 0; /* Buffers so far written */ - - ASSERT(iovcnt >= 0); - if ((fd_data = l_find_local_fd(fd)) != NULL) { - if (L_FD_IS_VALID(fd_data)) { - /* we are beyond eof and need to pad*/ - if (l_pad_file(fd_data, L_FD_CUR(fd_data)) < 0) { - return check_error(-1, errInfo); - } - } - } - while (cnt < iovcnt) { - if ((! iov[cnt].iov_base) || (iov[cnt].iov_len <= 0)) { - /* Empty buffer - skip */ - cnt++; - } - else { /* Non-empty buffer */ - ssize_t w; /* Bytes written in this call */ - do { - w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len); - } while (w < 0 && errno == EINTR); - - ASSERT(w <= iov[cnt].iov_len || w == -1); - - if (w < 0) { - return check_error(-1, errInfo); - } - /* Move forward to next buffer to write */ - for (; cnt < iovcnt && w > 0; cnt++) { - if (iov[cnt].iov_base && iov[cnt].iov_len > 0) { - if (w < iov[cnt].iov_len) { - /* Adjust the buffer for next write */ - iov[cnt].iov_len -= w; - iov[cnt].iov_base += w; - w = 0; - break; - } - else { - w -= iov[cnt].iov_len; - } - } - } - ASSERT(w == 0); - } /* else Non-empty buffer */ - } /* while (cnt< iovcnt) */ - return 1; -} - -/***************************************************************************/ - -int -efile_read(Efile_error* errInfo, /* Where to return error codes. */ - int flags, /* Flags given when file was opened. */ - int fd, /* File descriptor to read from. */ - char* buf, /* Buffer to read into. */ - size_t count, /* Number of bytes to read. */ - size_t *pBytesRead) /* Where to return number of - bytes read. */ -{ - ssize_t n; - struct fd_data *fd_data; - - if ((fd_data = l_find_local_fd(fd)) != NULL) { - if (L_FD_IS_VALID(fd_data)) { - *pBytesRead = 0; - return 1; - } - } - for (;;) { - if ((n = read(fd, buf, count)) >= 0) { - break; - } - else if (errno != EINTR) { - return check_error(-1, errInfo); - } - } - if (fd_data != NULL && L_FD_IS_VALID(fd_data)) { - L_FD_INVALIDATE(fd_data); - } - *pBytesRead = (size_t) n; - return 1; -} - -/* pread() and pwrite() */ -/* Some unix systems, notably Solaris has these syscalls */ -/* It is especially nice for i.e. the dets module to have support */ -/* for this, even if the underlying OS dosn't support it, it is */ -/* reasonably easy to work around by first calling seek, and then */ -/* calling read(). */ -/* This later strategy however changes the file pointer, which pread() */ -/* does not do. We choose to ignore this and say that the location */ -/* of the file pointer is undefined after a call to any of the p functions*/ - - -int -efile_pread(Efile_error* errInfo, /* Where to return error codes. */ - int fd, /* File descriptor to read from. */ - Sint64 offset, /* Offset in bytes from BOF. */ - char* buf, /* Buffer to read into. */ - size_t count, /* Number of bytes to read. */ - size_t *pBytesRead) /* Where to return - number of bytes read. */ -{ - int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); - if (res) { - return efile_read(errInfo, 0, fd, buf, count, pBytesRead); - } else { - return res; - } -} - - -/***************************************************************************/ - -int -efile_pwrite(Efile_error* errInfo, /* Where to return error codes. */ - int fd, /* File descriptor to write to. */ - char* buf, /* Buffer to write. */ - size_t count, /* Number of bytes to write. */ - Sint64 offset) /* where to write it */ -{ - int res = efile_seek(errInfo, fd, offset, EFILE_SEEK_SET, NULL); - - if (res) { - return efile_write(errInfo, 0, fd, buf, count); - } else { - return res; - } -} - -/***************************************************************************/ - -int -efile_seek(Efile_error* errInfo, /* Where to return error codes. */ - int fd, /* File descriptor to do the seek on. */ - Sint64 offset, /* Offset in bytes from the given - origin. */ - int origin, /* Origin of seek (SEEK_SET, SEEK_CUR, - SEEK_END). */ - Sint64 *new_location) /* Resulting new location in file. */ -{ - off_t off, result; - off = (off_t) offset; - - switch (origin) { - case EFILE_SEEK_SET: - origin = SEEK_SET; - break; - case EFILE_SEEK_CUR: - origin = SEEK_CUR; - break; - case EFILE_SEEK_END: - origin = SEEK_END; - break; - default: - errno = EINVAL; - return check_error(-1, errInfo); - } - - if (off != offset) { - errno = EINVAL; - return check_error(-1, errInfo); - } - - errno = 0; - result = lseek(fd, off, origin); - - if (result >= 0) { - l_invalidate_local_fd(fd); - } - - if (result < 0) - { - if (errno == ENOSYS) { - int size, cur_pos; - - if (off < 0) { - errno = EINVAL; - return check_error(-1, errInfo); - } - - cur_pos = lseek(fd, 0, SEEK_CUR); - size = lseek(fd, 0, SEEK_END); - - if (origin == SEEK_SET) { - result = offset; - } - else if (origin == SEEK_CUR) { - result = offset + cur_pos; - } - else if (origin == SEEK_END) { - result = size + offset; - } - - /* sanity check our result */ - if (size > result) { - return check_error(-1, errInfo); - } - - /* store the data localy */ - l_update_local_fd(fd, result, size); - - /* reset the original file position */ - if (origin != SEEK_END) { - lseek(fd, cur_pos, SEEK_SET); - } - } - else if (errno == 0) { - errno = EINVAL; - } - } - - if (new_location) { - *new_location = result; - } - - return 1; -} - -/***************************************************************************/ - -int -efile_truncate_file(Efile_error* errInfo, int *fd, int flags) -{ - off_t offset; - struct fd_data *fd_data; - - if ((fd_data = l_find_local_fd(*fd)) != NULL && L_FD_IS_VALID(fd_data)) { - offset = L_FD_CUR(fd_data); - } - else { - offset = lseek(*fd, 0, SEEK_CUR); - } - - return check_error(((offset >= 0) && - (ftruncate(*fd, offset) == 0)) ? 1 : -1, errInfo); -} - -/***************************************************************************/ - -int -efile_readlink(Efile_error* errInfo, char* name, char* buffer, size_t size) -{ - errno = ENOTSUP; - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_altname(Efile_error* errInfo, char* name, char* buffer, size_t size) -{ - errno = ENOTSUP; - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_link(Efile_error* errInfo, char* old, char* new) -{ - errno = ENOTSUP; - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_symlink(Efile_error* errInfo, char* old, char* new) -{ - errno = ENOTSUP; - return check_error(-1, errInfo); -} - -/***************************************************************************/ - -int -efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, - Sint64 length, int advise) -{ - return check_error(posix_fadvise(fd, offset, length, advise), errInfo); -} - -/***************************************************************************/ - -static int -call_posix_fallocate(int fd, Sint64 offset, Sint64 length) -{ - int ret; - - /* - * On Linux and Solaris for example, posix_fallocate() returns - * a positive error number on error and it does not set errno. - * On FreeBSD however (9.0 at least), it returns -1 on error - * and it sets errno. - */ - do { - ret = posix_fallocate(fd, (off_t) offset, (off_t) length); - if (ret > 0) { - errno = ret; - ret = -1; - } - } while (ret != 0 && errno == EINTR); - - return ret; -} - -/***************************************************************************/ - -int -efile_fallocate(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length) -{ - return check_error(call_posix_fallocate(fd, offset, length), errInfo); -} diff --git a/erts/emulator/drivers/ose/ose_signal_drv.c b/erts/emulator/drivers/ose/ose_signal_drv.c deleted file mode 100644 index 2be9462a47..0000000000 --- a/erts/emulator/drivers/ose/ose_signal_drv.c +++ /dev/null @@ -1,897 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2013-2013. 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% - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "errno.h" -#include "stdio.h" -#include "string.h" -#include "stddef.h" - -#include "sys.h" -#include "erl_driver.h" -#include "ose.h" - - -#ifdef HAVE_OSE_SPI_H -#include "ose_spi/ose_spi.h" -#endif - -#define DEBUG_ATTACH 0 -#define DEBUG_HUNT 0 -#define DEBUG_SEND 0 -#define DEBUG_LISTEN 0 - -#if 0 -#define DEBUGP(FMT,...) printf(FMT, __VA_ARGS__) -#else -#define DEBUGP(FMT,...) -#endif - -#if DEBUG_ATTACH -#define DEBUGP_ATTACH(...) DEBUGP( __VA_ARGS__) -#else -#define DEBUGP_ATTACH(...) -#endif - -#if DEBUG_HUNT -#define DEBUGP_HUNT(...) DEBUGP( __VA_ARGS__) -#else -#define DEBUGP_HUNT(...) -#endif - -#if DEBUG_LISTEN -#define DEBUGP_LISTEN(...) DEBUGP( __VA_ARGS__) -#else -#define DEBUGP_LISTEN(...) -#endif - -#if DEBUG_SEND -#define DEBUGP_SEND(...) DEBUGP( __VA_ARGS__) -#else -#define DEBUGP_SEND(...) -#endif - - -#define DRIVER_NAME "ose_signal_drv" -#define GET_SPID 1 -#define GET_NAME 2 -#define HUNT 100 -#define DEHUNT 101 -#define ATTACH 102 -#define DETACH 103 -#define SEND 104 -#define SEND_W_S 105 -#define LISTEN 106 -#define OPEN 200 - -#define REF_SEGMENT_SIZE 8 - -struct async { - SIGSELECT signo; - ErlDrvTermData port; - ErlDrvTermData proc; - PROCESS spid; - PROCESS target; - Uint32 ref; -}; - -/** - * OSE signals - **/ -union SIGNAL { - SIGSELECT signo; - struct async async; -}; - -/** - * The driver's context - **/ -typedef struct _driver_context { - ErlDrvPort port; - PROCESS spid; - ErlDrvEvent perm_events[2]; - ErlDrvEvent *events; - Uint32 event_cnt; - Uint32 ref; - Uint32 *outstanding_refs; - Uint32 outstanding_refs_max; - Uint32 outstanding_refs_cnt; -} driver_context_t; - -/** - * Global variables - **/ -static ErlDrvTermData a_ok; -static ErlDrvTermData a_error; -static ErlDrvTermData a_enomem; -static ErlDrvTermData a_enoent; -static ErlDrvTermData a_badarg; -static ErlDrvTermData a_mailbox_up; -static ErlDrvTermData a_mailbox_down; -static ErlDrvTermData a_ose_drv_reply; -static ErlDrvTermData a_message; -static PROCESS proxy_proc; - - -/** - * Serialize/unserialize unsigned 32-bit values - **/ -static char *put_u32(unsigned int value, char *ptr) { - *ptr++ = (value & 0xff000000) >> 24; - *ptr++ = (value & 0x00ff0000) >> 16; - *ptr++ = (value & 0x0000ff00) >> 8; - *ptr++ = (value & 0xff); - - return ptr; -} - -static unsigned int get_u32(char *ptr) { - unsigned int result = 0; - result += (ptr[0] & 0xff) << 24; - result += (ptr[1] & 0xff) << 16; - result += (ptr[2] & 0xff) << 8; - result += (ptr[3] & 0xff); - - return result; -} - - -/* Stolen from efile_drv.c */ - -/* char EV_CHAR_P(ErlIOVec *ev, int p, int q) */ -#define EV_CHAR_P(ev, p, q) \ - (((char *)(ev)->iov[(q)].iov_base) + (p)) - -/* int EV_GET_CHAR(ErlIOVec *ev, char *p, int *pp, int *qp) */ -#define EV_GET_CHAR(ev, p, pp, qp) ev_get_char(ev, p ,pp, qp) -static int -ev_get_char(ErlIOVec *ev, char *p, int *pp, int *qp) { - if (*(pp)+1 <= (ev)->iov[*(qp)].iov_len) { - *(p) = *EV_CHAR_P(ev, *(pp), *(qp)); - if (*(pp)+1 < (ev)->iov[*(qp)].iov_len) - *(pp) = *(pp)+1; - else { - (*(qp))++; - *pp = 0; - } - return !0; - } - return 0; -} - -/* Uint32 EV_UINT32(ErlIOVec *ev, int p, int q)*/ -#define EV_UINT32(ev, p, q) \ - ((Uint32) *(((unsigned char *)(ev)->iov[(q)].iov_base) + (p))) - -/* int EV_GET_UINT32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) */ -#define EV_GET_UINT32(ev, p, pp, qp) ev_get_uint32(ev,(Uint32*)(p),pp,qp) -static int -ev_get_uint32(ErlIOVec *ev, Uint32 *p, int *pp, int *qp) { - if (*(pp)+4 <= (ev)->iov[*(qp)].iov_len) { - *(p) = (EV_UINT32(ev, *(pp), *(qp)) << 24) - | (EV_UINT32(ev, *(pp)+1, *(qp)) << 16) - | (EV_UINT32(ev, *(pp)+2, *(qp)) << 8) - | (EV_UINT32(ev, *(pp)+3, *(qp))); - if (*(pp)+4 < (ev)->iov[*(qp)].iov_len) - *(pp) = *(pp)+4; - else { - (*(qp))++; - *pp = 0; - } - return !0; - } - return 0; -} - -/** - * Convinience macros - **/ -#define send_response(port,output) erl_drv_send_term(driver_mk_port(port),\ - driver_caller(port), output, sizeof(output) / sizeof(output[0])); - -void iov_memcpy(void *dest,ErlIOVec *ev,int ind,int off); -void iov_memcpy(void *dest,ErlIOVec *ev,int ind,int off) { - int i; - memcpy(dest,ev->iov[ind].iov_base+off,ev->iov[ind].iov_len-off); - for (i = ind+1; i < ev->vsize; i++) - memcpy(dest,ev->iov[i].iov_base,ev->iov[i].iov_len); -} - -/** - * Reference handling - **/ - -static int add_reference(driver_context_t *ctxt, Uint32 ref) { - - /* - * Premature optimizations may be evil, but they sure are fun. - */ - - if (ctxt->outstanding_refs == NULL) { - /* First ref to be ignored */ - ctxt->outstanding_refs = driver_alloc(REF_SEGMENT_SIZE*sizeof(Uint32)); - if (!ctxt->outstanding_refs) - return 1; - - memset(ctxt->outstanding_refs,0,REF_SEGMENT_SIZE*sizeof(Uint32)); - ctxt->outstanding_refs_max += REF_SEGMENT_SIZE; - ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref; - } else if (ctxt->outstanding_refs_cnt == ctxt->outstanding_refs_max) { - /* Expand ref array */ - Uint32 *new_array; - ctxt->outstanding_refs_max += REF_SEGMENT_SIZE; - new_array = driver_realloc(ctxt->outstanding_refs, - ctxt->outstanding_refs_max*sizeof(Uint32)); - - if (!new_array) { - ctxt->outstanding_refs_max -= REF_SEGMENT_SIZE; - return 1; - } - - ctxt->outstanding_refs = new_array; - - memset(ctxt->outstanding_refs+ctxt->outstanding_refs_cnt,0, - REF_SEGMENT_SIZE*sizeof(Uint32)); - ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref; - - } else { - /* Find an empty slot: - * First we try current index, - * then we scan for a slot. - */ - if (!ctxt->outstanding_refs[ctxt->outstanding_refs_cnt]) { - ctxt->outstanding_refs[ctxt->outstanding_refs_cnt++] = ref; - } else { - int i; - ASSERT(ctxt->outstanding_refs_cnt < ctxt->outstanding_refs_max); - for (i = 0; i < ctxt->outstanding_refs_max; i++) - if (!ctxt->outstanding_refs[i]) - break; - ASSERT(ctxt->outstanding_refs[i] == 0); - ctxt->outstanding_refs[i] = ref; - ctxt->outstanding_refs_cnt++; - } - } - return 0; -} - -/* Return 0 if removed, 1 if does not exist, */ -static int remove_reference(driver_context_t *ctxt, Uint32 ref) { - int i,j; - - if (ctxt->outstanding_refs_max == 0 && ctxt->outstanding_refs_cnt == 0) { - ASSERT(ctxt->outstanding_refs == NULL); - return 1; - } - - for (i = 0; i < ctxt->outstanding_refs_max; i++) { - if (ctxt->outstanding_refs[i] == ref) { - ctxt->outstanding_refs[i] = 0; - ctxt->outstanding_refs_cnt--; - i = -1; - break; - } - } - - if (i != -1) - return 1; - - if (ctxt->outstanding_refs_cnt == 0) { - driver_free(ctxt->outstanding_refs); - ctxt->outstanding_refs = NULL; - ctxt->outstanding_refs_max = 0; - } else if (ctxt->outstanding_refs_cnt == (ctxt->outstanding_refs_max - REF_SEGMENT_SIZE)) { - Uint32 *new_array; - for (i = 0, j = 0; i < ctxt->outstanding_refs_cnt; i++) { - if (ctxt->outstanding_refs[i] == 0) { - for (j = i+1; j < ctxt->outstanding_refs_max; j++) - if (ctxt->outstanding_refs[j]) { - ctxt->outstanding_refs[i] = ctxt->outstanding_refs[j]; - ctxt->outstanding_refs[j] = 0; - break; - } - } - } - ctxt->outstanding_refs_max -= REF_SEGMENT_SIZE; - new_array = driver_realloc(ctxt->outstanding_refs, - ctxt->outstanding_refs_max*sizeof(Uint32)); - if (!new_array) { - ctxt->outstanding_refs_max += REF_SEGMENT_SIZE; - return 2; - } - - ctxt->outstanding_refs = new_array; - - } - - return 0; -} - -/** - * The OSE proxy process. This only handles ERTS_SIGNAL_OSE_DRV_ATTACH. - * The process is needed because signals triggered by attach ignore - * redir tables. - * - * We have one global proxy process to save memory. An attempt to make each - * port phantom into a proxy was made, but that used way to much memory. - */ -static OS_PROCESS(driver_proxy_process) { - SIGSELECT sigs[] = {1,ERTS_SIGNAL_OSE_DRV_ATTACH}; - PROCESS master = 0; - - while (1) { - union SIGNAL *sig = receive(sigs); - - if (sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) { - - /* The first message is used to determine who to send messages to. */ - if (master == 0) - master = sender(&sig); - - if (sig->async.target == 0) { - PROCESS from = sender(&sig); - restore(sig); - DEBUGP_ATTACH("0x%x: got attach 0x%x, sending to 0x%x\n", - current_process(),from,master); - sig->async.target = from; - send(&sig,master); - } else { - PROCESS target = sig->async.target; - restore(sig); - sig->async.target = 0; - DEBUGP_ATTACH("0x%x: doing attach on 0x%x\n",current_process(),target); - attach(&sig,target); - } - } - } -} - - -/** - * Init routine for the driver - **/ -static int drv_init(void) { - - a_ok = driver_mk_atom("ok"); - a_error = driver_mk_atom("error"); - a_enomem = driver_mk_atom("enomem"); - a_enoent = driver_mk_atom("enoent"); - a_badarg = driver_mk_atom("badarg"); - a_mailbox_up = driver_mk_atom("mailbox_up"); - a_mailbox_down = driver_mk_atom("mailbox_down"); - a_ose_drv_reply = driver_mk_atom("ose_drv_reply"); - a_message = driver_mk_atom("message"); - - proxy_proc = create_process(get_ptype(current_process()), - "ose_signal_driver_proxy", - driver_proxy_process, 10000, - get_pri(current_process()), - 0, 0, NULL, 0, 0); - -#ifdef DEBUG - efs_clone(proxy_proc); -#endif - start(proxy_proc); - - return 0; -} - -/* Signal resolution callback */ -static ErlDrvOseEventId resolve_signal(union SIGNAL* osig) { - union SIGNAL *sig = osig; - if (sig->signo == ERTS_SIGNAL_OSE_DRV_HUNT || - sig->signo == ERTS_SIGNAL_OSE_DRV_ATTACH) { - return sig->async.spid; - } - DEBUGP("%p: Got signal %d sent to %p from 0x%p\n", - current_process(),sig->signo,addressee(&sig),sender(&sig)); - return addressee(&sig); -} - - -/** - * Start routine for the driver - **/ -static ErlDrvData drv_start(ErlDrvPort port, char *command) -{ - driver_context_t *ctxt = driver_alloc(sizeof(driver_context_t)); - - ctxt->perm_events[0] = NULL; - ctxt->perm_events[1] = NULL; - - ctxt->spid = 0; - ctxt->port = port; - ctxt->event_cnt = 0; - ctxt->events = NULL; - ctxt->ref = 0; - ctxt->outstanding_refs = NULL; - ctxt->outstanding_refs_max = 0; - ctxt->outstanding_refs_cnt = 0; - - - /* Set the communication protocol to Erlang to be binary */ - set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY); - - /* Everything ok */ - return (ErlDrvData)ctxt; -} - -/** - * Stop routine for the driver - **/ -static void drv_stop(ErlDrvData driver_data) -{ - driver_context_t *ctxt = (driver_context_t *)driver_data; - int i; - - /* HUNT + ATTACH */ - if (ctxt->perm_events[0]) - driver_select(ctxt->port, ctxt->perm_events[0], - ERL_DRV_USE|ERL_DRV_READ, 0); - if (ctxt->perm_events[1]) - driver_select(ctxt->port, ctxt->perm_events[1], - ERL_DRV_USE|ERL_DRV_READ, 0); - - for (i = 0; i < ctxt->event_cnt; i++) { - driver_select(ctxt->port, ctxt->events[i], ERL_DRV_USE|ERL_DRV_READ, 0); - } - - if (ctxt->spid != 0) - kill_proc(ctxt->spid); - DEBUGP("0x%x: stopped\n",ctxt->spid); - if (ctxt->events) - driver_free(ctxt->events); - if (ctxt->outstanding_refs) - driver_free(ctxt->outstanding_refs); - - driver_free(ctxt); -} - -/** - * Output from Erlang - **/ -static void outputv(ErlDrvData driver_data, ErlIOVec *ev) -{ - driver_context_t *ctxt = (driver_context_t *)driver_data; - int p = 0, q = 1; - char cmd; - - if (! EV_GET_CHAR(ev,&cmd,&p,&q)) { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_ATOM, a_badarg, - ERL_DRV_TUPLE, 3}; - send_response(ctxt->port, output); - return; - } - - /* Command is in the buffer's first byte */ - switch(cmd) { - - case OPEN: { - char *name = driver_alloc(ev->size - 1+1); - struct OS_redir_entry redir[2]; - - redir[0].sig = 1; - redir[0].pid = current_process(); - - iov_memcpy(name,ev,q,p); - name[ev->size-1] = '\0'; - - ctxt->spid = create_process(OS_PHANTOM, name, NULL, 0, - 0, 0, 0, redir, 0, 0); - - DEBUGP("0x%x: open\n",ctxt->spid); - - ctxt->perm_events[1] = - erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_ATTACH,(int)ctxt->spid, - resolve_signal, NULL); - driver_select(ctxt->port,ctxt->perm_events[1],ERL_DRV_READ|ERL_DRV_USE,1); - - ctxt->perm_events[0] = - erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_HUNT,(int)ctxt->spid, - resolve_signal, NULL); - driver_select(ctxt->port,ctxt->perm_events[0],ERL_DRV_READ|ERL_DRV_USE,1); - - start(ctxt->spid); - - { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_ATOM, a_ok, - ERL_DRV_TUPLE, 3}; - - send_response(ctxt->port, output); - } - - break; - - } - - case ATTACH: - case HUNT: - { - union SIGNAL *sig = alloc(sizeof(union SIGNAL), - cmd == HUNT ? ERTS_SIGNAL_OSE_DRV_HUNT:ERTS_SIGNAL_OSE_DRV_ATTACH); - - sig->async.port = driver_mk_port(ctxt->port); - sig->async.proc = driver_caller(ctxt->port); - sig->async.spid = ctxt->spid; - sig->async.ref = ++ctxt->ref; - - if (add_reference(ctxt,ctxt->ref)) { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_ATOM, a_enomem, - ERL_DRV_TUPLE, 3}; - send_response(ctxt->port, output); - free_buf(&sig); - } else { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_INT, (ErlDrvUInt)ctxt->ref, - ERL_DRV_TUPLE, 2, - ERL_DRV_TUPLE, 3}; - send_response(ctxt->port, output); - - if (cmd == HUNT) { - char *huntname = driver_alloc(sizeof(char)*((ev->size-1)+1)); - - iov_memcpy(huntname,ev,q,p); - huntname[ev->size-1] = '\0'; - - DEBUGP_HUNT("0x%x: hunt %s -> %u (%u,%u)\n", - ctxt->spid,huntname,ctxt->ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - - hunt(huntname, 0, NULL, &sig); - - driver_free(huntname); - } else { - EV_GET_UINT32(ev,&sig->async.target,&p,&q); - DEBUGP_ATTACH("0x%x: attach %u -> %u (%u,%u)\n", - ctxt->spid,sig->async.target, - ctxt->ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - - send(&sig,proxy_proc); - } - - } - - break; - } - - case DETACH: - case DEHUNT: - { - - Uint32 ref; - - EV_GET_UINT32(ev,&ref,&p,&q); - if (cmd == DETACH) { - DEBUGP_ATTACH("0x%x: detach %u (%u,%u)\n",ctxt->spid,ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - } else { - DEBUGP_HUNT("0x%x: dehunt %u (%u,%u)\n",ctxt->spid,ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - } - - if (remove_reference(ctxt,ref)) { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_ATOM, a_error, - ERL_DRV_ATOM, a_enoent, - ERL_DRV_TUPLE, 2, - ERL_DRV_TUPLE, 3}; - - send_response(ctxt->port, output); - } else { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_ATOM, a_ok, - ERL_DRV_TUPLE, 3}; - - send_response(ctxt->port, output); - } - - break; - } - - case SEND: - case SEND_W_S: - { - PROCESS spid; - PROCESS sender; - SIGSELECT signo; - OSBUFSIZE size = ev->size-9; - union SIGNAL *sig; - - EV_GET_UINT32(ev,&spid,&p,&q); - - if (cmd == SEND_W_S) { - EV_GET_UINT32(ev,&sender,&p,&q); - size -= 4; - } else { - sender = ctxt->spid; - } - - EV_GET_UINT32(ev,&signo,&p,&q); - - sig = alloc(size + sizeof(SIGSELECT),signo); - - if (cmd == SEND_W_S) { - DEBUGP_SEND("0x%x: send_w_s(%u,%u,%u)\n",ctxt->spid,spid,signo,sender); - } else { - DEBUGP_SEND("0x%x: send(%u,%u)\n",ctxt->spid,spid,signo); - } - - iov_memcpy(((char *)&sig->signo) + sizeof(SIGSELECT),ev,q,p); - - send_w_s(&sig, sender, spid); - - break; - } - - case LISTEN: - { - int i,j,event_cnt = (ev->size - 1)/4; - ErlDrvEvent *events = NULL; - SIGSELECT signo,tmp_signo; - - if (event_cnt == 0) { - for (i = 0; i < ctxt->event_cnt; i++) - driver_select(ctxt->port,ctxt->events[i],ERL_DRV_READ|ERL_DRV_USE,0); - if (ctxt->events) - driver_free(ctxt->events); - } else { - events = driver_alloc(sizeof(ErlDrvEvent)*event_cnt); - EV_GET_UINT32(ev,&signo,&p,&q); - for (i = 0, j = 0; i < event_cnt || j < ctxt->event_cnt; ) { - - if (ctxt->events) - erl_drv_ose_event_fetch(ctxt->events[j],&tmp_signo,NULL,NULL); - - if (signo == tmp_signo) { - events[i++] = ctxt->events[j++]; - EV_GET_UINT32(ev,&signo,&p,&q); - } else if (signo < tmp_signo || !ctxt->events) { - /* New signal to select on */ - events[i] = erl_drv_ose_event_alloc(signo,(int)ctxt->spid, - resolve_signal, NULL); - driver_select(ctxt->port,events[i++],ERL_DRV_READ|ERL_DRV_USE,1); - EV_GET_UINT32(ev,&signo,&p,&q); - } else { - /* Remove old signal to select on */ - driver_select(ctxt->port,ctxt->events[j++],ERL_DRV_READ|ERL_DRV_USE,0); - } - } - if (ctxt->events) - driver_free(ctxt->events); - } - ctxt->events = events; - ctxt->event_cnt = event_cnt; - - { - ErlDrvTermData output[] = { - ERL_DRV_ATOM, a_ose_drv_reply, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_ATOM, a_ok, - ERL_DRV_TUPLE, 3}; - send_response(ctxt->port, output); - } - break; - } - - default: - { - DEBUGP("Warning: 'ose_signal_drv' unknown command '%d'\n", cmd); - break; - } - } -} - -/** - * Handler for when OSE signal arrives - **/ -static void ready_input(ErlDrvData driver_data, ErlDrvEvent event) -{ - driver_context_t *ctxt = (driver_context_t *)driver_data; - union SIGNAL *sig = erl_drv_ose_get_signal(event); - - while (sig != NULL) { - - switch(sig->signo) - { - /* Remote process is available */ - case ERTS_SIGNAL_OSE_DRV_HUNT: - { - const PROCESS spid = sender(&sig); - - if (remove_reference(ctxt,sig->async.ref)) { - DEBUGP_HUNT("0x%x: Got hunt from 0x%x -> %u (CANCELLED) (%u,%u)\n", - ctxt->spid,spid,sig->async.ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - /* Already removed by dehunt */ - } else { - ErlDrvTermData reply[] = { - ERL_DRV_ATOM, a_mailbox_up, - ERL_DRV_PORT, sig->async.port, - ERL_DRV_PORT, sig->async.port, - ERL_DRV_UINT, (ErlDrvUInt)sig->async.ref, - ERL_DRV_TUPLE, 2, - ERL_DRV_UINT, (ErlDrvUInt)spid, - ERL_DRV_TUPLE, 4}; - DEBUGP_HUNT("0x%x: Got hunt from 0x%x -> %u (%u,%u)\n", - ctxt->spid,spid,sig->async.ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - erl_drv_send_term(sig->async.port, sig->async.proc, reply, - sizeof(reply) / sizeof(reply[0])); - } - break; - } - - /* Remote process is down */ - case ERTS_SIGNAL_OSE_DRV_ATTACH: - { - PROCESS spid = sig->async.target; - - if (remove_reference(ctxt,sig->async.ref)) { - DEBUGP_ATTACH("0x%x: Got attach from 0x%x -> %u (CANCELLED) (%u,%u)\n", - ctxt->spid,spid,sig->async.ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - /* Already removed by detach */ - } else { - ErlDrvTermData reply[] = { - ERL_DRV_ATOM, a_mailbox_down, - ERL_DRV_PORT, sig->async.port, - ERL_DRV_PORT, sig->async.port, - ERL_DRV_UINT, sig->async.ref, - ERL_DRV_TUPLE, 2, - ERL_DRV_UINT, (ErlDrvUInt)spid, - ERL_DRV_TUPLE, 4}; - DEBUGP_ATTACH("0x%x: Got attach from 0x%x -> %u (%u,%u)\n", - ctxt->spid,spid,sig->async.ref, - ctxt->outstanding_refs_cnt, - ctxt->outstanding_refs_max); - erl_drv_send_term(sig->async.port, sig->async.proc, reply, - sizeof(reply) / sizeof(reply[0])); - } - break; - } - - /* Received user defined signal */ - default: - { - const PROCESS spid = sender(&sig); - const OSBUFSIZE size = sigsize(&sig) - sizeof(SIGSELECT); - const char *sig_data = ((char *)&sig->signo) + sizeof(SIGSELECT); - - ErlDrvTermData reply[] = { - ERL_DRV_ATOM, a_message, - ERL_DRV_PORT, driver_mk_port(ctxt->port), - ERL_DRV_UINT, (ErlDrvUInt)spid, - ERL_DRV_UINT, (ErlDrvUInt)ctxt->spid, - ERL_DRV_UINT, (ErlDrvUInt)sig->signo, - ERL_DRV_BUF2BINARY, (ErlDrvTermData)sig_data, (ErlDrvUInt)size, - ERL_DRV_TUPLE, 4, - ERL_DRV_TUPLE, 3}; - - DEBUGP_SEND("0x%x: Got 0x%u\r\n", spid, sig->signo); - - erl_drv_output_term(driver_mk_port(ctxt->port), reply, - sizeof(reply) / sizeof(reply[0])); - break; - } - } - - free_buf(&sig); - sig = erl_drv_ose_get_signal(event); - } -} - -/** - * Handler for 'port_control' - **/ -static ErlDrvSSizeT control(ErlDrvData driver_data, unsigned int cmd, - char *buf, ErlDrvSizeT len, - char **rbuf, ErlDrvSizeT rlen) -{ - driver_context_t *ctxt = (driver_context_t *)driver_data; - - switch(cmd) - { - case GET_SPID: - { - const PROCESS spid = ctxt->spid; - put_u32(spid, *rbuf); - return sizeof(PROCESS); - } - -#ifdef HAVE_OSE_SPI_H - case GET_NAME: - { - const PROCESS spid = get_u32(buf); - char *name = (char*)get_pid_info(spid,OSE_PI_NAME); - int n; - if (!name) { - *rbuf = NULL; - return 0; - } - - if (rlen < (n = strlen(name))) { - ErlDrvBinary *bin = driver_alloc_binary(n); - strncpy(bin->orig_bytes,name,n); - *rbuf = (char*)bin; - } else - strncpy(*rbuf,name,n); - free_buf((union SIGNAL**)&name); - - return n; - } -#endif - default: - { - /* Unknown command */ - return (ErlDrvSSizeT)ERL_DRV_ERROR_GENERAL; - break; - } - } -} - -static void stop_select(ErlDrvEvent event, void *reserved) -{ - erl_drv_ose_event_free(event); -} - -/** - * Setup the driver entry for the Erlang runtime - **/ -ErlDrvEntry ose_signal_driver_entry = { - .init = drv_init, - .start = drv_start, - .stop = drv_stop, - .outputv = outputv, - .ready_input = ready_input, - .driver_name = DRIVER_NAME, - .control = control, - .extended_marker = ERL_DRV_EXTENDED_MARKER, - .major_version = ERL_DRV_EXTENDED_MAJOR_VERSION, - .minor_version = ERL_DRV_EXTENDED_MINOR_VERSION, - .driver_flags = ERL_DRV_FLAG_USE_PORT_LOCKING, - .stop_select = stop_select -}; - diff --git a/erts/emulator/drivers/ose/ttsl_drv.c b/erts/emulator/drivers/ose/ttsl_drv.c deleted file mode 100644 index f759b47984..0000000000 --- a/erts/emulator/drivers/ose/ttsl_drv.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2013. 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% - */ -/* - * Stub tty driver because group/user depend on this. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "erl_driver.h" - -static int ttysl_init(void); -static ErlDrvData ttysl_start(ErlDrvPort, char*); - -/* Define the driver table entry. */ -struct erl_drv_entry ttsl_driver_entry = { - ttysl_init, - ttysl_start, - NULL, - NULL, - NULL, - NULL, - "tty_sl", - NULL, - NULL, - NULL, - NULL, /* timeout */ - NULL, /* outputv */ - NULL, /* ready_async */ - NULL, /* flush */ - NULL, /* call */ - NULL, /* event */ - ERL_DRV_EXTENDED_MARKER, - ERL_DRV_EXTENDED_MAJOR_VERSION, - ERL_DRV_EXTENDED_MINOR_VERSION, - 0, /* ERL_DRV_FLAGs */ - NULL, - NULL, /* process_exit */ - NULL -}; - - -static int ttysl_init(void) -{ - return 0; -} - -static ErlDrvData ttysl_start(ErlDrvPort port, char* buf) -{ - return ERL_DRV_ERROR_GENERAL; -} diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index 53146e71f0..25cad37e25 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -733,13 +733,13 @@ static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT coun else written = 0; if (written < 0) { - if (errno == EAGAIN) { + if (errno == ERRNO_BLOCK || errno == EINTR) { driver_select(ttysl_port,(ErlDrvEvent)(long)ttysl_fd, ERL_DRV_USE|ERL_DRV_WRITE,1); break; } else { - /* we ignore all other errors */ - break; + driver_failure_posix(ttysl_port, errno); + return; } } else { if (driver_deq(ttysl_port, written) == 0) @@ -779,11 +779,12 @@ static void ttysl_to_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) { else written = 0; if (written < 0) { - if (errno == EAGAIN) { - break; - } else { - /* we ignore all other errors */ + if (errno == EINTR) { + continue; + } else if (errno != ERRNO_BLOCK){ + driver_failure_posix(ttysl_port, errno); } + break; } else { sz = driver_deq(ttysl_port, written); if (sz < TTY_BUFFSIZE && ttysl_send_ok) { diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 06ba986044..46eccc6568 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -45,10 +45,10 @@ #endif #if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) -#define DARWIN 1 +#define __DARWIN__ 1 #endif -#if defined(DARWIN) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) +#if defined(__DARWIN__) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) #include <fcntl.h> #endif @@ -476,11 +476,11 @@ efile_fsync(Efile_error *errInfo, /* Where to return error codes. */ #ifdef NO_FSYNC undefined fsync /* XXX: Really? */ #else -#if defined(DARWIN) && defined(F_FULLFSYNC) +#if defined(__DARWIN__) && defined(F_FULLFSYNC) return check_error(fcntl(fd, F_FULLFSYNC), errInfo); #else return check_error(fsync(fd), errInfo); -#endif /* DARWIN */ +#endif /* __DARWIN__ */ #endif /* NO_FSYNC */ } @@ -962,7 +962,7 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, retval = len; } } while (len == SENDFILE_CHUNK_SIZE); -#elif defined(DARWIN) +#elif defined(__DARWIN__) int retval; off_t len; do { diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c index 98bda43f0e..688378b2fe 100644 --- a/erts/emulator/hipe/hipe_native_bif.c +++ b/erts/emulator/hipe/hipe_native_bif.c @@ -93,9 +93,6 @@ BIF_RETTYPE hipe_set_timeout(BIF_ALIST_1) { Process* p = BIF_P; Eterm timeout_value = BIF_ARG_1; -#if !defined(ARCH_64) - Uint time_val; -#endif /* XXX: This should be converted to follow BEAM conventions, * but that requires some compiler changes. * diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c index 105b129065..f87196d724 100644 --- a/erts/emulator/sys/common/erl_check_io.c +++ b/erts/emulator/sys/common/erl_check_io.c @@ -1337,11 +1337,7 @@ print_select_op(erts_dsprintf_buf_t *dsbufp, { Port *pp = erts_drvport2port(ix); erts_dsprintf(dsbufp, -#ifdef __OSE__ - "driver_select(%p, %d,%s%s%s%s | %d, %d) " -#else "driver_select(%p, %d,%s%s%s%s, %d) " -#endif "by ", ix, (int) GET_FD(fd), @@ -1861,25 +1857,6 @@ stale_drv_select(Eterm id, ErtsDrvEventState *state, int mode) #ifndef ERTS_SYS_CONTINOUS_FD_NUMBERS -#ifdef __OSE__ -static SafeHashValue drv_ev_state_hash(void *des) -{ - ErtsSysFdType fd = ((ErtsDrvEventState *) des)->fd; - /* We use hash on signo ^ id in order for steal to happen when the - same signo + fd is selected on by two different ports */ - SafeHashValue val = (SafeHashValue)(fd->signo ^ fd->id); - return val ^ (val >> 8); -} - -static int drv_ev_state_cmp(void *des1, void *des2) -{ - ErtsSysFdType fd1 = ((ErtsDrvEventState *) des1)->fd; - ErtsSysFdType fd2 = ((ErtsDrvEventState *) des2)->fd; - if (fd1->signo == fd2->signo && fd1->id == fd2->id) - return 0; - return 1; -} -#else /* !__OSE__ && !ERTS_SYS_CONTINOUS_FD_NUMBERS i.e. probably windows */ static SafeHashValue drv_ev_state_hash(void *des) { SafeHashValue val = (SafeHashValue) ((ErtsDrvEventState *) des)->fd; @@ -1891,7 +1868,6 @@ static int drv_ev_state_cmp(void *des1, void *des2) return ( ((ErtsDrvEventState *) des1)->fd == ((ErtsDrvEventState *) des2)->fd ? 0 : 1); } -#endif static void *drv_ev_state_alloc(void *des_tmpl) { diff --git a/erts/emulator/sys/common/erl_mmap.c b/erts/emulator/sys/common/erl_mmap.c index 754047829f..e6d0e1e281 100644 --- a/erts/emulator/sys/common/erl_mmap.c +++ b/erts/emulator/sys/common/erl_mmap.c @@ -2453,7 +2453,6 @@ Eterm erts_mmap_debug_info(Process* p) UWord values[4]; Eterm *hp, *hp_end; Uint may_need; - const Uint PTR_BIG_SZ = HALFWORD_HEAP ? 3 : 2; erts_smp_mtx_lock(&mmap_state.mtx); values[0] = (UWord)mmap_state.sa.bot; @@ -2464,7 +2463,7 @@ Eterm erts_mmap_debug_info(Process* p) sua_list = build_free_seg_list(p, &mmap_state.sua.map); erts_smp_mtx_unlock(&mmap_state.mtx); - may_need = 4*(2+3+PTR_BIG_SZ) + 2*(2+3); + may_need = 4*(2+3+2) + 2*(2+3); hp = HAlloc(p, may_need); hp_end = hp + may_need; diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c index 0d51aad863..7eb8a4a460 100644 --- a/erts/emulator/sys/common/erl_mseg.c +++ b/erts/emulator/sys/common/erl_mseg.c @@ -99,17 +99,12 @@ static const int debruijn[32] = { static int atoms_initialized; -typedef struct mem_kind_t MemKind; - const ErtsMsegOpt_t erts_mseg_default_opt = { 1, /* Use cache */ 1, /* Preserv data */ 0, /* Absolute shrink threshold */ 0, /* Relative shrink threshold */ 0 /* Scheduler specific */ -#if HALFWORD_HEAP - ,0 /* need low memory */ -#endif }; @@ -142,7 +137,14 @@ struct cache_t_ { typedef struct ErtsMsegAllctr_t_ ErtsMsegAllctr_t; -struct mem_kind_t { +struct ErtsMsegAllctr_t_ { + int ix; + + int is_init_done; + int is_thread_safe; + erts_mtx_t mtx; + + int is_cache_check_scheduled; cache_t cache[MAX_CACHE_SIZE]; cache_t cache_unpowered_node; @@ -168,29 +170,6 @@ struct mem_kind_t { } max_ever; } segments; - ErtsMsegAllctr_t *ma; - const char* name; - MemKind* next; -};/*MemKind*/ - -struct ErtsMsegAllctr_t_ { - int ix; - - int is_init_done; - int is_thread_safe; - erts_mtx_t mtx; - - int is_cache_check_scheduled; - - MemKind* mk_list; - -#if HALFWORD_HEAP - MemKind low_mem; - MemKind hi_mem; -#else - MemKind the_mem; -#endif - Uint max_cache_size; Uint abs_max_cache_bad_fit; Uint rel_max_cache_bad_fit; @@ -302,18 +281,13 @@ schedule_cache_check(ErtsMsegAllctr_t *ma) { /* #define ERTS_PRINT_ERTS_MMAP */ static ERTS_INLINE void * -mseg_create(ErtsMsegAllctr_t *ma, Uint flags, MemKind* mk, UWord *sizep) +mseg_create(ErtsMsegAllctr_t *ma, Uint flags, UWord *sizep) { #ifdef ERTS_PRINT_ERTS_MMAP UWord req_size = *sizep; #endif void *seg; Uint32 mmap_flags = 0; -#if HALFWORD_HEAP - mmap_flags |= ((mk == &ma->low_mem) - ? ERTS_MMAPFLG_SUPERCARRIER_ONLY - : ERTS_MMAPFLG_OS_ONLY); -#endif if (MSEG_FLG_IS_2POW(flags)) mmap_flags |= ERTS_MMAPFLG_SUPERALIGNED; @@ -331,14 +305,9 @@ mseg_create(ErtsMsegAllctr_t *ma, Uint flags, MemKind* mk, UWord *sizep) } static ERTS_INLINE void -mseg_destroy(ErtsMsegAllctr_t *ma, Uint flags, MemKind* mk, void *seg_p, UWord size) { +mseg_destroy(ErtsMsegAllctr_t *ma, Uint flags, void *seg_p, UWord size) { Uint32 mmap_flags = 0; -#if HALFWORD_HEAP - mmap_flags |= ((mk == &ma->low_mem) - ? ERTS_MMAPFLG_SUPERCARRIER_ONLY - : ERTS_MMAPFLG_OS_ONLY); -#endif if (MSEG_FLG_IS_2POW(flags)) mmap_flags |= ERTS_MMAPFLG_SUPERALIGNED; @@ -353,18 +322,13 @@ mseg_destroy(ErtsMsegAllctr_t *ma, Uint flags, MemKind* mk, void *seg_p, UWord s } static ERTS_INLINE void * -mseg_recreate(ErtsMsegAllctr_t *ma, Uint flags, MemKind* mk, void *old_seg, UWord old_size, UWord *sizep) +mseg_recreate(ErtsMsegAllctr_t *ma, Uint flags, void *old_seg, UWord old_size, UWord *sizep) { #ifdef ERTS_PRINT_ERTS_MMAP UWord req_size = *sizep; #endif void *new_seg; Uint32 mmap_flags = 0; -#if HALFWORD_HEAP - mmap_flags |= ((mk == &ma->low_mem) - ? ERTS_MMAPFLG_SUPERCARRIER_ONLY - : ERTS_MMAPFLG_OS_ONLY); -#endif if (MSEG_FLG_IS_2POW(flags)) mmap_flags |= ERTS_MMAPFLG_SUPERALIGNED; @@ -392,11 +356,8 @@ do { \ || erts_smp_thr_progress_is_blocking() \ || ERTS_IS_CRASH_DUMPING); \ } while (0) -#define ERTS_DBG_MK_CHK_THR_ACCESS(MK) \ - ERTS_DBG_MA_CHK_THR_ACCESS((MK)->ma) #else #define ERTS_DBG_MA_CHK_THR_ACCESS(MA) -#define ERTS_DBG_MK_CHK_THR_ACCESS(MK) #endif /* Cache interface */ @@ -409,10 +370,10 @@ static ERTS_INLINE void mseg_cache_clear_node(cache_t *c) { c->prev = c; } -static ERTS_INLINE int cache_bless_segment(MemKind *mk, void *seg, UWord size, Uint flags) { +static ERTS_INLINE int cache_bless_segment(ErtsMsegAllctr_t *ma, void *seg, UWord size, Uint flags) { cache_t *c; - ERTS_DBG_MK_CHK_THR_ACCESS(mk); + ERTS_DBG_MA_CHK_THR_ACCESS(ma); ASSERT(!MSEG_FLG_IS_2POW(flags) || (MSEG_FLG_IS_2POW(flags) && MAP_IS_ALIGNED(seg) && IS_2POW(size))); @@ -421,11 +382,11 @@ static ERTS_INLINE int cache_bless_segment(MemKind *mk, void *seg, UWord size, U * Large blocks has no such cache and it is up to mseg to cache them to speed things up. */ - if (!erts_circleq_is_empty(&(mk->cache_free))) { + if (!erts_circleq_is_empty(&(ma->cache_free))) { /* We have free slots, use one to cache the segment */ - c = erts_circleq_head(&(mk->cache_free)); + c = erts_circleq_head(&(ma->cache_free)); erts_circleq_remove(c); c->seg = seg; @@ -437,29 +398,28 @@ static ERTS_INLINE int cache_bless_segment(MemKind *mk, void *seg, UWord size, U ASSERT(ix < CACHE_AREAS); ASSERT((1 << (ix + MSEG_ALIGN_BITS)) == size); - erts_circleq_push_head(&(mk->cache_powered_node[ix]), c); + erts_circleq_push_head(&(ma->cache_powered_node[ix]), c); } else - erts_circleq_push_head(&(mk->cache_unpowered_node), c); + erts_circleq_push_head(&(ma->cache_unpowered_node), c); - mk->cache_size++; - ASSERT(mk->cache_size <= mk->ma->max_cache_size); + ma->cache_size++; return 1; - } else if (!MSEG_FLG_IS_2POW(flags) && !erts_circleq_is_empty(&(mk->cache_unpowered_node))) { + } else if (!MSEG_FLG_IS_2POW(flags) && !erts_circleq_is_empty(&(ma->cache_unpowered_node))) { /* No free slots. * Evict oldest slot from unpowered cache so we can cache an unpowered (sbc) segment */ - c = erts_circleq_tail(&(mk->cache_unpowered_node)); + c = erts_circleq_tail(&(ma->cache_unpowered_node)); erts_circleq_remove(c); - mseg_destroy(mk->ma, ERTS_MSEG_FLG_NONE, mk, c->seg, c->size); + mseg_destroy(ma, ERTS_MSEG_FLG_NONE, c->seg, c->size); mseg_cache_clear_node(c); c->seg = seg; c->size = size; - erts_circleq_push_head(&(mk->cache_unpowered_node), c); + erts_circleq_push_head(&(ma->cache_unpowered_node), c); return 1; } else if (!MSEG_FLG_IS_2POW(flags)) { @@ -473,20 +433,20 @@ static ERTS_INLINE int cache_bless_segment(MemKind *mk, void *seg, UWord size, U int i; for( i = 0; i < CACHE_AREAS; i++) { - if (erts_circleq_is_empty(&(mk->cache_powered_node[i]))) + if (erts_circleq_is_empty(&(ma->cache_powered_node[i]))) continue; - c = erts_circleq_tail(&(mk->cache_powered_node[i])); + c = erts_circleq_tail(&(ma->cache_powered_node[i])); erts_circleq_remove(c); - mseg_destroy(mk->ma, ERTS_MSEG_FLG_2POW, mk, c->seg, c->size); + mseg_destroy(ma, ERTS_MSEG_FLG_2POW, c->seg, c->size); mseg_cache_clear_node(c); c->seg = seg; c->size = size; - erts_circleq_push_head(&(mk->cache_unpowered_node), c); + erts_circleq_push_head(&(ma->cache_unpowered_node), c); return 1; } @@ -495,11 +455,11 @@ static ERTS_INLINE int cache_bless_segment(MemKind *mk, void *seg, UWord size, U return 0; } -static ERTS_INLINE void *cache_get_segment(MemKind *mk, UWord *size_p, Uint flags) { +static ERTS_INLINE void *cache_get_segment(ErtsMsegAllctr_t *ma, UWord *size_p, Uint flags) { UWord size = *size_p; - ERTS_DBG_MK_CHK_THR_ACCESS(mk); + ERTS_DBG_MA_CHK_THR_ACCESS(ma); if (MSEG_FLG_IS_2POW(flags)) { @@ -512,10 +472,10 @@ static ERTS_INLINE void *cache_get_segment(MemKind *mk, UWord *size_p, Uint flag for( i = ix; i < CACHE_AREAS; i++) { - if (erts_circleq_is_empty(&(mk->cache_powered_node[i]))) + if (erts_circleq_is_empty(&(ma->cache_powered_node[i]))) continue; - c = erts_circleq_head(&(mk->cache_powered_node[i])); + c = erts_circleq_head(&(ma->cache_powered_node[i])); erts_circleq_remove(c); ASSERT(IS_2POW(c->size)); @@ -524,31 +484,31 @@ static ERTS_INLINE void *cache_get_segment(MemKind *mk, UWord *size_p, Uint flag csize = c->size; seg = (char*) c->seg; - mk->cache_size--; - mk->cache_hits++; + ma->cache_size--; + ma->cache_hits++; /* link to free cache list */ mseg_cache_clear_node(c); - erts_circleq_push_head(&(mk->cache_free), c); + erts_circleq_push_head(&(ma->cache_free), c); - ASSERT(!(mk->cache_size < 0)); + ASSERT(!(ma->cache_size < 0)); if (csize != size) - mseg_destroy(mk->ma, ERTS_MSEG_FLG_2POW, mk, seg + size, csize - size); + mseg_destroy(ma, ERTS_MSEG_FLG_2POW, seg + size, csize - size); return seg; } } - else if (!erts_circleq_is_empty(&(mk->cache_unpowered_node))) { + else if (!erts_circleq_is_empty(&(ma->cache_unpowered_node))) { void *seg; cache_t *c; cache_t *best = NULL; UWord bdiff = 0; UWord csize; - UWord bad_max_abs = mk->ma->abs_max_cache_bad_fit; - UWord bad_max_rel = mk->ma->rel_max_cache_bad_fit; + UWord bad_max_abs = ma->abs_max_cache_bad_fit; + UWord bad_max_rel = ma->rel_max_cache_bad_fit; - erts_circleq_foreach(c, &(mk->cache_unpowered_node)) { + erts_circleq_foreach(c, &(ma->cache_unpowered_node)) { csize = c->size; if (csize >= size) { if (((csize - size)*100 < bad_max_rel*size) && (csize - size) < bad_max_abs ) { @@ -557,11 +517,11 @@ static ERTS_INLINE void *cache_get_segment(MemKind *mk, UWord *size_p, Uint flag erts_circleq_remove(c); - mk->cache_size--; - mk->cache_hits++; + ma->cache_size--; + ma->cache_hits++; mseg_cache_clear_node(c); - erts_circleq_push_head(&(mk->cache_free), c); + erts_circleq_push_head(&(ma->cache_free), c); *size_p = csize; @@ -584,7 +544,7 @@ static ERTS_INLINE void *cache_get_segment(MemKind *mk, UWord *size_p, Uint flag ASSERT(best->seg); ASSERT(best->size > 0); - mk->cache_hits++; + ma->cache_hits++; /* Use current cache placement for remaining segment space */ @@ -608,7 +568,7 @@ static ERTS_INLINE void *cache_get_segment(MemKind *mk, UWord *size_p, Uint flag * using callbacks from aux-work in the scheduler. */ -static ERTS_INLINE Uint mseg_drop_one_memkind_cache_size(MemKind *mk, Uint flags, cache_t *head) { +static ERTS_INLINE Uint mseg_drop_one_cache_size(ErtsMsegAllctr_t *ma, Uint flags, cache_t *head) { cache_t *c = NULL; c = erts_circleq_tail(head); @@ -617,19 +577,19 @@ static ERTS_INLINE Uint mseg_drop_one_memkind_cache_size(MemKind *mk, Uint flags if (erts_mtrace_enabled) erts_mtrace_crr_free(SEGTYPE, SEGTYPE, c->seg); - mseg_destroy(mk->ma, flags, mk, c->seg, c->size); + mseg_destroy(ma, flags, c->seg, c->size); mseg_cache_clear_node(c); - erts_circleq_push_head(&(mk->cache_free), c); + erts_circleq_push_head(&(ma->cache_free), c); - mk->segments.current.watermark--; - mk->cache_size--; + ma->segments.current.watermark--; + ma->cache_size--; - ASSERT( mk->cache_size >= 0 ); + ASSERT(ma->cache_size >= 0); - return mk->cache_size; + return ma->cache_size; } -static ERTS_INLINE Uint mseg_drop_memkind_cache_size(MemKind *mk, Uint flags, cache_t *head) { +static ERTS_INLINE Uint mseg_drop_cache_size(ErtsMsegAllctr_t *ma, Uint flags, cache_t *head) { cache_t *c = NULL; while (!erts_circleq_is_empty(head)) { @@ -640,58 +600,52 @@ static ERTS_INLINE Uint mseg_drop_memkind_cache_size(MemKind *mk, Uint flags, ca if (erts_mtrace_enabled) erts_mtrace_crr_free(SEGTYPE, SEGTYPE, c->seg); - mseg_destroy(mk->ma, flags, mk, c->seg, c->size); + mseg_destroy(ma, flags, c->seg, c->size); mseg_cache_clear_node(c); - erts_circleq_push_head(&(mk->cache_free), c); - - mk->segments.current.watermark--; - mk->cache_size--; + erts_circleq_push_head(&(ma->cache_free), c); + ma->segments.current.watermark--; + ma->cache_size--; } - ASSERT( mk->cache_size >= 0 ); + ASSERT(ma->cache_size >= 0); - return mk->cache_size; + return ma->cache_size; } -/* mseg_check_memkind_cache - * - Check if we can empty some cached segments in this - * MemKind. +/* mseg_check_cache + * - Check if we can empty some cached segments in this allocator */ -static Uint mseg_check_memkind_cache(MemKind *mk) { +static Uint mseg_check_cache(ErtsMsegAllctr_t *ma) { int i; - ERTS_DBG_MK_CHK_THR_ACCESS(mk); + ERTS_DBG_MA_CHK_THR_ACCESS(ma); for (i = 0; i < CACHE_AREAS; i++) { - if (!erts_circleq_is_empty(&(mk->cache_powered_node[i]))) - return mseg_drop_one_memkind_cache_size(mk, ERTS_MSEG_FLG_2POW, &(mk->cache_powered_node[i])); + if (!erts_circleq_is_empty(&(ma->cache_powered_node[i]))) + return mseg_drop_one_cache_size(ma, ERTS_MSEG_FLG_2POW, &(ma->cache_powered_node[i])); } - if (!erts_circleq_is_empty(&(mk->cache_unpowered_node))) - return mseg_drop_one_memkind_cache_size(mk, ERTS_MSEG_FLG_NONE, &(mk->cache_unpowered_node)); + if (!erts_circleq_is_empty(&(ma->cache_unpowered_node))) + return mseg_drop_one_cache_size(ma, ERTS_MSEG_FLG_NONE, &(ma->cache_unpowered_node)); return 0; } /* mseg_cache_check * - Check if we have some cache we can purge - * in any of the memkinds. */ static void mseg_cache_check(ErtsMsegAllctr_t *ma) { - MemKind* mk; Uint empty_cache = 1; ERTS_MSEG_LOCK(ma); - for (mk = ma->mk_list; mk; mk = mk->next) { - if (mseg_check_memkind_cache(mk)) - empty_cache = 0; - } + if (mseg_check_cache(ma)) + empty_cache = 0; /* If all MemKinds caches are empty, * remove aux-work callback @@ -709,7 +663,7 @@ static void mseg_cache_check(ErtsMsegAllctr_t *ma) { /* erts_mseg_cache_check * - This is a callback that is scheduled as aux-work from * schedulers and is called at some interval if we have a cache - * on this mseg-allocator and memkind. + * on this mseg-allocator. * - Purpose: Empty cache slowly so we don't collect mapped areas * and bloat memory. */ @@ -719,42 +673,32 @@ void erts_mseg_cache_check(void) { } -/* *_mseg_clear_*_cache +/* mseg_clear_cache * Remove cached segments from the allocator completely */ -static void mseg_clear_memkind_cache(MemKind *mk) { + +static void mseg_clear_cache(ErtsMsegAllctr_t *ma) { int i; + ERTS_MSEG_LOCK(ma); + ERTS_DBG_MA_CHK_THR_ACCESS(ma); /* drop pow2 caches */ for (i = 0; i < CACHE_AREAS; i++) { - if (erts_circleq_is_empty(&(mk->cache_powered_node[i]))) + if (erts_circleq_is_empty(&(ma->cache_powered_node[i]))) continue; - mseg_drop_memkind_cache_size(mk, ERTS_MSEG_FLG_2POW, &(mk->cache_powered_node[i])); - ASSERT(erts_circleq_is_empty(&(mk->cache_powered_node[i]))); + mseg_drop_cache_size(ma, ERTS_MSEG_FLG_2POW, &(ma->cache_powered_node[i])); + ASSERT(erts_circleq_is_empty(&(ma->cache_powered_node[i]))); } /* drop varied caches */ - if (!erts_circleq_is_empty(&(mk->cache_unpowered_node))) - mseg_drop_memkind_cache_size(mk, ERTS_MSEG_FLG_NONE, &(mk->cache_unpowered_node)); - - ASSERT(erts_circleq_is_empty(&(mk->cache_unpowered_node))); - ASSERT(mk->cache_size == 0); -} - -static void mseg_clear_cache(ErtsMsegAllctr_t *ma) { - MemKind* mk; - - ERTS_MSEG_LOCK(ma); - ERTS_DBG_MA_CHK_THR_ACCESS(ma); + if (!erts_circleq_is_empty(&(ma->cache_unpowered_node))) + mseg_drop_cache_size(ma, ERTS_MSEG_FLG_NONE, &(ma->cache_unpowered_node)); - - for (mk = ma->mk_list; mk; mk = mk->next) { - mseg_clear_memkind_cache(mk); - } + ASSERT(erts_circleq_is_empty(&(ma->cache_unpowered_node))); + ASSERT(ma->cache_size == 0); INC_CC(ma, clear_cache); - ERTS_MSEG_UNLOCK(ma); } @@ -763,25 +707,12 @@ void erts_mseg_clear_cache(void) { mseg_clear_cache(ERTS_MSEG_ALLCTR_IX(0)); } - - -static ERTS_INLINE MemKind* memkind(ErtsMsegAllctr_t *ma, - const ErtsMsegOpt_t *opt) -{ -#if HALFWORD_HEAP - return opt->low_mem ? &ma->low_mem : &ma->hi_mem; -#else - return &ma->the_mem; -#endif -} - static void * mseg_alloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, UWord *size_p, Uint flags, const ErtsMsegOpt_t *opt) { UWord size; void *seg; - MemKind* mk = memkind(ma, opt); INC_CC(ma, alloc); @@ -795,10 +726,10 @@ mseg_alloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, UWord *size_p, } } - if (opt->cache && mk->cache_size > 0 && (seg = cache_get_segment(mk, &size, flags)) != NULL) + if (opt->cache && ma->cache_size > 0 && (seg = cache_get_segment(ma, &size, flags)) != NULL) goto done; - seg = mseg_create(ma, flags, mk, &size); + seg = mseg_create(ma, flags, &size); if (!seg) *size_p = 0; @@ -808,7 +739,7 @@ done: if (erts_mtrace_enabled) erts_mtrace_crr_alloc(seg, atype, ERTS_MTRACE_SEGMENT_ID, size); - ERTS_MSEG_ALLOC_STAT(mk,size); + ERTS_MSEG_ALLOC_STAT(ma,size); } return seg; @@ -819,11 +750,9 @@ static void mseg_dealloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg, UWord size, Uint flags, const ErtsMsegOpt_t *opt) { - MemKind* mk = memkind(ma, opt); + ERTS_MSEG_DEALLOC_STAT(ma,size); - ERTS_MSEG_DEALLOC_STAT(mk,size); - - if (opt->cache && cache_bless_segment(mk, seg, size, flags)) { + if (opt->cache && cache_bless_segment(ma, seg, size, flags)) { schedule_cache_check(ma); goto done; } @@ -831,7 +760,7 @@ mseg_dealloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg, UWord size, if (erts_mtrace_enabled) erts_mtrace_crr_free(atype, SEGTYPE, seg); - mseg_destroy(ma, flags, mk, seg, size); + mseg_destroy(ma, flags, seg, size); done: @@ -842,7 +771,6 @@ static void * mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg, UWord old_size, UWord *new_size_p, Uint flags, const ErtsMsegOpt_t *opt) { - MemKind* mk; void *new_seg; UWord new_size; @@ -861,7 +789,6 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg, return NULL; } - mk = memkind(ma, opt); new_seg = seg; if (!MSEG_FLG_IS_2POW(flags)) @@ -876,7 +803,7 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg, if (new_size > old_size) { if (opt->preserv) { - new_seg = mseg_recreate(ma, flags, mk, (void *) seg, old_size, &new_size); + new_seg = mseg_recreate(ma, flags, (void *) seg, old_size, &new_size); if (!new_seg) new_size = old_size; } @@ -896,7 +823,7 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg, new_size = old_size; } else { - new_seg = mseg_recreate(ma, flags, mk, (void *) seg, old_size, &new_size); + new_seg = mseg_recreate(ma, flags, (void *) seg, old_size, &new_size); if (!new_seg) new_size = old_size; } @@ -910,7 +837,7 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg, ASSERT(!MSEG_FLG_IS_2POW(flags) || IS_2POW(new_size)); *new_size_p = new_size; - ERTS_MSEG_REALLOC_STAT(mk, old_size, new_size); + ERTS_MSEG_REALLOC_STAT(ma, old_size, new_size); return new_seg; } @@ -1180,63 +1107,63 @@ info_calls(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, Uint **hpp } static Eterm -info_status(ErtsMsegAllctr_t *ma, MemKind* mk, int *print_to_p, void *print_to_arg, +info_status(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, int begin_new_max_period, Uint **hpp, Uint *szp) { Eterm res = THE_NON_VALUE; - if (mk->segments.max_ever.no < mk->segments.max.no) - mk->segments.max_ever.no = mk->segments.max.no; - if (mk->segments.max_ever.sz < mk->segments.max.sz) - mk->segments.max_ever.sz = mk->segments.max.sz; + if (ma->segments.max_ever.no < ma->segments.max.no) + ma->segments.max_ever.no = ma->segments.max.no; + if (ma->segments.max_ever.sz < ma->segments.max.sz) + ma->segments.max_ever.sz = ma->segments.max.sz; if (print_to_p) { int to = *print_to_p; void *arg = print_to_arg; - erts_print(to, arg, "cached_segments: %beu\n", mk->cache_size); - erts_print(to, arg, "cache_hits: %beu\n", mk->cache_hits); + erts_print(to, arg, "cached_segments: %beu\n", ma->cache_size); + erts_print(to, arg, "cache_hits: %beu\n", ma->cache_hits); erts_print(to, arg, "segments: %beu %beu %beu\n", - mk->segments.current.no, mk->segments.max.no, mk->segments.max_ever.no); + ma->segments.current.no, ma->segments.max.no, ma->segments.max_ever.no); erts_print(to, arg, "segments_size: %beu %beu %beu\n", - mk->segments.current.sz, mk->segments.max.sz, mk->segments.max_ever.sz); + ma->segments.current.sz, ma->segments.max.sz, ma->segments.max_ever.sz); erts_print(to, arg, "segments_watermark: %beu\n", - mk->segments.current.watermark); + ma->segments.current.watermark); } if (hpp || szp) { res = NIL; add_2tup(hpp, szp, &res, am.segments_watermark, - bld_unstable_uint(hpp, szp, mk->segments.current.watermark)); + bld_unstable_uint(hpp, szp, ma->segments.current.watermark)); add_4tup(hpp, szp, &res, am.segments_size, - bld_unstable_uint(hpp, szp, mk->segments.current.sz), - bld_unstable_uint(hpp, szp, mk->segments.max.sz), - bld_unstable_uint(hpp, szp, mk->segments.max_ever.sz)); + bld_unstable_uint(hpp, szp, ma->segments.current.sz), + bld_unstable_uint(hpp, szp, ma->segments.max.sz), + bld_unstable_uint(hpp, szp, ma->segments.max_ever.sz)); add_4tup(hpp, szp, &res, am.segments, - bld_unstable_uint(hpp, szp, mk->segments.current.no), - bld_unstable_uint(hpp, szp, mk->segments.max.no), - bld_unstable_uint(hpp, szp, mk->segments.max_ever.no)); + bld_unstable_uint(hpp, szp, ma->segments.current.no), + bld_unstable_uint(hpp, szp, ma->segments.max.no), + bld_unstable_uint(hpp, szp, ma->segments.max_ever.no)); add_2tup(hpp, szp, &res, am.cache_hits, - bld_unstable_uint(hpp, szp, mk->cache_hits)); + bld_unstable_uint(hpp, szp, ma->cache_hits)); add_2tup(hpp, szp, &res, am.cached_segments, - bld_unstable_uint(hpp, szp, mk->cache_size)); + bld_unstable_uint(hpp, szp, ma->cache_size)); } if (begin_new_max_period) { - mk->segments.max.no = mk->segments.current.no; - mk->segments.max.sz = mk->segments.current.sz; + ma->segments.max.no = ma->segments.current.no; + ma->segments.max.sz = ma->segments.current.sz; } return res; } -static Eterm info_memkind(ErtsMsegAllctr_t *ma, MemKind* mk, int *print_to_p, void *print_to_arg, +static Eterm info_memkind(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, int begin_max_per, Uint **hpp, Uint *szp) { Eterm res = THE_NON_VALUE; @@ -1244,15 +1171,15 @@ static Eterm info_memkind(ErtsMsegAllctr_t *ma, MemKind* mk, int *print_to_p, vo Eterm values[3]; if (print_to_p) { - erts_print(*print_to_p, print_to_arg, "memory kind: %s\n", mk->name); + erts_print(*print_to_p, print_to_arg, "memory kind: %s\n", "all memory"); } if (hpp || szp) { atoms[0] = am.name; atoms[1] = am.status; atoms[2] = am.calls; - values[0] = erts_bld_string(hpp, szp, mk->name); + values[0] = erts_bld_string(hpp, szp, "all memory"); } - values[1] = info_status(ma, mk, print_to_p, print_to_arg, begin_max_per, hpp, szp); + values[1] = info_status(ma, print_to_p, print_to_arg, begin_max_per, hpp, szp); values[2] = info_calls(ma, print_to_p, print_to_arg, hpp, szp); if (hpp || szp) @@ -1261,7 +1188,6 @@ static Eterm info_memkind(ErtsMsegAllctr_t *ma, MemKind* mk, int *print_to_p, vo return res; } - static Eterm info_version(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, Uint **hpp, Uint *szp) { @@ -1326,12 +1252,7 @@ erts_mseg_info(int ix, ERTS_MSEG_LOCK(ma); ERTS_DBG_MA_CHK_THR_ACCESS(ma); -#if HALFWORD_HEAP - values[n++] = info_memkind(ma, &ma->low_mem, print_to_p, print_to_arg, begin_max_per, hpp, szp); - values[n++] = info_memkind(ma, &ma->hi_mem, print_to_p, print_to_arg, begin_max_per, hpp, szp); -#else - values[n++] = info_memkind(ma, &ma->the_mem, print_to_p, print_to_arg, begin_max_per, hpp, szp); -#endif + values[n++] = info_memkind(ma, print_to_p, print_to_arg, begin_max_per, hpp, szp); if (hpp || szp) res = bld_2tup_list(hpp, szp, n, atoms, values); @@ -1408,13 +1329,10 @@ Uint erts_mseg_no(const ErtsMsegOpt_t *opt) { ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_OPT(opt); - MemKind* mk; - Uint n = 0; + Uint n; ERTS_MSEG_LOCK(ma); ERTS_DBG_MA_CHK_THR_ACCESS(ma); - for (mk=ma->mk_list; mk; mk=mk->next) { - n += mk->segments.current.no; - } + n = ma->segments.current.no; ERTS_MSEG_UNLOCK(ma); return n; } @@ -1426,16 +1344,16 @@ erts_mseg_unit_size(void) } -static void mem_kind_init(ErtsMsegAllctr_t *ma, MemKind* mk, const char* name) +static void mem_cache_init(ErtsMsegAllctr_t *ma) { int i; /* Clear all cache headers */ - mseg_cache_clear_node(&(mk->cache_free)); - mseg_cache_clear_node(&(mk->cache_unpowered_node)); + mseg_cache_clear_node(&(ma->cache_free)); + mseg_cache_clear_node(&(ma->cache_unpowered_node)); for (i = 0; i < CACHE_AREAS; i++) { - mseg_cache_clear_node(&(mk->cache_powered_node[i])); + mseg_cache_clear_node(&(ma->cache_powered_node[i])); } /* Populate cache free list */ @@ -1443,25 +1361,20 @@ static void mem_kind_init(ErtsMsegAllctr_t *ma, MemKind* mk, const char* name) ASSERT(ma->max_cache_size <= MAX_CACHE_SIZE); for (i = 0; i < ma->max_cache_size; i++) { - mseg_cache_clear_node(&(mk->cache[i])); - erts_circleq_push_head(&(mk->cache_free), &(mk->cache[i])); + mseg_cache_clear_node(&(ma->cache[i])); + erts_circleq_push_head(&(ma->cache_free), &(ma->cache[i])); } - mk->cache_size = 0; - mk->cache_hits = 0; - - mk->segments.current.watermark = 0; - mk->segments.current.no = 0; - mk->segments.current.sz = 0; - mk->segments.max.no = 0; - mk->segments.max.sz = 0; - mk->segments.max_ever.no = 0; - mk->segments.max_ever.sz = 0; - - mk->ma = ma; - mk->name = name; - mk->next = ma->mk_list; - ma->mk_list = mk; + ma->cache_size = 0; + ma->cache_hits = 0; + + ma->segments.current.watermark = 0; + ma->segments.current.no = 0; + ma->segments.current.sz = 0; + ma->segments.max.no = 0; + ma->segments.max.sz = 0; + ma->segments.max_ever.no = 0; + ma->segments.max_ever.sz = 0; } void @@ -1488,15 +1401,6 @@ erts_mseg_init(ErtsMsegInit_t *init) erts_mtx_init(&init_atoms_mutex, "mseg_init_atoms"); -#if HALFWORD_HEAP - if (sizeof(void *) != 8) - erl_exit(-1,"Halfword emulator cannot be run in 32bit mode"); - - init->mmap.virtual_range.start = (char *) sbrk(0); - init->mmap.virtual_range.end = (char *) 0x100000000UL; - init->mmap.sco = 0; -#endif - erts_mmap_init(&init->mmap); if (!IS_2POW(GET_PAGE_SIZE)) @@ -1529,14 +1433,7 @@ erts_mseg_init(ErtsMsegInit_t *init) if (ma->max_cache_size > MAX_CACHE_SIZE) ma->max_cache_size = MAX_CACHE_SIZE; - ma->mk_list = NULL; - -#if HALFWORD_HEAP - mem_kind_init(ma, &ma->low_mem, "low memory"); - mem_kind_init(ma, &ma->hi_mem, "high memory"); -#else - mem_kind_init(ma, &ma->the_mem, "all memory"); -#endif + mem_cache_init(ma); sys_memzero((void *) &ma->calls, sizeof(ErtsMsegCalls)); } @@ -1545,13 +1442,8 @@ erts_mseg_init(ErtsMsegInit_t *init) static ERTS_INLINE Uint tot_cache_size(ErtsMsegAllctr_t *ma) { - MemKind* mk; - Uint sz = 0; ERTS_DBG_MA_CHK_THR_ACCESS(ma); - for (mk=ma->mk_list; mk; mk=mk->next) { - sz += mk->cache_size; - } - return sz; + return ma->cache_size; } /* diff --git a/erts/emulator/sys/common/erl_mseg.h b/erts/emulator/sys/common/erl_mseg.h index ba04e919fc..656484702d 100644 --- a/erts/emulator/sys/common/erl_mseg.h +++ b/erts/emulator/sys/common/erl_mseg.h @@ -87,9 +87,6 @@ typedef struct { UWord abs_shrink_th; UWord rel_shrink_th; int sched_spec; -#if HALFWORD_HEAP - int low_mem; -#endif } ErtsMsegOpt_t; extern const ErtsMsegOpt_t erts_mseg_default_opt; diff --git a/erts/emulator/sys/common/erl_poll.h b/erts/emulator/sys/common/erl_poll.h index 19ce582154..6d8aef822e 100644 --- a/erts/emulator/sys/common/erl_poll.h +++ b/erts/emulator/sys/common/erl_poll.h @@ -93,7 +93,7 @@ # if defined(ERTS_USE_POLL) # undef ERTS_POLL_USE_POLL # define ERTS_POLL_USE_POLL 1 -# elif !defined(__WIN32__) && !defined(__OSE__) +# elif !defined(__WIN32__) # undef ERTS_POLL_USE_SELECT # define ERTS_POLL_USE_SELECT 1 # endif @@ -104,31 +104,13 @@ typedef Uint32 ErtsPollEvents; #undef ERTS_POLL_EV_E2N -#if defined(__WIN32__) || defined(__OSE__) /* --- win32 or ose -------- */ +#if defined(__WIN32__) /* --- win32 --------------------------------------- */ #define ERTS_POLL_EV_IN 1 #define ERTS_POLL_EV_OUT 2 #define ERTS_POLL_EV_ERR 4 #define ERTS_POLL_EV_NVAL 8 -#ifdef __OSE__ - -typedef struct ErtsPollOseMsgList_ { - struct ErtsPollOseMsgList_ *next; - union SIGNAL *data; -} ErtsPollOseMsgList; - -struct erts_sys_fd_type { - SIGSELECT signo; - ErlDrvOseEventId id; - ErtsPollOseMsgList *msgs; - ErlDrvOseEventId (*resolve_signal)(union SIGNAL *sig); - ethr_mutex mtx; - void *extra; -}; - -#endif - #elif ERTS_POLL_USE_EPOLL /* --- epoll ------------------------------- */ #include <sys/epoll.h> diff --git a/erts/emulator/sys/ose/beam.lmconf b/erts/emulator/sys/ose/beam.lmconf deleted file mode 100644 index 4ad46b01d9..0000000000 --- a/erts/emulator/sys/ose/beam.lmconf +++ /dev/null @@ -1,26 +0,0 @@ -OSE_LM_STACK_SIZES=256,512,1024,2048,4096,8192,16384,65536 -OSE_LM_SIGNAL_SIZES=31,63,127,255,1023,4095,16383,65535 -OSE_LM_POOL_SIZE=0x200000 -OSE_LM_MAIN_NAME=main -OSE_LM_MAIN_STACK_SIZE=0xF000 -OSE_LM_MAIN_PRIORITY=20 -## Has to be of a type that allows MAM -OSE_LM_PROGRAM_TYPE=APP_RAM -OSE_LM_DATA_INIT=YES -OSE_LM_BSS_INIT=YES -OSE_LM_EXEC_MODEL=SHARED -HEAP_MAX_SIZE=1000000000 -HEAP_SMALL_BUF_INIT_SIZE=20971520 -HEAP_LARGE_BUF_THRESHOLD=16000000 -HEAP_LOCK_TYPE=2 - -ERTS_DEFAULT_PRIO=24 -ERTS_SCHEDULER_PRIO=24 -ERTS_ASYNC_PRIO=22 -ERTS_AUX_PRIO=24 -ERTS_SYS_MSG_DISPATCHER_PRIO=21 - -# Setting the environment variable EFS_RESOLVE_TMO on the block to 0. -# This will eliminiate delays when trying to open files on not mounted -# volumes. -EFS_RESOLVE_TMO=0 diff --git a/erts/emulator/sys/ose/driver_int.h b/erts/emulator/sys/ose/driver_int.h deleted file mode 100644 index 4a5b7171d1..0000000000 --- a/erts/emulator/sys/ose/driver_int.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2009. 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% - */ -/* - * System dependant driver declarations - */ - -#ifndef __DRIVER_INT_H__ -#define __DRIVER_INT_H__ - -#ifdef HAVE_SYS_UIO_H -#include <sys/types.h> -#include <sys/uio.h> - -typedef struct iovec SysIOVec; - -#else - -typedef struct { - char* iov_base; - int iov_len; -} SysIOVec; - -#endif - -#endif diff --git a/erts/emulator/sys/ose/erl_main.c b/erts/emulator/sys/ose/erl_main.c deleted file mode 100644 index 877e85f43a..0000000000 --- a/erts/emulator/sys/ose/erl_main.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2000-2009. 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% - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include <stdlib.h> - -#include "sys.h" -#include "erl_vm.h" -#include "global.h" -#include "ose.h" - -int -main(int argc, char **argv) { - - (void)stdin;(void)stdout;(void)stderr; - - /* When starting using pm_create -c ARGV="-- -root ..", argv[0] is the first - part of ARGV and not the name of the executable. So we shuffle some - pointers here to make erl_start happy. */ - if (argv[0][0] == '-') { - int i; - char **tmp_argv = malloc(sizeof(char*)*(argc+1)); - for (i = 0; i < argc; i++) - tmp_argv[i+1] = argv[i]; - tmp_argv[0] = "beam"; - erl_start(argc+1,tmp_argv); - free(tmp_argv); - } else { - erl_start(argc,argv); - } - - stop(current_process()); - - return 0; -} diff --git a/erts/emulator/sys/ose/erl_ose_sys.h b/erts/emulator/sys/ose/erl_ose_sys.h deleted file mode 100644 index d0cd3180bf..0000000000 --- a/erts/emulator/sys/ose/erl_ose_sys.h +++ /dev/null @@ -1,356 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1997-2011. 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% - * - * This file handles differences between different Unix systems. - * This should be the only place with conditional compilation - * depending on the type of OS. - */ - -#ifndef _ERL_OSE_SYS_H -#define _ERL_OSE_SYS_H - -#include "ose.h" -#undef NIL -#include "ramlog.h" -#include "erts.sig" - -#include "fcntl.h" -#include "math.h" -#include "stdio.h" -#include "stdlib.h" -#include "string.h" -#include "sys/param.h" -#include "sys/time.h" -#include "time.h" -#include "dirent.h" -#include "ethread.h" - -/* FIXME: configuration options */ -#define ERTS_SCHED_MIN_SPIN 1 -#define ERTS_SCHED_ONLY_POLL_SCHED_1 1 -#define ERTS_SCHED_FAIR 1 -#define NO_SYSCONF 1 -#define OPEN_MAX FOPEN_MAX - -#define MAP_ANON MAP_ANONYMOUS - -#ifndef HAVE_MMAP -# define HAVE_MMAP 0 -#endif - -#if HAVE_MMAP -# include "sys/mman.h" -#endif - -/* - * Min number of async threads - */ -#define ERTS_MIN_NO_OF_ASYNC_THREADS 1 - -/* - * Our own type of "FD's" - */ -#define ERTS_SYS_FD_TYPE struct erts_sys_fd_type* -#define NO_FSTAT_ON_SYS_FD_TYPE 1 /* They are signals, not files */ - -#include "sys/stat.h" - -/* FIXME mremap is not defined in OSE - POSIX issue */ -extern void *mremap (void *__addr, size_t __old_len, size_t __new_len, - int __flags, ...); - -/* FIXME: mremap constants */ -#define MREMAP_MAYMOVE 1 -#define MREMAP_FIXED 2 - -typedef void *GETENV_STATE; - -/* -** For the erl_timer_sup module. -*/ -#define HAVE_GETHRTIME - -typedef long long SysHrTime; -extern SysHrTime sys_gethrtime(void); - -void sys_init_hrtime(void); - -typedef time_t erts_time_t; - -typedef struct timeval SysTimeval; - -#define sys_gettimeofday(Arg) ((void) gettimeofday((Arg), NULL)) - -typedef struct { - clock_t tms_utime; - clock_t tms_stime; - clock_t tms_cutime; - clock_t tms_cstime; -} SysTimes; - -extern int erts_ticks_per_sec; - -#define SYS_CLK_TCK (erts_ticks_per_sec) - -extern clock_t sys_times(SysTimes *buffer); - -/* No use in having other resolutions than 1 Ms. */ -#define SYS_CLOCK_RESOLUTION 1 - -#define erts_isfinite finite - -#ifdef NO_FPE_SIGNALS - -#define erts_get_current_fp_exception() NULL -#ifdef ERTS_SMP -#define erts_thread_init_fp_exception() do{}while(0) -#endif -# define __ERTS_FP_CHECK_INIT(fpexnp) do {} while (0) -# define __ERTS_FP_ERROR(fpexnp, f, Action) if (!finite(f)) { Action; } else {} -# define __ERTS_FP_ERROR_THOROUGH(fpexnp, f, Action) __ERTS_FP_ERROR(fpexnp, f, Action) -# define __ERTS_SAVE_FP_EXCEPTION(fpexnp) -# define __ERTS_RESTORE_FP_EXCEPTION(fpexnp) - -#define erts_sys_block_fpe() 0 -#define erts_sys_unblock_fpe(x) do{}while(0) - -#else /* !NO_FPE_SIGNALS */ - -extern volatile unsigned long *erts_get_current_fp_exception(void); -#ifdef ERTS_SMP -extern void erts_thread_init_fp_exception(void); -#endif -# if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) -# define erts_fwait(fpexnp,f) \ - __asm__ __volatile__("fwait" : "=m"(*(fpexnp)) : "m"(f)) -# elif (defined(__powerpc__) || defined(__ppc__)) && defined(__GNUC__) -# define erts_fwait(fpexnp,f) \ - __asm__ __volatile__("" : "=m"(*(fpexnp)) : "fm"(f)) -# elif defined(__sparc__) && defined(__linux__) && defined(__GNUC__) -# define erts_fwait(fpexnp,f) \ - __asm__ __volatile__("" : "=m"(*(fpexnp)) : "em"(f)) -# else -# define erts_fwait(fpexnp,f) \ - __asm__ __volatile__("" : "=m"(*(fpexnp)) : "g"(f)) -# endif -# if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) - extern void erts_restore_fpu(void); -# else -# define erts_restore_fpu() /*empty*/ -# endif -# if (!defined(__GNUC__) || \ - (__GNUC__ < 2) || \ - (__GNUC__ == 2 && __GNUC_MINOR < 96)) && \ - !defined(__builtin_expect) -# define __builtin_expect(x, expected_value) (x) -# endif -static __inline__ int erts_check_fpe(volatile unsigned long *fp_exception, double f) -{ - erts_fwait(fp_exception, f); - if (__builtin_expect(*fp_exception == 0, 1)) - return 0; - *fp_exception = 0; - erts_restore_fpu(); - return 1; -} -# undef erts_fwait -# undef erts_restore_fpu -extern void erts_fp_check_init_error(volatile unsigned long *fp_exception); -static __inline__ void __ERTS_FP_CHECK_INIT(volatile unsigned long *fp_exception) -{ - if (__builtin_expect(*fp_exception == 0, 1)) - return; - erts_fp_check_init_error(fp_exception); -} -# define __ERTS_FP_ERROR(fpexnp, f, Action) do { if (erts_check_fpe((fpexnp),(f))) { Action; } } while (0) -# define __ERTS_SAVE_FP_EXCEPTION(fpexnp) unsigned long old_erl_fp_exception = *(fpexnp) -# define __ERTS_RESTORE_FP_EXCEPTION(fpexnp) \ - do { *(fpexnp) = old_erl_fp_exception; } while (0) - /* This is for library calls where we don't trust the external - code to always throw floating-point exceptions on errors. */ -static __inline__ int erts_check_fpe_thorough(volatile unsigned long *fp_exception, double f) -{ - return erts_check_fpe(fp_exception, f) || !finite(f); -} -# define __ERTS_FP_ERROR_THOROUGH(fpexnp, f, Action) \ - do { if (erts_check_fpe_thorough((fpexnp),(f))) { Action; } } while (0) - -int erts_sys_block_fpe(void); -void erts_sys_unblock_fpe(int); - -#endif /* !NO_FPE_SIGNALS */ - -#define ERTS_FP_CHECK_INIT(p) __ERTS_FP_CHECK_INIT(&(p)->fp_exception) -#define ERTS_FP_ERROR(p, f, A) __ERTS_FP_ERROR(&(p)->fp_exception, f, A) -#define ERTS_FP_ERROR_THOROUGH(p, f, A) __ERTS_FP_ERROR_THOROUGH(&(p)->fp_exception, f, A) - -/* FIXME: force HAVE_GETPAGESIZE and stub getpagesize */ -#ifndef HAVE_GETPAGESIZE -#define HAVE_GETPAGESIZE 1 -#endif - -extern int getpagesize(void); - -#ifndef HZ -#define HZ 60 -#endif - -/* OSE5 doesn't provide limits.h so a number of macros should be - * added manually */ - -#ifndef CHAR_BIT -#define CHAR_BIT 8 -#endif - -/* Minimum and maximum values a `signed int' can hold. */ -#ifndef INT_MAX -#define INT_MAX 2147483647 -#endif - -#ifndef INT_MIN -#define INT_MIN (-INT_MAX - 1) -#endif - -#ifndef UINT_MAX -# define UINT_MAX 4294967295U -#endif - -/* -static void erts_ose_sys_send(union SIGNAL **signal,PROCESS dst, - char* file,int line) { - SIGSELECT **ziggy = (SIGSELECT**)signal; - printf("%s:%d 0x%x Send signal 0x%x(0x%x) to 0x%x\r\n", - file,line,current_process(),ziggy[0][0],*ziggy,dst); - send(signal,dst); -} -#define send(signal,dst) erts_ose_sys_send(signal,dst,__FILE__,__LINE__) - -static void erts_ose_sys_send_w_sender(union SIGNAL **signal, - PROCESS sender,PROCESS dst, - char* file,int line) { - SIGSELECT **ziggy = (SIGSELECT**)signal; - printf("%s:%d 0x%x Send signal 0x%x(0x%x) to 0x%x as 0x%x\r\n", - file,line,current_process(),ziggy[0][0],*ziggy,dst,sender); - send_w_sender(signal,sender,dst); -} -#define send_w_sender(signal,sender,dst) \ - erts_ose_sys_send_w_sender(signal,sender,dst,__FILE__,__LINE__) - - -static union SIGNAL *erts_ose_sys_receive(SIGSELECT *sigsel, - char *file, - int line) { - SIGSELECT *sig; - int i; - - printf("%s:%d 0x%x receive({%d,",file,line,current_process(),sigsel[0]); - for (i = 1; i < sigsel[0]; i++) - printf("0x%x, ",sigsel[i]); - if (sigsel[0] != 0) - printf("0x%x",sigsel[i]); - printf("})\n"); - sig = (SIGSELECT*)receive(sigsel); - printf("%s:%d 0x%x got 0x%x from 0x%x\n",file,line,current_process(), - *sig,sender((union SIGNAL**)(&sig))); - return (union SIGNAL*)sig; -} -#define receive(SIGSEL) erts_ose_sys_receive(SIGSEL,__FILE__,__LINE__) - -static union SIGNAL *erts_ose_sys_receive_w_tmo(OSTIME tmo,SIGSELECT *sigsel, - char *file,int line) { - SIGSELECT *sig; - int i; - if (tmo == 0) { - sig = (SIGSELECT*)receive_w_tmo(tmo,sigsel); - if (sig != NULL) { - printf("%s:%d 0x%x receive_w_tmo(0,{%d,",file,line,current_process(), - sigsel[0]); - for (i = 1; i < sigsel[0]; i++) - printf("0x%x, ",sigsel[i]); - if (sigsel[0] != 0) - printf("0x%x",sigsel[i]); - printf("})\n"); - printf("%s:%d 0x%x got 0x%x from 0x%x\n",file,line,current_process(), - *sig,sender((union SIGNAL**)(&sig))); - } - } else { - printf("%s:%d 0x%x receive_w_tmo(%u,{%d,",file,line,current_process(),tmo, - sigsel[0]); - for (i = 1; i < sigsel[0]; i++) - printf("0x%x, ",sigsel[i]); - if (sigsel[0] != 0) - printf("0x%x",sigsel[i]); - printf("})\n"); - sig = (SIGSELECT*)receive_w_tmo(tmo,sigsel); - printf("%s:%d 0x%x got ",file,line,current_process()); - if (sig == NULL) - printf("TIMEOUT\n"); - else - printf("0x%x from 0x%x\n",*sig,sender((union SIGNAL**)(&sig))); - } - - return (union SIGNAL*)sig; -} - -#define receive_w_tmo(tmo,sigsel) erts_ose_sys_receive_w_tmo(tmo,sigsel, \ - __FILE__,__LINE__) - -static union SIGNAL *erts_ose_sys_receive_fsem(OSTIME tmo,SIGSELECT *sigsel, - OSFSEMVAL fsem, - char *file,int line) { - SIGSELECT *sig; - int i; - if (tmo == 0) { - sig = (SIGSELECT*)receive_fsem(tmo,sigsel,fsem); - if (sig != NULL && sig != OS_RCV_FSEM) { - printf("%s:%d 0x%x receive_fsem(0,{%d,",file,line,current_process(), - sigsel[0]); - for (i = 1; i < sigsel[0]; i++) - printf("0x%x, ",sigsel[i]); - if (sigsel[0] != 0) - printf("0x%x",sigsel[i]); - printf("},%d)\n",fsem); - printf("%s:%d 0x%x got 0x%x from 0x%x\n",file,line,current_process(), - *sig,sender((union SIGNAL**)(&sig))); - } - } else { - printf("%s:%d 0x%x receive_fsem(%u,{%d,",file,line,current_process(),tmo, - sigsel[0]); - for (i = 1; i < sigsel[0]; i++) - printf("0x%x, ",sigsel[i]); - if (sigsel[0] != 0) - printf("0x%x",sigsel[i]); - printf("},%d)\n",fsem); - sig = (SIGSELECT*)receive_fsem(tmo,sigsel,fsem); - printf("%s:%d 0x%x got ",file,line,current_process()); - if (sig == NULL) - printf("TIMEOUT\n"); - else if (sig == OS_RCV_FSEM) - printf("FSEM\n"); - else - printf("0x%x from 0x%x\n",*sig,sender((union SIGNAL**)(&sig))); - } - - return (union SIGNAL*)sig; -} - -#define receive_fsem(tmo,sigsel,fsem) \ - erts_ose_sys_receive_fsem(tmo,sigsel,fsem,__FILE__,__LINE__) -*/ -#endif /* _ERL_OSE_SYS_H */ diff --git a/erts/emulator/sys/ose/erl_ose_sys_ddll.c b/erts/emulator/sys/ose/erl_ose_sys_ddll.c deleted file mode 100644 index 5051f7fcc1..0000000000 --- a/erts/emulator/sys/ose/erl_ose_sys_ddll.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2006-2013. 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% - */ - -/* - * Interface functions to the dynamic linker using dl* functions. - * (No support in OSE, we use static linkage instead) - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "sys.h" -#include "erl_vm.h" -#include "global.h" - - -void erl_sys_ddll_init(void) { -} - -/* - * Open a shared object - */ -int erts_sys_ddll_open(const char *full_name, void **handle, ErtsSysDdllError* err) -{ - return ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY; -} - -int erts_sys_ddll_open_noext(char *dlname, void **handle, ErtsSysDdllError* err) -{ - return ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY; -} - -/* - * Find a symbol in the shared object - */ -int erts_sys_ddll_sym2(void *handle, const char *func_name, void **function, - ErtsSysDdllError* err) -{ - return ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY; -} - -/* XXX:PaN These two will be changed with new driver interface! */ - -/* - * Load the driver init function, might appear under different names depending on object arch... - */ - -int erts_sys_ddll_load_driver_init(void *handle, void **function) -{ - void *fn; - int res; - if ((res = erts_sys_ddll_sym2(handle, "driver_init", &fn, NULL)) != ERL_DE_NO_ERROR) { - res = erts_sys_ddll_sym2(handle, "_driver_init", &fn, NULL); - } - if (res == ERL_DE_NO_ERROR) { - *function = fn; - } - return res; -} - -int erts_sys_ddll_load_nif_init(void *handle, void **function, ErtsSysDdllError* err) -{ - void *fn; - int res; - if ((res = erts_sys_ddll_sym2(handle, "nif_init", &fn, err)) != ERL_DE_NO_ERROR) { - res = erts_sys_ddll_sym2(handle, "_nif_init", &fn, err); - } - if (res == ERL_DE_NO_ERROR) { - *function = fn; - } - return res; -} - -/* - * Call the driver_init function, whatever it's really called, simple on unix... -*/ -void *erts_sys_ddll_call_init(void *function) { - void *(*initfn)(void) = function; - return (*initfn)(); -} -void *erts_sys_ddll_call_nif_init(void *function) { - return erts_sys_ddll_call_init(function); -} - - - -/* - * Close a chared object - */ -int erts_sys_ddll_close2(void *handle, ErtsSysDdllError* err) -{ - return ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY; -} - - -/* - * Return string that describes the (current) error - */ -char *erts_sys_ddll_error(int code) -{ - return "Unspecified error"; -} - -void erts_sys_ddll_free_error(ErtsSysDdllError* err) -{ - if (err->str != NULL) { - erts_free(ERTS_ALC_T_DDLL_TMP_BUF, err->str); - } -} diff --git a/erts/emulator/sys/ose/erl_poll.c b/erts/emulator/sys/ose/erl_poll.c deleted file mode 100644 index 5cee582a00..0000000000 --- a/erts/emulator/sys/ose/erl_poll.c +++ /dev/null @@ -1,818 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2006-2012. 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% - */ - -/* - * Description: Poll interface suitable for ERTS on OSE with or without - * SMP support. - * - * The interface is currently implemented using: - * - receive + receive_fsem - * - * Author: Lukas Larsson - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "erl_thr_progress.h" -#include "erl_driver.h" -#include "erl_alloc.h" -#include "erl_poll.h" - -#define NOFILE 4096 - -/* - * Some debug macros - */ - -/* #define HARDDEBUG -#define HARDTRACE*/ -#ifdef HARDDEBUG -#ifdef HARDTRACE -#define HARDTRACEF(X, ...) { fprintf(stderr, X, __VA_ARGS__); fprintf(stderr,"\r\n"); } -#else -#define HARDTRACEF(...) -#endif - -#else -#define HARDTRACEF(X,...) -#define HARDDEBUGF(...) -#endif - -#if 0 -#define ERTS_POLL_DEBUG_PRINT -#endif - -#if defined(DEBUG) && 0 -#define HARD_DEBUG -#endif - -# define SEL_ALLOC erts_alloc -# define SEL_REALLOC realloc_wrap -# define SEL_FREE erts_free - -#ifdef ERTS_SMP - -#define ERTS_POLLSET_LOCK(PS) \ - erts_smp_mtx_lock(&(PS)->mtx) -#define ERTS_POLLSET_UNLOCK(PS) \ - erts_smp_mtx_unlock(&(PS)->mtx) - -#else - -#define ERTS_POLLSET_LOCK(PS) -#define ERTS_POLLSET_UNLOCK(PS) - -#endif - -/* - * --- Data types ------------------------------------------------------------ - */ - -union SIGNAL { - SIGSELECT sig_no; -}; - -typedef struct erts_sigsel_item_ ErtsSigSelItem; - -struct erts_sigsel_item_ { - ErtsSigSelItem *next; - ErtsSysFdType fd; - ErtsPollEvents events; -}; - -typedef struct erts_sigsel_info_ ErtsSigSelInfo; - -struct erts_sigsel_info_ { - ErtsSigSelInfo *next; - SIGSELECT signo; - ErlDrvOseEventId (*decode)(union SIGNAL* sig); - ErtsSigSelItem *fds; -}; - -struct ErtsPollSet_ { - SIGSELECT *sigs; - ErtsSigSelInfo *info; - Uint sig_count; - Uint item_count; - PROCESS interrupt; - erts_atomic32_t wakeup_state; - erts_atomic64_t timeout_time; -#ifdef ERTS_SMP - erts_smp_mtx_t mtx; -#endif -}; - -static int max_fds = -1; - -static ERTS_INLINE void -init_timeout_time(ErtsPollSet ps) -{ - erts_atomic64_init_nob(&ps->timeout_time, - (erts_aint64_t) ERTS_MONOTONIC_TIME_MAX); -} - -static ERTS_INLINE void -set_timeout_time(ErtsPollSet ps, ErtsMonotonicTime time) -{ - erts_atomic64_set_relb(&ps->timeout_time, - (erts_aint64_t) time); -} - -static ERTS_INLINE ErtsMonotonicTime -get_timeout_time(ErtsPollSet ps) -{ - return (ErtsMonotonicTime) erts_atomic64_read_acqb(&ps->timeout_time); -} - -#define ERTS_POLL_NOT_WOKEN ((erts_aint32_t) (1 << 0)) -#define ERTS_POLL_WOKEN_INTR ((erts_aint32_t) (1 << 1)) -#define ERTS_POLL_WOKEN_TIMEDOUT ((erts_aint32_t) (1 << 2)) -#define ERTS_POLL_WOKEN_IO_READY ((erts_aint32_t) (1 << 3)) -#define ERTS_POLL_SLEEPING ((erts_aint32_t) (1 << 4)) - -/* signal list prototypes */ -static ErtsSigSelInfo *get_sigsel_info(ErtsPollSet ps, SIGSELECT signo); -static ErtsSigSelItem *get_sigsel_item(ErtsPollSet ps, ErtsSysFdType fd); -static ErtsSigSelInfo *add_sigsel_info(ErtsPollSet ps, ErtsSysFdType fd, - ErlDrvOseEventId (*decode)(union SIGNAL* sig)); -static ErtsSigSelItem *add_sigsel_item(ErtsPollSet ps, ErtsSysFdType fd, - ErlDrvOseEventId (*decode)(union SIGNAL* sig)); -static int del_sigsel_info(ErtsPollSet ps, ErtsSigSelInfo *info); -static int del_sigsel_item(ErtsPollSet ps, ErtsSigSelItem *item); -static int update_sigsel(ErtsPollSet ps); - -static ErtsSigSelInfo * -get_sigsel_info(ErtsPollSet ps, SIGSELECT signo) { - ErtsSigSelInfo *curr = ps->info; - while (curr != NULL) { - if (curr->signo == signo) - return curr; - curr = curr->next; - } - return NULL; -} - -static ErtsSigSelItem * -get_sigsel_item(ErtsPollSet ps, ErtsSysFdType fd) { - ErtsSigSelInfo *info = get_sigsel_info(ps,fd->signo); - ErtsSigSelItem *curr; - - if (info == NULL) - return NULL; - - curr = info->fds; - - while (curr != NULL) { - if (curr->fd->id == fd->id) { - ASSERT(curr->fd->signo == fd->signo); - return curr; - } - curr = curr->next; - } - return NULL; -} - -static ErtsSigSelInfo * -add_sigsel_info(ErtsPollSet ps, ErtsSysFdType fd, - ErlDrvOseEventId (*decode)(union SIGNAL* sig)) { - ErtsSigSelInfo *info = SEL_ALLOC(ERTS_ALC_T_POLLSET, - sizeof(ErtsSigSelInfo)); - info->next = ps->info; - info->fds = NULL; - info->signo = fd->signo; - info->decode = decode; - ps->info = info; - ps->sig_count++; - return info; -} - -static ErtsSigSelItem * -add_sigsel_item(ErtsPollSet ps, ErtsSysFdType fd, - ErlDrvOseEventId (*decode)(union SIGNAL* sig)) { - ErtsSigSelInfo *info = get_sigsel_info(ps,fd->signo); - ErtsSigSelItem *item = SEL_ALLOC(ERTS_ALC_T_POLLSET, - sizeof(ErtsSigSelItem)); - if (info == NULL) - info = add_sigsel_info(ps, fd, decode); - if (info->decode != decode) { - erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); - erts_dsprintf(dsbufp, "erts_poll_control() inconsistency: multiple resolve_signal functions for same signal (%d)\n", - fd->signo); - erts_send_error_to_logger_nogl(dsbufp); - } - ASSERT(info->decode == decode); - item->next = info->fds; - item->fd = fd; - item->events = 0; - info->fds = item; - ps->item_count++; - return item; -} - -static int del_sigsel_info(ErtsPollSet ps, ErtsSigSelInfo *info) { - ErtsSigSelInfo *curr, *prev; - - if (ps->info == info) { - ps->info = ps->info->next; - } else { - curr = ps->info->next; - prev = ps->info; - - while (curr != info) { - if (curr == NULL) - return 1; - prev = curr; - curr = curr->next; - } - prev->next = curr->next; - } - - ps->sig_count--; - SEL_FREE(ERTS_ALC_T_POLLSET, info); - return 0; -} - -static int del_sigsel_item(ErtsPollSet ps, ErtsSigSelItem *item) { - ErtsSigSelInfo *info = get_sigsel_info(ps,item->fd->signo); - ErtsSigSelItem *curr, *prev; - - ps->item_count--; - ASSERT(ps->item_count >= 0); - - if (info->fds == item) { - info->fds = info->fds->next; - SEL_FREE(ERTS_ALC_T_POLLSET,item); - if (info->fds == NULL) - return del_sigsel_info(ps,info); - return 0; - } - - curr = info->fds->next; - prev = info->fds; - - while (curr != item) { - if (curr == NULL) { - /* We did not find an item to delete so we have to - * increment item count again. - */ - ps->item_count++; - return 1; - } - prev = curr; - curr = curr->next; - } - prev->next = curr->next; - SEL_FREE(ERTS_ALC_T_POLLSET,item); - return 0; -} - -#ifdef ERTS_SMP - -static void update_redir_tables(ErtsPollSet ps) { - struct OS_redir_entry *redir_table; - PROCESS sched_1 = ERTS_SCHEDULER_IX(0)->tid.id; - int i; - redir_table = SEL_ALLOC(ERTS_ALC_T_POLLSET, - sizeof(struct OS_redir_entry)*(ps->sig_count+1)); - - redir_table[0].sig = ps->sig_count+1; - redir_table[0].pid = 0; - - for (i = 1; i < ps->sig_count+1; i++) { - redir_table[i].sig = ps->sigs[i]; - redir_table[i].pid = sched_1; - } - - for (i = 1; i < erts_no_schedulers; i++) { - ErtsSchedulerData *esdp = ERTS_SCHEDULER_IX(i); - set_redirection(esdp->tid.id,redir_table); - } - - SEL_FREE(ERTS_ALC_T_POLLSET,redir_table); -} - -#endif - -static int update_sigsel(ErtsPollSet ps) { - ErtsSigSelInfo *info = ps->info; - - int i; - - if (ps->sigs != NULL) - SEL_FREE(ERTS_ALC_T_POLLSET,ps->sigs); - - if (ps->sig_count == 0) { - /* If there are no signals we place a non-valid signal to make sure that - * we do not trigger on a any unrelated signals which are sent to the - * process. - */ - ps->sigs = SEL_ALLOC(ERTS_ALC_T_POLLSET,sizeof(SIGSELECT)*(2)); - ps->sigs[0] = 1; - ps->sigs[1] = ERTS_SIGNAL_INVALID; - return 0; - } - - ps->sigs = SEL_ALLOC(ERTS_ALC_T_POLLSET,sizeof(SIGSELECT)*(ps->sig_count+1)); - ps->sigs[0] = ps->sig_count; - - for (i = 1; info != NULL; i++, info = info->next) - ps->sigs[i] = info->signo; - -#ifdef ERTS_SMP - update_redir_tables(ps); -#endif - - return 0; -} - -static ERTS_INLINE void -wake_poller(ErtsPollSet ps) -{ - erts_aint32_t wakeup_state; - - ERTS_THR_MEMORY_BARRIER; - wakeup_state = erts_atomic32_read_nob(&ps->wakeup_state); - while (wakeup_state != ERTS_POLL_WOKEN_IO_READY - && wakeup_state != ERTS_POLL_WOKEN_INTR) { - erts_aint32_t act = erts_atomic32_cmpxchg_nob(&ps->wakeup_state, - ERTS_POLL_WOKEN_INTR, - wakeup_state); - if (act == wakeup_state) { - wakeup_state = act; - break; - } - wakeup_state = act; - } - if (wakeup_state == ERTS_POLL_SLEEPING) { - /* - * Since we don't know the internals of signal_fsem() we issue - * a memory barrier as a safety precaution ensuring that - * the store we just made to wakeup_state wont be reordered - * with loads in signal_fsem(). - */ - ERTS_THR_MEMORY_BARRIER; - signal_fsem(ps->interrupt); - } -} - -static ERTS_INLINE void -reset_interrupt(ErtsPollSet ps) -{ - /* We need to keep io-ready if set */ - erts_aint32_t wakeup_state = erts_atomic32_read_nob(&ps->wakeup_state); - while (wakeup_state != ERTS_POLL_NOT_WOKEN && - wakeup_state != ERTS_POLL_SLEEPING) { - erts_aint32_t act = erts_atomic32_cmpxchg_nob(&ps->wakeup_state, - ERTS_POLL_NOT_WOKEN, - wakeup_state); - if (wakeup_state == act) - break; - wakeup_state = act; - } - ERTS_THR_MEMORY_BARRIER; -} - -static ERTS_INLINE void -set_interrupt(ErtsPollSet ps) -{ - wake_poller(ps); -} - -void erts_poll_interrupt(ErtsPollSet ps,int set) { - HARDTRACEF("erts_poll_interrupt called!\n"); - - if (!set) - reset_interrupt(ps); - else - set_interrupt(ps); - -} - -void erts_poll_interrupt_timed(ErtsPollSet ps, - int set, - ErtsTimeoutTime timeout_time) { - HARDTRACEF("erts_poll_interrupt_timed called!\n"); - - if (!set) - reset_interrupt(ps); - else if (get_timeout_time(ps) > timeout_time) - set_interrupt(ps); -} - -ErtsPollEvents erts_poll_control(ErtsPollSet ps, ErtsSysFdType fd, - ErtsPollEvents pe, int on, int* do_wake) { - ErtsSigSelItem *curr; - ErtsPollEvents new_events; - int old_sig_count; - - HARDTRACEF( - "%ux: In erts_poll_control, fd = %d, pe = %d, on = %d, *do_wake = %d, curr = 0x%xu", - ps, fd, pe, on, do_wake, curr); - - ERTS_POLLSET_LOCK(ps); - - if (on && (pe & ERTS_POLL_EV_IN) && (pe & ERTS_POLL_EV_OUT)) { - /* Check to make sure both in and out are not used at the same time */ - new_events = ERTS_POLL_EV_NVAL; - goto done; - } - - curr = get_sigsel_item(ps, fd); - old_sig_count = ps->sig_count; - - if (curr == NULL && on) { - curr = add_sigsel_item(ps, fd, fd->resolve_signal); - } else if (curr == NULL && !on) { - new_events = ERTS_POLL_EV_NVAL; - goto done; - } - - new_events = curr->events; - - if (pe == 0) { - *do_wake = 0; - goto done; - } - - if (on) { - new_events |= pe; - curr->events = new_events; - } else { - new_events &= ~pe; - curr->events = new_events; - if (new_events == 0 && del_sigsel_item(ps, curr)) { - new_events = ERTS_POLL_EV_NVAL; - goto done; - } - } - - if (ps->sig_count != old_sig_count) { - if (update_sigsel(ps)) - new_events = ERTS_POLL_EV_NVAL; - } -done: - ERTS_POLLSET_UNLOCK(ps); - HARDTRACEF("%ux: Out erts_poll_control", ps); - return new_events; -} - -int erts_poll_wait(ErtsPollSet ps, - ErtsPollResFd pr[], - int *len, - ErtsMonotonicTime timeout_time) -{ - int res = ETIMEDOUT, no_fds, currid = 0; - OSTIME timeout; - union SIGNAL *sig; - ErtsMonotonicTime current_time, diff_time, timeout; - // HARDTRACEF("%ux: In erts_poll_wait",ps); - if (ps->interrupt == (PROCESS)0) - ps->interrupt = current_process(); - - ASSERT(current_process() == ps->interrupt); - ASSERT(get_fsem(current_process()) == 0); - ASSERT(erts_atomic32_read_nob(&ps->wakeup_state) & - (ERTS_POLL_NOT_WOKEN | ERTS_POLL_WOKEN_INTR)); - /* Max no of spots avable in pr */ - no_fds = *len; - - *len = 0; - - /* erts_printf("Entering erts_poll_wait(), timeout_time=%bps\n", - timeout_time); */ - - if (timeout_time == ERTS_POLL_NO_TIMEOUT) { - no_timeout: - timeout = (OSTIME) 0; - save_timeout_time = ERTS_MONOTONIC_TIME_MIN; - } - else { - ErtsMonotonicTime current_time, diff_time; - current_time = erts_get_monotonic_time(NULL); - diff_time = timeout_time - current_time; - if (diff_time <= 0) - goto no_timeout; - diff_time = (ERTS_MONOTONIC_TO_MSEC(diff_time - 1) + 1); - if (diff_time > INT_MAX) - diff_time = INT_MAX; - timeout = (OSTIME) diff_time; - save_timeout_time = current_time; - save_timeout_time += ERTS_MSEC_TO_MONOTONIC(diff_time); - } - - set_timeout_time(ps, save_timeout_time); - - while (currid < no_fds) { - if (timeout > 0) { - erts_aint32_t act = erts_atomic32_cmpxchg_nob(&ps->wakeup_state, - ERTS_POLL_SLEEPING, - ERTS_POLL_NOT_WOKEN); - if (act == ERTS_POLL_NOT_WOKEN) { -#ifdef ERTS_SMP - erts_thr_progress_prepare_wait(NULL); -#endif - sig = receive_fsem(timeout, ps->sigs, 1); -#ifdef ERTS_SMP - erts_thr_progress_finalize_wait(NULL); -#endif - } else { - ASSERT(act == ERTS_POLL_WOKEN_INTR); - sig = OS_RCV_FSEM; - } - } else - sig = receive_w_tmo(0, ps->sigs); - - if (sig == NULL) { - if (timeout > 0) { - erts_aint32_t act = erts_atomic32_cmpxchg_nob(&ps->wakeup_state, - ERTS_POLL_WOKEN_TIMEDOUT, - ERTS_POLL_SLEEPING); - if (act == ERTS_POLL_WOKEN_INTR) - /* Restore fsem as it was signaled but we got a timeout */ - wait_fsem(1); - } else - erts_atomic32_cmpxchg_nob(&ps->wakeup_state, - ERTS_POLL_WOKEN_TIMEDOUT, - ERTS_POLL_NOT_WOKEN); - break; - } else if (sig == OS_RCV_FSEM) { - ASSERT(erts_atomic32_read_nob(&ps->wakeup_state) == ERTS_POLL_WOKEN_INTR); - break; - } - { - ErtsSigSelInfo *info = get_sigsel_info(ps, sig->sig_no); - struct erts_sys_fd_type fd = { sig->sig_no, info->decode(sig) }; - ErtsSigSelItem *item = get_sigsel_item(ps, &fd); - - ASSERT(sig); - if (currid == 0 && timeout > 0) { - erts_aint32_t act = erts_atomic32_cmpxchg_nob(&ps->wakeup_state, - ERTS_POLL_WOKEN_IO_READY, - ERTS_POLL_SLEEPING); - if (act == ERTS_POLL_WOKEN_INTR) { - /* Restore fsem as it was signaled but we got a msg */ - wait_fsem(1); - act = erts_atomic32_cmpxchg_nob(&ps->wakeup_state, - ERTS_POLL_WOKEN_IO_READY, - ERTS_POLL_WOKEN_INTR); - } - } else if (currid == 0) { - erts_atomic32_set_nob(&ps->wakeup_state, - ERTS_POLL_WOKEN_IO_READY); - } - - if (item == NULL) { - erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); - erts_dsprintf( - dsbufp, - "erts_poll_wait() failed: found unkown signal id %d (signo %u) " - "(curr_proc 0x%x)\n", - fd.id, fd.signo, current_process()); - erts_send_error_to_logger_nogl(dsbufp); - timeout = 0; - /* Under normal circumstances the signal is deallocated by the - * driver that issued the select operation. But in this case - * there's no driver waiting for such signal so we have to - * deallocate it here */ - if (sig) - free_buf(&sig); - } else { - int i; - struct erts_sys_fd_type *fd = NULL; - ErtsPollOseMsgList *tl,*new; - - /* Check if this fd has already been triggered by a previous signal */ - for (i = 0; i < currid;i++) { - if (pr[i].fd == item->fd) { - fd = pr[i].fd; - pr[i].events |= item->events; - break; - } - } - - /* First time this fd is triggered */ - if (fd == NULL) { - pr[currid].fd = item->fd; - pr[currid].events = item->events; - fd = item->fd; - timeout = 0; - currid++; - } - - /* Insert new signal in approriate list */ - new = erts_alloc(ERTS_ALC_T_FD_SIG_LIST,sizeof(ErtsPollOseMsgList)); - new->next = NULL; - new->data = sig; - - ethr_mutex_lock(&fd->mtx); - tl = fd->msgs; - - if (tl == NULL) { - fd->msgs = new; - } else { - while (tl->next != NULL) - tl = tl->next; - tl->next = new; - } - ethr_mutex_unlock(&fd->mtx); - } - - } - } - - { - erts_aint32_t wakeup_state = erts_atomic32_read_nob(&ps->wakeup_state); - - switch (wakeup_state) { - case ERTS_POLL_WOKEN_IO_READY: - res = 0; - break; - case ERTS_POLL_WOKEN_INTR: - res = EINTR; - break; - case ERTS_POLL_WOKEN_TIMEDOUT: - res = ETIMEDOUT; - break; - case ERTS_POLL_NOT_WOKEN: - /* This happens when we get an invalid signal only */ - res = EINVAL; - break; - default: - res = 0; - erl_exit(ERTS_ABORT_EXIT, - "%s:%d: Internal error: Invalid wakeup_state=%d\n", - __FILE__, __LINE__, (int) wakeup_state); - } - } - - erts_atomic32_set_nob(&ps->wakeup_state, ERTS_POLL_NOT_WOKEN); - set_timeout_time(ps, ERTS_MONOTONIC_TIME_MAX); - - *len = currid; - - // HARDTRACEF("%ux: Out erts_poll_wait",ps); - return res; -} - -int erts_poll_max_fds(void) -{ - - HARDTRACEF("In/Out erts_poll_max_fds -> %d",max_fds); - return max_fds; -} - -void erts_poll_info(ErtsPollSet ps, - ErtsPollInfo *pip) -{ - Uint size = 0; - Uint num_events = 0; - - size += sizeof(struct ErtsPollSet_); - size += sizeof(ErtsSigSelInfo)*ps->sig_count; - size += sizeof(ErtsSigSelItem)*ps->item_count; - size += sizeof(SIGSELECT)*(ps->sig_count+1); - - pip->primary = "receive_fsem"; - - pip->fallback = NULL; - - pip->kernel_poll = NULL; - - pip->memory_size = size; - - pip->poll_set_size = num_events; - - pip->fallback_poll_set_size = 0; - - pip->lazy_updates = 0; - - pip->pending_updates = 0; - - pip->batch_updates = 0; - - pip->concurrent_updates = 0; - - - pip->max_fds = erts_poll_max_fds(); - HARDTRACEF("%ux: Out erts_poll_info",ps); - -} - -ErtsPollSet erts_poll_create_pollset(void) -{ - ErtsPollSet ps = SEL_ALLOC(ERTS_ALC_T_POLLSET, - sizeof(struct ErtsPollSet_)); - - ps->sigs = NULL; - ps->sig_count = 0; - ps->item_count = 0; - ps->info = NULL; - ps->interrupt = (PROCESS)0; - erts_atomic32_init_nob(&ps->wakeup_state, ERTS_POLL_NOT_WOKEN); - init_timeout_time(ps); -#ifdef ERTS_SMP - erts_smp_mtx_init(&ps->mtx, "pollset"); -#endif - update_sigsel(ps); - HARDTRACEF("%ux: Out erts_poll_create_pollset",ps); - return ps; -} - -void erts_poll_destroy_pollset(ErtsPollSet ps) -{ - ErtsSigSelInfo *info; - for (info = ps->info; ps->info != NULL; info = ps->info, ps->info = ps->info->next) { - ErtsSigSelItem *item; - for (item = info->fds; info->fds != NULL; item = info->fds, info->fds = info->fds->next) - SEL_FREE(ERTS_ALC_T_POLLSET, item); - SEL_FREE(ERTS_ALC_T_POLLSET, info); - } - - SEL_FREE(ERTS_ALC_T_POLLSET,ps->sigs); - -#ifdef ERTS_SMP - erts_smp_mtx_destroy(&ps->mtx); -#endif - - SEL_FREE(ERTS_ALC_T_POLLSET,ps); -} - -void erts_poll_init(void) -{ - HARDTRACEF("In %s", __FUNCTION__); - max_fds = 256; - - HARDTRACEF("Out %s", __FUNCTION__); -} - - -/* OSE driver functions */ - -union SIGNAL *erl_drv_ose_get_signal(ErlDrvEvent drv_ev) { - struct erts_sys_fd_type *ev = (struct erts_sys_fd_type *)drv_ev; - ethr_mutex_lock(&ev->mtx); - if (ev->msgs == NULL) { - ethr_mutex_unlock(&ev->mtx); - return NULL; - } else { - ErtsPollOseMsgList *msg = ev->msgs; - union SIGNAL *sig = (union SIGNAL*)msg->data; - ASSERT(msg->data); - ev->msgs = msg->next; - ethr_mutex_unlock(&ev->mtx); - erts_free(ERTS_ALC_T_FD_SIG_LIST,msg); - restore(sig); - return sig; - } -} - -ErlDrvEvent -erl_drv_ose_event_alloc(SIGSELECT signo, ErlDrvOseEventId id, - ErlDrvOseEventId (*resolve_signal)(union SIGNAL *sig), void *extra) { - struct erts_sys_fd_type *ev = erts_alloc(ERTS_ALC_T_DRV_EV, - sizeof(struct erts_sys_fd_type)); - ev->signo = signo; - ev->extra = extra; - ev->id = id; - ev->msgs = NULL; - ev->resolve_signal = resolve_signal; - ethr_mutex_init(&ev->mtx); - return (ErlDrvEvent)ev; -} - -void erl_drv_ose_event_free(ErlDrvEvent drv_ev) { - struct erts_sys_fd_type *ev = (struct erts_sys_fd_type *)drv_ev; - ASSERT(ev->msgs == NULL); - ethr_mutex_destroy(&ev->mtx); - erts_free(ERTS_ALC_T_DRV_EV,ev); -} - -void erl_drv_ose_event_fetch(ErlDrvEvent drv_ev, SIGSELECT *signo, - ErlDrvOseEventId *id, void **extra) { - struct erts_sys_fd_type *ev = (struct erts_sys_fd_type *)drv_ev; - if (signo) - *signo = ev->signo; - if (extra) - *extra = ev->extra; - if (id) - *id = ev->id; -} diff --git a/erts/emulator/sys/ose/erts.sig b/erts/emulator/sys/ose/erts.sig deleted file mode 100644 index 78b883ee6c..0000000000 --- a/erts/emulator/sys/ose/erts.sig +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef ERTS_OSE_SIGNALS -#define ERTS_OSE_SIGNALS - -#ifndef ERTS_OSE_SIGNAL_BASE -#define ERTS_OSE_SIGNAL_BASE 0x01900280 -#endif - -#define ERTS_SIGNAL_INVALID ERTS_OSE_SIGNAL_BASE -#define ERTS_SIGNAL_FD_DRV_CONFIG ERTS_OSE_SIGNAL_BASE+1 -#define ERTS_SIGNAL_FD_DRV_ASYNC ERTS_OSE_SIGNAL_BASE+2 -#define ERTS_SIGNAL_OSE_DRV_ATTACH ERTS_OSE_SIGNAL_BASE+3 -#define ERTS_SIGNAL_OSE_DRV_HUNT ERTS_OSE_SIGNAL_BASE+4 - -#define ERTS_SIGNAL_RUN_ERL_SETUP ERTS_OSE_SIGNAL_BASE+100 -#define ERTS_SIGNAL_RUN_ERL_DAEMON ERTS_OSE_SIGNAL_BASE+101 - -#endif diff --git a/erts/emulator/sys/ose/gcc_4.4.3_lm_ppc.lcf b/erts/emulator/sys/ose/gcc_4.4.3_lm_ppc.lcf deleted file mode 100644 index a19d23facf..0000000000 --- a/erts/emulator/sys/ose/gcc_4.4.3_lm_ppc.lcf +++ /dev/null @@ -1,182 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2013-2014 by Enea Software AB, - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") -OUTPUT_ARCH("powerpc") -ENTRY("crt0_lm") -MEMORY -{ - rom : ORIGIN = 0x01000000, LENGTH = 0x01000000 - ram : ORIGIN = 0x02000000, LENGTH = 0x01000000 -} -PHDRS -{ - ph_conf PT_LOAD ; - ph_rom PT_LOAD ; - ph_ram PT_LOAD ; -} -SECTIONS -{ - .text : - { - *(.text_first) - *(.text) - *(.text.*) - *(.stub) - *(oscode) - *(.init*) - *(.fini*) - *(.gnu.warning) - *(.gnu.linkonce.t.*) - *(.glue_7t) - *(.glue_7) - } > rom :ph_rom = 0 - .ose_sfk_biosentry : - { - *(.ose_sfk_biosentry) - } > rom :ph_rom - .ctors : - { - __CTOR_LIST__ = .; - *(.ctors) - *(SORT(.ctors.*)) - __CTOR_END__ = .; - } > rom :ph_rom - .dtors : - { - __DTOR_LIST__ = .; - *(.dtors) - *(SORT(.dtors.*)) - __DTOR_END__ = .; - } > rom :ph_rom - OSESYMS : - { - *(.osesyms) - } > rom :ph_rom - .rodata : - { - *(.rodata) - *(.rodata.*) - *(.gnu.linkonce.r.*) - } > rom :ph_rom - .eh_frame_hdr : - { - *(.eh_frame_hdr) - } > rom :ph_rom - .eh_frame : - { - __EH_FRAME_BEGIN__ = .; - *(.eh_frame) - LONG(0) - __EH_FRAME_END__ = .; - } > rom :ph_rom - .gcc_except_table : - { - *(.gcc_except_table .gcc_except_table.*) - } > rom :ph_rom - .sdata2 : - { - PROVIDE (_SDA2_BASE_ = .); - *(.sdata2) - *(.sdata2.*) - *(.gnu.linkonce.s2.*) - } > rom :ph_rom - .sbss2 : - { - *(.sbss2) - *(.sbss2.*) - *(.gnu.linkonce.sb2.*) - } > rom :ph_rom - LMCONF : - { - obj/?*?/ose_confd.o(.rodata) - *(LMCONF) - } > rom :ph_conf - .data : - { - LONG(0xDEADBABE) - *(.data) - *(.data.*) - *(.gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - . = ALIGN(0x10); - } > ram :ph_ram = 0 - .sdata2 : - { - _SDA2_BASE_ = .; - *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) - }> ram :ph_ram - .sdata : - { - PROVIDE (_SDA_BASE_ = .); - *(.sdata) - *(.sdata.*) - *(.gnu.linkonce.s.*) - } > ram :ph_ram - .sbss : - { - *(.sbss) - *(.sbss.*) - *(.scommon) - *(.gnu.linkonce.sb.*) - } > ram :ph_ram - .bss (NOLOAD) : - { - *(.bss) - *(.bss.*) - *(COMMON) - *(.gnu.linkonce.b.*) - *(.osvars) - } > ram :ph_ram - .ignore (NOLOAD) : - { - *(.rel.dyn) - } > ram :ph_ram - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } -} -__OSESYMS_START = ADDR(OSESYMS); -__OSESYMS_END = ADDR(OSESYMS) + SIZEOF(OSESYMS); diff --git a/erts/emulator/sys/ose/gcc_4.6.3_lm_ppc.lcf b/erts/emulator/sys/ose/gcc_4.6.3_lm_ppc.lcf deleted file mode 100644 index 3440c2961b..0000000000 --- a/erts/emulator/sys/ose/gcc_4.6.3_lm_ppc.lcf +++ /dev/null @@ -1,242 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2013-2014 by Enea Software AB, - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - ******************************************************************************/ - -OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc") -OUTPUT_ARCH("powerpc") - -ENTRY("crt0_lm") - -/* Note: - * You may have to increase the length of the "rom" memory region and the - * origin and length of the "ram" memory region below depending on the size - * of the code and data in your load module. - */ - -MEMORY -{ - conf : ORIGIN = 0x00100000, LENGTH = 0x00030000 - rom : ORIGIN = 0x01000000, LENGTH = 0x01000000 - ram : ORIGIN = 0x03000000, LENGTH = 0x01000000 -} - -PHDRS -{ - ph_conf PT_LOAD ; - ph_rom PT_LOAD ; - ph_ram PT_LOAD ; -} - -SECTIONS -{ -/*--------------------------------------------------------------------------- - * Load module configuration area - *-------------------------------------------------------------------------*/ - - /* Load module configuration section. */ - LMCONF : - { - obj/?*?/ose_confd.o(.rodata) - *(LMCONF) - } > conf :ph_conf - -/*--------------------------------------------------------------------------- - * Read-only area - *-------------------------------------------------------------------------*/ - - /* Code section. */ - .text : - { - *(.text) - *(.text.*) - *(.stub) - *(oscode) - *(.init*) - *(.fini*) - *(.gnu.warning) - *(.gnu.linkonce.t.*) - } > rom :ph_rom = 0 - - /* OSE symbols section. */ - OSESYMS : - { - *(.osesyms) - } > rom :ph_rom - - /* Read-only data section. */ - .rodata : - { - *(.rodata) - *(.rodata.*) - *(.gnu.linkonce.r.*) - } > rom :ph_rom - - /* C++ exception handling section. */ - .eh_frame : - { - __EH_FRAME_BEGIN__ = .; - *(.eh_frame) - LONG(0) - __EH_FRAME_END__ = .; - } > rom :ph_rom - - /* C++ exception handling section. */ - .gcc_except_table : - { - *(.gcc_except_table .gcc_except_table.*) - } > rom :ph_rom - - /* PowerPC EABI initialized read-only data section. */ - .sdata2 : - { - PROVIDE (_SDA2_BASE_ = .); - *(.sdata2) - *(.sdata2.*) - *(.gnu.linkonce.s2.*) - } > rom :ph_rom - - /* PowerPC EABI uninitialized read-only data section. */ - .sbss2 : - { - *(.sbss2) - *(.sbss2.*) - *(.gnu.linkonce.sb2.*) - } > rom :ph_rom - -/*--------------------------------------------------------------------------- - * Read-write area - *-------------------------------------------------------------------------*/ - - /*------------------------------------------------------------------- - * Initialized data (copied by PM) - *-----------------------------------------------------------------*/ - - /* Data section. */ - .data : - { - *(.data) - *(.data.*) - *(.gnu.linkonce.d.*) - SORT(CONSTRUCTORS) - } > ram :ph_ram - - /* C++ constructor section. */ - .ctors : - { - __CTOR_LIST__ = .; - *(.ctors) - *(SORT(.ctors.*)) - __CTOR_END__ = .; - } > ram :ph_ram - - /* C++ destructor section. */ - .dtors : - { - __DTOR_LIST__ = .; - *(.dtors) - *(SORT(.dtors.*)) - __DTOR_END__ = .; - } > ram :ph_ram - - - /* Small data section. */ - .sdata ALIGN(0x10) : - { - PROVIDE (_SDA_BASE_ = .); - *(.sdata) - *(.sdata.*) - *(.gnu.linkonce.s.*) - } > ram :ph_ram - - /*------------------------------------------------------------------- - * Uninitialized data (cleared by PM) - *-----------------------------------------------------------------*/ - - /* Small bss section. */ - .sbss : - { - *(.sbss) - *(.sbss.*) - *(.scommon) - *(.gnu.linkonce.sb.*) - } > ram :ph_ram - - /* Bss section. */ - .bss : - { - *(.bss) - *(.bss.*) - *(COMMON) - *(.gnu.linkonce.b.*) - } > ram :ph_ram - -/*--------------------------------------------------------------------------- - * Debug information - *-------------------------------------------------------------------------*/ - - /* - * Stabs debug sections. - */ - - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - - /* - * DWARF debug sections. - */ - - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } -} diff --git a/erts/emulator/sys/ose/sys.c b/erts/emulator/sys/ose/sys.c deleted file mode 100644 index bcd0ffa0b6..0000000000 --- a/erts/emulator/sys/ose/sys.c +++ /dev/null @@ -1,1847 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2013. 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% - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif -#include "sys/time.h" -#include "time.h" -#include "sys/uio.h" -#include "termios.h" -#include "ctype.h" -#include "termios.h" - -#ifdef HAVE_FCNTL_H -#include "fcntl.h" -#endif - -#ifdef HAVE_SYS_IOCTL_H -#include "sys/ioctl.h" -#endif - -#define ERTS_WANT_BREAK_HANDLING -#define WANT_NONBLOCKING -#include "sys.h" -#include "erl_thr_progress.h" - -#ifdef USE_THREADS -#include "erl_threads.h" -#endif - -#include "erl_mseg.h" - -#include "unistd.h" -#include "efs.h" -#include "erl_printf.h" -#include "aio.h" -#include "pm.h" -#include "fcntl.h" - -/* Set the define to 1 to get some logging */ -#if 0 -#include "ramlog.h" -#define LOG(output) ramlog_printf output -#else -#define LOG(output) -#endif - -extern char **environ; -static erts_smp_rwmtx_t environ_rwmtx; -static PROCESS sig_proxy_pid = 0; - -#define MAX_VSIZE 16 /* Max number of entries allowed in an I/O - * vector sock_sendv(). - */ -/* - * Don't need global.h, but bif_table.h (included by bif.h), - * won't compile otherwise - */ -#include "global.h" -#include "bif.h" - -#include "erl_sys_driver.h" -#include "erl_check_io.h" -#include "erl_cpu_topology.h" - -/* The priority for reader/writer processes */ -#define FD_PROC_PRI get_pri(current_process()) - -typedef struct ErtsSysReportExit_ ErtsSysReportExit; -struct ErtsSysReportExit_ { - ErtsSysReportExit *next; - Eterm port; - int pid; - int ifd; - int ofd; - ErlDrvEvent attach_event; - ErlDrvEvent input_event; - ErlDrvEvent output_event; -}; - -/* This data is shared by these drivers - initialized by spawn_init() */ -static struct driver_data { - ErlDrvPort port_num; - int ofd; - int ifd; - int packet_bytes; - ErtsSysReportExit *report_exit; - int pid; - int alive; - int status; - ErlDrvEvent input_event; - ErlDrvEvent output_event; - struct aiocb aiocb; - FmHandle handle; - char *install_handle; -} *driver_data; /* indexed by fd */ - -struct async { - SIGSELECT signo; - ErlDrvTermData port; - ErlDrvTermData proc; - PROCESS spid; - PROCESS target; - Uint32 ref; -}; - -static ErtsSysReportExit *report_exit_list; -static ERTS_INLINE void report_exit_status(ErtsSysReportExit *rep, int status); - -extern int driver_interrupt(int, int); -extern void do_break(void); - -extern void erl_sys_args(int*, char**); - -/* The following two defs should probably be moved somewhere else */ - -extern void erts_sys_init_float(void); - -extern void erl_crash_dump(char* file, int line, char* fmt, ...); - -#define DIR_SEPARATOR_CHAR '/' - -#if defined(DEBUG) -#define ERL_BUILD_TYPE_MARKER ".debug" -#else /* opt */ -#define ERL_BUILD_TYPE_MARKER -#endif - -#define CHILD_SETUP_PROG_NAME "child_setup" ERL_BUILD_TYPE_MARKER - -#ifdef DEBUG -static int debug_log = 0; -#endif - -#ifdef ERTS_SMP -static erts_smp_atomic32_t have_prepared_crash_dump; -#define ERTS_PREPARED_CRASH_DUMP \ - ((int) erts_smp_atomic32_xchg_nob(&have_prepared_crash_dump, 1)) -#else -static volatile int have_prepared_crash_dump; -#define ERTS_PREPARED_CRASH_DUMP \ - (have_prepared_crash_dump++) -#endif - -static erts_smp_atomic_t sys_misc_mem_sz; - -#if defined(ERTS_SMP) -erts_mtx_t chld_stat_mtx; -#endif - -#if defined(ERTS_SMP) /* ------------------------------------------------- */ -#define CHLD_STAT_LOCK erts_mtx_lock(&chld_stat_mtx) -#define CHLD_STAT_UNLOCK erts_mtx_unlock(&chld_stat_mtx) - -#else /* ------------------------------------------------------------------- */ -#define CHLD_STAT_LOCK -#define CHLD_STAT_UNLOCK -static volatile int children_died; -#endif - -#define SET_AIO(REQ,FD,SIZE,BUFF) \ - memset(&(REQ),0,sizeof(REQ)); \ - (REQ).aio_fildes = FD; \ - (REQ).aio_offset = FM_POSITION_CURRENT; \ - (REQ).aio_nbytes = SIZE; \ - (REQ).aio_buf = BUFF; \ - (REQ).aio_sigevent.sigev_notify = SIGEV_NONE - -/* the first sizeof(struct aiocb *) bytes of the write buffer - * will contain the pointer to the aiocb struct, this needs - * to be freed between asynchronous writes. - * A write of 0 bytes is ignored. */ -#define WRITE_AIO(FD,SIZE,BUFF) do { \ - if (SIZE > 0) { \ - struct aiocb *write_req = driver_alloc(sizeof(struct aiocb)); \ - char *write_buff = driver_alloc((sizeof(char)*SIZE)+1+ \ - (sizeof(struct aiocb *))); \ - *(struct aiocb **)write_buff = (struct aiocb *)write_req; \ - write_buff += sizeof(struct aiocb *); \ - memcpy(write_buff,BUFF,SIZE+1); \ - SET_AIO(*write_req,FD,SIZE,write_buff); \ - if (aio_write(write_req)) \ - ramlog_printf("%s:%d: write failed with %d\n", \ - __FILE__,__LINE__,errno); \ - } \ -} while(0) - -/* free the write_buffer and write_req - * created in the WRITE_AIO() request macro */ -#define FREE_AIO(ptr) do { \ - struct aiocb *aiocb_ptr; \ - char *buffer_ptr; \ - aiocb_ptr = *(struct aiocb **)((ptr)-sizeof(struct aiocb *)); \ - buffer_ptr = (((char*)ptr)-sizeof(struct aiocb *)); \ - driver_free(aiocb_ptr); \ - driver_free(buffer_ptr); \ -} while(0) - -#define DISPATCH_AIO(sig) do { \ - if (aio_dispatch(sig)) \ - ramlog_printf("%s:%d: dispatch failed with %d\n", \ - __FILE__,__LINE__,errno); \ - } while(0) - -#define AIO_PIPE_SIZE 1024 - -/* debug print macros */ -#define DEBUG_RES 0 - -#ifdef DEBUG_RES -#define DEBUG_CHECK_RES(actual, expected) \ - do { \ - if (actual != expected ) { \ - ramlog_printf("Result check failed" \ - " got: 0x%08x expected:0x%08x\nat: %s:%d\n", \ - actual, expected, __FILE__, __LINE__); \ - abort(); /* This might perhaps be too harsh? */ \ - } \ - } while(0) -#else -#define DEBUG_CHECK_RES -#endif - -static struct fd_data { - char pbuf[4]; /* hold partial packet bytes */ - int psz; /* size of pbuf */ - char *buf; - char *cpos; - int sz; - int remain; /* for input on fd */ -} *fd_data; /* indexed by fd */ - -/********************* General functions ****************************/ - -/* This is used by both the drivers and general I/O, must be set early */ -static int max_files = -1; - -/* - * a few variables used by the break handler - */ -#ifdef ERTS_SMP -erts_smp_atomic32_t erts_break_requested; -#define ERTS_SET_BREAK_REQUESTED \ - erts_smp_atomic32_set_nob(&erts_break_requested, (erts_aint32_t) 1) -#define ERTS_UNSET_BREAK_REQUESTED \ - erts_smp_atomic32_set_nob(&erts_break_requested, (erts_aint32_t) 0) -#else -volatile int erts_break_requested = 0; -#define ERTS_SET_BREAK_REQUESTED (erts_break_requested = 1) -#define ERTS_UNSET_BREAK_REQUESTED (erts_break_requested = 0) -#endif -/* set early so the break handler has access to initial mode */ -static struct termios initial_tty_mode; -static int replace_intr = 0; -/* assume yes initially, ttsl_init will clear it */ -int using_oldshell = 1; -static PROCESS get_signal_proxy_pid(void); - -static void -init_check_io(void) -{ - erts_init_check_io(); - max_files = erts_check_io_max_files(); -} - -#ifdef ERTS_POLL_NEED_ASYNC_INTERRUPT_SUPPORT -#define ERTS_CHK_IO_AS_INTR() erts_check_io_async_sig_interrupt() -#else -#define ERTS_CHK_IO_AS_INTR() erts_check_io_interrupt(1) -#endif -#define ERTS_CHK_IO_INTR erts_check_io_interrupt -#define ERTS_CHK_IO_INTR_TMD erts_check_io_interrupt_timed -#define ERTS_CHK_IO erts_check_io -#define ERTS_CHK_IO_SZ erts_check_io_size - - -void -erts_sys_schedule_interrupt(int set) -{ - ERTS_CHK_IO_INTR(set); -} - -#ifdef ERTS_SMP -void -erts_sys_schedule_interrupt_timed(int set, ErtsMonotonicTime timeout_time) -{ - ERTS_CHK_IO_INTR_TMD(set, timeout_time); -} -#endif - -Uint -erts_sys_misc_mem_sz(void) -{ - Uint res = ERTS_CHK_IO_SZ(); - res += erts_smp_atomic_read_mb(&sys_misc_mem_sz); - return res; -} - -/* - * reset the terminal to the original settings on exit - */ -void sys_tty_reset(int exit_code) -{ - if (using_oldshell && !replace_intr) { - SET_BLOCKING(0); - } - else if (isatty(0)) { - tcsetattr(0,TCSANOW,&initial_tty_mode); - } -} - -#ifdef USE_THREADS - -typedef struct { - int sched_bind_data; -} erts_thr_create_data_t; - -/* - * thr_create_prepare() is called in parent thread before thread creation. - * Returned value is passed as argument to thr_create_cleanup(). - */ -static void * -thr_create_prepare(void) -{ - erts_thr_create_data_t *tcdp; - - tcdp = erts_alloc(ERTS_ALC_T_TMP, sizeof(erts_thr_create_data_t)); - - tcdp->sched_bind_data = erts_sched_bind_atthrcreate_prepare(); - - return (void *) tcdp; -} - - -/* thr_create_cleanup() is called in parent thread after thread creation. */ -static void -thr_create_cleanup(void *vtcdp) -{ - erts_thr_create_data_t *tcdp = (erts_thr_create_data_t *) vtcdp; - - erts_sched_bind_atthrcreate_parent(tcdp->sched_bind_data); - - erts_free(ERTS_ALC_T_TMP, tcdp); -} - -static void -thr_create_prepare_child(void *vtcdp) -{ - erts_thr_create_data_t *tcdp = (erts_thr_create_data_t *) vtcdp; - -#ifdef ERTS_ENABLE_LOCK_COUNT - erts_lcnt_thread_setup(); -#endif - - erts_sched_bind_atthrcreate_child(tcdp->sched_bind_data); -} - -#endif /* #ifdef USE_THREADS */ - -/* The two functions below are stolen from win_con.c - They have to use malloc/free/realloc directly becasue - we want to do able to do erts_printf very early on. - */ -#define VPRINTF_BUF_INC_SIZE 128 -static erts_dsprintf_buf_t * -grow_vprintf_buf(erts_dsprintf_buf_t *dsbufp, size_t need) -{ - char *buf; - size_t size; - - ASSERT(dsbufp); - - if (!dsbufp->str) { - size = (((need + VPRINTF_BUF_INC_SIZE - 1) - / VPRINTF_BUF_INC_SIZE) - * VPRINTF_BUF_INC_SIZE); - buf = (char *) malloc(size * sizeof(char)); - } - else { - size_t free_size = dsbufp->size - dsbufp->str_len; - - if (need <= free_size) - return dsbufp; - - size = need - free_size + VPRINTF_BUF_INC_SIZE; - size = (((size + VPRINTF_BUF_INC_SIZE - 1) - / VPRINTF_BUF_INC_SIZE) - * VPRINTF_BUF_INC_SIZE); - size += dsbufp->size; - buf = (char *) realloc((void *) dsbufp->str, - size * sizeof(char)); - } - if (!buf) - return NULL; - if (buf != dsbufp->str) - dsbufp->str = buf; - dsbufp->size = size; - return dsbufp; -} - -static int erts_sys_ramlog_printf(char *format, va_list arg_list) -{ - int res,i; - erts_dsprintf_buf_t dsbuf = ERTS_DSPRINTF_BUF_INITER(grow_vprintf_buf); - res = erts_vdsprintf(&dsbuf, format, arg_list); - if (res >= 0) { - for (i = 0; i < dsbuf.str_len; i+= 50) - /* We print 50 characters at a time because otherwise - the ramlog looks broken */ - ramlog_printf("%.*s",dsbuf.str_len-50 < 0?dsbuf.str_len:50,dsbuf.str+i); - } - if (dsbuf.str) - free((void *) dsbuf.str); - return res; -} - -void -erts_sys_pre_init(void) -{ - erts_printf_add_cr_to_stdout = 1; - erts_printf_add_cr_to_stderr = 1; -#ifdef USE_THREADS - { - erts_thr_init_data_t eid = ERTS_THR_INIT_DATA_DEF_INITER; - - eid.thread_create_child_func = thr_create_prepare_child; - /* Before creation in parent */ - eid.thread_create_prepare_func = thr_create_prepare; - /* After creation in parent */ - eid.thread_create_parent_func = thr_create_cleanup, - - erts_thr_init(&eid); - - report_exit_list = NULL; - -#ifdef ERTS_ENABLE_LOCK_COUNT - erts_lcnt_init(); -#endif - -#if defined(ERTS_SMP) - erts_mtx_init(&chld_stat_mtx, "child_status"); -#endif - } -#ifdef ERTS_SMP - erts_smp_atomic32_init_nob(&erts_break_requested, 0); - erts_smp_atomic32_init_nob(&have_prepared_crash_dump, 0); -#else - erts_break_requested = 0; - have_prepared_crash_dump = 0; -#endif -#if !defined(ERTS_SMP) - children_died = 0; -#endif -#endif /* USE_THREADS */ - - erts_printf_stdout_func = erts_sys_ramlog_printf; - - erts_smp_atomic_init_nob(&sys_misc_mem_sz, 0); -} - -void -erl_sys_init(void) -{ - -#ifdef USE_SETLINEBUF - setlinebuf(stdout); -#else - setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ); -#endif - - erts_sys_init_float(); - - /* we save this so the break handler can set and reset it properly */ - /* also so that we can reset on exit (break handler or not) */ - if (isatty(0)) { - tcgetattr(0,&initial_tty_mode); - } - tzset(); /* Required at least for NetBSD with localtime_r() */ -} - -static ERTS_INLINE int -prepare_crash_dump(int secs) -{ -#define NUFBUF (3) - int i, max; - char env[21]; /* enough to hold any 64-bit integer */ - size_t envsz; - /*DeclareTmpHeapNoproc(heap,NUFBUF);*/ - /*Eterm *hp = heap;*/ - /*Eterm list = NIL;*/ - int has_heart = 0; - - UseTmpHeapNoproc(NUFBUF); - - if (ERTS_PREPARED_CRASH_DUMP) - return 0; /* We have already been called */ - - - /* Positive secs means an alarm must be set - * 0 or negative means no alarm - * - * Set alarm before we try to write to a port - * we don't want to hang on a port write with - * no alarm. - * - */ - -#if 0 /*ose TBD!!!*/ - if (secs >= 0) { - alarm((unsigned int)secs); - } -#endif - - /* Make sure we unregister at epmd (unknown fd) and get at least - one free filedescriptor (for erl_crash.dump) */ - - max = max_files; - if (max < 1024) - max = 1024; - for (i = 3; i < max; i++) { - close(i); - } - - envsz = sizeof(env); - i = erts_sys_getenv__("ERL_CRASH_DUMP_NICE", env, &envsz); - if (i >= 0) { - int nice_val; - nice_val = i != 0 ? 0 : atoi(env); - if (nice_val > 39) { - nice_val = 39; - } - set_pri(nice_val); - } - - UnUseTmpHeapNoproc(NUFBUF); -#undef NUFBUF - return has_heart; -} - -int erts_sys_prepare_crash_dump(int secs) -{ - return prepare_crash_dump(secs); -} - -static ERTS_INLINE void -break_requested(void) -{ - /* - * just set a flag - checked for and handled by - * scheduler threads erts_check_io() (not signal handler). - */ -#ifdef DEBUG - fprintf(stderr,"break!\n"); -#endif - if (ERTS_BREAK_REQUESTED) - erl_exit(ERTS_INTR_EXIT, ""); - - ERTS_SET_BREAK_REQUESTED; - ERTS_CHK_IO_AS_INTR(); /* Make sure we don't sleep in poll */ -} - -/* Disable break */ -void erts_set_ignore_break(void) { - -} - -/* Don't use ctrl-c for break handler but let it be - used by the shell instead (see user_drv.erl) */ -void erts_replace_intr(void) { - struct termios mode; - - if (isatty(0)) { - tcgetattr(0, &mode); - - /* here's an example of how to replace ctrl-c with ctrl-u */ - /* mode.c_cc[VKILL] = 0; - mode.c_cc[VINTR] = CKILL; */ - - mode.c_cc[VINTR] = 0; /* disable ctrl-c */ - tcsetattr(0, TCSANOW, &mode); - replace_intr = 1; - } -} - -void init_break_handler(void) -{ - -} - -int sys_max_files(void) -{ - return(max_files); -} - - -/************************** OS info *******************************/ - -/* Used by erlang:info/1. */ -/* (This code was formerly in drv.XXX/XXX_os_drv.c) */ - -char os_type[] = "ose"; - -void -os_flavor(char* namebuf, /* Where to return the name. */ - unsigned size) /* Size of name buffer. */ -{ -#if 0 - struct utsname uts; /* Information about the system. */ - char* s; - - (void) uname(&uts); - for (s = uts.sysname; *s; s++) { - if (isupper((int) *s)) { - *s = tolower((int) *s); - } - } - strcpy(namebuf, uts.sysname); -#else - strncpy(namebuf, "release", size); -#endif -} - -void -os_version(pMajor, pMinor, pBuild) -int* pMajor; /* Pointer to major version. */ -int* pMinor; /* Pointer to minor version. */ -int* pBuild; /* Pointer to build number. */ -{ - *pMajor = 5; - *pMinor = 7; - *pBuild = 0; -} - -void init_getenv_state(GETENV_STATE *state) -{ - erts_smp_rwmtx_rlock(&environ_rwmtx); - *state = NULL; -} - -char **environ; /*ose - needs replacement*/ - -char *getenv_string(GETENV_STATE *state0) -{ - char **state = (char **) *state0; - char *cp; - - ERTS_SMP_LC_ASSERT(erts_smp_lc_rwmtx_is_rlocked(&environ_rwmtx)); - - if (state == NULL) - state = environ; - - cp = *state++; - *state0 = (GETENV_STATE) state; - - return cp; -} - -void fini_getenv_state(GETENV_STATE *state) -{ - *state = NULL; - erts_smp_rwmtx_runlock(&environ_rwmtx); -} - - -/************************** Port I/O *******************************/ - -/* I. Common stuff */ - -union SIGNAL { - SIGSELECT sig_no; - struct FmReadPtr fm_read_reply; - struct FmWritePtr fm_write_reply; - struct async async; -}; - -/* II. The spawn/fd drivers */ - -/* - * Decreasing the size of it below 16384 is not allowed. - */ -#define ERTS_SYS_READ_BUF_SZ (64*1024) - -/* Driver interfaces */ -static ErlDrvData spawn_start(ErlDrvPort, char*, SysDriverOpts*); -static ErlDrvData fd_start(ErlDrvPort, char*, SysDriverOpts*); -static ErlDrvSSizeT fd_control(ErlDrvData, unsigned int, char *, ErlDrvSizeT, - char **, ErlDrvSizeT); -static int spawn_init(void); -static void fd_stop(ErlDrvData); -static void erl_stop(ErlDrvData); -static void ready_input(ErlDrvData, ErlDrvEvent); -static void ready_output(ErlDrvData, ErlDrvEvent); -static void output(ErlDrvData, char*, ErlDrvSizeT); -static void stop_select(ErlDrvEvent, void*); - -static PROCESS -get_signal_proxy_pid(void) { - union SIGNAL *sig; - SIGSELECT any_sig[] = {1,ERTS_SIGNAL_OSE_DRV_ATTACH}; - - if (!sig_proxy_pid) { - sig = alloc(sizeof(union SIGNAL), ERTS_SIGNAL_OSE_DRV_ATTACH); - hunt("ose_signal_driver_proxy", 0, NULL, &sig); - sig = receive(any_sig); - sig_proxy_pid = sender(&sig); - free_buf(&sig); - } - ASSERT(sig_proxy_pid); - return sig_proxy_pid; -} - -static ErlDrvOseEventId -resolve_signal(union SIGNAL* sig) { - switch(sig->sig_no) { - - case FM_READ_PTR_REPLY: - return (ErlDrvOseEventId)sig->fm_read_reply.handle; - - case FM_WRITE_PTR_REPLY: - return (ErlDrvOseEventId)sig->fm_write_reply.handle; - - case ERTS_SIGNAL_OSE_DRV_ATTACH: - return (ErlDrvOseEventId)sig->async.target; - - default: - break; - } - return (ErlDrvOseEventId)-1; -} - -struct erl_drv_entry spawn_driver_entry = { - spawn_init, - spawn_start, - NULL, /* erl_stop, */ - output, - ready_input, - ready_output, - "spawn", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - ERL_DRV_EXTENDED_MARKER, - ERL_DRV_EXTENDED_MAJOR_VERSION, - ERL_DRV_EXTENDED_MINOR_VERSION, - ERL_DRV_FLAG_USE_PORT_LOCKING, - NULL, NULL, - stop_select -}; -struct erl_drv_entry fd_driver_entry = { - NULL, - fd_start, - fd_stop, - output, - ready_input, - ready_output, - "fd", - NULL, - NULL, - fd_control, - NULL, - NULL, - NULL, /* ready_async */ - NULL, /* flush */ - NULL, /* call */ - NULL, /* event */ - ERL_DRV_EXTENDED_MARKER, - ERL_DRV_EXTENDED_MAJOR_VERSION, - ERL_DRV_EXTENDED_MINOR_VERSION, - 0, /* ERL_DRV_FLAGs */ - NULL, /* handle2 */ - NULL, /* process_exit */ - stop_select -}; - -static void -set_spawn_fd(int local_fd, int remote_fd, PROCESS remote_pid) { - PROCESS vm_pid; - FmHandle handle; - char env_val[55]; - char env_name[10]; - EfsStatus efs_res; - - /* get pid of pipevm and handle of chosen fd */ - efs_res = efs_examine_fd(local_fd, FLIB_FD_VMPID, &vm_pid, 0); - DEBUG_CHECK_RES(efs_res, EFS_SUCCESS); - - /* setup the file descriptor to buffer per line */ - efs_res = efs_config_fd(local_fd, FLIB_FD_BUFMODE, FM_BUFF_LINE, - FLIB_FD_BUFSIZE, 80, 0); - DEBUG_CHECK_RES(efs_res, EFS_SUCCESS); - - /* duplicate handle and set spawn pid owner */ - efs_res = efs_dup_to(local_fd, remote_pid, &handle); - DEBUG_CHECK_RES(efs_res, EFS_SUCCESS); - - sprintf(env_name, "FD%d", remote_fd); - - /* Syntax of the environment variable: - * "FD#" "<pid of pipevm>,<handle>,<buffer mode>,<buff size>,<omode>" */ - sprintf(env_val, "0x%lx,0x%lx,%lu,%lu,0x%x", - vm_pid, handle, - FM_BUFF_LINE, 80, - O_APPEND); - - set_env(remote_pid, env_name, env_val); -} - -static ErlDrvData -set_driver_data(ErlDrvPort port_num, - int ifd, - int ofd, - int packet_bytes, - int read_write, - int exit_status, - PROCESS pid) -{ - Port *prt; - ErtsSysReportExit *report_exit; - - prt = erts_drvport2port(port_num); - if (prt != ERTS_INVALID_ERL_DRV_PORT) { - prt->os_pid = pid; - } - - /* READ */ - if (read_write & DO_READ) { - EfsStatus res = efs_examine_fd(ifd, FLIB_FD_HANDLE, - &driver_data[ifd].handle, 0); - if (res != EFS_SUCCESS) - ramlog_printf("%s:%d: efs_examine_fd(%d) failed with %d\n", - __FILE__,__LINE__,ifd,errno); - driver_data[ifd].ifd = ifd; - driver_data[ifd].packet_bytes = packet_bytes; - driver_data[ifd].port_num = port_num; - driver_data[ifd].pid = pid; - - /* async read struct */ - memset(&driver_data[ifd].aiocb, 0, sizeof(struct aiocb)); - driver_data[ifd].aiocb.aio_buf = driver_alloc(AIO_PIPE_SIZE); - driver_data[ifd].aiocb.aio_fildes = ifd; - driver_data[ifd].aiocb.aio_nbytes = (packet_bytes?packet_bytes:AIO_PIPE_SIZE); - driver_data[ifd].alive = 1; - driver_data[ifd].status = 0; - driver_data[ifd].input_event = - erl_drv_ose_event_alloc(FM_READ_PTR_REPLY, - driver_data[ifd].handle, resolve_signal, - &driver_data[ifd].ifd); - - /* READ & WRITE */ - if (read_write & DO_WRITE) { - driver_data[ifd].ofd = ofd; - efs_examine_fd(ofd, FLIB_FD_HANDLE, &driver_data[ofd].handle, 0); - - driver_data[ifd].output_event = - erl_drv_ose_event_alloc(FM_WRITE_PTR_REPLY, - driver_data[ofd].handle, resolve_signal, - &driver_data[ofd].ofd); - driver_data[ofd].pid = pid; - if (ifd != ofd) { - driver_data[ofd] = driver_data[ifd]; - driver_data[ofd].aiocb.aio_buf = NULL; - } - } - else { /* READ ONLY */ - driver_data[ifd].ofd = -1; - } - - /* enable input event */ - (void) driver_select(port_num, driver_data[ifd].input_event, - (ERL_DRV_READ | ERL_DRV_USE), 1); - - if (aio_read(&driver_data[ifd].aiocb)) - ramlog_printf("%s:%d: aio_read(%d) failed with %d\n", - __FILE__,__LINE__,ifd,errno); - } - else { /* WRITE ONLY */ - efs_examine_fd(ofd, FLIB_FD_HANDLE, &driver_data[ofd].handle, 0); - driver_data[ofd].packet_bytes = packet_bytes; - driver_data[ofd].port_num = port_num; - driver_data[ofd].ofd = ofd; - driver_data[ofd].pid = pid; - driver_data[ofd].alive = 1; - driver_data[ofd].status = 0; - driver_data[ofd].output_event = - erl_drv_ose_event_alloc(FM_WRITE_PTR_REPLY, driver_data[ofd].handle, - resolve_signal, &driver_data[ofd].ofd); - driver_data[ofd].input_event = driver_data[ofd].output_event; - } - - /* this is used for spawned load modules, and is needed - * to properly uninstall them */ - if (exit_status) { - struct PmProgramInfo *info; - int install_handle_size; - union SIGNAL *sig; - PmStatus pm_status; - report_exit = erts_alloc(ERTS_ALC_T_PRT_REP_EXIT, - sizeof(ErtsSysReportExit)); - report_exit->next = report_exit_list; - report_exit->port = erts_drvport2id(port_num); - report_exit->pid = pid; - report_exit->ifd = (read_write & DO_READ) ? ifd : -1; - report_exit->ofd = (read_write & DO_WRITE) ? ofd : -1; - report_exit_list = report_exit; - report_exit->attach_event = - erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_ATTACH, pid, - resolve_signal, &driver_data[ifd].ifd); - - /* setup ifd and ofd report exit */ - driver_data[ifd].report_exit = report_exit; - driver_data[ofd].report_exit = report_exit; - - pm_status = ose_pm_program_info(pid, &info); - DEBUG_CHECK_RES(pm_status, PM_SUCCESS); - - install_handle_size = strlen(info->install_handle)+1; - driver_data[ifd].install_handle = driver_alloc(install_handle_size); - strcpy(driver_data[ifd].install_handle, - info->install_handle); - - free_buf((union SIGNAL **)&info); - - sig = alloc(sizeof(struct async), ERTS_SIGNAL_OSE_DRV_ATTACH); - sig->async.target = pid; - send(&sig, get_signal_proxy_pid()); - - /* this event will trigger when we receive an attach signal - * from the recently dead load module */ - (void)driver_select(port_num,report_exit->attach_event, DO_READ, 1); - } - else { - report_exit = NULL; - } - - /* the return value is the pointer to the driver_data struct we created - * in this function, it will be used in the drivers input - * and output functions */ - return (ErlDrvData)((!(read_write & DO_READ) && read_write & DO_WRITE) - ? &driver_data[ofd] - : &driver_data[ifd]); -} - -static int spawn_init() -{ - int i; - - driver_data = (struct driver_data *) - erts_alloc(ERTS_ALC_T_DRV_TAB, max_files * sizeof(struct driver_data)); - erts_smp_atomic_add_nob(&sys_misc_mem_sz, - max_files * sizeof(struct driver_data)); - - for (i = 0; i < max_files; i++) - driver_data[i].pid = -1; - - return 1; -} - -static void -init_fd_data(int fd, ErlDrvPort port_num) -{ - fd_data[fd].buf = NULL; - fd_data[fd].cpos = NULL; - fd_data[fd].remain = 0; - fd_data[fd].sz = 0; - fd_data[fd].psz = 0; -} - -/* FIXME write a decent text on pipes on ose */ -static ErlDrvData -spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts) -{ - int ifd[2]; - int ofd[2]; - static uint32_t ticker = 1; - PmStatus pm_status; - OSDOMAIN domain = PM_NEW_DOMAIN; - PROCESS progpid, mainbid, mainpid; - char *handle = NULL; - struct PmProgramInfo *info; - char *args = NULL; - char *tmp_handle; - ErlDrvData res = (ErlDrvData)-1; - int handle_size; - char *ptr; - - - args = driver_alloc(strlen(name)+1); - strcpy(args, name); - /* We need to handle name in three parts - * - install handle (must be unique) - * - install binary (needed for ose_pm_install_load_module()) - * - full path (as argument to the spawned applications env.var - */ - - /* full path including arguments */ - args = driver_alloc(strlen(name)+1); - strcpy(args, name); - - /* handle path */ - tmp_handle = strrchr(name, '/'); - if (tmp_handle == NULL) { - tmp_handle = name; - } - else { - tmp_handle++; - } - - /* handle args */ - ptr = strchr(tmp_handle, ' '); - if (ptr != NULL) { - *ptr = '\0'; - handle_size = ptr - tmp_handle; - } - else { - handle_size = strlen(name)+1; - } - - /* make room for ticker */ - handle_size += (ticker<10)?3:((ticker<100)?4:5); - handle = driver_alloc(handle_size); - - do { - snprintf(handle, handle_size, "%s_%d", tmp_handle, ticker); - pm_status = ose_pm_install_load_module(0, "ELF", name, handle, - 0, 0, NULL); - ticker++; - } while (pm_status == PM_EINSTALL_HANDLE_ALREADY_INSTALLED); - - if (pm_status != PM_SUCCESS) { - errno = ENOSYS; /* FIXME add comment */ - return ERL_DRV_ERROR_ERRNO; - } - - /* Create Program */ - pm_status = ose_pm_create_program(&domain, handle, 0, 0, - NULL, &progpid, &mainbid); - DEBUG_CHECK_RES(pm_status, PM_SUCCESS); - - /* Get the mainpid from the newly created program */ - pm_status = ose_pm_program_info(progpid, &info); - DEBUG_CHECK_RES(pm_status, PM_SUCCESS); - - mainpid = info->main_process; - free_buf ((union SIGNAL **)&info); - - /* pipevm needs to be started - * pipe will return 0 if success, -1 if not, - * errno will be set */ - if (pipe(ifd) != 0 || pipe(ofd) != 0) { - DEBUG_CHECK_RES(0, -1); - ASSERT(0); - } - - /* setup driver data */ - res = set_driver_data(port_num, ofd[0], ifd[1], opts->packet_bytes, - opts->read_write, 1 /* opts->exit_status */, progpid); - - /* init the fd_data array for read/write */ - init_fd_data(ofd[0], port_num); - init_fd_data(ifd[1], port_num); - - /* setup additional configurations - * for the spawned applications environment */ - if (args != NULL) { - set_env(progpid, "ARGV", args); - } - set_env(mainbid, "EFS_RESOLVE_TMO", 0); - set_spawn_fd(ifd[0], 0, mainpid); - set_spawn_fd(ofd[1], 1, mainpid); - set_spawn_fd(ofd[1], 2, mainpid); - - /* start the spawned program */ - pm_status = ose_pm_start_program(mainbid); - DEBUG_CHECK_RES(pm_status, PM_SUCCESS); - - /* close unused fd's */ - close(ifd[0]); - close(ofd[1]); - - if (handle) { - driver_free(handle); - } - - return (ErlDrvData)res; -} - -#define FD_DEF_HEIGHT 24 -#define FD_DEF_WIDTH 80 -/* Control op */ -#define FD_CTRL_OP_GET_WINSIZE 100 - -static int fd_get_window_size(int fd, Uint32 *width, Uint32 *height) -{ -#ifdef TIOCGWINSZ - struct winsize ws; - if (ioctl(fd,TIOCGWINSZ,&ws) == 0) { - *width = (Uint32) ws.ws_col; - *height = (Uint32) ws.ws_row; - return 0; - } -#endif - return -1; -} - -static ErlDrvSSizeT fd_control(ErlDrvData drv_data, - unsigned int command, - char *buf, ErlDrvSizeT len, - char **rbuf, ErlDrvSizeT rlen) -{ - struct driver_data *data = (struct driver_data *)drv_data; - char resbuff[2*sizeof(Uint32)]; - switch (command) { - case FD_CTRL_OP_GET_WINSIZE: - { - Uint32 w,h; - if (fd_get_window_size(data->ifd,&w,&h)) - return 0; - memcpy(resbuff,&w,sizeof(Uint32)); - memcpy(resbuff+sizeof(Uint32),&h,sizeof(Uint32)); - } - break; - default: - return 0; - } - if (rlen < 2*sizeof(Uint32)) { - *rbuf = driver_alloc(2*sizeof(Uint32)); - } - memcpy(*rbuf,resbuff,2*sizeof(Uint32)); - return 2*sizeof(Uint32); -} - -static ErlDrvData fd_start(ErlDrvPort port_num, char* name, - SysDriverOpts* opts) -{ - ErlDrvData res; - - CHLD_STAT_LOCK; - if (opts->read_write & DO_READ) { - init_fd_data(opts->ifd, port_num); - } - if (opts->read_write & DO_WRITE) { - init_fd_data(opts->ofd, port_num); - } - res = set_driver_data(port_num, opts->ifd, opts->ofd, - opts->packet_bytes, - opts->read_write, 0, -1); - CHLD_STAT_UNLOCK; - return res; -} - -static void clear_fd_data(int fd) -{ - if (fd_data[fd].sz > 0) { - erts_free(ERTS_ALC_T_FD_ENTRY_BUF, (void *) fd_data[fd].buf); - ASSERT(erts_smp_atomic_read_nob(&sys_misc_mem_sz) >= fd_data[fd].sz); - erts_smp_atomic_add_nob(&sys_misc_mem_sz, -1*fd_data[fd].sz); - } - fd_data[fd].buf = NULL; - fd_data[fd].sz = 0; - fd_data[fd].remain = 0; - fd_data[fd].cpos = NULL; - fd_data[fd].psz = 0; -} - -static void nbio_stop_fd(ErlDrvPort prt, ErlDrvEvent ev) -{ - int *fd; - driver_select(prt,ev,DO_READ|DO_WRITE,0); - erl_drv_ose_event_fetch(ev, NULL, NULL, (void **)&fd); - clear_fd_data(*fd); - SET_BLOCKING(*fd); -} - -static void fd_stop(ErlDrvData drv_data) /* Does not close the fds */ -{ - struct driver_data *data = (struct driver_data *)drv_data; - - if (data->ofd != -1) { - if (data->ifd != data->ofd) { /* read and write */ - nbio_stop_fd(data->port_num, data->input_event); - nbio_stop_fd(data->port_num, data->output_event); - } - else { /* write only */ - nbio_stop_fd(data->port_num, data->output_event); - } - } - else { /* read only */ - nbio_stop_fd(data->port_num, data->input_event); - } -} - - -static void erl_stop(ErlDrvData drv_data) -{ - struct driver_data *data = (struct driver_data *)drv_data; - - CHLD_STAT_LOCK; - data->pid = -1; - CHLD_STAT_UNLOCK; - - if (data->ofd != -1) { - if (data->ifd != data->ofd) { /* read and write */ - nbio_stop_fd(data->port_num, data->input_event); - nbio_stop_fd(data->port_num, data->output_event); - } - else { /* write only */ - nbio_stop_fd(data->port_num, data->output_event); - } - } - else { /* read only */ - nbio_stop_fd(data->port_num, data->input_event); - } - close(data->ifd); - close(data->ofd); -} - -/* The parameter e is a pointer to the driver_data structure - * related to the fd to be used as output */ -static void output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len) -{ - ErlDrvSizeT sz; - char lb[4]; - char* lbp; - struct driver_data *data = (struct driver_data *)drv_data; - - if (((data->packet_bytes == 2) && - (len > 0xffff)) || (data->packet_bytes == 1 && len > 0xff)) { - driver_failure_posix(data->port_num, EINVAL); - return; /* -1; */ - } - put_int32(len, lb); - lbp = lb + (4-(data->packet_bytes)); - - if ((sz = driver_sizeq(data->port_num)) > 0) { - if (data->packet_bytes != 0) { - driver_enq(data->port_num, lbp, data->packet_bytes); - } - driver_enq(data->port_num, buf, len); - - if (sz + len + data->packet_bytes >= (1 << 13)) - set_busy_port(data->port_num, 1); - } - else { - char *pbbuf; - if (data->packet_bytes != 0) { - pbbuf = malloc(len + data->packet_bytes); - int i; - for (i = 0; i < data->packet_bytes; i++) { - *pbbuf++ = *lbp++; - } - strncpy(pbbuf, buf, len); - pbbuf -= data->packet_bytes; - } - driver_select(data->port_num, data->output_event, - ERL_DRV_WRITE|ERL_DRV_USE, 1); - WRITE_AIO(data->ofd, - (data->packet_bytes ? len+data->packet_bytes : len), - (data->packet_bytes ? pbbuf : buf)); - if (data->packet_bytes != 0) free(pbbuf); - } - return; /* 0; */ -} - -/* This function is being run when we in recieve - * either a read of 0 bytes, or the attach signal from a dying - * spawned load module */ -static int port_inp_failure(ErlDrvPort port_num, ErlDrvEvent ready_fd, int res) - /* Result: 0 (eof) or -1 (error) */ -{ - int *fd; - SIGSELECT sig_no; - ASSERT(res <= 0); - - erl_drv_ose_event_fetch(ready_fd,&sig_no, NULL, (void **)&fd); - /* As we need to handle two signals, we do this in two steps */ - if (driver_data[*fd].alive) { - report_exit_status(driver_data[*fd].report_exit, 0); /* status? */ - } - else { - driver_select(port_num,ready_fd,DO_READ|DO_WRITE,0); - clear_fd_data(*fd); - driver_report_exit(driver_data[*fd].port_num, driver_data[*fd].status); - /* As we do not really know if the spawn has crashed or exited nicely - * we do not check the result status of the following call.. FIXME - * can we handle this in a better way? */ - ose_pm_uninstall_load_module(driver_data[*fd].install_handle); - driver_free(driver_data[*fd].install_handle); - driver_free((void *)driver_data[*fd].aiocb.aio_buf); - - close(*fd); - } - - return 0; -} - -/* The parameter e is a pointer to the driver_data structure - * related to the fd to be used as output. - * ready_fd is the event that triggered this call to ready_input */ -static void ready_input(ErlDrvData drv_data, ErlDrvEvent ready_fd) -{ - int res; - Uint h; - char *buf; - union SIGNAL *sig; - struct driver_data *data = (struct driver_data *)drv_data; - - sig = erl_drv_ose_get_signal(ready_fd); - ASSERT(sig); - - - while (sig) { - /* If we've recieved an attach signal, we need to handle - * it in port_inp_failure */ - if (sig->sig_no == ERTS_SIGNAL_OSE_DRV_ATTACH) { - port_inp_failure(data->port_num, ready_fd, 0); - } - else { - res = sig->fm_read_reply.actual; - if (res == 0) { - port_inp_failure(data->port_num, ready_fd, res); - break; - } - - if (data->packet_bytes == 0) { - if (res < 0) { - if ((errno != EINTR) && (errno != ERRNO_BLOCK)) { - port_inp_failure(data->port_num, ready_fd, res); - } - } - else if (res == 0) { - /* read of 0 bytes, eof, otherside of pipe is assumed dead */ - port_inp_failure(data->port_num, ready_fd, res); - break; - } - else { - buf = driver_alloc(res); - memcpy(buf, (void *)data->aiocb.aio_buf, res); - driver_select(data->port_num, data->output_event, - ERL_DRV_WRITE|ERL_DRV_USE, 1); - driver_output(data->port_num, (char*) buf, res); - driver_free(buf); - } - /* clear the previous read */ - memset(data->aiocb.aio_buf, 0, res); - - /* issue a new read */ - DISPATCH_AIO(sig); - aio_read(&data->aiocb); - } - else if (data->packet_bytes && fd_data[data->ifd].remain > 0) { - /* we've read a partial package, or a header */ - - if (res == fd_data[data->ifd].remain) { /* we are done! */ - char *buf = data->aiocb.aio_buf; - int i; - - /* do we have anything buffered? */ - if (fd_data[data->ifd].buf != NULL) { - memcpy(fd_data[data->ifd].buf + fd_data[data->ifd].sz, - buf, res); - buf = fd_data[data->ifd].buf; - } - - fd_data[data->ifd].sz += res; - driver_output(data->port_num, buf, (fd_data[data->ifd].sz>0?fd_data[data->ifd].sz:res)); - clear_fd_data(data->ifd); - - /* clear the previous read */ - memset(data->aiocb.aio_buf, 0, res); - - /* issue a new read */ - DISPATCH_AIO(sig); - data->aiocb.aio_nbytes = data->packet_bytes; - - if (data->aiocb.aio_buf == NULL) { - port_inp_failure(data->port_num, ready_fd, -1); - } - aio_read(&data->aiocb); - } - else if(res < fd_data[data->ifd].remain) { /* received part of a package */ - if (fd_data[data->ifd].sz == 0) { - - fd_data[data->ifd].sz += res; - memcpy(fd_data[data->ifd].buf, data->aiocb.aio_buf, res); - fd_data[data->ifd].remain -= res; - } - else { - memcpy(fd_data[data->ifd].buf + fd_data[data->ifd].sz, - data->aiocb.aio_buf, res); - fd_data[data->ifd].sz += res; - fd_data[data->ifd].remain -= res; - } - /* clear the previous read */ - memset(data->aiocb.aio_buf, 0, res); - - /* issue a new read */ - DISPATCH_AIO(sig); - data->aiocb.aio_nbytes = fd_data[data->ifd].remain; - - if (data->aiocb.aio_buf == NULL) { - port_inp_failure(data->port_num, ready_fd, -1); - } - aio_read(&data->aiocb); - } - } - else if (data->packet_bytes && fd_data[data->ifd].remain == 0) { /* we've recieved a header */ - - /* analyze the header FIXME */ - switch (data->packet_bytes) { - case 1: h = get_int8(data->aiocb.aio_buf); break; - case 2: h = get_int16(data->aiocb.aio_buf); break; - case 4: h = get_int32(data->aiocb.aio_buf); break; - } - - fd_data[data->ifd].buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h + data->packet_bytes); - fd_data[data->ifd].remain = ((h + data->packet_bytes) - res); - - /* clear the previous read */ - memset(data->aiocb.aio_buf, 0, data->packet_bytes); - - /* issue a new read */ - DISPATCH_AIO(sig); - data->aiocb.aio_nbytes = h; - - if (data->aiocb.aio_buf == NULL) { - port_inp_failure(data->port_num, ready_fd, -1); - } - aio_read(&data->aiocb); - } - } - sig = erl_drv_ose_get_signal(ready_fd); - } -} - - -/* The parameter e is a pointer to the driver_data structure - * related to the fd to be used as output. - * ready_fd is the event that triggered this call to ready_input */ -static void ready_output(ErlDrvData drv_data, ErlDrvEvent ready_fd) -{ - SysIOVec *iov; - int vlen; - int res; - union SIGNAL *sig; - struct driver_data *data = (struct driver_data *)drv_data; - - sig = erl_drv_ose_get_signal(ready_fd); - ASSERT(sig); - - while (sig != NULL) { - if (sig->fm_write_reply.actual <= 0) { - int status; - - status = efs_status_to_errno(sig->fm_write_reply.status); - driver_select(data->port_num, ready_fd, ERL_DRV_WRITE, 0); - DISPATCH_AIO(sig); - FREE_AIO(sig->fm_write_reply.buffer); - - driver_failure_posix(data->port_num, status); - } - else { /* written bytes > 0 */ - iov = driver_peekq(data->port_num, &vlen); - if (vlen > 0) { - DISPATCH_AIO(sig); - FREE_AIO(sig->fm_write_reply.buffer); - res = driver_deq(data->port_num, iov[0].iov_len); - if (res > 0) { - iov = driver_peekq(data->port_num, &vlen); - WRITE_AIO(data->ofd, iov[0].iov_len, iov[0].iov_base); - } - } - else if (vlen == 0) { - DISPATCH_AIO(sig); - FREE_AIO(sig->fm_write_reply.buffer); - } - - } - sig = erl_drv_ose_get_signal(ready_fd); - } -} - -static void stop_select(ErlDrvEvent ready_fd, void* _) -{ - int *fd; - erl_drv_ose_event_fetch(ready_fd, NULL, NULL, (void **)&fd); - erl_drv_ose_event_free(ready_fd); - close(*fd); -} - - -void erts_do_break_handling(void) -{ - struct termios temp_mode; - int saved = 0; - - /* - * Most functions that do_break() calls are intentionally not thread safe; - * therefore, make sure that all threads but this one are blocked before - * proceeding! - */ - erts_smp_thr_progress_block(); - - /* during break we revert to initial settings */ - /* this is done differently for oldshell */ - if (using_oldshell && !replace_intr) { - SET_BLOCKING(1); - } - else if (isatty(0)) { - tcgetattr(0,&temp_mode); - tcsetattr(0,TCSANOW,&initial_tty_mode); - saved = 1; - } - - /* call the break handling function, reset the flag */ - do_break(); - - fflush(stdout); - - /* after break we go back to saved settings */ - if (using_oldshell && !replace_intr) { - SET_NONBLOCKING(1); - } - else if (saved) { - tcsetattr(0,TCSANOW,&temp_mode); - } - - erts_smp_thr_progress_unblock(); -} - -static pid_t -getpid(void) -{ - return get_bid(current_process()); -} - -int getpagesize(void) -{ - return 1024; -} - - -/* Fills in the systems representation of the jam/beam process identifier. -** The Pid is put in STRING representation in the supplied buffer, -** no interpretatione of this should be done by the rest of the -** emulator. The buffer should be at least 21 bytes long. -*/ -void sys_get_pid(char *buffer, size_t buffer_size){ - pid_t p = getpid(); - /* Assume the pid is scalar and can rest in an unsigned long... */ - erts_snprintf(buffer, buffer_size, "%lu",(unsigned long) p); -} - -int -erts_sys_putenv_raw(char *key, char *value) { - return erts_sys_putenv(key, value); -} -int -erts_sys_putenv(char *key, char *value) -{ - int res; - - erts_smp_rwmtx_rwlock(&environ_rwmtx); - res = set_env(get_bid(current_process()), key, - value); - erts_smp_rwmtx_rwunlock(&environ_rwmtx); - return res; -} - - -int -erts_sys_unsetenv(char *key) -{ - int res; - - erts_smp_rwmtx_rwlock(&environ_rwmtx); - res = set_env(get_bid(current_process()),key,NULL); - erts_smp_rwmtx_rwunlock(&environ_rwmtx); - - return res; -} - -int -erts_sys_getenv__(char *key, char *value, size_t *size) -{ - int res; - char *orig_value = get_env(get_bid(current_process()), key); - if (!orig_value) - res = -1; - else { - size_t len = sys_strlen(orig_value); - if (len >= *size) { - *size = len + 1; - res = 1; - } - else { - *size = len; - sys_memcpy((void *) value, (void *) orig_value, len+1); - res = 0; - } - free_buf((union SIGNAL **)&orig_value); - } - return res; -} - -int -erts_sys_getenv_raw(char *key, char *value, size_t *size) { - return erts_sys_getenv(key, value, size); -} - -/* - * erts_sys_getenv - * returns: - * -1, if environment key is not set with a value - * 0, if environment key is set and value fits into buffer res - * 1, if environment key is set but does not fit into buffer res - * res is set with the needed buffer res value - */ - -int -erts_sys_getenv(char *key, char *value, size_t *size) -{ - int res; - erts_smp_rwmtx_rlock(&environ_rwmtx); - res = erts_sys_getenv__(key, value, size); - erts_smp_rwmtx_runlock(&environ_rwmtx); - return res; -} - -void -sys_init_io(void) -{ - fd_data = (struct fd_data *) - erts_alloc(ERTS_ALC_T_FD_TAB, max_files * sizeof(struct fd_data)); - erts_smp_atomic_add_nob(&sys_misc_mem_sz, - max_files * sizeof(struct fd_data)); -} - -extern const char pre_loaded_code[]; -extern Preload pre_loaded[]; - -void erts_sys_alloc_init(void) -{ -} - -void *erts_sys_alloc(ErtsAlcType_t t, void *x, Uint sz) -{ - void *res = malloc((size_t) sz); -#if HAVE_ERTS_MSEG - if (!res) { - erts_mseg_clear_cache(); - return malloc((size_t) sz); - } -#endif - return res; -} - -void *erts_sys_realloc(ErtsAlcType_t t, void *x, void *p, Uint sz) -{ - void *res = realloc(p, (size_t) sz); -#if HAVE_ERTS_MSEG - if (!res) { - erts_mseg_clear_cache(); - return realloc(p, (size_t) sz); - } -#endif - return res; -} - -void erts_sys_free(ErtsAlcType_t t, void *x, void *p) -{ - free(p); -} - -/* Return a pointer to a vector of names of preloaded modules */ - -Preload* -sys_preloaded(void) -{ - return pre_loaded; -} - -/* Return a pointer to preloaded code for module "module" */ -unsigned char* -sys_preload_begin(Preload* p) -{ - return p->code; -} - -/* Clean up if allocated */ -void sys_preload_end(Preload* p) -{ - /* Nothing */ -} - -/* Read a key from console (?) */ - -int sys_get_key(fd) -int fd; -{ - int c; - unsigned char rbuf[64]; - - fflush(stdout); /* Flush query ??? */ - - if ((c = read(fd,rbuf,64)) <= 0) { - return c; - } - - return rbuf[0]; -} - - -#ifdef DEBUG - -extern int erts_initialized; -void -erl_assert_error(const char* expr, const char* func, - const char* file, int line) -{ - fflush(stdout); - fprintf(stderr, "%s:%d:%s() Assertion failed: %s\n", - file, line, func, expr); - fflush(stderr); - ramlog_printf("%s:%d:%s() Assertion failed: %s\n", - file, line, func, expr); - - abort(); -} - -void -erl_debug(char* fmt, ...) -{ - char sbuf[1024]; /* Temporary buffer. */ - va_list va; - - if (debug_log) { - va_start(va, fmt); - vsprintf(sbuf, fmt, va); - va_end(va); - fprintf(stderr, "%s", sbuf); - } -} - -#endif /* DEBUG */ - -static ERTS_INLINE void -report_exit_status(ErtsSysReportExit *rep, int status) -{ - if (rep->ifd >= 0) { - driver_data[rep->ifd].alive = 0; - driver_data[rep->ifd].status = status; - } - if (rep->ofd >= 0) { - driver_data[rep->ofd].alive = 0; - driver_data[rep->ofd].status = status; - } - - erts_free(ERTS_ALC_T_PRT_REP_EXIT, rep); -} - -#define ERTS_REPORT_EXIT_STATUS report_exit_status - -/* - * Called from schedule() when it runs out of runnable processes, - * or when Erlang code has performed INPUT_REDUCTIONS reduction - * steps. runnable == 0 iff there are no runnable Erlang processes. - */ -void -erl_sys_schedule(int runnable) -{ - ASSERT(get_fsem(current_process()) == 0); -#ifdef ERTS_SMP - ASSERT(erts_get_scheduler_data()->no == 1); - ERTS_CHK_IO(!runnable); -#else - ERTS_CHK_IO( 1 ); -#endif - ASSERT(get_fsem(current_process()) == 0); - ERTS_SMP_LC_ASSERT(!erts_thr_progress_is_blocking()); -} - - -#ifdef ERTS_SMP - -void -erts_sys_main_thread(void) -{ - erts_thread_disable_fpe(); - - /* Become signal receiver thread... */ -#ifdef ERTS_ENABLE_LOCK_CHECK - erts_lc_set_thread_name("signal_receiver"); -#endif - - while (1) { - static const SIGSELECT sigsel[] = {0}; - union SIGNAL *msg = receive(sigsel); - - fprintf(stderr,"Main thread got message %d from 0x%x!!\r\n", - msg->sig_no, sender(&msg)); - free_buf(&msg); - } -} - -#endif /* ERTS_SMP */ - -void -erl_sys_args(int* argc, char** argv) -{ - int i, j; - - erts_smp_rwmtx_init(&environ_rwmtx, "environ"); - - init_check_io(); - - /* Handled arguments have been marked with NULL. Slide arguments - not handled towards the beginning of argv. */ - for (i = 0, j = 0; i < *argc; i++) { - if (argv[i]) - argv[j++] = argv[i]; - } - *argc = j; - -} diff --git a/erts/emulator/sys/ose/sys_float.c b/erts/emulator/sys/ose/sys_float.c deleted file mode 100644 index 3d9abc6bd1..0000000000 --- a/erts/emulator/sys/ose/sys_float.c +++ /dev/null @@ -1,845 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2001-2013. 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% - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "sys.h" -#include "global.h" -#include "erl_process.h" - - -#ifdef NO_FPE_SIGNALS - -void -erts_sys_init_float(void) -{ -# ifdef SIGFPE - sys_sigset(SIGFPE, SIG_IGN); /* Ignore so we can test for NaN and Inf */ -# endif -} - -#else /* !NO_FPE_SIGNALS */ - -#ifdef ERTS_SMP -static erts_tsd_key_t fpe_key; - -/* once-only initialisation early in the main thread (via erts_sys_init_float()) */ -static void erts_init_fp_exception(void) -{ - /* XXX: the wrappers prevent using a pthread destructor to - deallocate the key's value; so when/where do we do that? */ - erts_tsd_key_create(&fpe_key); -} - -void erts_thread_init_fp_exception(void) -{ - unsigned long *fpe = erts_alloc(ERTS_ALC_T_FP_EXCEPTION, sizeof(*fpe)); - *fpe = 0L; - erts_tsd_set(fpe_key, fpe); -} - -static ERTS_INLINE volatile unsigned long *erts_thread_get_fp_exception(void) -{ - return (volatile unsigned long*)erts_tsd_get(fpe_key); -} -#else /* !SMP */ -#define erts_init_fp_exception() /*empty*/ -static volatile unsigned long fp_exception; -#define erts_thread_get_fp_exception() (&fp_exception) -#endif /* SMP */ - -volatile unsigned long *erts_get_current_fp_exception(void) -{ - Process *c_p; - - c_p = erts_get_current_process(); - if (c_p) - return &c_p->fp_exception; - return erts_thread_get_fp_exception(); -} - -static void set_current_fp_exception(unsigned long pc) -{ - volatile unsigned long *fpexnp = erts_get_current_fp_exception(); - ASSERT(fpexnp != NULL); - *fpexnp = pc; -} - -void erts_fp_check_init_error(volatile unsigned long *fpexnp) -{ - char buf[64]; - snprintf(buf, sizeof buf, "ERTS_FP_CHECK_INIT at %p: detected unhandled FPE at %p\r\n", - __builtin_return_address(0), (void*)*fpexnp); - if (write(2, buf, strlen(buf)) <= 0) - erl_exit(ERTS_ABORT_EXIT, "%s", buf); - *fpexnp = 0; -#if defined(__i386__) || defined(__x86_64__) - erts_restore_fpu(); -#endif -} - -/* Is there no standard identifier for Darwin/MacOSX ? */ -#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) -#define __DARWIN__ 1 -#endif - -#if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) - -static void unmask_x87(void) -{ - unsigned short cw; - - __asm__ __volatile__("fstcw %0" : "=m"(cw)); - cw &= ~(0x01|0x04|0x08); /* unmask IM, ZM, OM */ - __asm__ __volatile__("fldcw %0" : : "m"(cw)); -} - -/* mask x87 FPE, return true if the previous state was unmasked */ -static int mask_x87(void) -{ - unsigned short cw; - int unmasked; - - __asm__ __volatile__("fstcw %0" : "=m"(cw)); - unmasked = (cw & (0x01|0x04|0x08)) == 0; - /* or just set cw = 0x37f */ - cw |= (0x01|0x04|0x08); /* mask IM, ZM, OM */ - __asm__ __volatile__("fldcw %0" : : "m"(cw)); - return unmasked; -} - -static void unmask_sse2(void) -{ - unsigned int mxcsr; - - __asm__ __volatile__("stmxcsr %0" : "=m"(mxcsr)); - mxcsr &= ~(0x003F|0x0680); /* clear exn flags, unmask OM, ZM, IM (not PM, UM, DM) */ - __asm__ __volatile__("ldmxcsr %0" : : "m"(mxcsr)); -} - -/* mask SSE2 FPE, return true if the previous state was unmasked */ -static int mask_sse2(void) -{ - unsigned int mxcsr; - int unmasked; - - __asm__ __volatile__("stmxcsr %0" : "=m"(mxcsr)); - unmasked = (mxcsr & 0x0680) == 0; - /* or just set mxcsr = 0x1f80 */ - mxcsr &= ~0x003F; /* clear exn flags */ - mxcsr |= 0x0680; /* mask OM, ZM, IM (not PM, UM, DM) */ - __asm__ __volatile__("ldmxcsr %0" : : "m"(mxcsr)); - return unmasked; -} - -#if defined(__x86_64__) - -static inline int cpu_has_sse2(void) { return 1; } - -#else /* !__x86_64__ */ - -/* - * Check if an x86-32 processor has SSE2. - */ -static unsigned int xor_eflags(unsigned int mask) -{ - unsigned int eax, edx; - - eax = mask; /* eax = mask */ - __asm__("pushfl\n\t" - "popl %0\n\t" /* edx = original EFLAGS */ - "xorl %0, %1\n\t" /* eax = mask ^ EFLAGS */ - "pushl %1\n\t" - "popfl\n\t" /* new EFLAGS = mask ^ original EFLAGS */ - "pushfl\n\t" - "popl %1\n\t" /* eax = new EFLAGS */ - "xorl %0, %1\n\t" /* eax = new EFLAGS ^ old EFLAGS */ - "pushl %0\n\t" - "popfl" /* restore original EFLAGS */ - : "=d"(edx), "=a"(eax) - : "1"(eax)); - return eax; -} - -static __inline__ unsigned int cpuid_eax(unsigned int op) -{ - unsigned int eax, save_ebx; - - /* In PIC mode i386 reserves EBX. So we must save - and restore it ourselves to not upset gcc. */ - __asm__( - "movl %%ebx, %1\n\t" - "cpuid\n\t" - "movl %1, %%ebx" - : "=a"(eax), "=m"(save_ebx) - : "0"(op) - : "cx", "dx"); - return eax; -} - -static __inline__ unsigned int cpuid_edx(unsigned int op) -{ - unsigned int eax, edx, save_ebx; - - /* In PIC mode i386 reserves EBX. So we must save - and restore it ourselves to not upset gcc. */ - __asm__( - "movl %%ebx, %2\n\t" - "cpuid\n\t" - "movl %2, %%ebx" - : "=a"(eax), "=d"(edx), "=m"(save_ebx) - : "0"(op) - : "cx"); - return edx; -} - -/* The AC bit, bit #18, is a new bit introduced in the EFLAGS - * register on the Intel486 processor to generate alignment - * faults. This bit cannot be set on the Intel386 processor. - */ -static __inline__ int is_386(void) -{ - return ((xor_eflags(1<<18) >> 18) & 1) == 0; -} - -/* Newer x86 processors have a CPUID instruction, as indicated by - * the ID bit (#21) in EFLAGS being modifiable. - */ -static __inline__ int has_CPUID(void) -{ - return (xor_eflags(1<<21) >> 21) & 1; -} - -static int cpu_has_sse2(void) -{ - unsigned int maxlev, features; - static int has_sse2 = -1; - - if (has_sse2 >= 0) - return has_sse2; - has_sse2 = 0; - - if (is_386()) - return 0; - if (!has_CPUID()) - return 0; - maxlev = cpuid_eax(0); - /* Intel A-step Pentium had a preliminary version of CPUID. - It also didn't have SSE2. */ - if ((maxlev & 0xFFFFFF00) == 0x0500) - return 0; - /* If max level is zero then CPUID cannot report any features. */ - if (maxlev == 0) - return 0; - features = cpuid_edx(1); - has_sse2 = (features & (1 << 26)) != 0; - - return has_sse2; -} -#endif /* !__x86_64__ */ - -static void unmask_fpe(void) -{ - __asm__ __volatile__("fnclex"); - unmask_x87(); - if (cpu_has_sse2()) - unmask_sse2(); -} - -static void unmask_fpe_conditional(int unmasked) -{ - if (unmasked) - unmask_fpe(); -} - -/* mask x86 FPE, return true if the previous state was unmasked */ -static int mask_fpe(void) -{ - int unmasked; - - unmasked = mask_x87(); - if (cpu_has_sse2()) - unmasked |= mask_sse2(); - return unmasked; -} - -void erts_restore_fpu(void) -{ - __asm__ __volatile__("fninit"); - unmask_x87(); - if (cpu_has_sse2()) - unmask_sse2(); -} - -#elif defined(__sparc__) && defined(__linux__) - -#if defined(__arch64__) -#define LDX "ldx" -#define STX "stx" -#else -#define LDX "ld" -#define STX "st" -#endif - -static void unmask_fpe(void) -{ - unsigned long fsr; - - __asm__(STX " %%fsr, %0" : "=m"(fsr)); - fsr &= ~(0x1FUL << 23); /* clear FSR[TEM] field */ - fsr |= (0x1AUL << 23); /* enable NV, OF, DZ exceptions */ - __asm__ __volatile__(LDX " %0, %%fsr" : : "m"(fsr)); -} - -static void unmask_fpe_conditional(int unmasked) -{ - if (unmasked) - unmask_fpe(); -} - -/* mask SPARC FPE, return true if the previous state was unmasked */ -static int mask_fpe(void) -{ - unsigned long fsr; - int unmasked; - - __asm__(STX " %%fsr, %0" : "=m"(fsr)); - unmasked = ((fsr >> 23) & 0x1A) == 0x1A; - fsr &= ~(0x1FUL << 23); /* clear FSR[TEM] field */ - __asm__ __volatile__(LDX " %0, %%fsr" : : "m"(fsr)); - return unmasked; -} - -#elif (defined(__powerpc__) && defined(__linux__)) || (defined(__ppc__) && defined(__DARWIN__)) - -#if defined(__linux__) -#include <sys/prctl.h> - -static void set_fpexc_precise(void) -{ - if (prctl(PR_SET_FPEXC, PR_FP_EXC_PRECISE) < 0) { - perror("PR_SET_FPEXC"); - exit(1); - } -} - -#elif defined(__DARWIN__) - -#include <mach/mach.h> -#include <pthread.h> - -/* - * FE0 FE1 MSR bits - * 0 0 floating-point exceptions disabled - * 0 1 floating-point imprecise nonrecoverable - * 1 0 floating-point imprecise recoverable - * 1 1 floating-point precise mode - * - * Apparently: - * - Darwin 5.5 (MacOS X <= 10.1) starts with FE0 == FE1 == 0, - * and resets FE0 and FE1 to 0 after each SIGFPE. - * - Darwin 6.0 (MacOS X 10.2) starts with FE0 == FE1 == 1, - * and does not reset FE0 or FE1 after a SIGFPE. - */ -#define FE0_MASK (1<<11) -#define FE1_MASK (1<<8) - -/* a thread cannot get or set its own MSR bits */ -static void *fpu_fpe_enable(void *arg) -{ - thread_t t = *(thread_t*)arg; - struct ppc_thread_state state; - unsigned int state_size = PPC_THREAD_STATE_COUNT; - - if (thread_get_state(t, PPC_THREAD_STATE, (natural_t*)&state, &state_size) != KERN_SUCCESS) { - perror("thread_get_state"); - exit(1); - } - if ((state.srr1 & (FE1_MASK|FE0_MASK)) != (FE1_MASK|FE0_MASK)) { -#if 1 - /* This would also have to be performed in the SIGFPE handler - to work around the MSR reset older Darwin releases do. */ - state.srr1 |= (FE1_MASK|FE0_MASK); - thread_set_state(t, PPC_THREAD_STATE, (natural_t*)&state, state_size); -#else - fprintf(stderr, "srr1 == 0x%08x, your Darwin is too old\n", state.srr1); - exit(1); -#endif - } - return NULL; /* Ok, we appear to be on Darwin 6.0 or later */ -} - -static void set_fpexc_precise(void) -{ - thread_t self = mach_thread_self(); - pthread_t enabler; - - if (pthread_create(&enabler, NULL, fpu_fpe_enable, &self)) { - perror("pthread_create"); - } else if (pthread_join(enabler, NULL)) { - perror("pthread_join"); - } -} - -#endif - -static void set_fpscr(unsigned int fpscr) -{ - union { - double d; - unsigned int fpscr[2]; - } u; - - u.fpscr[0] = 0xFFF80000; - u.fpscr[1] = fpscr; - __asm__ __volatile__("mtfsf 255,%0" : : "f"(u.d)); -} - -static unsigned int get_fpscr(void) -{ - union { - double d; - unsigned int fpscr[2]; - } u; - - __asm__("mffs %0" : "=f"(u.d)); - return u.fpscr[1]; -} - -static void unmask_fpe(void) -{ - set_fpexc_precise(); - set_fpscr(0x80|0x40|0x10); /* VE, OE, ZE; not UE or XE */ -} - -static void unmask_fpe_conditional(int unmasked) -{ - if (unmasked) - unmask_fpe(); -} - -/* mask PowerPC FPE, return true if the previous state was unmasked */ -static int mask_fpe(void) -{ - int unmasked; - - unmasked = (get_fpscr() & (0x80|0x40|0x10)) == (0x80|0x40|0x10); - set_fpscr(0x00); - return unmasked; -} - -#else - -static void unmask_fpe(void) -{ - fpsetmask(FP_X_INV | FP_X_OFL | FP_X_DZ); -} - -static void unmask_fpe_conditional(int unmasked) -{ - if (unmasked) - unmask_fpe(); -} - -/* mask IEEE FPE, return true if previous state was unmasked */ -static int mask_fpe(void) -{ - const fp_except unmasked_mask = FP_X_INV | FP_X_OFL | FP_X_DZ; - fp_except old_mask; - - old_mask = fpsetmask(0); - return (old_mask & unmasked_mask) == unmasked_mask; -} - -#endif - -#if (defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__sparc__) || defined(__powerpc__))) || (defined(__DARWIN__) && (defined(__i386__) || defined(__x86_64__) || defined(__ppc__))) || (defined(__FreeBSD__) && (defined(__x86_64__) || defined(__i386__))) || ((defined(__NetBSD__) || defined(__OpenBSD__)) && defined(__x86_64__)) || (defined(__sun__) && defined(__x86_64__)) - -#if defined(__linux__) && defined(__i386__) -#if !defined(X86_FXSR_MAGIC) -#define X86_FXSR_MAGIC 0x0000 -#endif -#elif defined(__FreeBSD__) && defined(__x86_64__) -#include <sys/types.h> -#include <machine/fpu.h> -#elif defined(__FreeBSD__) && defined(__i386__) -#include <sys/types.h> -#include <machine/npx.h> -#elif defined(__DARWIN__) -#include <machine/signal.h> -#elif defined(__OpenBSD__) && defined(__x86_64__) -#include <sys/types.h> -#include <machine/fpu.h> -#endif -#if !(defined(__OpenBSD__) && defined(__x86_64__)) -#include <ucontext.h> -#endif -#include <string.h> - -#if defined(__linux__) && defined(__x86_64__) -#define mc_pc(mc) ((mc)->gregs[REG_RIP]) -#elif defined(__linux__) && defined(__i386__) -#define mc_pc(mc) ((mc)->gregs[REG_EIP]) -#elif defined(__DARWIN__) && defined(__i386__) -#ifdef DARWIN_MODERN_MCONTEXT -#define mc_pc(mc) ((mc)->__ss.__eip) -#else -#define mc_pc(mc) ((mc)->ss.eip) -#endif -#elif defined(__DARWIN__) && defined(__x86_64__) -#ifdef DARWIN_MODERN_MCONTEXT -#define mc_pc(mc) ((mc)->__ss.__rip) -#else -#define mc_pc(mc) ((mc)->ss.rip) -#endif -#elif defined(__FreeBSD__) && defined(__x86_64__) -#define mc_pc(mc) ((mc)->mc_rip) -#elif defined(__FreeBSD__) && defined(__i386__) -#define mc_pc(mc) ((mc)->mc_eip) -#elif defined(__NetBSD__) && defined(__x86_64__) -#define mc_pc(mc) ((mc)->__gregs[_REG_RIP]) -#elif defined(__NetBSD__) && defined(__i386__) -#define mc_pc(mc) ((mc)->__gregs[_REG_EIP]) -#elif defined(__OpenBSD__) && defined(__x86_64__) -#define mc_pc(mc) ((mc)->sc_rip) -#elif defined(__sun__) && defined(__x86_64__) -#define mc_pc(mc) ((mc)->gregs[REG_RIP]) -#endif - -static void fpe_sig_action(int sig, siginfo_t *si, void *puc) -{ - ucontext_t *uc = puc; - unsigned long pc; - -#if defined(__linux__) -#if defined(__x86_64__) - mcontext_t *mc = &uc->uc_mcontext; - fpregset_t fpstate = mc->fpregs; - pc = mc_pc(mc); - /* A failed SSE2 instruction will restart. To avoid - looping we mask SSE2 exceptions now and unmask them - again later in erts_check_fpe()/erts_restore_fpu(). - On RISCs we update PC to skip the failed instruction, - but the ever increasing complexity of the x86 instruction - set encoding makes that a poor solution here. */ - fpstate->mxcsr = 0x1F80; - fpstate->swd &= ~0xFF; -#elif defined(__i386__) - mcontext_t *mc = &uc->uc_mcontext; - fpregset_t fpstate = mc->fpregs; - pc = mc_pc(mc); - if ((fpstate->status >> 16) == X86_FXSR_MAGIC) - ((struct _fpstate*)fpstate)->mxcsr = 0x1F80; - fpstate->sw &= ~0xFF; -#elif defined(__sparc__) && defined(__arch64__) - /* on SPARC the 3rd parameter points to a sigcontext not a ucontext */ - struct sigcontext *sc = (struct sigcontext*)puc; - pc = sc->sigc_regs.tpc; - sc->sigc_regs.tpc = sc->sigc_regs.tnpc; - sc->sigc_regs.tnpc += 4; -#elif defined(__sparc__) - /* on SPARC the 3rd parameter points to a sigcontext not a ucontext */ - struct sigcontext *sc = (struct sigcontext*)puc; - pc = sc->si_regs.pc; - sc->si_regs.pc = sc->si_regs.npc; - sc->si_regs.npc = (unsigned long)sc->si_regs.npc + 4; -#elif defined(__powerpc__) -#if defined(__powerpc64__) - mcontext_t *mc = &uc->uc_mcontext; - unsigned long *regs = &mc->gp_regs[0]; -#else - mcontext_t *mc = uc->uc_mcontext.uc_regs; - unsigned long *regs = &mc->gregs[0]; -#endif - pc = regs[PT_NIP]; - regs[PT_NIP] += 4; - regs[PT_FPSCR] = 0x80|0x40|0x10; /* VE, OE, ZE; not UE or XE */ -#endif -#elif defined(__DARWIN__) && (defined(__i386__) || defined(__x86_64__)) -#ifdef DARWIN_MODERN_MCONTEXT - mcontext_t mc = uc->uc_mcontext; - pc = mc_pc(mc); - mc->__fs.__fpu_mxcsr = 0x1F80; - *(unsigned short *)&mc->__fs.__fpu_fsw &= ~0xFF; -#else - mcontext_t mc = uc->uc_mcontext; - pc = mc_pc(mc); - mc->fs.fpu_mxcsr = 0x1F80; - *(unsigned short *)&mc->fs.fpu_fsw &= ~0xFF; -#endif /* DARWIN_MODERN_MCONTEXT */ -#elif defined(__DARWIN__) && defined(__ppc__) - mcontext_t mc = uc->uc_mcontext; - pc = mc->ss.srr0; - mc->ss.srr0 += 4; - mc->fs.fpscr = 0x80|0x40|0x10; -#elif defined(__FreeBSD__) && defined(__x86_64__) - mcontext_t *mc = &uc->uc_mcontext; - struct savefpu *savefpu = (struct savefpu*)&mc->mc_fpstate; - struct envxmm *envxmm = &savefpu->sv_env; - pc = mc_pc(mc); - envxmm->en_mxcsr = 0x1F80; - envxmm->en_sw &= ~0xFF; -#elif defined(__FreeBSD__) && defined(__i386__) - mcontext_t *mc = &uc->uc_mcontext; - union savefpu *savefpu = (union savefpu*)&mc->mc_fpstate; - pc = mc_pc(mc); - if (mc->mc_fpformat == _MC_FPFMT_XMM) { - struct envxmm *envxmm = &savefpu->sv_xmm.sv_env; - envxmm->en_mxcsr = 0x1F80; - envxmm->en_sw &= ~0xFF; - } else { - struct env87 *env87 = &savefpu->sv_87.sv_env; - env87->en_sw &= ~0xFF; - } -#elif defined(__NetBSD__) && defined(__x86_64__) - mcontext_t *mc = &uc->uc_mcontext; - struct fxsave64 *fxsave = (struct fxsave64 *)&mc->__fpregs; - pc = mc_pc(mc); - fxsave->fx_mxcsr = 0x1F80; - fxsave->fx_fsw &= ~0xFF; -#elif defined(__NetBSD__) && defined(__i386__) - mcontext_t *mc = &uc->uc_mcontext; - pc = mc_pc(mc); - if (uc->uc_flags & _UC_FXSAVE) { - struct envxmm *envxmm = (struct envxmm *)&mc->__fpregs; - envxmm->en_mxcsr = 0x1F80; - envxmm->en_sw &= ~0xFF; - } else { - struct env87 *env87 = (struct env87 *)&mc->__fpregs; - env87->en_sw &= ~0xFF; - } -#elif defined(__OpenBSD__) && defined(__x86_64__) - struct fxsave64 *fxsave = uc->sc_fpstate; - pc = mc_pc(uc); - fxsave->fx_mxcsr = 0x1F80; - fxsave->fx_fsw &= ~0xFF; -#elif defined(__sun__) && defined(__x86_64__) - mcontext_t *mc = &uc->uc_mcontext; - struct fpchip_state *fpstate = &mc->fpregs.fp_reg_set.fpchip_state; - pc = mc_pc(mc); - fpstate->mxcsr = 0x1F80; - fpstate->sw &= ~0xFF; -#endif -#if 0 - { - char buf[64]; - snprintf(buf, sizeof buf, "%s: FPE at %p\r\n", __FUNCTION__, (void*)pc); - write(2, buf, strlen(buf)); - } -#endif - set_current_fp_exception(pc); -} - -static void erts_thread_catch_fp_exceptions(void) -{ - struct sigaction act; - memset(&act, 0, sizeof act); - act.sa_sigaction = fpe_sig_action; - act.sa_flags = SA_SIGINFO; - sigaction(SIGFPE, &act, NULL); - unmask_fpe(); -} - -#else /* !((__linux__ && (__i386__ || __x86_64__ || __powerpc__)) || (__DARWIN__ && (__i386__ || __x86_64__ || __ppc__))) */ - -static void fpe_sig_handler(int sig) -{ - set_current_fp_exception(1); /* XXX: convert to sigaction so we can get the trap PC */ -} - -static void erts_thread_catch_fp_exceptions(void) -{ - sys_sigset(SIGFPE, fpe_sig_handler); - unmask_fpe(); -} - -#endif /* (__linux__ && (__i386__ || __x86_64__ || __powerpc__)) || (__DARWIN__ && (__i386__ || __x86_64__ || __ppc__))) */ - -/* once-only initialisation early in the main thread */ -void erts_sys_init_float(void) -{ - erts_init_fp_exception(); - erts_thread_catch_fp_exceptions(); - erts_printf_block_fpe = erts_sys_block_fpe; - erts_printf_unblock_fpe = erts_sys_unblock_fpe; -} - -#endif /* NO_FPE_SIGNALS */ - -void erts_thread_init_float(void) -{ -#ifdef ERTS_SMP - /* This allows Erlang schedulers to leave Erlang-process context - and still have working FP exceptions. XXX: is this needed? */ - erts_thread_init_fp_exception(); -#endif - -#ifndef NO_FPE_SIGNALS - /* NOTE: - * erts_thread_disable_fpe() is called in all threads at - * creation. We at least need to call unmask_fpe() - */ -#if defined(__DARWIN__) || defined(__FreeBSD__) - /* Darwin (7.9.0) does not appear to propagate FP exception settings - to a new thread from its parent. So if we want FP exceptions, we - must manually re-enable them in each new thread. - FreeBSD 6.1 appears to suffer from a similar issue. */ - erts_thread_catch_fp_exceptions(); -#else - unmask_fpe(); -#endif - -#endif -} - -void erts_thread_disable_fpe(void) -{ -#if !defined(NO_FPE_SIGNALS) - (void)mask_fpe(); -#endif -} - -#if !defined(NO_FPE_SIGNALS) -int erts_sys_block_fpe(void) -{ - return mask_fpe(); -} - -void erts_sys_unblock_fpe(int unmasked) -{ - unmask_fpe_conditional(unmasked); -} -#endif - -/* The following check is incorporated from the Vee machine */ - -#define ISDIGIT(d) ((d) >= '0' && (d) <= '9') - -/* - ** Convert a double to ascii format 0.dddde[+|-]ddd - ** return number of characters converted or -1 if error. - ** - ** These two functions should maybe use localeconv() to pick up - ** the current radix character, but since it is uncertain how - ** expensive such a system call is, and since no-one has heard - ** of other radix characters than '.' and ',' an ad-hoc - ** low execution time solution is used instead. - */ - -int -sys_double_to_chars_ext(double fp, char *buffer, size_t buffer_size, size_t decimals) -{ - char *s = buffer; - - if (erts_snprintf(buffer, buffer_size, "%.*e", decimals, fp) >= buffer_size) - return -1; - /* Search upto decimal point */ - if (*s == '+' || *s == '-') s++; - while (ISDIGIT(*s)) s++; - if (*s == ',') *s++ = '.'; /* Replace ',' with '.' */ - /* Scan to end of string */ - while (*s) s++; - return s-buffer; /* i.e strlen(buffer) */ -} - -/* Float conversion */ - -int -sys_chars_to_double(char* buf, double* fp) -{ -#ifndef NO_FPE_SIGNALS - volatile unsigned long *fpexnp = erts_get_current_fp_exception(); -#endif - char *s = buf, *t, *dp; - - /* Robert says that something like this is what he really wanted: - * (The [.,] radix test is NOT what Robert wanted - it was added later) - * - * 7 == sscanf(Tbuf, "%[+-]%[0-9][.,]%[0-9]%[eE]%[+-]%[0-9]%s", ....); - * if (*s2 == 0 || *s3 == 0 || *s4 == 0 || *s6 == 0 || *s7) - * break; - */ - - /* Scan string to check syntax. */ - if (*s == '+' || *s == '-') s++; - if (!ISDIGIT(*s)) /* Leading digits. */ - return -1; - while (ISDIGIT(*s)) s++; - if (*s != '.' && *s != ',') /* Decimal part. */ - return -1; - dp = s++; /* Remember decimal point pos just in case */ - if (!ISDIGIT(*s)) - return -1; - while (ISDIGIT(*s)) s++; - if (*s == 'e' || *s == 'E') { - /* There is an exponent. */ - s++; - if (*s == '+' || *s == '-') s++; - if (!ISDIGIT(*s)) - return -1; - while (ISDIGIT(*s)) s++; - } - if (*s) /* That should be it */ - return -1; - -#ifdef NO_FPE_SIGNALS - errno = 0; -#endif - __ERTS_FP_CHECK_INIT(fpexnp); - *fp = strtod(buf, &t); - __ERTS_FP_ERROR_THOROUGH(fpexnp, *fp, return -1); - if (t != s) { /* Whole string not scanned */ - /* Try again with other radix char */ - *dp = (*dp == '.') ? ',' : '.'; - errno = 0; - __ERTS_FP_CHECK_INIT(fpexnp); - *fp = strtod(buf, &t); - __ERTS_FP_ERROR_THOROUGH(fpexnp, *fp, return -1); - } - -#ifdef NO_FPE_SIGNALS - if (errno == ERANGE) { - if (*fp == HUGE_VAL || *fp == -HUGE_VAL) { - /* overflow, should give error */ - return -1; - } else if (t == s && *fp == 0.0) { - /* This should give 0.0 - OTP-7178 */ - errno = 0; - - } else if (*fp == 0.0) { - return -1; - } - } -#endif - return 0; -} - -int -matherr(struct exception *exc) -{ -#if !defined(NO_FPE_SIGNALS) - volatile unsigned long *fpexnp = erts_get_current_fp_exception(); - if (fpexnp != NULL) - *fpexnp = (unsigned long)__builtin_return_address(0); -#endif - return 1; -} diff --git a/erts/emulator/sys/ose/sys_time.c b/erts/emulator/sys/ose/sys_time.c deleted file mode 100644 index 5dac75956a..0000000000 --- a/erts/emulator/sys/ose/sys_time.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2005-2009. 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% - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "sys.h" -#include "global.h" - -/******************* Routines for time measurement *********************/ - -int erts_ticks_per_sec = 0; /* Will be SYS_CLK_TCK in erl_unix_sys.h */ - -int sys_init_time(void) -{ - return SYS_CLOCK_RESOLUTION; -} - -clock_t sys_times(SysTimes *now) { - now->tms_utime = now->tms_stime = now->tms_cutime = now->tms_cstime = 0; - return 0; -} - -static OSTICK last_tick_count = 0; -static SysHrTime wrap = 0; -static OSTICK us_per_tick; - -void sys_init_hrtime() { - us_per_tick = system_tick(); -} - -SysHrTime sys_gethrtime() { - OSTICK ticks = get_ticks(); - if (ticks < (SysHrTime) last_tick_count) { - wrap += 1ULL << 32; - } - last_tick_count = ticks; - return ((((SysHrTime) ticks) + wrap) * 1000*us_per_tick); -} diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl index 7c7ddde5d4..3ad1b88b2d 100644 --- a/erts/emulator/test/alloc_SUITE.erl +++ b/erts/emulator/test/alloc_SUITE.erl @@ -113,13 +113,10 @@ cpool(doc) -> []; cpool(Cfg) -> ?line drv_case(Cfg). erts_mmap(Config) when is_list(Config) -> - case {?t:os_type(), is_halfword_vm()} of - {{unix, _}, false} -> + case ?t:os_type() of + {unix, _} -> [erts_mmap_do(Config, SCO, SCRPM, SCRFSD) || SCO <-[true,false], SCRFSD <-[1234,0], SCRPM <- [true,false]]; - - {_,true} -> - {skipped, "No supercarrier support on halfword vm"}; {SkipOs,_} -> ?line {skipped, lists:flatten(["Not run on " @@ -254,10 +251,3 @@ start_node(Config, Opts) when is_list(Config), is_list(Opts) -> stop_node(Node) -> ?t:stop_node(Node). - -is_halfword_vm() -> - case {erlang:system_info({wordsize, internal}), - erlang:system_info({wordsize, external})} of - {4, 8} -> true; - {WS, WS} -> false - end. diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl index d6a771e7b9..ebc4db53c4 100644 --- a/erts/emulator/test/bif_SUITE.erl +++ b/erts/emulator/test/bif_SUITE.erl @@ -32,7 +32,8 @@ specs/1,improper_bif_stubs/1,auto_imports/1, t_list_to_existing_atom/1,os_env/1,otp_7526/1, binary_to_atom/1,binary_to_existing_atom/1, - atom_to_binary/1,min_max/1, erlang_halt/1]). + atom_to_binary/1,min_max/1, erlang_halt/1, + is_builtin/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -42,7 +43,7 @@ all() -> t_list_to_existing_atom, os_env, otp_7526, display, atom_to_binary, binary_to_atom, binary_to_existing_atom, - min_max, erlang_halt]. + min_max, erlang_halt, is_builtin]. groups() -> []. @@ -716,6 +717,22 @@ wait_until_stable_size(File,PrevSz) -> wait_until_stable_size(File,NewSz) end. +is_builtin(_Config) -> + Exp0 = [{M,F,A} || {M,_} <- code:all_loaded(), + {F,A} <- M:module_info(exports)], + Exp = ordsets:from_list(Exp0), + + %% erlang:apply/3 is considered to be built-in, but is not + %% implemented as other BIFs. + + Builtins0 = [{erlang,apply,3}|erlang:system_info(snifs)], + Builtins = ordsets:from_list(Builtins0), + NotBuiltin = ordsets:subtract(Exp, Builtins), + _ = [true = erlang:is_builtin(M, F, A) || {M,F,A} <- Builtins], + _ = [false = erlang:is_builtin(M, F, A) || {M,F,A} <- NotBuiltin], + + ok. + %% Helpers diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl index 4211c49848..b72d6cbe52 100644 --- a/erts/emulator/test/driver_SUITE.erl +++ b/erts/emulator/test/driver_SUITE.erl @@ -1877,10 +1877,7 @@ mseg_alloc_cached_segments() -> mseg_alloc_cached_segments(mseg_inst_info(0)). mseg_alloc_cached_segments(MsegAllocInfo) -> - MemName = case is_halfword_vm() of - true -> "high memory"; - false -> "all memory" - end, + MemName = "all memory", ?line [{memkind,DrvMem}] = lists:filter(fun(E) -> case E of {memkind, [{name, MemName} | _]} -> true; @@ -1899,13 +1896,6 @@ mseg_inst_info(I) -> erlang:system_info({allocator,mseg_alloc})), Value. -is_halfword_vm() -> - case {erlang:system_info({wordsize, internal}), - erlang:system_info({wordsize, external})} of - {4, 8} -> true; - {WS, WS} -> false - end. - driver_alloc_sbct() -> {_, _, _, As} = erlang:system_info(allocator), case lists:keysearch(driver_alloc, 1, As) of diff --git a/erts/emulator/test/emulator.spec.ose b/erts/emulator/test/emulator.spec.ose deleted file mode 100644 index 9f494609d9..0000000000 --- a/erts/emulator/test/emulator.spec.ose +++ /dev/null @@ -1,2 +0,0 @@ -{topcase, {dir, "../emulator_test"}}. -{skip, {obsolete_SUITE, "Not on ose"}}. diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl index f07f79b83d..90b6a36262 100644 --- a/erts/emulator/test/num_bif_SUITE.erl +++ b/erts/emulator/test/num_bif_SUITE.erl @@ -429,7 +429,7 @@ t_string_to_integer(Config) when is_list(Config) -> list_to_binary(Value))), {'EXIT', {badarg, _}} = (catch erlang:list_to_integer(Value)) - end,["1.0"," 1"," -1",""]), + end,["1.0"," 1"," -1","","+"]), % Custom base error cases lists:foreach(fun({Value,Base}) -> diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index 4c311e1f06..97aa5e573e 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -1478,7 +1478,15 @@ processes_this_tab(doc) -> processes_this_tab(suite) -> []; processes_this_tab(Config) when is_list(Config) -> - sys_mem_cond_run(1024, fun () -> chk_processes_bif_test_res(processes_bif_test()) end). + Mem = case {erlang:system_info(build_type), + erlang:system_info(allocator)} of + {lcnt, {_, _Vsn, [sys_alloc], _Opts}} -> + %% When running +Mea min + lcnt we may need more memory + 1024 * 4; + _ -> + 1024 + end, + sys_mem_cond_run(Mem, fun () -> chk_processes_bif_test_res(processes_bif_test()) end). chk_processes_bif_test_res(ok) -> ok; chk_processes_bif_test_res({comment, _} = Comment) -> Comment; diff --git a/erts/emulator/test/system_info_SUITE.erl b/erts/emulator/test/system_info_SUITE.erl index bee42c07d9..51122e5d55 100644 --- a/erts/emulator/test/system_info_SUITE.erl +++ b/erts/emulator/test/system_info_SUITE.erl @@ -185,8 +185,6 @@ wordsize(Config) when is_list(Config) -> {comment, "True 32-bit emulator"}; {8,8} -> {comment, "True 64-bit emulator"}; - {8,4} -> - {comment, "Halfword 64-bit emulator"}; Other -> exit({unexpected_wordsizes,Other}) end. diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops index 9a8c3585e6..f805e7cc64 100755 --- a/erts/emulator/utils/beam_makeops +++ b/erts/emulator/utils/beam_makeops @@ -48,12 +48,17 @@ $pack_shift[4] = ['0', 'BEAM_LOOSE_SHIFT', # Only for 64 bit wordsize '(3*BEAM_LOOSE_SHIFT)']; $pack_mask[2] = ['BEAM_LOOSE_MASK', $WHOLE_WORD]; -$pack_mask[3] = ['BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK']; +$pack_mask[3] = ['BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK', $WHOLE_WORD]; $pack_mask[4] = ['BEAM_LOOSE_MASK', # Only for 64 bit wordsize 'BEAM_LOOSE_MASK', 'BEAM_LOOSE_MASK', $WHOLE_WORD]; +# Mapping from packagable arguments to number of packed arguments per +# word. Initialized after the wordsize is known. + +my @args_per_word; + # There are two types of instructions: generic and specific. # The generic instructions are those generated by the Beam compiler. # Corresponding to each generic instruction, there is generally a @@ -176,11 +181,12 @@ sub define_type_bit { } # Composed types. - define_type_bit('d', $type_bit{'x'} | $type_bit{'y'} | $type_bit{'r'}); + define_type_bit('d', $type_bit{'x'} | $type_bit{'y'}); define_type_bit('c', $type_bit{'i'} | $type_bit{'a'} | $type_bit{'n'} | $type_bit{'q'}); define_type_bit('s', $type_bit{'d'} | $type_bit{'i'} | - $type_bit{'a'} | $type_bit{'n'}); + $type_bit{'a'} | $type_bit{'n'} | + $type_bit{'q'}); define_type_bit('j', $type_bit{'f'} | $type_bit{'p'}); # Aliases (for matching purposes). @@ -236,6 +242,20 @@ while (@ARGV && $ARGV[0] =~ /^-(.*)/) { } # +# Initialize number of arguments per packed word. +# + +$args_per_word[2] = 2; +$args_per_word[3] = 3; +$args_per_word[4] = 2; +$args_per_word[5] = 3; +$args_per_word[6] = 3; + +if ($wordsize == 64) { + $args_per_word[4] = 4; +} + +# # Parse the input files. # @@ -527,12 +547,16 @@ sub emulator_output { my(@bits) = (0) x ($max_spec_operands/2); my($i); + my $involves_r = 0; for ($i = 0; $i < $max_spec_operands && defined $args[$i]; $i++) { my $t = $args[$i]; - if (defined $type_bit{$t}) { - my $shift = $max_genop_types * ($i % 2); - $bits[int($i/2)] |= $type_bit{$t} << $shift; + my $bits = $type_bit{$t}; + if ($t eq 'r') { + $bits |= $type_bit{'x'}; + $involves_r |= 1 << $i; } + my $shift = $max_genop_types * ($i % 2); + $bits[int($i/2)] |= $bits << $shift; } printf "/* %3d */ ", $spec_opnum; @@ -544,7 +568,7 @@ sub emulator_output { $sep = ","; } $init .= "}"; - &init_item($print_name, $init, $size, $pack, $sign, 0); + init_item($print_name, $init, $involves_r, $size, $pack, $sign, 0); $op_to_name[$spec_opnum] = $instr; $spec_opnum++; } @@ -601,15 +625,12 @@ sub emulator_output { print "#define MAX_GENERIC_OPCODE ", $num_file_opcodes-1, "\n"; print "#define NUM_GENERIC_OPS ", scalar(@gen_opname), "\n"; print "#define NUM_SPECIFIC_OPS ", scalar(@op_to_name), "\n"; + print "#define SCRATCH_X_REG 1023\n"; print "\n"; print "#ifdef ARCH_64\n"; print "# define BEAM_WIDE_MASK 0xFFFFUL\n"; - print "# define BEAM_LOOSE_MASK 0x1FFFUL\n"; - print "#if HALFWORD_HEAP\n"; - print "# define BEAM_TIGHT_MASK 0x1FFCUL\n"; - print "#else\n"; - print "# define BEAM_TIGHT_MASK 0x1FF8UL\n"; - print "#endif\n"; + print "# define BEAM_LOOSE_MASK 0xFFFFUL\n"; + print "# define BEAM_TIGHT_MASK 0xFFFFUL\n"; print "# define BEAM_WIDE_SHIFT 32\n"; print "# define BEAM_LOOSE_SHIFT 16\n"; print "# define BEAM_TIGHT_SHIFT 16\n"; @@ -734,7 +755,7 @@ sub init_item { print "${sep}NULL"; } elsif (/^\{/) { print "$sep$_"; - } elsif (/^-?\d/) { + } elsif (/^-?\d+$/) { print "$sep$_"; } else { print "$sep\"$_\""; @@ -896,6 +917,7 @@ sub basic_generator { my($var_decls) = ''; my($gen_dest_arg) = 'StoreSimpleDest'; my($i); + my($no_prefetch) = 0; # The following argument types should be included as macro arguments. my(%incl_arg) = ('c' => 1, @@ -994,6 +1016,7 @@ sub basic_generator { # $flags =~ /-fail_action/ and do { + $no_prefetch = 1; if (!defined $fail_type) { my($i); for ($i = 0; $i < @f_types; $i++) { @@ -1040,6 +1063,12 @@ sub basic_generator { "I += $size + 1;", "goto $goto;", "}"); + } elsif ($no_prefetch) { + $code = join("\n", + "{ $var_decls", + $macro_code, + "Next($size);", + "}", ""); } else { $code = join("\n", "{ $var_decls", @@ -1061,6 +1090,7 @@ sub do_pack { my($packable_args) = 0; my @is_packable; # Packability (boolean) for each argument. my $wide_packing = 0; + my(@orig_args) = @args; # # Count the number of packable arguments. If we encounter any 's' or 'd' @@ -1081,6 +1111,18 @@ sub do_pack { } } elsif ($arg =~ /^[sd]/) { return ('', '', @args); + } elsif ($arg =~ /^[scq]/ and $packable_args > 0) { + # When packing, this operand will be picked up from the + # code array, put onto the packing stack, and later put + # back into a different location in the code. The problem + # is that if this operand is a literal, the original + # location in the code would have been remembered in a + # literal patch. For packing to work, we would have to + # adjust the position in the literal patch. For the + # moment, adding additional instructions to the packing + # engine to handle this does not seem worth it, so we will + # just turn off packing. + return ('', '', @args); } else { push @is_packable, 0; } @@ -1090,7 +1132,6 @@ sub do_pack { # Get out of here if too few or too many arguments. # return ('', '', @args) if $packable_args < 2; - &error("too many packable arguments") if $packable_args > 4; my($size) = 0; my($pack_prefix) = ''; @@ -1098,14 +1139,8 @@ sub do_pack { # beginning). my($up) = ''; # Pack commands (storing back while # moving forward). - my $args_per_word; - if ($packable_args < 4 or $wordsize == 64) { - $args_per_word = $packable_args; - } else { - # 4 packable argument, 32 bit wordsize. Need 2 words. - $args_per_word = 2; - } + my $args_per_word = $args_per_word[$packable_args]; my @shift; my @mask; my @instr; @@ -1299,6 +1334,8 @@ sub tr_parse_op { foreach (split('', $type)) { &error("bad type in $op") unless defined $type_bit{$_} or $type eq '*'; + $_ eq 'r' and + error("$op: 'r' is not allowed in transformations") } } @@ -1332,7 +1369,10 @@ sub tr_parse_op { } # Get an optional value. (In destination.) + $type_val = $type eq 'x' ? 1023 : 0; if (/^=(.*)/) { + error("value not allowed in source: $op") + if $src; $type_val = $1; $_ = ''; } @@ -1351,11 +1391,6 @@ sub tr_parse_op { if $var && $type; } - # Test that source has no values. - if ($src) { - error("value not allowed in source: $op") - if $type_val; - } ($var,$type,$type_val,$cond,$cond_val); } diff --git a/erts/emulator/utils/make_alloc_types b/erts/emulator/utils/make_alloc_types index 88f537ea09..925b9d5810 100755 --- a/erts/emulator/utils/make_alloc_types +++ b/erts/emulator/utils/make_alloc_types @@ -246,7 +246,7 @@ print DST " print DST "#define ERTS_ALC_C_MIN ($c_no)\n\n"; -foreach my $c (keys(%c_tab)) { +foreach my $c (sort keys(%c_tab)) { push(@c_order, $c); set_number($c_tab{$c}, $c_no); print DST "#define ERTS_ALC_C_$c ($c_no)\n"; diff --git a/erts/emulator/utils/make_version b/erts/emulator/utils/make_version index 3461dc1637..37bdff181a 100755 --- a/erts/emulator/utils/make_version +++ b/erts/emulator/utils/make_version @@ -59,7 +59,11 @@ print FILE <<EOF; #define ERLANG_OTP_RELEASE "$release" #define ERLANG_OTP_VERSION "$otp_version" #define ERLANG_VERSION "$version" -#define ERLANG_COMPILE_DATE "$time_str" +#if ERTS_SAVED_COMPILE_TIME +# define ERLANG_COMPILE_DATE "$time_str" +#else +# define ERLANG_COMPILE_DATE "" +#endif #define ERLANG_ARCHITECTURE "$architecture" EOF diff --git a/erts/emulator/utils/mkver.c b/erts/emulator/utils/mkver.c index 96cd315a95..6641873712 100644 --- a/erts/emulator/utils/mkver.c +++ b/erts/emulator/utils/mkver.c @@ -35,8 +35,10 @@ int argc; char** argv; { FILE *file; +#if ERTS_SAVED_COMPILE_TIME time_t now; - char *cnow; +#endif + char *cnow = ""; if (argc != 2) { fprintf(stderr, "usage: mkver version\n"); @@ -48,9 +50,11 @@ char** argv; exit(1); } +#if ERTS_SAVED_COMPILE_TIME time(&now); cnow = ctime(&now); cnow[24] = '\0'; /* tidelipom */ +#endif fprintf(file, "/* This file was created by mkver -- don't modify.*/\n"); fprintf(file, "#define ERLANG_VERSION \"%s\"\n", argv[1]); fprintf(file, "#define ERLANG_COMPILE_DATE \"%s\"\n", cnow); diff --git a/erts/emulator/valgrind/suppress.halfword b/erts/emulator/valgrind/suppress.halfword deleted file mode 100644 index 8fe448d897..0000000000 --- a/erts/emulator/valgrind/suppress.halfword +++ /dev/null @@ -1,56 +0,0 @@ -# Extra suppressions specific for the halfword emulator. - -# --- Suppress all offheap binaries --- -# Valgrinds leak check does not recognize pointers that are stored -# at unaligned addresses. In halfword emulator we store 64-bit pointers -# to offheap data on 32-bit aligned heaps. -# We solve this by suppressing allocation of all offheap structures -# that are not referenced by other tables (ie binaries). - -{ -Halfword erts_bin_nrml_alloc -Memcheck:Leak -... -fun:erts_bin_nrml_alloc -... -} - -{ -Halfword erts_bin_realloc -Memcheck:Leak -... -fun:erts_bin_realloc -... -} - -{ -Halfword erts_bin_realloc_fnf -Memcheck:Leak -... -fun:erts_bin_realloc_fnf -... -} - -{ -Halfword erts_bin_drv_alloc -Memcheck:Leak -... -fun:erts_bin_drv_alloc -... -} - -{ -Halfword erts_bin_drv_alloc_fnf -Memcheck:Leak -... -fun:erts_bin_drv_alloc_fnf -... -} - -{ -Halfword erts_create_magic_binary -Memcheck:Leak -... -fun:erts_create_magic_binary -... -} diff --git a/erts/epmd/src/Makefile.in b/erts/epmd/src/Makefile.in index b6e3ba7762..1266be44cb 100644 --- a/erts/epmd/src/Makefile.in +++ b/erts/epmd/src/Makefile.in @@ -19,10 +19,6 @@ # include $(ERL_TOP)/make/target.mk -ifeq ($(findstring ose,$(TARGET)),ose) -include $(ERL_TOP)/make/$(TARGET)/ose_lm.mk -endif - ifeq ($(TYPE),debug) PURIFY = TYPEMARKER = .debug @@ -32,21 +28,13 @@ else ifeq ($(TYPE),purify) PURIFY = purify TYPEMARKER = -ifeq ($(findstring ose,$(TARGET)),ose) - TYPE_FLAGS = -DPURIFY -else - TYPE_FLAGS = -O2 -DPURIFY -endif +TYPE_FLAGS = -O2 -DPURIFY else override TYPE = opt PURIFY = TYPEMARKER = -ifeq ($(findstring ose,$(TARGET)),ose) - TYPE_FLAGS = -else - TYPE_FLAGS = -O2 -endif +TYPE_FLAGS = -O2 endif endif @@ -68,13 +56,9 @@ else ifeq ($(findstring vxworks,$(TARGET)),vxworks) ERTS_INTERNAL_LIBS=-L../../lib/internal/$(TARGET) -lerts_internal$(ERTS_LIB_TYPEMARKER) @ERTS_INTERNAL_X_LIBS@ else -ifeq ($(findstring ose,$(TARGET)),ose) -ERTS_INTERNAL_LIBS=-L../../lib/internal/$(TARGET) -lerts_internal$(ERTS_LIB_TYPEMARKER) @ERTS_INTERNAL_X_LIBS@ -else ERTS_INTERNAL_LIBS=-L../../lib/internal/$(TARGET) -lerts_internal$(ERTS_LIB_TYPEMARKER) @ERTS_INTERNAL_X_LIBS@ -lm endif endif -endif ERTS_LIB = $(ERL_TOP)/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE @@ -82,11 +66,7 @@ CC = @CC@ WFLAGS = @WFLAGS@ CFLAGS = @CFLAGS@ @DEFS@ $(TYPE_FLAGS) $(WFLAGS) $(ERTS_INCL) LD = @LD@ -ifeq ($(findstring ose,$(TARGET)),ose) -LIBS = $(ERTS_INTERNAL_LIBS) @LIBS@ -else LIBS = @LIBS@ @SYSTEMD_DAEMON_LIBS@ $(ERTS_INTERNAL_LIBS) -endif LDFLAGS = @LDFLAGS@ @@ -135,25 +115,12 @@ clean: rm -f *.o rm -f *~ core -ifeq ($(findstring ose,$(TARGET)),ose) -$(OBJDIR)/ose_confd.o: $(OSE_CONFD) - $(V_CC) $(CFLAGS) -o $@ -c $< -$(OBJDIR)/crt0_lm.o: $(CRT0_LM) - $(V_CC) $(CFLAGS) -o $@ -c $< -OSE_LM_OBJS += $(OBJDIR)/ose_confd.o $(OBJDIR)/crt0_lm.o -endif - # # Objects & executables # -ifeq ($(findstring ose,$(TARGET)),ose) -$(BINDIR)/$(EPMD): $(EPMD_OBJS) $(ERTS_LIB) $(OSE_LM_OBJS) - $(call build-ose-load-module, $@, $(EPMD_OBJS) $(OSE_LM_OBJS), $(LIBS), $(EPMD_LMCONF)) -else $(BINDIR)/$(EPMD): $(EPMD_OBJS) $(ERTS_LIB) $(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) -o $@ $(EPMD_OBJS) $(LIBS) -endif $(OBJDIR)/%.o: %.c epmd.h epmd_int.h $(V_CC) $(CFLAGS) $(EPMD_FLAGS) -o $@ -c $< diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c index 132bda725c..7c373509be 100644 --- a/erts/epmd/src/epmd.c +++ b/erts/epmd/src/epmd.c @@ -397,7 +397,7 @@ static void run_daemon(EpmdVars *g) } #endif -#if defined(VXWORKS) || defined(__OSE__) +#if defined(VXWORKS) static void run_daemon(EpmdVars *g) { run(g); diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h index 26100afc93..e222abb4b7 100644 --- a/erts/epmd/src/epmd_int.h +++ b/erts/epmd/src/epmd_int.h @@ -37,13 +37,6 @@ #define DONT_USE_MAIN #endif -#ifdef __OSE__ -# define NO_DAEMON -# define NO_SYSLOG -# define NO_SYSCONF -# define NO_FCNTL -#endif - /* ************************************************************************ */ /* Standard includes */ @@ -100,12 +93,7 @@ #endif /* ! WIN32 */ #include <ctype.h> - -#if !defined(__OSE__) -# include <signal.h> -#endif - - +#include <signal.h> #include <errno.h> #ifdef HAVE_SYSLOG_H @@ -122,10 +110,6 @@ #include <stdarg.h> -#ifdef __OSE__ -# include "sys/select.h" -#endif - #ifdef HAVE_SYSTEMD_DAEMON # include <systemd/sd-daemon.h> #endif /* HAVE_SYSTEMD_DAEMON */ diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c index 8c8d7304f2..829eb4c74d 100644 --- a/erts/epmd/src/epmd_srv.c +++ b/erts/epmd/src/epmd_srv.c @@ -30,11 +30,6 @@ # define INADDR_NONE 0xffffffff #endif -#if defined(__OSE__) -# include "sys/ioctl.h" -# define sleep(x) delay(x*1000) -#endif - /* * * This server is a local name server for Erlang nodes. Erlang nodes can @@ -315,7 +310,7 @@ void run(EpmdVars *g) } #endif /* HAVE_SYSTEMD_DAEMON */ -#if !defined(__WIN32__) && !defined(__OSE__) +#if !defined(__WIN32__) /* We ignore the SIGPIPE signal that is raised when we call write twice on a socket closed by the other end. */ signal(SIGPIPE, SIG_IGN); diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in index 8e55fa78c9..05d925f19f 100644 --- a/erts/etc/common/Makefile.in +++ b/erts/etc/common/Makefile.in @@ -21,10 +21,6 @@ include $(ERL_TOP)/make/output.mk include $(ERL_TOP)/make/target.mk -ifeq ($(findstring ose,$(TARGET)),ose) -include $(ERL_TOP)/make/$(TARGET)/ose_lm.mk -endif - ERTS_LIB_TYPEMARKER=.$(TYPE) USING_MINGW=@MIXED_CYGWIN_MINGW@ @@ -85,18 +81,13 @@ EMUOSDIR = $(ERL_TOP)/erts/emulator/@ERLANG_OSTYPE@ SYSDIR = $(ERL_TOP)/erts/emulator/sys/@ERLANG_OSTYPE@ DRVDIR = $(ERL_TOP)/erts/emulator/drivers/@ERLANG_OSTYPE@ UXETC = ../unix -OSEETC = ../ose WINETC = ../win32 ifeq ($(TARGET), win32) ETC = $(WINETC) else -ifeq ($(findstring ose,$(TARGET)),ose) -ETC = $(OSEETC) -else ETC = $(UXETC) endif -endif ifeq ($(TARGET), win32) ERLEXEC = erlexec.dll @@ -180,25 +171,6 @@ PORT_ENTRY_POINT=erl_port_entry ENTRY_LDFLAGS=-entry:$(PORT_ENTRY_POINT) else -ifeq ($(findstring ose,$(TARGET)),ose) -ENTRY_LDFLAGS= -ENTRY_OBJ= -ERLSRV_OBJECTS= -MC_OUTPUTS= -INET_GETHOST = -INSTALL_EMBEDDED_PROGS = $(BINDIR)/run_erl_lm -INSTALL_EMBEDDED_DATA = -INSTALL_TOP = Install -INSTALL_TOP_BIN = -INSTALL_MISC = -INSTALL_SRC = -ERLEXECDIR = . -INSTALL_LIBS = -INSTALL_OBJS = -INSTALL_INCLUDES = -TEXTFILES = Install erl.src -INSTALL_PROGS = $(INSTALL_EMBEDDED_PROGS) -else # UNIX (!win32 && !ose) ENTRY_LDFLAGS= ENTRY_OBJ= ERLSRV_OBJECTS= @@ -223,7 +195,6 @@ INSTALL_PROGS = \ $(BINDIR)/$(ERLEXEC) \ $(INSTALL_EMBEDDED_PROGS) endif -endif .PHONY: etc etc: $(ENTRY_OBJ) $(INSTALL_PROGS) $(INSTALL_LIBS) $(TEXTFILES) $(INSTALL_TOP_BIN) @@ -269,8 +240,8 @@ endif rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/to_erl.o rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/dyn_erl.o rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/safe_string.o - rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/run_erl_common.o - rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/to_erl_common.o + rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/run_erl.o + rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/to_erl.o rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/typer.o rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/ct_run.o rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/vxcall.o @@ -423,28 +394,24 @@ $(BINDIR)/inet_gethost@EXEEXT@: $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(ERTS_LIB $(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(LIBS) $(ERTS_INTERNAL_LIBS) # run_erl -$(BINDIR)/run_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(OBJDIR)/run_erl_common.o - $(V_LD) $(LDFLAGS) -o $@ $^ $(LIBS) -$(OBJDIR)/run_erl.o: $(ETC)/run_erl.c ../common/run_erl_common.h $(RC_GENERATED) - $(V_CC) $(CFLAGS) -I ../common/ -o $@ -c $(ETC)/run_erl.c -$(OBJDIR)/run_erl_common.o: ../common/run_erl_common.c ../common/run_erl_common.h $(RC_GENERATED) - $(V_CC) $(CFLAGS) -o $@ -c $< +$(BINDIR)/run_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o + $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(LIBS) +$(OBJDIR)/run_erl.o: $(ETC)/run_erl.c $(RC_GENERATED) + $(V_CC) $(CFLAGS) -o $@ -c $(ETC)/run_erl.c # to_erl -$(BINDIR)/to_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o $(OBJDIR)/to_erl_common.o - $(V_LD) $(LDFLAGS) -o $@ $^ -$(OBJDIR)/to_erl.o: $(ETC)/to_erl.c ../common/safe_string.h $(RC_GENERATED) - $(V_CC) $(CFLAGS) -I ../common/ -o $@ -c $(ETC)/to_erl.c -$(OBJDIR)/to_erl_common.o: ../common/to_erl_common.c ../common/to_erl_common.h $(RC_GENERATED) - $(V_CC) $(CFLAGS) -o $@ -c $< +$(BINDIR)/to_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o + $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o +$(OBJDIR)/to_erl.o: $(ETC)/to_erl.c $(RC_GENERATED) + $(V_CC) $(CFLAGS) -o $@ -c $(ETC)/to_erl.c # dyn_erl $(BINDIR)/dyn_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o $(OBJDIR)/dyn_erl.o: $(UXETC)/dyn_erl.c $(RC_GENERATED) $(V_CC) $(CFLAGS) -o $@ -c $(UXETC)/dyn_erl.c -$(OBJDIR)/safe_string.o: ../common/safe_string.c $(RC_GENERATED) - $(V_CC) $(CFLAGS) -o $@ -c ../common/safe_string.c +$(OBJDIR)/safe_string.o: $(ETC)/safe_string.c $(RC_GENERATED) + $(V_CC) $(CFLAGS) -o $@ -c $(ETC)/safe_string.c ifneq ($(TARGET),win32) $(BINDIR)/$(ERLEXEC): $(OBJDIR)/$(ERLEXEC).o $(ERTS_LIB) @@ -499,30 +466,6 @@ erl.src: $(UXETC)/erl.src.src ../../vsn.mk $(TARGET)/Makefile -e 's;%VSN%;$(VSN);' \ $(UXETC)/erl.src.src > erl.src -#--------------------------------------------------------- -# OSE specific targets -#--------------------------------------------------------- -ifeq ($(findstring ose,$(TARGET)),ose) -$(OBJDIR)/ose_confd.o: $(OSE_CONFD) - $(V_CC) $(CFLAGS) -o $@ -c $< -$(OBJDIR)/crt0_lm.o: $(CRT0_LM) - $(V_CC) $(CFLAGS) -o $@ -c $< -OSE_LM_OBJS += $(OBJDIR)/ose_confd.o $(OBJDIR)/crt0_lm.o - -$(BINDIR)/run_erl_lm: $(OBJDIR)/run_erl_main.o $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(OBJDIR)/run_erl_common.o $(OBJDIR)/to_erl_common.o $(OSE_LM_OBJS) - $(call build-ose-load-module, $@, $^, $(LIBS), $(RUN_ERL_LMCONF)) - - -$(OBJDIR)/run_erl_main.o: $(OSEETC)/run_erl_main.c $(OSEETC)/run_erl.h ../common/to_erl_common.h $(RC_GENERATED) - $(V_CC) $(CFLAGS) -I ../common/ -o $@ -c $(OSEETC)/run_erl_main.c - -endif - -#--------------------------------------------------------- -# End of ose specific targets. -#--------------------------------------------------------- - - # ---------------------------------------------------- # Release Target # ---------------------------------------------------- @@ -537,11 +480,9 @@ endif $(INSTALL_DIR) "$(RELEASE_PATH)/erts-$(VSN)/bin" ifneq ($(TARGET), win32) ifneq ($(findstring vxworks,$(TARGET)), vxworks) -ifneq ($(findstring ose,$(TARGET)), ose) $(INSTALL_SCRIPT) erl.src "$(RELEASE_PATH)/erts-$(VSN)/bin" endif endif -endif ifneq ($(INSTALL_PROGS),) $(INSTALL_PROGRAM) $(INSTALL_PROGS) "$(RELEASE_PATH)/erts-$(VSN)/bin" endif diff --git a/erts/etc/common/run_erl_common.c b/erts/etc/common/run_erl_common.c deleted file mode 100644 index c03d5e3ae2..0000000000 --- a/erts/etc/common/run_erl_common.c +++ /dev/null @@ -1,696 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2014. 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% - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <time.h> -#include <unistd.h> - -#ifdef __ANDROID__ -# include <termios.h> -#endif - -#ifdef HAVE_SYSLOG_H -# include <syslog.h> -#endif - -#ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -#endif - -#ifdef __OSE__ -# include "ramlog.h" -#endif - -#include "run_erl_common.h" -#include "safe_string.h" - -#define DEFAULT_LOG_GENERATIONS 5 -#define LOG_MAX_GENERATIONS 1000 /* No more than 1000 log files */ -#define LOG_MIN_GENERATIONS 2 /* At least two to switch between */ -#define DEFAULT_LOG_MAXSIZE 100000 -#define LOG_MIN_MAXSIZE 1000 /* Smallast value for changing log file */ -#define LOG_STUBNAME "erlang.log." -#define LOG_PERM 0664 -#define DEFAULT_LOG_ACTIVITY_MINUTES 5 -#define DEFAULT_LOG_ALIVE_MINUTES 15 -#define DEFAULT_LOG_ALIVE_FORMAT "%a %b %e %T %Z %Y" -#define ALIVE_BUFFSIZ 1024 - -#define STATUSFILENAME "/run_erl.log" - -#define PIPE_STUBNAME "erlang.pipe" -#define PIPE_STUBLEN strlen(PIPE_STUBNAME) -#define PERM (S_IWUSR | S_IRUSR | S_IWOTH | S_IROTH | S_IWGRP | S_IRGRP) - -/* OSE has defined O_SYNC but it is not recognized by open */ -#if !defined(O_SYNC) || defined(__OSE__) -#undef O_SYNC -#define O_SYNC 0 -#define USE_FSYNC 1 -#endif - -/* Global variable definitions - * We need this complex way of handling global variables because of how - * OSE works here. We want to make it possible to run the shell command - * run_erl multiple times with different global variables without them - * effecting eachother. - */ - -#define STATUSFILE (RE_DATA->statusfile) -#define LOG_DIR (RE_DATA->log_dir) -#define STDSTATUS (RE_DATA->stdstatus) -#define LOG_GENERATIONS (RE_DATA->log_generations) -#define LOG_MAXSIZE (RE_DATA->log_maxsize) -#define LOG_ACTIVITY_MINUTES (RE_DATA->log_activity_minutes) -#define LOG_ALIVE_IN_GMT (RE_DATA->log_alive_in_gmt) -#define LOG_ALIVE_FORMAT (RE_DATA->log_alive_format) -#define RUN_DAEMON (RE_DATA->run_daemon) -#define LOG_ALIVE_MINUTES (RE_DATA->log_alive_minutes) -#define LOG_NUM (RE_DATA->log_num) -#define LFD (RE_DATA->lfd) -#define PROTOCOL_VER (RE_DATA->protocol_ver) - -struct run_erl_ { - /* constant config data */ - char statusfile[FILENAME_BUFSIZ]; - char log_dir[FILENAME_BUFSIZ]; - FILE *stdstatus; - int log_generations; - int log_maxsize; - int log_activity_minutes; - int log_alive_in_gmt; - char log_alive_format[ALIVE_BUFFSIZ+1]; - int run_daemon; - int log_alive_minutes; - /* Current log number and log fd */ - int log_num; - int lfd; - unsigned protocol_ver; -}; - -typedef struct run_erl_ run_erl; - -#ifdef __OSE__ -static OSPPDKEY run_erl_pp_key; -#define RE_DATA (*(run_erl**)ose_get_ppdata(run_erl_pp_key)) -#else -static run_erl re; -#define RE_DATA (&re) -#endif - -/* prototypes */ - -static int next_log(int log_num); -static int prev_log(int log_num); -static int find_next_log_num(void); -static int open_log(int log_num, int flags); - -/* - * getenv_int: - */ -static char *getenv_int(const char *name) { -#ifdef __OSE__ - return get_env(get_bid(current_process()),name); -#else - return getenv(name); -#endif -} - -/* - * next_log: - * Returns the index number that follows the given index number. - * (Wrapping after log_generations) - */ -static int next_log(int log_num) { - return log_num>=LOG_GENERATIONS?1:log_num+1; -} - -/* - * prev_log: - * Returns the index number that precedes the given index number. - * (Wrapping after log_generations) - */ -static int prev_log(int log_num) { - return log_num<=1?LOG_GENERATIONS:log_num-1; -} - -/* - * find_next_log_num() - * Searches through the log directory to check which logs that already - * exist. It finds the "hole" in the sequence, and returns the index - * number for the last log in the log sequence. If there is no hole, index - * 1 is returned. - */ -static int find_next_log_num(void) { - int i, next_gen, log_gen; - DIR *dirp; - struct dirent *direntp; - int log_exists[LOG_MAX_GENERATIONS+1]; - int stub_len = strlen(LOG_STUBNAME); - - /* Initialize exiting log table */ - - for(i=LOG_GENERATIONS; i>=0; i--) - log_exists[i] = 0; - dirp = opendir(LOG_DIR); - if(!dirp) { - ERRNO_ERR1(LOG_ERR,"Can't access log directory '%s'", LOG_DIR); - exit(1); - } - - /* Check the directory for existing logs */ - - while((direntp=readdir(dirp)) != NULL) { - if(strncmp(direntp->d_name,LOG_STUBNAME,stub_len)==0) { - int num = atoi(direntp->d_name+stub_len); - if(num < 1 || num > LOG_GENERATIONS) - continue; - log_exists[num] = 1; - } - } - closedir(dirp); - - /* Find out the next available log file number */ - - next_gen = 0; - for(i=LOG_GENERATIONS; i>=0; i--) { - if(log_exists[i]) - if(next_gen) - break; - else - ; - else - next_gen = i; - } - - /* Find out the current log file number */ - - if(next_gen) - log_gen = prev_log(next_gen); - else - log_gen = 1; - - return log_gen; -} /* find_next_log_num() */ - -static int open_log(int log_num, int flags) -{ - char buf[FILENAME_MAX]; - time_t now; - struct tm *tmptr; - char log_buffer[ALIVE_BUFFSIZ+1]; - - /* Remove the next log (to keep a "hole" in the log sequence) */ - sn_printf(buf, sizeof(buf), "%s/%s%d", - LOG_DIR, LOG_STUBNAME, next_log(log_num)); - unlink(buf); - - /* Create or continue on the current log file */ - sn_printf(buf, sizeof(buf), "%s/%s%d", LOG_DIR, LOG_STUBNAME, log_num); - - LFD = sf_open(buf, flags, LOG_PERM); - - if(LFD <0){ - ERRNO_ERR1(LOG_ERR,"Can't open log file '%s'.", buf); - exit(1); - } - - /* Write a LOGGING STARTED and time stamp into the log file */ - time(&now); - if (LOG_ALIVE_IN_GMT) { - tmptr = gmtime(&now); - } else { - tmptr = localtime(&now); - } - if (!strftime(log_buffer, ALIVE_BUFFSIZ, LOG_ALIVE_FORMAT, - tmptr)) { - strn_cpy(log_buffer, sizeof(log_buffer), - "(could not format time in 256 positions " - "with current format string.)"); - } - log_buffer[ALIVE_BUFFSIZ] = '\0'; - - sn_printf(buf, sizeof(buf), "\n=====\n===== LOGGING STARTED %s\n=====\n", - log_buffer); - if (erts_run_erl_write_all(LFD, buf, strlen(buf)) < 0) - erts_run_erl_log_status("Error in writing to log.\n"); - -#if USE_FSYNC - fsync(LFD); -#endif - - return LFD; -} - -/* Instead of making sure basename exists, we do our own */ -char *simple_basename(char *path) -{ - char *ptr; - for (ptr = path; *ptr != '\0'; ++ptr) { - if (*ptr == '/') { - path = ptr + 1; - } - } - return path; -} - -ssize_t sf_read(int fd, void *buffer, size_t len) { - ssize_t n = 0; - - do { n = read(fd, buffer, len); } while (n < 0 && errno == EINTR); - - return n; -} - -ssize_t sf_write(int fd, const void *buffer, size_t len) { - ssize_t n = 0; - - do { n = write(fd, buffer, len); } while (n < 0 && errno == EINTR); - - return n; -} - -int sf_open(const char *path, int type, mode_t mode) { - int fd = 0; - - do { fd = open(path, type, mode); } while(fd < 0 && errno == EINTR); - - return fd; -} - -int sf_close(int fd) { - int res = 0; - - do { res = close(fd); } while(res < 0 && errno == EINTR); - - return res; -} - -/* Call write() until entire buffer has been written or error. - * Return len or -1. - */ -int erts_run_erl_write_all(int fd, const char* buf, int len) -{ - int left = len; - int written; - for (;;) { - do { - written = write(fd,buf,left); - } while (written < 0 && errno == EINTR); - if (written == left) { - return len; - } - if (written < 0) { - return -1; - } - left -= written; - buf += written; - } - return written; -} - -/* erts_run_erl_log_status() - * Prints the arguments to a status file - * Works like printf (see vfrpintf) - */ -void erts_run_erl_log_status(const char *format,...) -{ - va_list args; - time_t now; - - if (STDSTATUS == NULL) - STDSTATUS = fopen(STATUSFILE, "w"); - if (STDSTATUS == NULL) - return; - now = time(NULL); - fprintf(STDSTATUS, "run_erl [%d] %s", -#ifdef __OSE__ - (int)current_process(), -#else - (int)getpid(), -#endif - ctime(&now)); - va_start(args, format); - vfprintf(STDSTATUS, format, args); - va_end(args); - fflush(STDSTATUS); - return; -} - -/* Fetch the current log alive minutes */ -int erts_run_erl_log_alive_minutes() { - return LOG_ALIVE_MINUTES; -} - -/* error_logf() - * Prints the arguments to stderr or syslog - * Works like printf (see vfprintf) - */ -void erts_run_erl_log_error(int priority, int line, const char *format, ...) -{ - va_list args; - va_start(args, format); - -#ifdef HAVE_SYSLOG_H - if (RUN_DAEMON) { - vsyslog(priority,format,args); - } - else -#endif -#ifdef __OSE__ - if (RUN_DAEMON) { - char *buff = malloc(sizeof(char)*1024); - vsnprintf(buff,1024,format, args); - ramlog_printf(buff); - } - else -#endif - { - time_t now = time(NULL); - fprintf(stderr, "run_erl:%d [%d] %s", line, -#ifdef __OSE__ - (int)current_process(), -#else - (int)getpid(), -#endif - ctime(&now)); - vfprintf(stderr, format, args); - } - va_end(args); -} - -/* erts_run_erl_log_write() - * Writes a message to lfd. If the current log file is full, - * a new log file is opened. - */ -int erts_run_erl_log_write(char* buf, size_t len) -{ - int size; - ssize_t res; - /* Decide if new logfile needed, and open if so */ - - size = lseek(LFD,0,SEEK_END); - if(size+len > LOG_MAXSIZE) { - int res; - do { - res = close(LFD); - } while (res < 0 && errno == EINTR); - LOG_NUM = next_log(LOG_NUM); - LFD = open_log(LOG_NUM, O_RDWR|O_CREAT|O_TRUNC|O_SYNC); - } - - /* Write to log file */ - - if ((res = erts_run_erl_write_all(LFD, buf, len)) < 0) { - erts_run_erl_log_status("Error in writing to log.\n"); - } - -#if USE_FSYNC - fsync(LFD); -#endif - return res; -} - -int erts_run_erl_log_activity(int timeout,time_t now,time_t last_activity) { - char log_alive_buffer[ALIVE_BUFFSIZ+1]; - char buf[BUFSIZ]; - - if (timeout || now - last_activity > LOG_ACTIVITY_MINUTES*60) { - /* Either a time out: 15 minutes without action, */ - /* or something is coming in right now, but it's a long time */ - /* since last time, so let's write a time stamp this message */ - struct tm *tmptr; - if (LOG_ALIVE_IN_GMT) { - tmptr = gmtime(&now); - } else { - tmptr = localtime(&now); - } - if (!strftime(log_alive_buffer, ALIVE_BUFFSIZ, LOG_ALIVE_FORMAT, - tmptr)) { - strn_cpy(log_alive_buffer, sizeof(log_alive_buffer), - "(could not format time in 256 positions " - "with current format string.)"); - } - log_alive_buffer[ALIVE_BUFFSIZ] = '\0'; - - sn_printf(buf, sizeof(buf), "\n===== %s%s\n", - timeout?"ALIVE ":"", log_alive_buffer); - return erts_run_erl_log_write(buf, strlen(buf)); - } - return 0; -} - -int erts_run_erl_log_open() { - - LOG_NUM = find_next_log_num(); - LFD = open_log(LOG_NUM, O_RDWR|O_APPEND|O_CREAT|O_SYNC); - return 0; -} - -int erts_run_erl_log_init(int daemon, char* logdir) { - char *p; - -#ifdef __OSE__ - run_erl **re_pp; - if (!run_erl_pp_key) - ose_create_ppdata("run_erl_ppdata",&run_erl_pp_key); - re_pp = (run_erl **)ose_get_ppdata(run_erl_pp_key); - *re_pp = malloc(sizeof(run_erl)); -#endif - - STDSTATUS = NULL; - LOG_GENERATIONS = DEFAULT_LOG_GENERATIONS; - LOG_MAXSIZE = DEFAULT_LOG_MAXSIZE; - LOG_ACTIVITY_MINUTES = DEFAULT_LOG_ACTIVITY_MINUTES; - LOG_ALIVE_IN_GMT = 0; - RUN_DAEMON = 0; - LOG_ALIVE_MINUTES = DEFAULT_LOG_ALIVE_MINUTES; - LFD = 0; - PROTOCOL_VER = RUN_ERL_LO_VER; /* assume lowest to begin with */ - - /* Get values for LOG file handling from the environment */ - if ((p = getenv_int("RUN_ERL_LOG_ALIVE_MINUTES"))) { - LOG_ALIVE_MINUTES = atoi(p); - if (!LOG_ALIVE_MINUTES) { - ERROR1(LOG_ERR,"Minimum value for RUN_ERL_LOG_ALIVE_MINUTES is 1 " - "(current value is %s)",p); - } - LOG_ACTIVITY_MINUTES = LOG_ALIVE_MINUTES / 3; - if (!LOG_ACTIVITY_MINUTES) { - ++LOG_ACTIVITY_MINUTES; - } - } - if ((p = getenv_int( - "RUN_ERL_LOG_ACTIVITY_MINUTES"))) { - LOG_ACTIVITY_MINUTES = atoi(p); - if (!LOG_ACTIVITY_MINUTES) { - ERROR1(LOG_ERR,"Minimum value for RUN_ERL_LOG_ACTIVITY_MINUTES is 1 " - "(current value is %s)",p); - } - } - if ((p = getenv_int("RUN_ERL_LOG_ALIVE_FORMAT"))) { - if (strlen(p) > ALIVE_BUFFSIZ) { - ERROR1(LOG_ERR, "RUN_ERL_LOG_ALIVE_FORMAT can contain a maximum of " - "%d characters", ALIVE_BUFFSIZ); - } - strn_cpy(LOG_ALIVE_FORMAT, sizeof(LOG_ALIVE_FORMAT), p); - } else { - strn_cpy(LOG_ALIVE_FORMAT, sizeof(LOG_ALIVE_FORMAT), - DEFAULT_LOG_ALIVE_FORMAT); - } - if ((p = getenv_int("RUN_ERL_LOG_ALIVE_IN_UTC")) - && strcmp(p,"0")) { - ++LOG_ALIVE_IN_GMT; - } - if ((p = getenv_int("RUN_ERL_LOG_GENERATIONS"))) { - LOG_GENERATIONS = atoi(p); - if (LOG_GENERATIONS < LOG_MIN_GENERATIONS) - ERROR1(LOG_ERR,"Minimum RUN_ERL_LOG_GENERATIONS is %d", - LOG_MIN_GENERATIONS); - if (LOG_GENERATIONS > LOG_MAX_GENERATIONS) - ERROR1(LOG_ERR,"Maximum RUN_ERL_LOG_GENERATIONS is %d", - LOG_MAX_GENERATIONS); - } - - if ((p = getenv_int("RUN_ERL_LOG_MAXSIZE"))) { - LOG_MAXSIZE = atoi(p); - if (LOG_MAXSIZE < LOG_MIN_MAXSIZE) - ERROR1(LOG_ERR,"Minimum RUN_ERL_LOG_MAXSIZE is %d", LOG_MIN_MAXSIZE); - } - - RUN_DAEMON = daemon; - - strn_cpy(LOG_DIR, sizeof(LOG_DIR), logdir); - strn_cpy(STATUSFILE, sizeof(STATUSFILE), LOG_DIR); - strn_cat(STATUSFILE, sizeof(STATUSFILE), STATUSFILENAME); - - return 0; -} - -/* create_fifo() - * Creates a new fifo with the given name and permission. - */ -static int create_fifo(char *name, int perm) -{ - if ((mkfifo(name, perm) < 0) && (errno != EEXIST)) - return -1; - return 0; -} - -/* - * w- and r_pipename have to be pre-allocated of atleast FILENAME_MAX size - */ -int erts_run_erl_open_fifo(char *pipename,char *w_pipename,char *r_pipename) { - int calculated_pipename = 0; - int highest_pipe_num = 0; - int fd; - - /* - * Create FIFOs and open them - */ - - if(*pipename && pipename[strlen(pipename)-1] == '/') { - /* The user wishes us to find a unique pipe name in the specified */ - /* directory */ - DIR *dirp; - struct dirent *direntp; - - calculated_pipename = 1; - dirp = opendir(pipename); - if(!dirp) { - ERRNO_ERR1(LOG_ERR,"Can't access pipe directory '%s'.", pipename); - return 1; - } - - /* Check the directory for existing pipes */ - - while((direntp=readdir(dirp)) != NULL) { - if(strncmp(direntp->d_name,PIPE_STUBNAME,PIPE_STUBLEN)==0) { - int num = atoi(direntp->d_name+PIPE_STUBLEN+1); - if(num > highest_pipe_num) - highest_pipe_num = num; - } - } - closedir(dirp); - strn_catf(pipename, BUFSIZ, "%s.%d", - PIPE_STUBNAME, highest_pipe_num+1); - } /* if */ - - for(;;) { - /* write FIFO - is read FIFO for `to_erl' program */ - strn_cpy(w_pipename, BUFSIZ, pipename); - strn_cat(w_pipename, BUFSIZ, ".r"); - if (create_fifo(w_pipename, PERM) < 0) { - ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for writing.", - w_pipename); - return 1; - } - - /* read FIFO - is write FIFO for `to_erl' program */ - strn_cpy(r_pipename, BUFSIZ, pipename); - strn_cat(r_pipename, BUFSIZ, ".w"); - - /* Check that nobody is running run_erl already */ - if ((fd = sf_open(r_pipename, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) { - /* Open as client succeeded -- run_erl is already running! */ - sf_close(fd); - if (calculated_pipename) { - ++highest_pipe_num; - strn_catf(pipename, BUFSIZ, "%s.%d", - PIPE_STUBNAME, highest_pipe_num+1); - continue; - } - ERROR1(LOG_ERR, "Erlang already running on pipe %s.\n", pipename); - unlink(w_pipename); - return 1; - } - if (create_fifo(r_pipename, PERM) < 0) { - unlink(w_pipename); - ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for reading.", - r_pipename); - return 1; - } - break; - } - return 0; -} - -/* Extract any control sequences that are ment only for run_erl - * and should not be forwarded to the pty. - */ -int erts_run_erl_extract_ctrl_seq(char* buf, int len, int mfd) -{ - static const char prefix[] = "\033_"; - static const char suffix[] = "\033\\"; - char* bufend = buf + len; - char* start = buf; - char* command; - char* end; - - for (;;) { - start = find_str(start, bufend-start, prefix); - if (!start) break; - - command = start + strlen(prefix); - end = find_str(command, bufend-command, suffix); - if (end) { - unsigned col, row; - if (sscanf(command,"version=%u", &PROTOCOL_VER)==1) { - /*fprintf(stderr,"to_erl v%u\n", protocol_ver);*/ - } - else if (sscanf(command,"winsize=%u,%u", &col, &row)==2) { -#ifdef TIOCSWINSZ - struct winsize ws; - ws.ws_col = col; - ws.ws_row = row; - if (ioctl(mfd, TIOCSWINSZ, &ws) < 0) { - ERRNO_ERR0(LOG_ERR,"Failed to set window size"); - } -#endif - } - else { - ERROR2(LOG_ERR, "Ignoring unknown ctrl command '%.*s'\n", - (int)(end-command), command); - } - - /* Remove ctrl sequence from buf */ - end += strlen(suffix); - memmove(start, end, bufend-end); - bufend -= end - start; - } - else { - ERROR2(LOG_ERR, "Missing suffix in ctrl sequence '%.*s'\n", - (int)(bufend-start), start); - break; - } - } - return bufend - buf; -} diff --git a/erts/etc/common/run_erl_common.h b/erts/etc/common/run_erl_common.h deleted file mode 100644 index cecf7521f9..0000000000 --- a/erts/etc/common/run_erl_common.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2013. 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% - */ -/* - * Functions that are common to both OSE and unix implementations of run_erl - */ -#ifndef ERL_RUN_ERL_LOG_H -#define ERL_RUN_ERL_LOG_H - -#include <stdio.h> -#include <time.h> -#include <unistd.h> - -#include "run_erl_vsn.h" - -/* Log handling */ -int erts_run_erl_log_init(int run_daemon, char* logdir); -int erts_run_erl_log_open(void); -int erts_run_erl_log_close(void); -int erts_run_erl_log_write(char *buff, size_t len); -int erts_run_erl_log_activity(int timeout, time_t now, time_t last_activity); - -void erts_run_erl_log_status(const char *format,...); -void erts_run_erl_log_error(int priority, int line, const char *format,...); - -int erts_run_erl_open_fifo(char *pipename,char *w_pipename,char *r_pipename); -int erts_run_erl_log_alive_minutes(void); -int erts_run_erl_extract_ctrl_seq(char* buf, int len, int mfd); - -/* File operations */ -ssize_t sf_read(int fd, void *buffer, size_t len); -ssize_t sf_write(int fd, const void *buffer, size_t len); -int sf_open(const char *path, int type, mode_t mode); -int sf_close(int fd); -int erts_run_erl_write_all(int fd, const char* buf, int len); -char *simple_basename(char *path); - -#ifndef LOG_ERR -#ifdef __OSE__ -#define LOG_ERR 0 -#else -#define LOG_ERR NULL -#endif -#endif - -#define ERROR0(Prio,Format) erts_run_erl_log_error(Prio,__LINE__,Format"\n") -#define ERROR1(Prio,Format,A1) erts_run_erl_log_error(Prio,__LINE__,Format"\n",A1) -#define ERROR2(Prio,Format,A1,A2) erts_run_erl_log_error(Prio,__LINE__,Format"\n",A1,A2) - -#ifdef HAVE_STRERROR -# define ADD_ERRNO(Format) "errno=%d '%s'\n"Format"\n",errno,strerror(errno) -#else -# define ADD_ERRNO(Format) "errno=%d\n"Format"\n",errno -#endif -#define ERRNO_ERR0(Prio,Format) erts_run_erl_log_error(Prio,__LINE__,ADD_ERRNO(Format)) -#define ERRNO_ERR1(Prio,Format,A1) erts_run_erl_log_error(Prio,__LINE__,ADD_ERRNO(Format),A1) -#define ERRNO_ERR2(Prio,Format,A1,A2) erts_run_erl_log_error(Prio,__LINE__,ADD_ERRNO(Format),A1,A2) - -#define RUN_ERL_USAGE \ - "%s (pipe_name|pipe_dir/) log_dir \"command [parameters ...]\"" \ - "\n\nDESCRIPTION:\n" \ - "You may also set the environment variables RUN_ERL_LOG_GENERATIONS\n" \ - "and RUN_ERL_LOG_MAXSIZE to the number of log files to use and the\n" \ - "size of the log file when to switch to the next log file\n" - -#ifndef FILENAME_MAX -#define FILENAME_MAX 250 -#endif - -#define FILENAME_BUFSIZ FILENAME_MAX - -#ifdef O_NONBLOCK -# define DONT_BLOCK_PLEASE O_NONBLOCK -#else -# define DONT_BLOCK_PLEASE O_NDELAY -# ifndef EAGAIN -# define EAGAIN -3898734 -# endif -#endif - -#endif diff --git a/erts/etc/common/to_erl_common.c b/erts/etc/common/to_erl_common.c deleted file mode 100644 index 8aa94ccfa4..0000000000 --- a/erts/etc/common/to_erl_common.c +++ /dev/null @@ -1,717 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 1996-2013. 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% - */ -/* - * Module: to_erl.c - * - * This module implements a process that opens two specified FIFOs, one - * for reading and one for writing; reads from its stdin, and writes what - * it has read to the write FIF0; reads from the read FIFO, and writes to - * its stdout. - * - ________ _________ - | |--<-- pipe.r (fifo1) --<--| | - | to_erl | | run_erl | (parent) - |________|-->-- pipe.w (fifo2) -->--|_________| - ^ master pty - | - | slave pty - ____V____ - | | - | "erl" | (child) - |_________| - */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/types.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <dirent.h> -#include <errno.h> - -#ifdef __OSE__ -#include <aio.h> -#include "ose.h" -#include "efs.h" -#include "ose_spi/fm.sig" -#else /* __UNIX__ */ -#include <termios.h> -#include <signal.h> -#endif - -#ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -#endif - -#include "to_erl_common.h" -#include "run_erl_vsn.h" -#include "safe_string.h" /* strn_cpy, strn_catf, sn_printf, etc. */ - -#if defined(O_NONBLOCK) -# define DONT_BLOCK_PLEASE O_NONBLOCK -#else -# define DONT_BLOCK_PLEASE O_NDELAY -# if !defined(EAGAIN) -# define EAGAIN -3898734 -# endif -#endif - -#ifdef HAVE_STRERROR -# define STRERROR(x) strerror(x) -#else -# define STRERROR(x) "" -#endif - -#define noDEBUG - -#ifdef __OSE__ -#define PIPE_DIR "/pipe/" -#else -#define PIPE_DIR "/tmp/" -#endif -#define PIPE_STUBNAME "erlang.pipe" -#define PIPE_STUBLEN strlen(PIPE_STUBNAME) - -#ifdef DEBUG -#define STATUS(s) { fprintf(stderr, (s)); fflush(stderr); } -#else -#define STATUS(s) -#endif - -#ifndef FILENAME_MAX -#define FILENAME_MAX 250 -#endif - -static int tty_eof = 0; -static int protocol_ver = RUN_ERL_LO_VER; /* assume lowest to begin with */ - -static int write_all(int fd, const char* buf, int len); -static int version_handshake(char* buf, int len, int wfd); - - -#ifdef __OSE__ - -#define SET_AIO(REQ,FD,SIZE,BUFF) \ - /* Make sure to clean data structure of previous request */ \ - memset(&(REQ),0,sizeof(REQ)); \ - (REQ).aio_fildes = FD; \ - (REQ).aio_offset = FM_POSITION_CURRENT; \ - (REQ).aio_nbytes = SIZE; \ - (REQ).aio_buf = BUFF; \ - (REQ).aio_sigevent.sigev_notify = SIGEV_NONE - -#define READ_AIO(REQ,FD,SIZE,BUFF) \ - SET_AIO(REQ,FD,SIZE,BUFF); \ - if (aio_read(&(REQ)) != 0) \ - fprintf(stderr,"aio_read of child_read_req(%d) failed" \ - "with error %d\n",FD,errno) - -union SIGNAL { - SIGSELECT signo; - struct FmReadPtr fm_read_ptr; -}; - -#else /* __UNIX__ */ -static int recv_sig = 0; -static struct termios tty_smode, tty_rmode; -static int window_size_seq(char* buf, size_t bufsz); -#ifdef DEBUG -static void show_terminal_settings(struct termios *); -#endif - -static void handle_ctrlc(int sig) -{ - /* Reinstall the handler, and signal break flag */ - signal(SIGINT,handle_ctrlc); - recv_sig = SIGINT; -} - -static void handle_sigwinch(int sig) -{ - recv_sig = SIGWINCH; -} -#endif - -static void usage(char *pname) -{ - fprintf(stderr, "Usage: "); - fprintf(stderr,TO_ERL_USAGE,pname); -} - -int to_erl(int argc, char **argv) -{ - char FIFO1[FILENAME_MAX], FIFO2[FILENAME_MAX]; - int i, len, wfd, rfd; - char pipename[FILENAME_MAX]; - int pipeIx = 1; - int force_lock = 0; - int got_some = 0; - -#ifdef __OSE__ - struct aiocb stdin_read_req, pipe_read_req; - FmHandle stdin_fh, pipe_fh; - char *stdin_buf, *pipe_buf; - char *buf; - union SIGNAL *sig; -#else /* __UNIX__ */ - char buf[BUFSIZ]; - fd_set readfds; -#endif - - if (argc >= 2 && argv[1][0]=='-') { - switch (argv[1][1]) { - case 'h': - usage(argv[0]); - exit(1); - case 'F': - force_lock = 1; - break; - default: - fprintf(stderr,"Invalid option '%s'\n",argv[1]); - exit(1); - } - pipeIx = 2; - } - -#ifdef DEBUG - fprintf(stderr, "%s: pid is : %d\n", argv[0],(int) -#ifdef __OSE__ - current_process() -#else /* __UNIX__ */ - getpid() -#endif - ); -#endif - - strn_cpy(pipename, sizeof(pipename), - (argv[pipeIx] ? argv[pipeIx] : PIPE_DIR)); - - if(*pipename && pipename[strlen(pipename)-1] == '/') { - /* The user wishes us to find a pipe name in the specified */ - /* directory */ - int highest_pipe_num = 0; - DIR *dirp; - struct dirent *direntp; - - dirp = opendir(pipename); - if(!dirp) { - fprintf(stderr, "Can't access pipe directory %s: %s\n", pipename, strerror(errno)); - exit(1); - } - - /* Check the directory for existing pipes */ - - while((direntp=readdir(dirp)) != NULL) { - if(strncmp(direntp->d_name,PIPE_STUBNAME,PIPE_STUBLEN)==0) { - int num = atoi(direntp->d_name+PIPE_STUBLEN+1); - if(num > highest_pipe_num) - highest_pipe_num = num; - } - } - closedir(dirp); - strn_catf(pipename, sizeof(pipename), (highest_pipe_num?"%s.%d":"%s"), - PIPE_STUBNAME, highest_pipe_num); - } /* if */ - - /* read FIFO */ - sn_printf(FIFO1,sizeof(FIFO1),"%s.r",pipename); - /* write FIFO */ - sn_printf(FIFO2,sizeof(FIFO2),"%s.w",pipename); - -#ifndef __OSE__ - /* Check that nobody is running to_erl on this pipe already */ - if ((wfd = open (FIFO1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) { - /* Open as server succeeded -- to_erl is already running! */ - close(wfd); - fprintf(stderr, "Another to_erl process already attached to pipe " - "%s.\n", pipename); - if (force_lock) { - fprintf(stderr, "But we proceed anyway by force (-F).\n"); - } - else { - exit(1); - } - } -#endif - - if ((rfd = open (FIFO1, O_RDONLY|DONT_BLOCK_PLEASE, 0)) < 0) { -#ifdef DEBUG - fprintf(stderr, "Could not open FIFO %s for reading.\n", FIFO1); -#endif - fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno)); - exit(1); - } -#ifdef DEBUG - fprintf(stderr, "to_erl: %s opened for reading\n", FIFO1); -#endif - - if ((wfd = open (FIFO2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) { -#ifdef DEBUG - fprintf(stderr, "Could not open FIFO %s for writing.\n", FIFO2); -#endif - fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno)); - close(rfd); - exit(1); - } -#ifdef DEBUG - fprintf(stderr, "to_erl: %s opened for writing\n", FIFO2); -#endif - -#ifndef __OSE__ - fprintf(stderr, "Attaching to %s (^D to exit)\n\n", pipename); -#else - fprintf(stderr, "Attaching to %s (^C to exit)\n\n", pipename); -#endif - -#ifndef __OSE__ - /* Set break handler to our handler */ - signal(SIGINT,handle_ctrlc); - - /* - * Save the current state of the terminal, and set raw mode. - */ - if (tcgetattr(0, &tty_rmode) , 0) { - fprintf(stderr, "Cannot get terminals current mode\n"); - exit(-1); - } - tty_smode = tty_rmode; - tty_eof = '\004'; /* Ctrl+D to exit */ -#ifdef DEBUG - show_terminal_settings(&tty_rmode); -#endif - tty_smode.c_iflag = - 1*BRKINT |/*Signal interrupt on break.*/ - 1*IGNPAR |/*Ignore characters with parity errors.*/ - 1*ISTRIP |/*Strip character.*/ - 0; - -#if 0 -0*IGNBRK |/*Ignore break condition.*/ -0*PARMRK |/*Mark parity errors.*/ -0*INPCK |/*Enable input parity check.*/ -0*INLCR |/*Map NL to CR on input.*/ -0*IGNCR |/*Ignore CR.*/ -0*ICRNL |/*Map CR to NL on input.*/ -0*IUCLC |/*Map upper-case to lower-case on input.*/ -0*IXON |/*Enable start/stop output control.*/ -0*IXANY |/*Enable any character to restart output.*/ -0*IXOFF |/*Enable start/stop input control.*/ -0*IMAXBEL|/*Echo BEL on input line too long.*/ -#endif - - tty_smode.c_oflag = - 1*OPOST |/*Post-process output.*/ - 1*ONLCR |/*Map NL to CR-NL on output.*/ -#ifdef XTABS - 1*XTABS |/*Expand tabs to spaces. (Linux)*/ -#endif -#ifdef OXTABS - 1*OXTABS |/*Expand tabs to spaces. (FreeBSD)*/ -#endif -#ifdef NL0 - 1*NL0 |/*Select newline delays*/ -#endif -#ifdef CR0 - 1*CR0 |/*Select carriage-return delays*/ -#endif -#ifdef TAB0 - 1*TAB0 |/*Select horizontal tab delays*/ -#endif -#ifdef BS0 - 1*BS0 |/*Select backspace delays*/ -#endif -#ifdef VT0 - 1*VT0 |/*Select vertical tab delays*/ -#endif -#ifdef FF0 - 1*FF0 |/*Select form feed delays*/ -#endif - 0; - -#if 0 -0*OLCUC |/*Map lower case to upper on output.*/ -0*OCRNL |/*Map CR to NL on output.*/ -0*ONOCR |/*No CR output at column 0.*/ -0*ONLRET |/*NL performs CR function.*/ -0*OFILL |/*Use fill characters for delay.*/ -0*OFDEL |/*Fill is DEL, else NULL.*/ -0*NL1 | -0*CR1 | -0*CR2 | -0*CR3 | -0*TAB1 | -0*TAB2 | -0*TAB3 |/*Expand tabs to spaces.*/ -0*BS1 | -0*VT1 | -0*FF1 | -#endif - - /* JALI: removed setting the tty_smode.c_cflag flags, since this is not */ - /* advisable if this is a *real* terminal, such as the console. In fact */ - /* this may hang the entire machine, deep, deep down (signalling break */ - /* or toggling the abort switch doesn't help) */ - - tty_smode.c_lflag = - 0; - -#if 0 -0*ISIG |/*Enable signals.*/ -0*ICANON |/*Canonical input (erase and kill processing).*/ -0*XCASE |/*Canonical upper/lower presentation.*/ -0*ECHO |/*Enable echo.*/ -0*ECHOE |/*Echo erase character as BS-SP-BS.*/ -0*ECHOK |/*Echo NL after kill character.*/ -0*ECHONL |/*Echo NL.*/ -0*NOFLSH |/*Disable flush after interrupt or quit.*/ -0*TOSTOP |/*Send SIGTTOU for background output.*/ -0*ECHOCTL|/*Echo control characters as ^char, delete as ^?.*/ -0*ECHOPRT|/*Echo erase character as character erased.*/ -0*ECHOKE |/*BS-SP-BS erase entire line on line kill.*/ -0*FLUSHO |/*Output is being flushed.*/ -0*PENDIN |/*Retype pending input at next read or input character.*/ -0*IEXTEN |/*Enable extended (implementation-defined) functions.*/ -#endif - - tty_smode.c_cc[VMIN] =0;/* Note that VMIN is the same as VEOF! */ - tty_smode.c_cc[VTIME] =0;/* Note that VTIME is the same as VEOL! */ - tty_smode.c_cc[VINTR] =3; - - tcsetattr(0, TCSADRAIN, &tty_smode); - -#ifdef DEBUG - show_terminal_settings(&tty_smode); -#endif - -#endif /* !__OSE__ */ - /* - * "Write a ^L to the FIFO which causes the other end to redisplay - * the input line." - * This does not seem to work as was intended in old comment above. - * However, this control character is now (R12B-3) used by run_erl - * to trigger the version handshaking between to_erl and run_erl - * at the start of every new to_erl-session. - */ - - if (write(wfd, "\014", 1) < 0) { - fprintf(stderr, "Error in writing ^L to FIFO.\n"); - } - -#ifdef __OSE__ - /* we have a tiny stack so we malloc the buffers */ - stdin_buf = malloc(sizeof(char) * BUFSIZ); - pipe_buf = malloc(sizeof(char) * BUFSIZ); - - efs_examine_fd(rfd,FLIB_FD_HANDLE,&pipe_fh); - efs_examine_fd(0,FLIB_FD_HANDLE,&stdin_fh); - READ_AIO(stdin_read_req,0,BUFSIZ,stdin_buf); - READ_AIO(pipe_read_req,rfd,BUFSIZ,pipe_buf); -#endif - - /* - * read and write - */ - while (1) { -#ifndef __OSE__ - FD_ZERO(&readfds); - FD_SET(0, &readfds); - FD_SET(rfd, &readfds); - if (select(rfd + 1, &readfds, NULL, NULL, NULL) < 0) { - if (recv_sig) { - FD_ZERO(&readfds); - } - else { - fprintf(stderr, "Error in select.\n"); - break; - } - } - len = 0; - - /* - * Read from terminal and write to FIFO - */ - if (recv_sig) { - switch (recv_sig) { - case SIGINT: - fprintf(stderr, "[Break]\n\r"); - buf[0] = '\003'; - len = 1; - break; - case SIGWINCH: - len = window_size_seq(buf,sizeof(buf)); - break; - default: - fprintf(stderr,"Unexpected signal: %u\n",recv_sig); - } - recv_sig = 0; - } - else -#else /* __OSE__ */ - SIGSELECT sigsel[] = {0}; - sig = receive(sigsel); - len = 0; -#endif -#ifndef __OSE__ - if (FD_ISSET(0,&readfds)) { - len = read(0, buf, sizeof(buf)); -#else /* __OSE__ */ - if (sig->signo == FM_READ_PTR_REPLY && - sig->fm_read_ptr.handle == stdin_fh) { - len = sig->fm_read_ptr.status == EFS_SUCCESS ? sig->fm_read_ptr.actual : -1; - buf = sig->fm_read_ptr.buffer; -#endif - if (len <= 0) { - close(rfd); - close(wfd); - if (len < 0) { - fprintf(stderr, "Error in reading from stdin.\n"); - } else { - fprintf(stderr, "[EOF]\n\r"); - } - break; - } - /* check if there is an eof character in input */ - for (i = 0; i < len-1 && buf[i] != tty_eof; i++); - if (buf[i] == tty_eof) { - fprintf(stderr, "[Quit]\n\r"); - break; - } - } - - if (len) { -#ifdef DEBUG - if(write(1, buf, len)); -#endif - if (write_all(wfd, buf, len) != len) { - fprintf(stderr, "Error in writing to FIFO.\n"); - close(rfd); - close(wfd); - break; - } - STATUS("\" OK\r\n"); -#ifdef __OSE__ - aio_dispatch(sig); - READ_AIO(stdin_read_req, 0, BUFSIZ, stdin_buf); -#endif - } - - /* - * Read from FIFO, write to terminal. - */ -#ifndef __OSE__ - if (FD_ISSET(rfd, &readfds)) { - STATUS("FIFO read: "); - len = read(rfd, buf, BUFSIZ); -#else /* __OSE__ */ - if (sig->signo == FM_READ_PTR_REPLY && - sig->fm_read_ptr.handle == pipe_fh) { - len = sig->fm_read_ptr.status == EFS_SUCCESS ? sig->fm_read_ptr.actual : -1; - buf = sig->fm_read_ptr.buffer; -#endif - if (len < 0 && errno == EAGAIN) { - /* - * No data this time, but the writing end of the FIFO is still open. - * Do nothing. - */ - ; - } else if (len <= 0) { - /* - * Either an error or end of file. In either case, break out - * of the loop. - */ - close(rfd); - close(wfd); - if (len < 0) { - fprintf(stderr, "Error in reading from FIFO.\n"); - } else - fprintf(stderr, "[End]\n\r"); - break; - } else { - if (!got_some) { - if ((len=version_handshake(buf,len,wfd)) < 0) { - close(rfd); - close(wfd); - break; - } -#ifndef __OSE__ - if (protocol_ver >= 1) { - /* Tell run_erl size of terminal window */ - signal(SIGWINCH, handle_sigwinch); - raise(SIGWINCH); - } -#endif - got_some = 1; - } - - /* - * We successfully read at least one character. Write what we got. - */ - STATUS("Terminal write: \""); - if (write_all(1, buf, len) != len) { - fprintf(stderr, "Error in writing to terminal.\n"); - close(rfd); - close(wfd); - break; - } - STATUS("\" OK\r\n"); -#ifdef __OSE__ - aio_dispatch(sig); - READ_AIO(pipe_read_req, rfd, BUFSIZ, pipe_buf); -#endif - } - } - } - -#ifndef __OSE__ - /* - * Reset terminal characterstics - * XXX - */ - tcsetattr(0, TCSADRAIN, &tty_rmode); -#endif - return 0; -} - -/* Call write() until entire buffer has been written or error. - * Return len or -1. - */ -static int write_all(int fd, const char* buf, int len) -{ - int left = len; - int written; - while (left) { - written = write(fd,buf,left); - if (written < 0) { - return -1; - } - left -= written; - buf += written; - } - return len; -} - -#ifndef __OSE__ -static int window_size_seq(char* buf, size_t bufsz) -{ -#ifdef TIOCGWINSZ - struct winsize ws; - static const char prefix[] = "\033_"; - static const char suffix[] = "\033\\"; - /* This Esc sequence is called "Application Program Command" - and seems suitable to use for our own customized stuff. */ - - if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) { - int len = sn_printf(buf, bufsz, "%swinsize=%u,%u%s", - prefix, ws.ws_col, ws.ws_row, suffix); - return len; - } -#endif /* TIOCGWINSZ */ - return 0; -} -#endif /* !__OSE__ */ - -/* to_erl run_erl - * | | - * |---------- '\014' -------->| (session start) - * | | - * |<---- "[run_erl v1-0]" ----| (version interval) - * | | - * |--- Esc_"version=1"Esc\ -->| (common version) - * | | - */ -static int version_handshake(char* buf, int len, int wfd) -{ - unsigned re_high=0, re_low; - char *end = find_str(buf,len,"]\n"); - - if (end && sscanf(buf,"[run_erl v%u-%u",&re_high,&re_low)==2) { - char wbuf[30]; - int wlen; - - if (re_low > RUN_ERL_HI_VER || re_high < RUN_ERL_LO_VER) { - fprintf(stderr,"Incompatible versions: to_erl=v%u-%u run_erl=v%u-%u\n", - RUN_ERL_HI_VER, RUN_ERL_LO_VER, re_high, re_low); - return -1; - } - /* Choose highest common version */ - protocol_ver = re_high < RUN_ERL_HI_VER ? re_high : RUN_ERL_HI_VER; - - wlen = sn_printf(wbuf, sizeof(wbuf), "\033_version=%u\033\\", - protocol_ver); - if (write_all(wfd, wbuf, wlen) < 0) { - fprintf(stderr,"Failed to send version handshake\n"); - return -1; - } - end += 2; - len -= (end-buf); - memmove(buf,end,len); - - } - else { /* we assume old run_erl without version handshake */ - protocol_ver = 0; - } - - if (re_high != RUN_ERL_HI_VER) { - fprintf(stderr,"run_erl has different version, " - "using common protocol level %u\n", protocol_ver); - } - - return len; -} - - -#if defined(DEBUG) && !defined(__OSE__) -#define S(x) ((x) > 0 ? 1 : 0) - -static void show_terminal_settings(struct termios *t) -{ - fprintf(stderr,"c_iflag:\n"); - fprintf(stderr,"Signal interrupt on break: BRKINT %d\n", S(t->c_iflag & BRKINT)); - fprintf(stderr,"Map CR to NL on input: ICRNL %d\n", S(t->c_iflag & ICRNL)); - fprintf(stderr,"Ignore break condition: IGNBRK %d\n", S(t->c_iflag & IGNBRK)); - fprintf(stderr,"Ignore CR: IGNCR %d\n", S(t->c_iflag & IGNCR)); - fprintf(stderr,"Ignore char with par. err's: IGNPAR %d\n", S(t->c_iflag & IGNPAR)); - fprintf(stderr,"Map NL to CR on input: INLCR %d\n", S(t->c_iflag & INLCR)); - fprintf(stderr,"Enable input parity check: INPCK %d\n", S(t->c_iflag & INPCK)); - fprintf(stderr,"Strip character ISTRIP %d\n", S(t->c_iflag & ISTRIP)); - fprintf(stderr,"Enable start/stop input ctrl IXOFF %d\n", S(t->c_iflag & IXOFF)); - fprintf(stderr,"ditto output ctrl IXON %d\n", S(t->c_iflag & IXON)); - fprintf(stderr,"Mark parity errors PARMRK %d\n", S(t->c_iflag & PARMRK)); - fprintf(stderr,"\n"); - fprintf(stderr,"c_oflag:\n"); - fprintf(stderr,"Perform output processing OPOST %d\n", S(t->c_oflag & OPOST)); - fprintf(stderr,"\n"); - fprintf(stderr,"c_cflag:\n"); - fprintf(stderr,"Ignore modem status lines CLOCAL %d\n", S(t->c_cflag & CLOCAL)); - fprintf(stderr,"\n"); - fprintf(stderr,"c_local:\n"); - fprintf(stderr,"Enable echo ECHO %d\n", S(t->c_lflag & ECHO)); - fprintf(stderr,"\n"); - fprintf(stderr,"c_cc:\n"); - fprintf(stderr,"c_cc[VEOF] %d\n", t->c_cc[VEOF]); -} -#endif /* DEBUG && !__OSE__ */ diff --git a/erts/etc/common/to_erl_common.h b/erts/etc/common/to_erl_common.h deleted file mode 100644 index a139da418f..0000000000 --- a/erts/etc/common/to_erl_common.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2013. 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% - */ -#ifndef ERL_TO_ERL_H -#define ERL_TO_ERL_H - -#define TO_ERL_USAGE "to_erl [-h|-F] %s\n" \ - "\t-h\tThis help text.\n" \ - "\t-f\tForce connection even though pipe is locked by other to_erl process." - -int to_erl(int argc, char **argv); - -#endif diff --git a/erts/etc/ose/etc.lmconf b/erts/etc/ose/etc.lmconf deleted file mode 100644 index b402b325b1..0000000000 --- a/erts/etc/ose/etc.lmconf +++ /dev/null @@ -1,20 +0,0 @@ -OSE_LM_STACK_SIZES=256,512,1024,2048,4096,8192,16384,65536 -OSE_LM_SIGNAL_SIZES=31,63,127,255,1023,4095,16383,65535 -OSE_LM_POOL_SIZE=0x200000 -OSE_LM_MAIN_NAME=main -OSE_LM_MAIN_STACK_SIZE=0xF000 -OSE_LM_MAIN_PRIORITY=20 -## Has to be of a type that allows MAM -OSE_LM_PROGRAM_TYPE=APP_RAM -OSE_LM_DATA_INIT=YES -OSE_LM_BSS_INIT=YES -OSE_LM_EXEC_MODEL=SHARED -HEAP_MAX_SIZE=1000000000 -HEAP_SMALL_BUF_INIT_SIZE=64000000 -HEAP_LARGE_BUF_THRESHOLD=16000000 -HEAP_LOCK_TYPE=2 - -# Setting the environment variable EFS_RESOLVE_TMO on the block to 0. -# This will eliminiate delays when trying to open files on not mounted -# volumes. -EFS_RESOLVE_TMO=0 diff --git a/erts/etc/ose/run_erl.c b/erts/etc/ose/run_erl.c deleted file mode 100644 index 6775525297..0000000000 --- a/erts/etc/ose/run_erl.c +++ /dev/null @@ -1,664 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2013. 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% - */ -/* - * Module: run_erl.c - * - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -/* System includes */ -#include <aio.h> -#include <errno.h> -#include <dirent.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <sys/stat.h> -#include <unistd.h> - -/* OSE includes */ -#include "ose.h" -#include "ose_spi/ose_spi.h" -#include "efs.h" -#include "pm.h" -#include "ose_spi/fm.sig" - -/* erts includes */ -#include "run_erl.h" -#include "run_erl_common.h" -#include "safe_string.h" /* sn_printf, strn_cpy, strn_cat, etc */ - -typedef struct RunErlSetup_ { - SIGSELECT signo; - int run_daemon; - char *logdir; - char *command; - char *pipename; - char *blockname; -} RunErlSetup; - -typedef struct ProgramState_ { - /* child process */ - int ifd, ofd; - OSDOMAIN domain; - PROCESS progpid, mainbid; - struct PmProgramInfo *info; - /* to_erl */ - char w_pipe[FILENAME_BUFSIZ], - r_pipe[FILENAME_BUFSIZ]; -} ProgramState; - -union SIGNAL { - SIGSELECT signo; - RunErlSetup setup; - struct FmReadPtr fm_read_ptr; - struct FmWritePtr fm_write_ptr; -}; - -static OSBOOLEAN hunt_in_block(char *block_name, - char *process_name, - PROCESS *pid); -static int create_child_process(char *command_string, char *blockname, - ProgramState *state); - - -static OSBOOLEAN hunt_in_block(char *block_name, - char *process_name, - PROCESS *pid) { - struct OS_pid_list *list; - PROCESS block_id = OSE_ILLEGAL_PROCESS; - int i; - char *name; - - *pid = OSE_ILLEGAL_PROCESS; - - list = get_bid_list(0); - - if (!list) - return 0; - - for (i = 0; i < list->count; i++) { - - if (list->list[i] == get_bid(current_process())) - continue; - - name = (char*)get_pid_info(list->list[i], OSE_PI_NAME); - if (name) { - if (strcmp(name,block_name) == 0) { - block_id = list->list[i]; - free_buf((union SIGNAL**)&name); - break; - } - free_buf((union SIGNAL**)&name); - } - } - - free_buf((union SIGNAL**)&list); - - if (block_id == OSE_ILLEGAL_PROCESS) - return 0; - - list = get_pid_list(block_id); - - if (!list) - return 0; - - for (i = 0; i < list->count; i++) { - name = (char*)get_pid_info(list->list[i], OSE_PI_NAME); - if (name) { - if (strcmp(name,process_name) == 0) { - *pid = list->list[i]; - free_buf((union SIGNAL**)&name); - break; - } - free_buf((union SIGNAL**)&name); - } - } - - free_buf((union SIGNAL**)&list); - - if (*pid == OSE_ILLEGAL_PROCESS) - return 0; - - return 1; - -} - - -static int create_child_process(char *command_string, char *blockname, - ProgramState *state) { - char *command = command_string; - char *argv; - int i = 0; - int ret_status; - PmStatus pm_status; - int tmp_io[2]; - int fd_arr[3]; - int ifd[2], ofd[2]; - char *handle; - struct PmLoadModuleInfoReply *mod_info; - - /* Parse out cmd and argv from the command string */ - while (1) { - if (command[i] == ' ' || command[i] == '\0') { - if (command[i] == '\0') - argv = NULL; - else { - command[i] = '\0'; - argv = command_string + i + 1; - } - break; - } - i++; - } - - if (blockname) - handle = blockname; - else - handle = simple_basename(command); - - if (ose_pm_load_module_info(handle,&mod_info) == PM_SUCCESS) { - /* Already installed */ - free_buf((union SIGNAL**)&mod_info); - } else if ((pm_status = ose_pm_install_load_module(0,"ELF",command,handle,0,0,NULL)) - != PM_SUCCESS) { - ERROR1(LOG_ERR,"ose_pm_install_load_module failed - pmstatus: 0x%08x\n", - pm_status); - return 0; - } - - state->domain = PM_NEW_DOMAIN; - - pm_status = ose_pm_create_program(&state->domain, handle, 0, 0 , NULL, - &state->progpid, &state->mainbid); - - if (pm_status != PM_SUCCESS) { - if (pm_status == PM_EINSTALL_HANDLE_IN_USE) - ERROR1(LOG_ERR,"ose_pm_create_program failed - " - "install handle \"%s\" is in use. You can specify another " - "install handle by using the -block option to run_erl.\n",handle); - else - ERROR1(LOG_ERR,"ose_pm_create_program failed - pmstatus: 0x%08x\n", - pm_status); - return 0; - } - - pm_status = ose_pm_program_info(state->progpid, &state->info); - /* FIXME don't forget to free this ((union SIGNAL **)&info) */ - if (pm_status != PM_SUCCESS) { - ERROR1(LOG_ERR,"ose_pm_program_info failed - pmstatus: 0x%08x\n", - pm_status); - return 0; - } - - /* We only clone stdin+stdout, what about stderr? */ - - /* create pipes */ - if (pipe(ifd) < 0) { - if (errno == ENOENT) - ERRNO_ERR0(LOG_ERR,"The /pipe file system is not available\n"); - else - ERRNO_ERR0(LOG_ERR,"pipe ifd failed\n"); - return 0; - } - - if (pipe(ofd) < 0) { - ERRNO_ERR0(LOG_ERR,"pipe ofd failed\n"); - return 0; - } - - /* FIXME Lock? */ - - /* backup our stdin stdout */ - if ((tmp_io[0] = dup(0)) < 0) { - ERRNO_ERR0(LOG_ERR,"dup 0 failed\n"); - return 0; - } - - if ((tmp_io[1] = dup(1)) < 0) { - ERRNO_ERR0(LOG_ERR,"dup 1 failed\n"); - return 0; - } - - /* set new pipe to fd 0,1 */ - if (dup2(ifd[1], 1) < 0) { - ERRNO_ERR0(LOG_ERR,"dup2 1 failed\n"); - return 0; - } - - if (dup2(ofd[0], 0) < 0) { - ERRNO_ERR0(LOG_ERR,"dup2 0 failed\n"); - return 0; - } - - /* clone array to newly created */ - fd_arr[0] = 2; /* Number of fd's */ - fd_arr[1] = 0; - fd_arr[2] = 1; - - if ((ret_status = efs_clone_array(state->info->main_process, fd_arr)) - != EFS_SUCCESS) { - ERROR1(LOG_ERR,"efs_close_array filed, errcode: %d\n", ret_status); - return 0; - } - - if (dup2(tmp_io[1], 1) < 0) { - ERRNO_ERR0(LOG_ERR,"restoring dup2 1 failed\n"); - return 0; - } - - if (dup2(tmp_io[0], 0) < 0) { - ERRNO_ERR0(LOG_ERR,"restoring dup2 1 failed\n"); - return 0; - } - - /* close loose-ends */ - sf_close(tmp_io[0]); - sf_close(tmp_io[1]); - sf_close(ifd[1]); - sf_close(ofd[0]); - state->ifd = ifd[0]; - state->ofd = ofd[1]; - - if (argv && set_env(state->progpid, "ARGV", argv)) { - ERRNO_ERR0(LOG_ERR,"something went wrong with set_env\n"); - } - - /* - * Start the program. - */ - pm_status = ose_pm_start_program(state->progpid); - if (pm_status != PM_SUCCESS) { - ERROR1(LOG_ERR,"ose_pm_install_load_module failed - pmstatus: 0x%08x\n", - pm_status); - return 0; - } - - return 1; -} - -#define SET_AIO(REQ,FD,SIZE,BUFF) \ - /* Make sure to clean data structure of previous request */ \ - memset(&(REQ),0,sizeof(REQ)); \ - (REQ).aio_fildes = FD; \ - (REQ).aio_offset = FM_POSITION_CURRENT; \ - (REQ).aio_nbytes = SIZE; \ - (REQ).aio_buf = BUFF; \ - (REQ).aio_sigevent.sigev_notify = SIGEV_NONE - -#define READ_AIO(REQ,FD,SIZE,BUFF) do { \ - SET_AIO(REQ,FD,SIZE,BUFF); \ - if (aio_read(&(REQ)) != 0) \ - ERRNO_ERR1(LOG_ERR,"aio_read of child_read_req(%d) failed\n",FD); \ - } while (0) - -#define WRITE_AIO(FD,SIZE,BUFF) do { \ - struct aiocb *write_req = malloc(sizeof(struct aiocb)); \ - char *write_buff = malloc(sizeof(char)*SIZE); \ - memcpy(write_buff,BUFF,SIZE); \ - SET_AIO(*write_req,FD,SIZE,write_buff); \ - if (aio_write(write_req) != 0) \ - ERRNO_ERR1(LOG_ERR,"aio_write of write_req(%d) failed\n",FD); \ - } while(0) - -int pass_on(ProgramState *state); -int pass_on(ProgramState *s) { - SIGSELECT sigsel[] = {0,FM_READ_PTR_REPLY}; - union SIGNAL *sig; - char child_read_buff[BUFSIZ], pipe_read_buff[BUFSIZ]; - struct aiocb child_read_req, pipe_read_req; - int rfd, wfd = 0; - FmHandle rfh, child_rfh; - int outstanding_writes = 0, got_some = 0, child_done = 0; - - if ((rfd = sf_open(s->r_pipe, O_RDONLY, 0)) < 0) { - ERRNO_ERR1(LOG_ERR,"Could not open FIFO '%s' for reading.\n", s->r_pipe); - rfd = 0; - return 1; - } - - attach(NULL,s->progpid); - - /* Open the log file */ - erts_run_erl_log_open(); - - efs_examine_fd(rfd,FLIB_FD_HANDLE,&rfh); - efs_examine_fd(s->ifd,FLIB_FD_HANDLE,&child_rfh); - - READ_AIO(child_read_req,s->ifd,BUFSIZ,child_read_buff); - READ_AIO(pipe_read_req,rfd,BUFSIZ,pipe_read_buff); - - while (1) { - time_t now,last_activity; - - time(&last_activity); - sig = receive_w_tmo(erts_run_erl_log_alive_minutes()*60000,sigsel); - - time(&now); - - if (sig) { - erts_run_erl_log_activity(0,now,last_activity); - } else { - /* timeout */ - erts_run_erl_log_activity(1,now,last_activity); - continue; - } - - switch (sig->signo) { - case OS_ATTACH_SIG: { - if (rfd) { sf_close(rfd); rfd = 0; } - free_buf(&sig); - child_done = 1; - /* Make sure to to let all outstanding write request finish */ - if (outstanding_writes) - break; - if (wfd) sf_close(wfd); - return 0; - } - case FM_WRITE_PTR_REPLY: { - if (sig->fm_write_ptr.status == EFS_SUCCESS) { - if (sig->fm_write_ptr.actual < sig->fm_write_ptr.requested) { - WRITE_AIO(wfd, sig->fm_write_ptr.requested-sig->fm_write_ptr.actual, - sig->fm_write_ptr.buffer+sig->fm_write_ptr.actual); - } - } else { - /* Assume to_erl has terminated. */ - sf_close(wfd); - wfd = 0; - } - free((char*)sig->fm_write_ptr.buffer); - aio_dispatch(sig); - if ((--outstanding_writes == 0) && child_done) { - if (wfd) sf_close(wfd); - return 0; - } - break; - } - case FM_READ_PTR_REPLY: { - /* Child fd */ - if (sig->fm_read_ptr.handle == child_rfh) { - - /* Child terminated */ - if (sig->fm_read_ptr.status != EFS_SUCCESS || - sig->fm_read_ptr.actual == 0) { - - if (rfd) { sf_close(rfd); rfd = 0; } - - if (sig->fm_read_ptr.status != EFS_SUCCESS) { - ERROR0(LOG_ERR,"Erlang closed the connection."); - aio_dispatch(sig); - return 1; - } - - /* child closed connection gracefully */ - aio_dispatch(sig); - if (outstanding_writes) { - child_done = 1; - break; - } - - if (wfd) sf_close(wfd); - - return 0; - } else { - erts_run_erl_log_write(sig->fm_read_ptr.buffer, - sig->fm_read_ptr.actual); - if (wfd) { - WRITE_AIO(wfd, sig->fm_read_ptr.actual, sig->fm_read_ptr.buffer); - outstanding_writes++; - } - aio_dispatch(sig); - READ_AIO(child_read_req, s->ifd,BUFSIZ, child_read_buff); - } - /* pipe fd */ - } else if (sig->fm_read_ptr.handle == rfh) { - if (sig->fm_read_ptr.status != EFS_SUCCESS) { - if(rfd) sf_close(rfd); - if(wfd) sf_close(wfd); - aio_dispatch(sig); - ERRNO_ERR0(LOG_ERR,"Error in reading from FIFO."); - return 1; - } - if (sig->fm_read_ptr.actual == 0) { - /* to_erl closed its end of the pipe */ - aio_dispatch(sig); - sf_close(rfd); - rfd = sf_open(s->r_pipe,O_RDONLY|DONT_BLOCK_PLEASE, 0); - if (rfd < 0) { - ERRNO_ERR1(LOG_ERR,"Could not open FIFO '%s' for reading.", - s->r_pipe); - rfd = 0; - } else { - READ_AIO(pipe_read_req,rfd,BUFSIZ,pipe_read_buff); - } - got_some = 0; /* reset for next session */ - } else { - int len = sig->fm_read_ptr.actual; - char *buffer = sig->fm_read_ptr.buffer; - if (!wfd) { - /* Try to open the write pipe to to_erl. Now that we got some data - * from to_erl, to_erl should already be reading this pipe - open - * should succeed. But in case of error, we just ignore it. - */ - if ((wfd = sf_open(s->w_pipe, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) { - erts_run_erl_log_status("Client expected on FIFO %s, " - "but can't open (len=%d)\n", - s->w_pipe, sig->fm_read_ptr.actual); - sf_close(rfd); - rfd = sf_open(s->r_pipe, O_RDONLY|DONT_BLOCK_PLEASE, 0); - if (rfd < 0) { - ERRNO_ERR1(LOG_ERR,"Could not open FIFO '%s' for reading.", - s->r_pipe); - return 1; - } - wfd = 0; - } else { -#ifdef DEBUG - erts_run_erl_log_status("run_erl: %s opened for writing\n", - s->w_pipe); -#endif - } - } - - if (!got_some && wfd && buffer[0] == '\014') { - char wbuf[30]; - int wlen = sn_printf(wbuf,sizeof(wbuf),"[run_erl v%u-%u]\n", - RUN_ERL_HI_VER, RUN_ERL_LO_VER); - /* For some reason this, the first write aio seems to - not get an FM_WRITE_PTR_REPLY, so we do not do: - outstanding_writes++; - */ - WRITE_AIO(wfd, wlen, wbuf); - } - got_some = 1; - - /* Write the message */ -#ifdef DEBUG - erts_run_erl_log_status("Pty master write; "); -#endif - len = erts_run_erl_extract_ctrl_seq(buffer,len, s->ofd); - - if (len > 0) { - int wlen = erts_run_erl_write_all(s->ofd, buffer, len); - if (wlen != len) { - aio_dispatch(sig); - ERRNO_ERR0(LOG_ERR,"Error in writing to terminal."); - if(rfd) sf_close(rfd); - if(wfd) sf_close(wfd); - return 1; - } - } -#ifdef DEBUG - erts_run_erl_log_status("OK\n"); -#endif - aio_dispatch(sig); - READ_AIO(pipe_read_req,rfd,BUFSIZ,pipe_read_buff); - } - } - break; - } - default: { - free_buf(&sig); - break; - } - } - } -} - -OS_PROCESS(run_erl_process) { - char *logdir, *command, *blockname; - SIGSELECT sigsel[] = {1,ERTS_SIGNAL_RUN_ERL_SETUP}; - union SIGNAL *sig = receive(sigsel); - ProgramState state; - char pipename[FILENAME_BUFSIZ]; - - state.info = NULL; - - logdir = strdup(sig->setup.logdir); - command = strdup(sig->setup.command); - strn_cpy(pipename,sizeof(pipename),sig->setup.pipename); - - if (sig->setup.blockname) - blockname = strdup(sig->setup.blockname); - else - blockname = NULL; - - erts_run_erl_log_init(sig->setup.run_daemon, logdir); - - free_buf(&sig); - - if (erts_run_erl_open_fifo(pipename,state.w_pipe,state.r_pipe)) - kill_proc(current_process()); - - if (create_child_process(command,blockname,&state)) - pass_on(&state); - - free(logdir); - free(command); - if (blockname) - free(blockname); - - if (state.info) - free_buf(((union SIGNAL**)&state.info)); - - sf_close(state.ifd); - sf_close(state.ofd); - - unlink(state.w_pipe); - unlink(state.r_pipe); - - kill_proc(current_process()); -} - -int run_erl(int argc,char **argv) { - char *pipename, *logdir, *command, *blockname = NULL; - int pipename_len, logdir_len, command_len, blockname_len = 0; - int i = 1, run_daemon = 0; - PROCESS pid; - SIGSELECT sigsel[] = {0}; - union SIGNAL *sig; - - if(argc < 4) { - fprintf(stderr,RUN_ERL_USAGE,"run_erl"); - return 1; - } - - while (1) { - if (argv[i][0] != '-') - break; - if (!strcmp(argv[i],"-daemon")) { - run_daemon = 1; - i++; - continue; - } - if (!strcmp(argv[i],"-block")) { - blockname = argv[i+1]; - blockname_len = strlen(argv[i+1]) + 1; - i+=2; - continue; - } - fprintf(stderr,RUN_ERL_USAGE,"run_erl"); - return 1; - } - - pipename = argv[i++]; - logdir = argv[i++]; - command = argv[i++]; - - /* + 1 to include NULL at end */ - logdir_len = strlen(logdir) + 1; - command_len = strlen(command) + 1; - pipename_len = strlen(pipename) + 1; - - if (run_daemon) { - /* We request that the run_erl_process should be started from the - main process so that it does not die when the shell command - returns */ - PROCESS main_pid; - hunt_in_block("run_erl","main",&main_pid); - sig = alloc(sizeof(*sig),ERTS_SIGNAL_RUN_ERL_DAEMON); - send(&sig,main_pid); - sig = receive(sigsel); - pid = sender(&sig); - free_buf(&sig); - } else { - pid = create_process(OS_BG_PROC,"run_erl_process", - run_erl_process, 0x800, - 0, 0, 0, NULL, 0, 0); - } - - sig = alloc(sizeof(RunErlSetup)+ - logdir_len+command_len+pipename_len+blockname_len, - ERTS_SIGNAL_RUN_ERL_SETUP); - sig->setup.run_daemon = run_daemon; - sig->setup.logdir = ((char*)sig)+sizeof(RunErlSetup); - sig->setup.command = ((char*)sig)+sizeof(RunErlSetup)+logdir_len; - sig->setup.pipename = ((char*)sig)+sizeof(RunErlSetup)+logdir_len+command_len; - if (blockname) - sig->setup.blockname = ((char*)sig)+sizeof(RunErlSetup)+ - logdir_len+command_len+pipename_len; - else - sig->setup.blockname = NULL; - - strcpy(sig->setup.logdir,logdir); - strcpy(sig->setup.command,command); - strcpy(sig->setup.pipename,pipename); - if (blockname) strcpy(sig->setup.blockname,blockname); - - send(&sig,pid); - - if (run_daemon) { - /* We are a daemon, error msgs will be sent to ramlog */ - start(pid); - return 1; - } - - /* We are not daemon, error msgs will be sent to stderr and we block here */ - efs_clone(pid); - start(pid); - - attach(NULL,pid); - sig = receive(sigsel); - - return 1; -} diff --git a/erts/etc/ose/run_erl.h b/erts/etc/ose/run_erl.h deleted file mode 100644 index bdc8b6c355..0000000000 --- a/erts/etc/ose/run_erl.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2013. 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% - */ -#ifndef ERL_RUN_ERL_H -#define ERL_RUN_ERL_H - -#include "ose.h" - -#include "erts.sig" - -int run_erl(int argc, char **argv); -OS_PROCESS(run_erl_process); - -#endif diff --git a/erts/etc/ose/run_erl_main.c b/erts/etc/ose/run_erl_main.c deleted file mode 100644 index 8895c773a1..0000000000 --- a/erts/etc/ose/run_erl_main.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2013. 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% - */ -/* - * Module: run_erl_main.c - * - * Container for load module that installs both run_erl and to_erl command. - */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <stdio.h> - -#include "ose.h" -#include "shell.h" - -#include "run_erl_common.h" -#include "run_erl.h" -#include "to_erl_common.h" - -union SIGNAL { - SIGSELECT signo; -}; - -int main(int argc, char **argv) -{ - - char run_erl_usage[320], - to_erl_usage[120]; - - (void)stdin;(void)stdout;(void)stderr; - - sprintf(run_erl_usage,RUN_ERL_USAGE,"run_erl [-daemon] [-block blockname]"); - sprintf(to_erl_usage,TO_ERL_USAGE,"pipename"); - - shell_add_cmd_attrs( - "run_erl",run_erl_usage, - "Redirect Erlang input and output streams", - run_erl,DEFAULT_PROC_TYPE,DEFAULT_PRIORITY,DEFAULT_STACK_SIZE); - - shell_add_cmd_attrs( - "to_erl",to_erl_usage, - "Attach to redirected Erlang input and output streams", - to_erl,DEFAULT_PROC_TYPE,DEFAULT_PRIORITY,DEFAULT_STACK_SIZE); - - while (1) { - static const SIGSELECT sigsel[] = {0}; - union SIGNAL *sig = receive(sigsel); - - if (sig->signo == ERTS_SIGNAL_RUN_ERL_DAEMON) { - PROCESS pid = create_process(OS_BG_PROC,"run_erl_daemon", - run_erl_process, 0x800, - 0, 0, 0, NULL, 0, 0); - send_w_s(&sig,pid,sender(&sig)); - } else { - printf("Got unexpected signal!"); - free_buf(&sig); - } - } - - return 1; -} diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in index 19d67de92f..7b554e71f2 100644 --- a/erts/etc/unix/etp-commands.in +++ b/erts/etc/unix/etp-commands.in @@ -774,7 +774,7 @@ define etp-pid-1 # set $etp_pid_1 = (Eterm)($arg0) if ($etp_pid_1 & 0xF) == 0x3 - if (etp_arch_bits == 64 && etp_halfword == 0) + if (etp_arch_bits == 64) if (etp_big_endian) set $etp_pid_data = (unsigned) ((((Uint64) $etp_pid_1) >> 36) & 0x0fffffff) else @@ -834,7 +834,7 @@ define etp-port-1 # set $etp_port_1 = (Eterm)($arg0) if ($etp_port_1 & 0xF) == 0x7 - if (etp_arch_bits == 64 && etp_halfword == 0) + if (etp_arch_bits == 64) if (etp_big_endian) set $etp_port_data = (unsigned) ((((Uint64) $etp_port_1) >> 36) & 0x0fffffff) else @@ -1577,7 +1577,7 @@ define etp-term-dump-pid # set $etp_pid_1 = (Eterm)($arg0) if ($etp_pid_1 & 0xF) == 0x3 - if (etp_arch_bits == 64 && etp_halfword == 0) + if (etp_arch_bits == 64) if (etp_big_endian) set $etp_pid_data = (unsigned) ((((Uint64) $etp_pid_1) >> 36) & 0x0fffffff) else @@ -1622,7 +1622,7 @@ end define etp-pid2pix-1 # Args: Eterm # - if (etp_arch_bits == 64 && etp_halfword == 0) + if (etp_arch_bits == 64) if (etp_big_endian) set $etp_pix = (int) (((Uint64) $arg0) & 0x0fffffff) else @@ -1965,7 +1965,7 @@ end define etp-port-id2pix-1 # Args: Eterm # - if (etp_arch_bits == 64 && etp_halfword == 0) + if (etp_arch_bits == 64) if (etp_big_endian) set $etp_pix = (int) (((Uint64) $arg0) & 0x0fffffff) elser @@ -2493,12 +2493,6 @@ define etp-system-info printf "Little\n" end printf "Word size: %d-bit\n", etp_arch_bits - printf "Halfword: " - if (etp_halfword) - printf "yes\n" - else - printf "no\n" - end printf "HiPE support: " if (etp_hipe) printf "yes\n" diff --git a/erts/etc/unix/run_erl.c b/erts/etc/unix/run_erl.c index c8414030ca..44efb975ba 100644 --- a/erts/etc/unix/run_erl.c +++ b/erts/etc/unix/run_erl.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2013. All Rights Reserved. + * Copyright Ericsson AB 1996-2015. 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. @@ -41,13 +41,11 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif - #ifdef HAVE_WORKING_POSIX_OPENPT #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 600 #endif #endif - #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h> @@ -65,6 +63,11 @@ #include <dirent.h> #include <termios.h> #include <time.h> + +#ifdef __ANDROID__ +# include <termios.h> +#endif + #ifdef HAVE_SYSLOG_H # include <syslog.h> #endif @@ -84,25 +87,81 @@ # include <stropts.h> #endif -#include "run_erl_common.h" +#include "run_erl.h" #include "safe_string.h" /* sn_printf, strn_cpy, strn_cat, etc */ +#ifdef O_NONBLOCK +# define DONT_BLOCK_PLEASE O_NONBLOCK +#else +# define DONT_BLOCK_PLEASE O_NDELAY +# ifndef EAGAIN +# define EAGAIN -3898734 +# endif +#endif + +#define noDEBUG + +#define DEFAULT_LOG_GENERATIONS 5 +#define LOG_MAX_GENERATIONS 1000 /* No more than 1000 log files */ +#define LOG_MIN_GENERATIONS 2 /* At least two to switch between */ +#define DEFAULT_LOG_MAXSIZE 100000 +#define LOG_MIN_MAXSIZE 1000 /* Smallast value for changing log file */ +#define LOG_STUBNAME "erlang.log." +#define LOG_PERM 0664 +#define DEFAULT_LOG_ACTIVITY_MINUTES 5 +#define DEFAULT_LOG_ALIVE_MINUTES 15 +#define DEFAULT_LOG_ALIVE_FORMAT "%a %b %e %T %Z %Y" +#define ALIVE_BUFFSIZ 256 + +#define PERM 0600 +#define STATUSFILENAME "/run_erl.log" +#define PIPE_STUBNAME "erlang.pipe" +#define PIPE_STUBLEN strlen(PIPE_STUBNAME) + +#ifndef FILENAME_MAX +#define FILENAME_MAX 250 +#endif + +#ifndef O_SYNC +#define O_SYNC 0 +#define USE_FSYNC 1 +#endif + #define MAX(x,y) ((x) > (y) ? (x) : (y)) +#define FILENAME_BUFSIZ FILENAME_MAX + /* prototypes */ static void usage(char *); +static int create_fifo(char *name, int perm); static int open_pty_master(char **name, int *sfd); static int open_pty_slave(char *name); static void pass_on(pid_t); static void exec_shell(char **); +static void status(const char *format,...); +static void error_logf(int priority, int line, const char *format,...); static void catch_sigchild(int); +static int next_log(int log_num); +static int prev_log(int log_num); +static int find_next_log_num(void); +static int open_log(int log_num, int flags); +static void write_to_log(int* lfd, int* log_num, char* buf, int len); static void daemon_init(void); +static char *simple_basename(char *path); static void init_outbuf(void); static int outbuf_size(void); static void clear_outbuf(void); static char* outbuf_first(void); static void outbuf_delete(int bytes); static void outbuf_append(const char* bytes, int n); +static int write_all(int fd, const char* buf, int len); +static int extract_ctrl_seq(char* buf, int len); +static void set_window_size(unsigned col, unsigned row); + +static ssize_t sf_write(int fd, const void *buffer, size_t len); +static ssize_t sf_read(int fd, void *buffer, size_t len); +static int sf_open(const char *path, int flags, mode_t mode); +static int sf_close(int fd); #ifdef DEBUG static void show_terminal_settings(struct termios *t); @@ -110,11 +169,20 @@ static void show_terminal_settings(struct termios *t); /* static data */ static char fifo1[FILENAME_BUFSIZ], fifo2[FILENAME_BUFSIZ]; +static char statusfile[FILENAME_BUFSIZ]; +static char log_dir[FILENAME_BUFSIZ]; static char pipename[FILENAME_BUFSIZ]; static FILE *stdstatus = NULL; +static int log_generations = DEFAULT_LOG_GENERATIONS; +static int log_maxsize = DEFAULT_LOG_MAXSIZE; +static int log_alive_minutes = DEFAULT_LOG_ALIVE_MINUTES; +static int log_activity_minutes = DEFAULT_LOG_ACTIVITY_MINUTES; +static int log_alive_in_gmt = 0; +static char log_alive_format[ALIVE_BUFFSIZ+1]; static int run_daemon = 0; static char *program_name; static int mfd; /* master pty fd */ +static unsigned protocol_ver = RUN_ERL_LO_VER; /* assume lowest to begin with */ /* * Output buffer. @@ -145,13 +213,29 @@ static char* outbuf_in; LOG_PID|LOG_CONS|LOG_NOWAIT,LOG_USER) #endif +#define ERROR0(Prio,Format) error_logf(Prio,__LINE__,Format"\n") +#define ERROR1(Prio,Format,A1) error_logf(Prio,__LINE__,Format"\n",A1) +#define ERROR2(Prio,Format,A1,A2) error_logf(Prio,__LINE__,Format"\n",A1,A2) + +#ifdef HAVE_STRERROR +# define ADD_ERRNO(Format) "errno=%d '%s'\n"Format"\n",errno,strerror(errno) +#else +# define ADD_ERRNO(Format) "errno=%d\n"Format"\n",errno +#endif +#define ERRNO_ERR0(Prio,Format) error_logf(Prio,__LINE__,ADD_ERRNO(Format)) +#define ERRNO_ERR1(Prio,Format,A1) error_logf(Prio,__LINE__,ADD_ERRNO(Format),A1) + + int main(int argc, char **argv) { int childpid; int sfd = -1; - char *ptyslave=NULL; + int fd; + char *p, *ptyslave=NULL; int i = 1; int off_argv; + int calculated_pipename = 0; + int highest_pipe_num = 0; program_name = argv[0]; @@ -169,16 +253,122 @@ int main(int argc, char **argv) off_argv = i; strn_cpy(pipename, sizeof(pipename), argv[i++]); - - erts_run_erl_log_init(run_daemon,argv[i]); + strn_cpy(log_dir, sizeof(log_dir), argv[i]); + strn_cpy(statusfile, sizeof(statusfile), log_dir); + strn_cat(statusfile, sizeof(statusfile), STATUSFILENAME); #ifdef DEBUG - erts_run_erl_log_status("%s: pid is : %d\n", argv[0], getpid()); + status("%s: pid is : %d\n", argv[0], getpid()); #endif - /* Open read and write fifo */ - if (erts_run_erl_open_fifo(pipename,fifo1,fifo2)) - exit(1); + /* Get values for LOG file handling from the environment */ + if ((p = getenv("RUN_ERL_LOG_ALIVE_MINUTES"))) { + log_alive_minutes = atoi(p); + if (!log_alive_minutes) { + ERROR1(LOG_ERR,"Minimum value for RUN_ERL_LOG_ALIVE_MINUTES is 1 " + "(current value is %s)",p); + } + log_activity_minutes = log_alive_minutes / 3; + if (!log_activity_minutes) { + ++log_activity_minutes; + } + } + if ((p = getenv("RUN_ERL_LOG_ACTIVITY_MINUTES"))) { + log_activity_minutes = atoi(p); + if (!log_activity_minutes) { + ERROR1(LOG_ERR,"Minimum value for RUN_ERL_LOG_ACTIVITY_MINUTES is 1 " + "(current value is %s)",p); + } + } + if ((p = getenv("RUN_ERL_LOG_ALIVE_FORMAT"))) { + if (strlen(p) > ALIVE_BUFFSIZ) { + ERROR1(LOG_ERR, "RUN_ERL_LOG_ALIVE_FORMAT can contain a maximum of " + "%d characters", ALIVE_BUFFSIZ); + } + strn_cpy(log_alive_format, sizeof(log_alive_format), p); + } else { + strn_cpy(log_alive_format, sizeof(log_alive_format), DEFAULT_LOG_ALIVE_FORMAT); + } + if ((p = getenv("RUN_ERL_LOG_ALIVE_IN_UTC")) && strcmp(p,"0")) { + ++log_alive_in_gmt; + } + if ((p = getenv("RUN_ERL_LOG_GENERATIONS"))) { + log_generations = atoi(p); + if (log_generations < LOG_MIN_GENERATIONS) + ERROR1(LOG_ERR,"Minimum RUN_ERL_LOG_GENERATIONS is %d", LOG_MIN_GENERATIONS); + if (log_generations > LOG_MAX_GENERATIONS) + ERROR1(LOG_ERR,"Maximum RUN_ERL_LOG_GENERATIONS is %d", LOG_MAX_GENERATIONS); + } + + if ((p = getenv("RUN_ERL_LOG_MAXSIZE"))) { + log_maxsize = atoi(p); + if (log_maxsize < LOG_MIN_MAXSIZE) + ERROR1(LOG_ERR,"Minimum RUN_ERL_LOG_MAXSIZE is %d", LOG_MIN_MAXSIZE); + } + + /* + * Create FIFOs and open them + */ + + if(*pipename && pipename[strlen(pipename)-1] == '/') { + /* The user wishes us to find a unique pipe name in the specified */ + /* directory */ + DIR *dirp; + struct dirent *direntp; + + calculated_pipename = 1; + dirp = opendir(pipename); + if(!dirp) { + ERRNO_ERR1(LOG_ERR,"Can't access pipe directory '%s'.", pipename); + exit(1); + } + + /* Check the directory for existing pipes */ + + while((direntp=readdir(dirp)) != NULL) { + if(strncmp(direntp->d_name,PIPE_STUBNAME,PIPE_STUBLEN)==0) { + int num = atoi(direntp->d_name+PIPE_STUBLEN+1); + if(num > highest_pipe_num) + highest_pipe_num = num; + } + } + closedir(dirp); + strn_catf(pipename, sizeof(pipename), "%s.%d", + PIPE_STUBNAME, highest_pipe_num+1); + } /* if */ + + for(;;) { + /* write FIFO - is read FIFO for `to_erl' program */ + strn_cpy(fifo1, sizeof(fifo1), pipename); + strn_cat(fifo1, sizeof(fifo1), ".r"); + if (create_fifo(fifo1, PERM) < 0) { + ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for writing.", fifo1); + exit(1); + } + + /* read FIFO - is write FIFO for `to_erl' program */ + strn_cpy(fifo2, sizeof(fifo2), pipename); + strn_cat(fifo2, sizeof(fifo2), ".w"); + + /* Check that nobody is running run_erl already */ + if ((fd = sf_open(fifo2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) { + /* Open as client succeeded -- run_erl is already running! */ + sf_close(fd); + if (calculated_pipename) { + ++highest_pipe_num; + strn_catf(pipename, sizeof(pipename), "%s.%d", + PIPE_STUBNAME, highest_pipe_num+1); + continue; + } + fprintf(stderr, "Erlang already running on pipe %s.\n", pipename); + exit(1); + } + if (create_fifo(fifo2, PERM) < 0) { + ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for reading.", fifo2); + exit(1); + } + break; + } /* * Open master pseudo-terminal @@ -250,7 +440,7 @@ int main(int argc, char **argv) sf_close(2); if (dup(sfd) != 0 || dup(sfd) != 1 || dup(sfd) != 2) { - erts_run_erl_log_status("Cannot dup\n"); + status("Cannot dup\n"); } sf_close(sfd); exec_shell(argv+off_argv); /* exec_shell expects argv[2] to be */ @@ -293,7 +483,9 @@ static void pass_on(pid_t childpid) struct timeval timeout; time_t last_activity; char buf[BUFSIZ]; - int rfd, wfd=0; + char log_alive_buffer[ALIVE_BUFFSIZ+1]; + int lognum; + int rfd, wfd=0, lfd=0; int maxfd; int ready; int got_some = 0; /* from to_erl */ @@ -308,12 +500,13 @@ static void pass_on(pid_t childpid) } #ifdef DEBUG - erts_run_erl_log_status("run_erl: %s opened for reading\n", fifo2); + status("run_erl: %s opened for reading\n", fifo2); #endif /* Open the log file */ - erts_run_erl_log_open(); + lognum = find_next_log_num(); + lfd = open_log(lognum, O_RDWR|O_APPEND|O_CREAT|O_SYNC); /* Enter the work loop */ @@ -332,8 +525,7 @@ static void pass_on(pid_t childpid) writefds_ptr = &writefds; } time(&last_activity); - /* don't assume old BSD bug */ - timeout.tv_sec = erts_run_erl_log_alive_minutes()*60; + timeout.tv_sec = log_alive_minutes*60; /* don't assume old BSD bug */ timeout.tv_usec = 0; ready = select(maxfd + 1, &readfds, writefds_ptr, NULL, &timeout); if (ready < 0) { @@ -363,7 +555,28 @@ static void pass_on(pid_t childpid) /* Check how long time we've been inactive */ time(&now); - erts_run_erl_log_activity(!ready,now,last_activity); + if(!ready || now - last_activity > log_activity_minutes*60) { + /* Either a time out: 15 minutes without action, */ + /* or something is coming in right now, but it's a long time */ + /* since last time, so let's write a time stamp this message */ + struct tm *tmptr; + if (log_alive_in_gmt) { + tmptr = gmtime(&now); + } else { + tmptr = localtime(&now); + } + if (!strftime(log_alive_buffer, ALIVE_BUFFSIZ, log_alive_format, + tmptr)) { + strn_cpy(log_alive_buffer, sizeof(log_alive_buffer), + "(could not format time in 256 positions " + "with current format string.)"); + } + log_alive_buffer[ALIVE_BUFFSIZ] = '\0'; + + sn_printf(buf, sizeof(buf), "\n===== %s%s\n", + ready?"":"ALIVE ", log_alive_buffer); + write_to_log(&lfd, &lognum, buf, strlen(buf)); + } } /* @@ -398,7 +611,7 @@ static void pass_on(pid_t childpid) */ if (FD_ISSET(mfd, &readfds)) { #ifdef DEBUG - erts_run_erl_log_status("Pty master read; "); + status("Pty master read; "); #endif if ((len = sf_read(mfd, buf, BUFSIZ)) <= 0) { sf_close(rfd); @@ -416,7 +629,7 @@ static void pass_on(pid_t childpid) exit(0); } - erts_run_erl_log_write(buf, len); + write_to_log(&lfd, &lognum, buf, len); /* * Save in the output queue. @@ -432,7 +645,7 @@ static void pass_on(pid_t childpid) */ if (FD_ISSET(rfd, &readfds)) { #ifdef DEBUG - erts_run_erl_log_status("FIFO read; "); + status("FIFO read; "); #endif if ((len = sf_read(rfd, buf, BUFSIZ)) < 0) { sf_close(rfd); @@ -461,7 +674,7 @@ static void pass_on(pid_t childpid) * should succeed. But in case of error, we just ignore it. */ if ((wfd = sf_open(fifo1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) { - erts_run_erl_log_status("Client expected on FIFO %s, but can't open (len=%d)\n", + status("Client expected on FIFO %s, but can't open (len=%d)\n", fifo1, len); sf_close(rfd); rfd = sf_open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0); @@ -473,7 +686,7 @@ static void pass_on(pid_t childpid) } else { #ifdef DEBUG - erts_run_erl_log_status("run_erl: %s opened for writing\n", fifo1); + status("run_erl: %s opened for writing\n", fifo1); #endif } } @@ -489,15 +702,14 @@ static void pass_on(pid_t childpid) /* Write the message */ #ifdef DEBUG - erts_run_erl_log_status("Pty master write; "); + status("Pty master write; "); #endif - len = erts_run_erl_extract_ctrl_seq(buf, len, mfd); + len = extract_ctrl_seq(buf, len); if(len==1 && buf[0] == '\003') { kill(childpid,SIGINT); - } - else if (len>0 && erts_run_erl_write_all(mfd, buf, len) != len) - { + } + else if (len>0 && write_all(mfd, buf, len) != len) { ERRNO_ERR0(LOG_ERR,"Error in writing to terminal."); sf_close(rfd); if(wfd) sf_close(wfd); @@ -506,7 +718,7 @@ static void pass_on(pid_t childpid) } } #ifdef DEBUG - erts_run_erl_log_status("OK\n"); + status("OK\n"); #endif } } @@ -516,6 +728,173 @@ static void catch_sigchild(int sig) { } +/* + * next_log: + * Returns the index number that follows the given index number. + * (Wrapping after log_generations) + */ +static int next_log(int log_num) { + return log_num>=log_generations?1:log_num+1; +} + +/* + * prev_log: + * Returns the index number that precedes the given index number. + * (Wrapping after log_generations) + */ +static int prev_log(int log_num) { + return log_num<=1?log_generations:log_num-1; +} + +/* + * find_next_log_num() + * Searches through the log directory to check which logs that already + * exist. It finds the "hole" in the sequence, and returns the index + * number for the last log in the log sequence. If there is no hole, index + * 1 is returned. + */ +static int find_next_log_num(void) { + int i, next_gen, log_gen; + DIR *dirp; + struct dirent *direntp; + int log_exists[LOG_MAX_GENERATIONS+1]; + int stub_len = strlen(LOG_STUBNAME); + + /* Initialize exiting log table */ + + for(i=log_generations; i>=0; i--) + log_exists[i] = 0; + dirp = opendir(log_dir); + if(!dirp) { + ERRNO_ERR1(LOG_ERR,"Can't access log directory '%s'", log_dir); + exit(1); + } + + /* Check the directory for existing logs */ + + while((direntp=readdir(dirp)) != NULL) { + if(strncmp(direntp->d_name,LOG_STUBNAME,stub_len)==0) { + int num = atoi(direntp->d_name+stub_len); + if(num < 1 || num > log_generations) + continue; + log_exists[num] = 1; + } + } + closedir(dirp); + + /* Find out the next available log file number */ + + next_gen = 0; + for(i=log_generations; i>=0; i--) { + if(log_exists[i]) + if(next_gen) + break; + else + ; + else + next_gen = i; + } + + /* Find out the current log file number */ + + if(next_gen) + log_gen = prev_log(next_gen); + else + log_gen = 1; + + return log_gen; +} /* find_next_log_num() */ + +/* open_log() + * Opens a log file (with given index) for writing. Writing may be + * at the end or a trucnating write, according to flags. + * A LOGGING STARTED and time stamp message is inserted into the log file + */ +static int open_log(int log_num, int flags) +{ + char buf[FILENAME_MAX]; + time_t now; + struct tm *tmptr; + char log_buffer[ALIVE_BUFFSIZ+1]; + int lfd; + + /* Remove the next log (to keep a "hole" in the log sequence) */ + sn_printf(buf, sizeof(buf), "%s/%s%d", + log_dir, LOG_STUBNAME, next_log(log_num)); + unlink(buf); + + /* Create or continue on the current log file */ + sn_printf(buf, sizeof(buf), "%s/%s%d", log_dir, LOG_STUBNAME, log_num); + if((lfd = sf_open(buf, flags, LOG_PERM))<0){ + ERRNO_ERR1(LOG_ERR,"Can't open log file '%s'.", buf); + exit(1); + } + + /* Write a LOGGING STARTED and time stamp into the log file */ + time(&now); + if (log_alive_in_gmt) { + tmptr = gmtime(&now); + } else { + tmptr = localtime(&now); + } + if (!strftime(log_buffer, ALIVE_BUFFSIZ, log_alive_format, + tmptr)) { + strn_cpy(log_buffer, sizeof(log_buffer), + "(could not format time in 256 positions " + "with current format string.)"); + } + log_buffer[ALIVE_BUFFSIZ] = '\0'; + + sn_printf(buf, sizeof(buf), "\n=====\n===== LOGGING STARTED %s\n=====\n", + log_buffer); + if (write_all(lfd, buf, strlen(buf)) < 0) + status("Error in writing to log.\n"); + +#if USE_FSYNC + fsync(lfd); +#endif + + return lfd; +} + +/* write_to_log() + * Writes a message to a log file. If the current log file is full, + * a new log file is opened. + */ +static void write_to_log(int* lfd, int* log_num, char* buf, int len) +{ + int size; + + /* Decide if new logfile needed, and open if so */ + + size = lseek(*lfd,0,SEEK_END); + if(size+len > log_maxsize) { + sf_close(*lfd); + *log_num = next_log(*log_num); + *lfd = open_log(*log_num, O_RDWR|O_CREAT|O_TRUNC|O_SYNC); + } + + /* Write to log file */ + + if (write_all(*lfd, buf, len) < 0) { + status("Error in writing to log.\n"); + } + +#if USE_FSYNC + fsync(*lfd); +#endif +} + +/* create_fifo() + * Creates a new fifo with the given name and permission. + */ +static int create_fifo(char *name, int perm) +{ + if ((mkfifo(name, perm) < 0) && (errno != EEXIST)) + return -1; + return 0; +} + /* open_pty_master() * Find a master device, open and return fd and slave device name. @@ -712,9 +1091,9 @@ static void exec_shell(char **argv) else argv[0] = sh; argv[1] = "-c"; - erts_run_erl_log_status("Args before exec of shell:\n"); + status("Args before exec of shell:\n"); for (vp = argv, i = 0; *vp; vp++, i++) - erts_run_erl_log_status("argv[%d] = %s\n", i, *vp); + status("argv[%d] = %s\n", i, *vp); if (stdstatus) { fclose(stdstatus); } @@ -725,6 +1104,26 @@ static void exec_shell(char **argv) ERRNO_ERR0(LOG_ERR,"Could not execv"); } +/* status() + * Prints the arguments to a status file + * Works like printf (see vfrpintf) + */ +static void status(const char *format,...) +{ + va_list args; + time_t now; + + if (stdstatus == NULL) + stdstatus = fopen(statusfile, "w"); + if (stdstatus == NULL) + return; + now = time(NULL); + fprintf(stdstatus, "run_erl [%d] %s", (int)getpid(), ctime(&now)); + va_start(args, format); + vfprintf(stdstatus, format, args); + va_end(args); + fflush(stdstatus); +} static void daemon_init(void) /* As R Stevens wants it, to a certain extent anyway... */ @@ -764,10 +1163,47 @@ static void daemon_init(void) run_daemon = 1; } +/* error_logf() + * Prints the arguments to stderr or syslog + * Works like printf (see vfprintf) + */ +static void error_logf(int priority, int line, const char *format, ...) +{ + va_list args; + va_start(args, format); + +#ifdef HAVE_SYSLOG_H + if (run_daemon) { + vsyslog(priority,format,args); + } + else +#endif + { + time_t now = time(NULL); + fprintf(stderr, "run_erl:%d [%d] %s", line, (int)getpid(), ctime(&now)); + vfprintf(stderr, format, args); + } + va_end(args); +} + static void usage(char *pname) { - fprintf(stderr, "Usage: "); - fprintf(stderr, RUN_ERL_USAGE, pname); + fprintf(stderr, "Usage: %s (pipe_name|pipe_dir/) log_dir \"command [parameters ...]\"\n", pname); + fprintf(stderr, "\nYou may also set the environment variables RUN_ERL_LOG_GENERATIONS\n"); + fprintf(stderr, "and RUN_ERL_LOG_MAXSIZE to the number of log files to use and the\n"); + fprintf(stderr, "size of the log file when to switch to the next log file\n"); +} + +/* Instead of making sure basename exists, we do our own */ +static char *simple_basename(char *path) +{ + char *ptr; + for (ptr = path; *ptr != '\0'; ++ptr) { + if (*ptr == '/') { + path = ptr + 1; + } + } + return path; } static void init_outbuf(void) @@ -838,6 +1274,114 @@ static void outbuf_append(const char* buf, int n) outbuf_in += n; } +/* Call write() until entire buffer has been written or error. + * Return len or -1. + */ +static int write_all(int fd, const char* buf, int len) +{ + int left = len; + int written; + for (;;) { + written = sf_write(fd,buf,left); + if (written == left) { + return len; + } + if (written < 0) { + return -1; + } + left -= written; + buf += written; + } +} + +static ssize_t sf_read(int fd, void *buffer, size_t len) { + ssize_t n = 0; + + do { n = read(fd, buffer, len); } while (n < 0 && errno == EINTR); + + return n; +} + +static ssize_t sf_write(int fd, const void *buffer, size_t len) { + ssize_t n = 0; + + do { n = write(fd, buffer, len); } while (n < 0 && errno == EINTR); + + return n; +} + +static int sf_open(const char *path, int type, mode_t mode) { + int fd = 0; + + do { fd = open(path, type, mode); } while(fd < 0 && errno == EINTR); + + return fd; +} +static int sf_close(int fd) { + int res = 0; + + do { res = close(fd); } while(fd < 0 && errno == EINTR); + + return res; +} +/* Extract any control sequences that are ment only for run_erl + * and should not be forwarded to the pty. + */ +static int extract_ctrl_seq(char* buf, int len) +{ + static const char prefix[] = "\033_"; + static const char suffix[] = "\033\\"; + char* bufend = buf + len; + char* start = buf; + char* command; + char* end; + + for (;;) { + start = find_str(start, bufend-start, prefix); + if (!start) break; + + command = start + strlen(prefix); + end = find_str(command, bufend-command, suffix); + if (end) { + unsigned col, row; + if (sscanf(command,"version=%u", &protocol_ver)==1) { + /*fprintf(stderr,"to_erl v%u\n", protocol_ver);*/ + } + else if (sscanf(command,"winsize=%u,%u", &col, &row)==2) { + set_window_size(col,row); + } + else { + ERROR2(LOG_ERR, "Ignoring unknown ctrl command '%.*s'\n", + (int)(end-command), command); + } + + /* Remove ctrl sequence from buf */ + end += strlen(suffix); + memmove(start, end, bufend-end); + bufend -= end - start; + } + else { + ERROR2(LOG_ERR, "Missing suffix in ctrl sequence '%.*s'\n", + (int)(bufend-start), start); + break; + } + } + return bufend - buf; +} + +static void set_window_size(unsigned col, unsigned row) +{ +#ifdef TIOCSWINSZ + struct winsize ws; + ws.ws_col = col; + ws.ws_row = row; + if (ioctl(mfd, TIOCSWINSZ, &ws) < 0) { + ERRNO_ERR0(LOG_ERR,"Failed to set window size"); + } +#endif +} + + #ifdef DEBUG #define S(x) ((x) > 0 ? 1 : 0) diff --git a/erts/etc/common/run_erl_vsn.h b/erts/etc/unix/run_erl.h index 2c3e67e81c..cc70a98e52 100644 --- a/erts/etc/common/run_erl_vsn.h +++ b/erts/etc/unix/run_erl.h @@ -1,8 +1,8 @@ /* * %CopyrightBegin% - * + * * Copyright Ericsson AB 2008-2009. 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 @@ -14,7 +14,7 @@ * 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% */ @@ -28,3 +28,4 @@ * 0: Older, without version handshake * 1: R12B-3, version handshake + window size ctrl */ + diff --git a/erts/etc/common/safe_string.c b/erts/etc/unix/safe_string.c index cdcdbf16f0..a5c11d41d8 100644 --- a/erts/etc/common/safe_string.c +++ b/erts/etc/unix/safe_string.c @@ -1,8 +1,8 @@ /* * %CopyrightBegin% - * + * * Copyright Ericsson AB 2008-2009. 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 @@ -14,12 +14,12 @@ * 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% */ -/* +/* * Module: safe_string.c - * + * * This is a bunch of generic string operation * that are safe regarding buffer overflow. * @@ -121,3 +121,4 @@ void* memmove(void *dest, const void *src, size_t n) return dest; } #endif /* HAVE_MEMMOVE */ + diff --git a/erts/etc/common/safe_string.h b/erts/etc/unix/safe_string.h index f9d2b2023a..5a471f10de 100644 --- a/erts/etc/common/safe_string.h +++ b/erts/etc/unix/safe_string.h @@ -1,8 +1,8 @@ /* * %CopyrightBegin% - * + * * Copyright Ericsson AB 2008-2009. 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 @@ -14,12 +14,12 @@ * 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% */ -/* +/* * Module: safe_string.h - * + * * This is an interface to a bunch of generic string operation * that are safe regarding buffer overflow. * @@ -63,3 +63,4 @@ char* find_str(const char* haystack, int size, const char* needle); #ifndef HAVE_MEMMOVE void* memmove(void *dest, const void *src, size_t n); #endif + diff --git a/erts/etc/unix/to_erl.c b/erts/etc/unix/to_erl.c index 82d3218964..0bd469727c 100644 --- a/erts/etc/unix/to_erl.c +++ b/erts/etc/unix/to_erl.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2013. All Rights Reserved. + * Copyright Ericsson AB 1996-2015. 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. @@ -17,9 +17,592 @@ * * %CopyrightEnd% */ +/* + * Module: to_erl.c + * + * This module implements a process that opens two specified FIFOs, one + * for reading and one for writing; reads from its stdin, and writes what + * it has read to the write FIF0; reads from the read FIFO, and writes to + * its stdout. + * + ________ _________ + | |--<-- pipe.r (fifo1) --<--| | + | to_erl | | run_erl | (parent) + |________|-->-- pipe.w (fifo2) -->--|_________| + ^ master pty + | + | slave pty + ____V____ + | | + | "erl" | (child) + |_________| + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <termios.h> +#include <dirent.h> +#include <signal.h> +#include <errno.h> +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif + +#include "run_erl.h" +#include "safe_string.h" /* strn_cpy, strn_catf, sn_printf, etc. */ + +#if defined(O_NONBLOCK) +# define DONT_BLOCK_PLEASE O_NONBLOCK +#else +# define DONT_BLOCK_PLEASE O_NDELAY +# if !defined(EAGAIN) +# define EAGAIN -3898734 +# endif +#endif + +#ifdef HAVE_STRERROR +# define STRERROR(x) strerror(x) +#else +# define STRERROR(x) "" +#endif + +#define noDEBUG + +#define PIPE_DIR "/tmp/" +#define PIPE_STUBNAME "erlang.pipe" +#define PIPE_STUBLEN strlen(PIPE_STUBNAME) + +#ifdef DEBUG +#define STATUS(s) { fprintf(stderr, (s)); fflush(stderr); } +#else +#define STATUS(s) +#endif + +#ifndef FILENAME_MAX +#define FILENAME_MAX 250 +#endif + +static struct termios tty_smode, tty_rmode; +static int tty_eof = 0; +static int recv_sig = 0; +static int protocol_ver = RUN_ERL_LO_VER; /* assume lowest to begin with */ + +static int write_all(int fd, const char* buf, int len); +static int window_size_seq(char* buf, size_t bufsz); +static int version_handshake(char* buf, int len, int wfd); +#ifdef DEBUG +static void show_terminal_settings(struct termios *); +#endif + +static void handle_ctrlc(int sig) +{ + /* Reinstall the handler, and signal break flag */ + signal(SIGINT,handle_ctrlc); + recv_sig = SIGINT; +} + +static void handle_sigwinch(int sig) +{ + recv_sig = SIGWINCH; +} + +static void usage(char *pname) +{ + fprintf(stderr, "Usage: %s [-h|-F] [pipe_name|pipe_dir/]\n", pname); + fprintf(stderr, "\t-h\tThis help text.\n"); + fprintf(stderr, "\t-F\tForce connection even though pipe is locked by other to_erl process.\n"); +} + +int main(int argc, char **argv) +{ + char FIFO1[FILENAME_MAX], FIFO2[FILENAME_MAX]; + int i, len, wfd, rfd; + fd_set readfds; + char buf[BUFSIZ]; + char pipename[FILENAME_MAX]; + int pipeIx = 1; + int force_lock = 0; + int got_some = 0; + + if (argc >= 2 && argv[1][0]=='-') { + switch (argv[1][1]) { + case 'h': + usage(argv[0]); + exit(1); + case 'F': + force_lock = 1; + break; + default: + fprintf(stderr,"Invalid option '%s'\n",argv[1]); + exit(1); + } + pipeIx = 2; + } + +#ifdef DEBUG + fprintf(stderr, "%s: pid is : %d\n", argv[0], (int)getpid()); +#endif + + strn_cpy(pipename, sizeof(pipename), + (argv[pipeIx] ? argv[pipeIx] : PIPE_DIR)); + + if(*pipename && pipename[strlen(pipename)-1] == '/') { + /* The user wishes us to find a pipe name in the specified */ + /* directory */ + int highest_pipe_num = 0; + DIR *dirp; + struct dirent *direntp; + + dirp = opendir(pipename); + if(!dirp) { + fprintf(stderr, "Can't access pipe directory %s: %s\n", pipename, strerror(errno)); + exit(1); + } + + /* Check the directory for existing pipes */ + + while((direntp=readdir(dirp)) != NULL) { + if(strncmp(direntp->d_name,PIPE_STUBNAME,PIPE_STUBLEN)==0) { + int num = atoi(direntp->d_name+PIPE_STUBLEN+1); + if(num > highest_pipe_num) + highest_pipe_num = num; + } + } + closedir(dirp); + strn_catf(pipename, sizeof(pipename), (highest_pipe_num?"%s.%d":"%s"), + PIPE_STUBNAME, highest_pipe_num); + } /* if */ + + /* read FIFO */ + sn_printf(FIFO1,sizeof(FIFO1),"%s.r",pipename); + /* write FIFO */ + sn_printf(FIFO2,sizeof(FIFO2),"%s.w",pipename); + + /* Check that nobody is running to_erl on this pipe already */ + if ((wfd = open (FIFO1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) { + /* Open as server succeeded -- to_erl is already running! */ + close(wfd); + fprintf(stderr, "Another to_erl process already attached to pipe " + "%s.\n", pipename); + if (force_lock) { + fprintf(stderr, "But we proceed anyway by force (-F).\n"); + } + else { + exit(1); + } + } + + if ((rfd = open (FIFO1, O_RDONLY|DONT_BLOCK_PLEASE, 0)) < 0) { +#ifdef DEBUG + fprintf(stderr, "Could not open FIFO %s for reading.\n", FIFO1); +#endif + fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno)); + exit(1); + } +#ifdef DEBUG + fprintf(stderr, "to_erl: %s opened for reading\n", FIFO1); +#endif + + if ((wfd = open (FIFO2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) { +#ifdef DEBUG + fprintf(stderr, "Could not open FIFO %s for writing.\n", FIFO2); +#endif + fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno)); + close(rfd); + exit(1); + } +#ifdef DEBUG + fprintf(stderr, "to_erl: %s opened for writing\n", FIFO2); +#endif + + fprintf(stderr, "Attaching to %s (^D to exit)\n\n", pipename); + + /* Set break handler to our handler */ + signal(SIGINT,handle_ctrlc); + + /* + * Save the current state of the terminal, and set raw mode. + */ + if (tcgetattr(0, &tty_rmode) , 0) { + fprintf(stderr, "Cannot get terminals current mode\n"); + exit(-1); + } + tty_smode = tty_rmode; + tty_eof = '\004'; /* Ctrl+D to exit */ +#ifdef DEBUG + show_terminal_settings(&tty_rmode); +#endif + tty_smode.c_iflag = + 1*BRKINT |/*Signal interrupt on break.*/ + 1*IGNPAR |/*Ignore characters with parity errors.*/ + 1*ISTRIP |/*Strip character.*/ + 0; + +#if 0 +0*IGNBRK |/*Ignore break condition.*/ +0*PARMRK |/*Mark parity errors.*/ +0*INPCK |/*Enable input parity check.*/ +0*INLCR |/*Map NL to CR on input.*/ +0*IGNCR |/*Ignore CR.*/ +0*ICRNL |/*Map CR to NL on input.*/ +0*IUCLC |/*Map upper-case to lower-case on input.*/ +0*IXON |/*Enable start/stop output control.*/ +0*IXANY |/*Enable any character to restart output.*/ +0*IXOFF |/*Enable start/stop input control.*/ +0*IMAXBEL|/*Echo BEL on input line too long.*/ +#endif + + tty_smode.c_oflag = + 1*OPOST |/*Post-process output.*/ + 1*ONLCR |/*Map NL to CR-NL on output.*/ +#ifdef XTABS + 1*XTABS |/*Expand tabs to spaces. (Linux)*/ +#endif +#ifdef OXTABS + 1*OXTABS |/*Expand tabs to spaces. (FreeBSD)*/ +#endif +#ifdef NL0 + 1*NL0 |/*Select newline delays*/ +#endif +#ifdef CR0 + 1*CR0 |/*Select carriage-return delays*/ +#endif +#ifdef TAB0 + 1*TAB0 |/*Select horizontal tab delays*/ +#endif +#ifdef BS0 + 1*BS0 |/*Select backspace delays*/ +#endif +#ifdef VT0 + 1*VT0 |/*Select vertical tab delays*/ +#endif +#ifdef FF0 + 1*FF0 |/*Select form feed delays*/ +#endif + 0; + +#if 0 +0*OLCUC |/*Map lower case to upper on output.*/ +0*OCRNL |/*Map CR to NL on output.*/ +0*ONOCR |/*No CR output at column 0.*/ +0*ONLRET |/*NL performs CR function.*/ +0*OFILL |/*Use fill characters for delay.*/ +0*OFDEL |/*Fill is DEL, else NULL.*/ +0*NL1 | +0*CR1 | +0*CR2 | +0*CR3 | +0*TAB1 | +0*TAB2 | +0*TAB3 |/*Expand tabs to spaces.*/ +0*BS1 | +0*VT1 | +0*FF1 | +#endif + + /* JALI: removed setting the tty_smode.c_cflag flags, since this is not */ + /* advisable if this is a *real* terminal, such as the console. In fact */ + /* this may hang the entire machine, deep, deep down (signalling break */ + /* or toggling the abort switch doesn't help) */ + + tty_smode.c_lflag = + 0; + +#if 0 +0*ISIG |/*Enable signals.*/ +0*ICANON |/*Canonical input (erase and kill processing).*/ +0*XCASE |/*Canonical upper/lower presentation.*/ +0*ECHO |/*Enable echo.*/ +0*ECHOE |/*Echo erase character as BS-SP-BS.*/ +0*ECHOK |/*Echo NL after kill character.*/ +0*ECHONL |/*Echo NL.*/ +0*NOFLSH |/*Disable flush after interrupt or quit.*/ +0*TOSTOP |/*Send SIGTTOU for background output.*/ +0*ECHOCTL|/*Echo control characters as ^char, delete as ^?.*/ +0*ECHOPRT|/*Echo erase character as character erased.*/ +0*ECHOKE |/*BS-SP-BS erase entire line on line kill.*/ +0*FLUSHO |/*Output is being flushed.*/ +0*PENDIN |/*Retype pending input at next read or input character.*/ +0*IEXTEN |/*Enable extended (implementation-defined) functions.*/ +#endif + + tty_smode.c_cc[VMIN] =0;/* Note that VMIN is the same as VEOF! */ + tty_smode.c_cc[VTIME] =0;/* Note that VTIME is the same as VEOL! */ + tty_smode.c_cc[VINTR] =3; + + tcsetattr(0, TCSADRAIN, &tty_smode); + +#ifdef DEBUG + show_terminal_settings(&tty_smode); +#endif + /* + * "Write a ^L to the FIFO which causes the other end to redisplay + * the input line." + * This does not seem to work as was intended in old comment above. + * However, this control character is now (R12B-3) used by run_erl + * to trigger the version handshaking between to_erl and run_erl + * at the start of every new to_erl-session. + */ + + if (write(wfd, "\014", 1) < 0) { + fprintf(stderr, "Error in writing ^L to FIFO.\n"); + } + + /* + * read and write + */ + while (1) { + FD_ZERO(&readfds); + FD_SET(0, &readfds); + FD_SET(rfd, &readfds); + if (select(rfd + 1, &readfds, NULL, NULL, NULL) < 0) { + if (recv_sig) { + FD_ZERO(&readfds); + } + else { + fprintf(stderr, "Error in select.\n"); + break; + } + } + len = 0; + + /* + * Read from terminal and write to FIFO + */ + if (recv_sig) { + switch (recv_sig) { + case SIGINT: + fprintf(stderr, "[Break]\n\r"); + buf[0] = '\003'; + len = 1; + break; + case SIGWINCH: + len = window_size_seq(buf,sizeof(buf)); + break; + default: + fprintf(stderr,"Unexpected signal: %u\n",recv_sig); + } + recv_sig = 0; + } + else if (FD_ISSET(0, &readfds)) { + len = read(0, buf, sizeof(buf)); + if (len <= 0) { + close(rfd); + close(wfd); + if (len < 0) { + fprintf(stderr, "Error in reading from stdin.\n"); + } else { + fprintf(stderr, "[EOF]\n\r"); + } + break; + } + /* check if there is an eof character in input */ + for (i = 0; i < len && buf[i] != tty_eof; i++); + if (buf[i] == tty_eof) { + fprintf(stderr, "[Quit]\n\r"); + break; + } + } + + if (len) { +#ifdef DEBUG + if(write(1, buf, len)); +#endif + if (write_all(wfd, buf, len) != len) { + fprintf(stderr, "Error in writing to FIFO.\n"); + close(rfd); + close(wfd); + break; + } + STATUS("\" OK\r\n"); + } + + /* + * Read from FIFO, write to terminal. + */ + if (FD_ISSET(rfd, &readfds)) { + STATUS("FIFO read: "); + len = read(rfd, buf, BUFSIZ); + if (len < 0 && errno == EAGAIN) { + /* + * No data this time, but the writing end of the FIFO is still open. + * Do nothing. + */ + ; + } else if (len <= 0) { + /* + * Either an error or end of file. In either case, break out + * of the loop. + */ + close(rfd); + close(wfd); + if (len < 0) { + fprintf(stderr, "Error in reading from FIFO.\n"); + } else + fprintf(stderr, "[End]\n\r"); + break; + } else { + if (!got_some) { + if ((len=version_handshake(buf,len,wfd)) < 0) { + close(rfd); + close(wfd); + break; + } + if (protocol_ver >= 1) { + /* Tell run_erl size of terminal window */ + signal(SIGWINCH, handle_sigwinch); + raise(SIGWINCH); + } + got_some = 1; + } + + /* + * We successfully read at least one character. Write what we got. + */ + STATUS("Terminal write: \""); + if (write_all(1, buf, len) != len) { + fprintf(stderr, "Error in writing to terminal.\n"); + close(rfd); + close(wfd); + break; + } + STATUS("\" OK\r\n"); + } + } + } + + /* + * Reset terminal characterstics + * XXX + */ + tcsetattr(0, TCSADRAIN, &tty_rmode); + return 0; +} + +/* Call write() until entire buffer has been written or error. + * Return len or -1. + */ +static int write_all(int fd, const char* buf, int len) +{ + int left = len; + int written; + while (left) { + written = write(fd,buf,left); + if (written < 0) { + return -1; + } + left -= written; + buf += written; + } + return len; +} + +static int window_size_seq(char* buf, size_t bufsz) +{ +#ifdef TIOCGWINSZ + struct winsize ws; + static const char prefix[] = "\033_"; + static const char suffix[] = "\033\\"; + /* This Esc sequence is called "Application Program Command" + and seems suitable to use for our own customized stuff. */ + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) { + int len = sn_printf(buf, bufsz, "%swinsize=%u,%u%s", + prefix, ws.ws_col, ws.ws_row, suffix); + return len; + } +#endif /* TIOCGWINSZ */ + return 0; +} + +/* to_erl run_erl + * | | + * |---------- '\014' -------->| (session start) + * | | + * |<---- "[run_erl v1-0]" ----| (version interval) + * | | + * |--- Esc_"version=1"Esc\ -->| (common version) + * | | + */ +static int version_handshake(char* buf, int len, int wfd) +{ + unsigned re_high=0, re_low; + char *end = find_str(buf,len,"]\n"); + + if (end && sscanf(buf,"[run_erl v%u-%u",&re_high,&re_low)==2) { + char wbuf[30]; + int wlen; + + if (re_low > RUN_ERL_HI_VER || re_high < RUN_ERL_LO_VER) { + fprintf(stderr,"Incompatible versions: to_erl=v%u-%u run_erl=v%u-%u\n", + RUN_ERL_HI_VER, RUN_ERL_LO_VER, re_high, re_low); + return -1; + } + /* Choose highest common version */ + protocol_ver = re_high < RUN_ERL_HI_VER ? re_high : RUN_ERL_HI_VER; + + wlen = sn_printf(wbuf, sizeof(wbuf), "\033_version=%u\033\\", + protocol_ver); + if (write_all(wfd, wbuf, wlen) < 0) { + fprintf(stderr,"Failed to send version handshake\n"); + return -1; + } + end += 2; + len -= (end-buf); + memmove(buf,end,len); + + } + else { /* we assume old run_erl without version handshake */ + protocol_ver = 0; + } + + if (re_high != RUN_ERL_HI_VER) { + fprintf(stderr,"run_erl has different version, " + "using common protocol level %u\n", protocol_ver); + } + + return len; +} + -#include "to_erl_common.h" +#ifdef DEBUG +#define S(x) ((x) > 0 ? 1 : 0) -int main(int argc,char **argv) { - return to_erl(argc,argv); +static void show_terminal_settings(struct termios *t) +{ + fprintf(stderr,"c_iflag:\n"); + fprintf(stderr,"Signal interrupt on break: BRKINT %d\n", S(t->c_iflag & BRKINT)); + fprintf(stderr,"Map CR to NL on input: ICRNL %d\n", S(t->c_iflag & ICRNL)); + fprintf(stderr,"Ignore break condition: IGNBRK %d\n", S(t->c_iflag & IGNBRK)); + fprintf(stderr,"Ignore CR: IGNCR %d\n", S(t->c_iflag & IGNCR)); + fprintf(stderr,"Ignore char with par. err's: IGNPAR %d\n", S(t->c_iflag & IGNPAR)); + fprintf(stderr,"Map NL to CR on input: INLCR %d\n", S(t->c_iflag & INLCR)); + fprintf(stderr,"Enable input parity check: INPCK %d\n", S(t->c_iflag & INPCK)); + fprintf(stderr,"Strip character ISTRIP %d\n", S(t->c_iflag & ISTRIP)); + fprintf(stderr,"Enable start/stop input ctrl IXOFF %d\n", S(t->c_iflag & IXOFF)); + fprintf(stderr,"ditto output ctrl IXON %d\n", S(t->c_iflag & IXON)); + fprintf(stderr,"Mark parity errors PARMRK %d\n", S(t->c_iflag & PARMRK)); + fprintf(stderr,"\n"); + fprintf(stderr,"c_oflag:\n"); + fprintf(stderr,"Perform output processing OPOST %d\n", S(t->c_oflag & OPOST)); + fprintf(stderr,"\n"); + fprintf(stderr,"c_cflag:\n"); + fprintf(stderr,"Ignore modem status lines CLOCAL %d\n", S(t->c_cflag & CLOCAL)); + fprintf(stderr,"\n"); + fprintf(stderr,"c_local:\n"); + fprintf(stderr,"Enable echo ECHO %d\n", S(t->c_lflag & ECHO)); + fprintf(stderr,"\n"); + fprintf(stderr,"c_cc:\n"); + fprintf(stderr,"c_cc[VEOF] %d\n", t->c_cc[VEOF]); } +#endif diff --git a/erts/etc/win32/msys_tools/vc/cc.sh b/erts/etc/win32/msys_tools/vc/cc.sh index ad05e5375b..ac89aac34e 100644 --- a/erts/etc/win32/msys_tools/vc/cc.sh +++ b/erts/etc/win32/msys_tools/vc/cc.sh @@ -242,7 +242,7 @@ for x in $SOURCES; do if [ $PREPROCESSING = true ]; then output_flag="-E" else - output_flag="-c -Fo`cmd //C echo ${output_filename}`" + output_flag="-FS -c -Fo`cmd //C echo ${output_filename}`" fi params="$COMMON_CFLAGS $MD $DEBUG_FLAGS $OPTIMIZE_FLAGS \ $CMD ${output_flag} $MPATH" @@ -250,6 +250,8 @@ for x in $SOURCES; do echo cc.sh "$SAVE" >>$CC_SH_DEBUG_LOG echo cl.exe $params >>$CC_SH_DEBUG_LOG fi + # MSYS2 (currently) converts the paths wrong, avoid it + export MSYS2_ARG_CONV_EXCL=-FoC eval cl.exe $params >$MSG_FILE 2>$ERR_FILE RES=$? if test $PREPROCESSING = false; then @@ -274,6 +276,7 @@ for x in $SOURCES; do fi rm -f $ERR_FILE $MSG_FILE if [ $RES != 0 ]; then + echo Failed: cl.exe $params rm -rf $TMPOBJDIR exit $RES fi @@ -312,7 +315,10 @@ if [ $LINKING = true ]; then stdlib="-lLIBMTD";; esac # And finally call the next script to do the linking... - params="$out_spec $LINKCMD $stdlib" + params="$out_spec $LINKCMD $stdlib" + if [ "X$CC_SH_DEBUG_LOG" != "X" ]; then + echo ld.sh $ACCUM_OBJECTS $params + fi eval ld.sh $ACCUM_OBJECTS $params RES=$? fi diff --git a/erts/etc/win32/msys_tools/vc/emu_cc.sh b/erts/etc/win32/msys_tools/vc/emu_cc.sh index 01f75b2468..10d59214ea 100644 --- a/erts/etc/win32/msys_tools/vc/emu_cc.sh +++ b/erts/etc/win32/msys_tools/vc/emu_cc.sh @@ -29,6 +29,7 @@ WTOOLDIR0=`win2msys_path.sh "$TOOLDIR"` WTOOLDIR=`cmd //C echo $WTOOLDIR0` # Do primitive 'make' newer_exe=`find $TOOLDIR -newer $COFFIX.c -name coffix.exe -print` +export MSYS2_ARG_CONV_EXCL="-FeC" if [ -z $newer_exe ]; then echo recompiling $COFFIX.exe cl.exe -Fe${WTOOLDIR}/coffix.exe ${WTOOLDIR}/coffix.c diff --git a/erts/etc/win32/msys_tools/vc/mc.sh b/erts/etc/win32/msys_tools/vc/mc.sh index e9ea9ff9a9..14b5ebaa8f 100644 --- a/erts/etc/win32/msys_tools/vc/mc.sh +++ b/erts/etc/win32/msys_tools/vc/mc.sh @@ -80,9 +80,14 @@ if [ -n "$OUTPUT_DIRNAME" ]; then exit $RES fi fi +# MSYS2 (currently) converts the paths wrong, avoid it +export MSYS2_ARG_CONV_EXCL= eval $MCC "$CMD" >/tmp/mc.exe.${p}.1 2>/tmp/mc.exe.${p}.2 RES=$? -tail +2 /tmp/mc.exe.${p}.2 >&2 +if [ $RES != 0 ]; then + echo Failed: $MCC "$CMD" +fi +tail -n +2 /tmp/mc.exe.${p}.2 >&2 cat /tmp/mc.exe.${p}.1 rm -f /tmp/mc.exe.${p}.2 /tmp/mc.exe.${p}.1 exit $RES diff --git a/erts/etc/win32/msys_tools/vc/rc.sh b/erts/etc/win32/msys_tools/vc/rc.sh index 1b3b1c85bd..1f8ade17cb 100644 --- a/erts/etc/win32/msys_tools/vc/rc.sh +++ b/erts/etc/win32/msys_tools/vc/rc.sh @@ -79,9 +79,14 @@ if [ "X$RC_SH_DEBUG_LOG" != "X" ]; then echo rc.sh "$SAVE" >>$RC_SH_DEBUG_LOG echo rc.exe $CMD >>$RC_SH_DEBUG_LOG fi +# MSYS2 (currently) converts the paths wrong, avoid it +export MSYS2_ARG_CONV_EXCL=-Fo eval $RCC "$CMD" >/tmp/rc.exe.${p}.1 2>/tmp/rc.exe.${p}.2 RES=$? -tail +2 /tmp/rc.exe.${p}.2 >&2 +if [ $RES != 0 ]; then + echo Failed: $RCC "$CMD" +fi +tail -n +2 /tmp/rc.exe.${p}.2 >&2 cat /tmp/rc.exe.${p}.1 rm -f /tmp/rc.exe.${p}.2 /tmp/rc.exe.${p}.1 exit $RES diff --git a/erts/etc/win32/nsis/Makefile b/erts/etc/win32/nsis/Makefile index 49d835170a..64f44ff86d 100644 --- a/erts/etc/win32/nsis/Makefile +++ b/erts/etc/win32/nsis/Makefile @@ -42,7 +42,13 @@ include $(ERL_TOP)/make/otp_release_targets.mk TARGET_DIR = $(RELEASE_PATH) -ifeq ($(MSYSTEM),MINGW32) +ifdef MSYSTEM + ifeq ($(MSYSTEM),$(filter $(MSYSTEM),MSYS MINGW32 MINGW64)) + USEMSYS := true + endif +endif + +ifeq ($(USEMSYS),true) MAKENSISFLAGS = //V2 WTESTROOT=$(shell (msys2win_path.sh "$(RELEASE_PATH)")) @@ -63,7 +69,7 @@ else endif REDIST_FILE=$(shell (sh ./find_redist.sh || echo "")) -ifeq ($(MSYSTEM),MINGW32) +ifeq ($(USEMSYS),true) NICEREDISTFILE=$(shell (msys2win_path.sh -m "$(REDIST_FILE)" 2>/dev/null || echo "")) else NICEREDISTFILE=$(shell (cygpath -d -m "$(REDIST_FILE)" 2>/dev/null || echo "")) diff --git a/erts/etc/win32/nsis/find_redist.sh b/erts/etc/win32/nsis/find_redist.sh index c0895c9dd5..03e92b21c7 100755 --- a/erts/etc/win32/nsis/find_redist.sh +++ b/erts/etc/win32/nsis/find_redist.sh @@ -164,7 +164,7 @@ fi #echo $BPATH_LIST for BP in $BPATH_LIST; do - for verdir in "sdk v2.0" "sdk v3.5" "v6.0A" "v7.0" "v7.0A" "v7.1"; do + for verdir in "sdk v2.0" "sdk v3.5" "v6.0A" "v7.0" "v7.0A" "v7.1" "VC redist 1033"; do BPATH=$BP fail=false allow_fail=false diff --git a/erts/include/erl_int_sizes_config.h.in b/erts/include/erl_int_sizes_config.h.in index b18f5ebc00..88c74cdeff 100644 --- a/erts/include/erl_int_sizes_config.h.in +++ b/erts/include/erl_int_sizes_config.h.in @@ -35,6 +35,3 @@ /* The size of a pointer. */ #undef SIZEOF_VOID_P - -/* Define if building a halfword-heap 64bit emulator (needed for NIF's) */ -#undef HALFWORD_HEAP_EMULATOR diff --git a/erts/include/internal/erl_printf_format.h b/erts/include/internal/erl_printf_format.h index efd926be99..953022017a 100644 --- a/erts/include/internal/erl_printf_format.h +++ b/erts/include/internal/erl_printf_format.h @@ -44,7 +44,6 @@ typedef long long ErlPfSWord; #error Found no appropriate type to use for 'Eterm', 'Uint' and 'Sint' #endif - typedef int (*fmtfn_t)(void*, char*, size_t); extern int erts_printf_format(fmtfn_t, void*, char*, va_list); @@ -57,17 +56,9 @@ extern int erts_printf_uword(fmtfn_t, void*, char, int, int, ErlPfUWord); extern int erts_printf_sword(fmtfn_t, void*, char, int, int, ErlPfSWord); extern int erts_printf_double(fmtfn_t, void *, char, int, int, double); -#ifdef HALFWORD_HEAP_EMULATOR -# if SIZEOF_INT != 4 -# error Unsupported integer size for HALFWORD_HEAP_EMULATOR -# endif -typedef unsigned int ErlPfEterm; -#else typedef ErlPfUWord ErlPfEterm; -#endif - -extern int (*erts_printf_eterm_func)(fmtfn_t, void*, ErlPfEterm, long, ErlPfEterm*); +extern int (*erts_printf_eterm_func)(fmtfn_t, void*, ErlPfEterm, long); #endif /* ERL_PRINTF_FORMAT_H__ */ diff --git a/erts/include/internal/ethr_mutex.h b/erts/include/internal/ethr_mutex.h index f76c4262ca..b402a139f5 100644 --- a/erts/include/internal/ethr_mutex.h +++ b/erts/include/internal/ethr_mutex.h @@ -98,7 +98,7 @@ void LeaveCriticalSection(CRITICAL_SECTION *); #if 0 # define ETHR_MTX_Q_LOCK_SPINLOCK__ # define ETHR_MTX_QLOCK_TYPE__ ethr_spinlock_t -#elif defined(ETHR_PTHREADS) || defined(ETHR_OSE_THREADS) +#elif defined(ETHR_PTHREADS) # define ETHR_MTX_Q_LOCK_PTHREAD_MUTEX__ # define ETHR_MTX_QLOCK_TYPE__ pthread_mutex_t #elif defined(ETHR_WIN32_THREADS) @@ -211,7 +211,7 @@ struct ethr_cond_ { #endif }; -#elif (defined(ETHR_PTHREADS) || defined(ETHR_OSE_THREADS)) && !defined(ETHR_DBG_WIN_MTX_WITH_PTHREADS) +#elif defined(ETHR_PTHREADS) && !defined(ETHR_DBG_WIN_MTX_WITH_PTHREADS) typedef struct ethr_mutex_ ethr_mutex; struct ethr_mutex_ { @@ -355,7 +355,7 @@ void ethr_rwmutex_rwunlock(ethr_rwmutex *); #ifdef ETHR_MTX_HARD_DEBUG #define ETHR_MTX_HARD_ASSERT(A) \ - ((void) ((A) ? 1 : ethr_assert_failed(__FILE__, __LINE__, __func__,#A))) + ((void) ((A) ? 1 : ethr_assert_failed(__FILE__, __LINE__, __func__, #A))) #else #define ETHR_MTX_HARD_ASSERT(A) ((void) 1) #endif @@ -634,7 +634,7 @@ ETHR_INLINE_MTX_FUNC_NAME_(ethr_mutex_unlock)(ethr_mutex *mtx) #endif /* ETHR_TRY_INLINE_FUNCS */ -#elif (defined(ETHR_PTHREADS) || defined(ETHR_OSE_THREADS)) && !defined(ETHR_DBG_WIN_MTX_WITH_PTHREADS) +#elif defined(ETHR_PTHREADS) && !defined(ETHR_DBG_WIN_MTX_WITH_PTHREADS) #if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_MUTEX_IMPL__) diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h index f9c203e97c..899aa4ad3c 100644 --- a/erts/include/internal/ethread.h +++ b/erts/include/internal/ethread.h @@ -193,28 +193,6 @@ typedef DWORD ethr_tsd_key; #define ETHR_YIELD() (Sleep(0), 0) -#elif defined(ETHR_OSE_THREADS) - -#include "ose.h" -#undef NIL - -#if defined(ETHR_HAVE_PTHREAD_H) -#include <pthread.h> -#endif - -typedef struct { - PROCESS id; - unsigned int tsd_key_index; - void *res; -} ethr_tid; - -typedef OSPPDKEY ethr_tsd_key; - -#undef ETHR_HAVE_ETHR_SIG_FUNCS - -/* Out own RW mutexes are probably faster, but use OSEs mutexes */ -#define ETHR_USE_OWN_RWMTX_IMPL__ - #else /* No supported thread lib found */ #ifdef ETHR_NO_SUPP_THR_LIB_NOT_FATAL @@ -382,19 +360,7 @@ extern ethr_runtime_t ethr_runtime__; #include "ethr_atomics.h" /* The atomics API */ -#if defined (ETHR_OSE_THREADS) -static ETHR_INLINE void -ose_yield(void) -{ - if (get_ptype(current_process()) == OS_PRI_PROC) { - set_pri(get_pri(current_process())); - } else { - delay(1); - } -} -#endif - -#if defined(__GNUC__) && !defined(ETHR_OSE_THREADS) +#if defined(__GNUC__) # ifndef ETHR_SPIN_BODY # if defined(__i386__) || defined(__x86_64__) # define ETHR_SPIN_BODY __asm__ __volatile__("rep;nop" : : : "memory") @@ -410,20 +376,9 @@ ose_yield(void) # ifndef ETHR_SPIN_BODY # define ETHR_SPIN_BODY do {YieldProcessor();ETHR_COMPILER_BARRIER;} while(0) # endif -#elif defined(ETHR_OSE_THREADS) -# ifndef ETHR_SPIN_BODY -# define ETHR_SPIN_BODY ose_yield() -# else -# error "OSE should use ose_yield()" -# endif #endif -#ifndef ETHR_OSE_THREADS #define ETHR_YIELD_AFTER_BUSY_LOOPS 50 -#else -#define ETHR_YIELD_AFTER_BUSY_LOOPS 0 -#endif - #ifndef ETHR_SPIN_BODY # define ETHR_SPIN_BODY ETHR_COMPILER_BARRIER @@ -446,18 +401,13 @@ ose_yield(void) # else # define ETHR_YIELD() (pthread_yield(), 0) # endif -# elif defined(ETHR_OSE_THREADS) -# define ETHR_YIELD() (ose_yield(), 0) # else # define ETHR_YIELD() (ethr_compiler_barrier(), 0) # endif #endif -#if defined(VALGRIND) || defined(ETHR_OSE_THREADS) -/* mutex as fallback for spinlock for VALGRIND and OSE. - OSE cannot use spinlocks as processes working on the - same execution unit have a tendency to deadlock. - */ +#if defined(VALGRIND) +/* mutex as fallback for spinlock for VALGRIND. */ # undef ETHR_HAVE_NATIVE_SPINLOCKS # undef ETHR_HAVE_NATIVE_RWSPINLOCKS #else @@ -504,16 +454,9 @@ typedef struct { int detached; /* boolean (default false) */ int suggested_stack_size; /* kilo words (default sys dependent) */ char *name; /* max 14 char long (default no-name) */ -#ifdef ETHR_OSE_THREADS - U32 coreNo; -#endif } ethr_thr_opts; -#if defined(ETHR_OSE_THREADS) -#define ETHR_THR_OPTS_DEFAULT_INITER {0, -1, NULL, 0} -#else #define ETHR_THR_OPTS_DEFAULT_INITER {0, -1, NULL} -#endif #if !defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_AUX_IMPL__) # define ETHR_NEED_SPINLOCK_PROTOTYPES__ @@ -627,8 +570,6 @@ typedef struct ethr_ts_event_ ethr_ts_event; /* Needed by ethr_mutex.h */ # include "win/ethr_event.h" #elif defined(ETHR_PTHREADS) # include "pthread/ethr_event.h" -#elif defined(ETHR_OSE_THREADS) -# include "ose/ethr_event.h" #endif int ethr_set_main_thr_status(int, int); @@ -718,37 +659,6 @@ ETHR_INLINE_FUNC_NAME_(ethr_leave_ts_event)(ethr_ts_event *tsep) #endif -#elif defined (ETHR_OSE_THREADS) - -#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHREAD_IMPL__) - -extern ethr_tsd_key ethr_ts_event_key__; - -static ETHR_INLINE ethr_ts_event * -ETHR_INLINE_FUNC_NAME_(ethr_get_ts_event)(void) -{ - ethr_ts_event *tsep = *(ethr_ts_event**)ose_get_ppdata(ethr_ts_event_key__); - if (!tsep) { - int res = ethr_get_tmp_ts_event__(&tsep); - if (res != 0) - ETHR_FATAL_ERROR__(res); - ETHR_ASSERT(tsep); - } - return tsep; -} - -static ETHR_INLINE void -ETHR_INLINE_FUNC_NAME_(ethr_leave_ts_event)(ethr_ts_event *tsep) -{ - if (tsep->iflgs & ETHR_TS_EV_TMP) { - int res = ethr_free_ts_event__(tsep); - if (res != 0) - ETHR_FATAL_ERROR__(res); - } -} - -#endif - #endif #include "ethr_mutex.h" /* Need atomic declarations and tse */ diff --git a/erts/include/internal/ose/ethr_event.h b/erts/include/internal/ose/ethr_event.h deleted file mode 100644 index c18f30aa4a..0000000000 --- a/erts/include/internal/ose/ethr_event.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2009-2011. 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% - */ - -/* - * Author: Rickard Green - */ - -//#define USE_PTHREAD_API - -#define ETHR_EVENT_OFF_WAITER__ -1L -#define ETHR_EVENT_OFF__ 1L -#define ETHR_EVENT_ON__ 0L - -#ifdef USE_PTHREAD_API - -typedef struct { - ethr_atomic32_t state; - pthread_mutex_t mtx; - pthread_cond_t cnd; -} ethr_event; - -#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_EVENT_IMPL__) - -static void ETHR_INLINE -ETHR_INLINE_FUNC_NAME_(ethr_event_set)(ethr_event *e) -{ - ethr_sint32_t val; - val = ethr_atomic32_xchg_mb(&e->state, ETHR_EVENT_ON__); - if (val == ETHR_EVENT_OFF_WAITER__) { - int res = pthread_mutex_lock(&e->mtx); - if (res != 0) - ETHR_FATAL_ERROR__(res); - res = pthread_cond_signal(&e->cnd); - if (res != 0) - ETHR_FATAL_ERROR__(res); - res = pthread_mutex_unlock(&e->mtx); - if (res != 0) - ETHR_FATAL_ERROR__(res); - } -} - -static void ETHR_INLINE -ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e) -{ - ethr_atomic32_set(&e->state, ETHR_EVENT_OFF__); - ETHR_MEMORY_BARRIER; -} - -#endif - -#else - -typedef struct { - ethr_atomic32_t state; - PROCESS proc; -} ethr_event; - -#if defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_EVENT_IMPL__) - -static void ETHR_INLINE -ETHR_INLINE_FUNC_NAME_(ethr_event_set)(ethr_event *e) -{ - ethr_sint32_t val = ethr_atomic32_xchg_mb(&e->state, ETHR_EVENT_ON__); - if (val == ETHR_EVENT_OFF_WAITER__) { -#ifdef DEBUG - OSFSEMVAL fsem_val = get_fsem(e->proc); - - /* There is a race in this assert. - This is because the state is set before the wait call in wait__. - We hope that a delay of 10 ms is enough */ - if (fsem_val == 0) - delay(10); - ETHR_ASSERT(get_fsem(e->proc) == -1); -#endif - signal_fsem(e->proc); - } -} - -static void ETHR_INLINE -ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e) -{ - ethr_atomic32_set(&e->state, ETHR_EVENT_OFF__); - ETHR_MEMORY_BARRIER; -} - -#endif - -#endif - -int ethr_event_init(ethr_event *e); -int ethr_event_destroy(ethr_event *e); -int ethr_event_wait(ethr_event *e); -int ethr_event_swait(ethr_event *e, int spincount); -#if !defined(ETHR_TRY_INLINE_FUNCS) || defined(ETHR_EVENT_IMPL__) -void ethr_event_set(ethr_event *e); -void ethr_event_reset(ethr_event *e); -#endif diff --git a/erts/include/internal/pthread/ethr_event.h b/erts/include/internal/pthread/ethr_event.h index 74cfa68e16..deb4b29686 100644 --- a/erts/include/internal/pthread/ethr_event.h +++ b/erts/include/internal/pthread/ethr_event.h @@ -83,12 +83,22 @@ ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e) #elif defined(ETHR_PTHREADS) /* --- Posix mutex/cond pipe/select implementation of events ---------------- */ +#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) +# define __DARWIN__ 1 +#endif + +#ifdef __DARWIN__ +typedef struct ethr_event_fdsets___ ethr_event_fdsets__; +#endif typedef struct { ethr_atomic32_t state; pthread_mutex_t mtx; pthread_cond_t cnd; int fd[2]; +#ifdef __DARWIN__ + ethr_event_fdsets__ *fdsets; +#endif } ethr_event; #define ETHR_EVENT_OFF_WAITER_SELECT__ ((ethr_sint32_t) -2) @@ -148,6 +158,7 @@ ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e) #endif int ethr_event_init(ethr_event *e); +int ethr_event_prepare_timed(ethr_event *e); int ethr_event_destroy(ethr_event *e); int ethr_event_wait(ethr_event *e); int ethr_event_swait(ethr_event *e, int spincount); diff --git a/erts/include/internal/win/ethr_event.h b/erts/include/internal/win/ethr_event.h index bf110e10f9..458565b9ea 100644 --- a/erts/include/internal/win/ethr_event.h +++ b/erts/include/internal/win/ethr_event.h @@ -56,6 +56,7 @@ ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e) #endif int ethr_event_init(ethr_event *e); +int ethr_event_prepare_timed(ethr_event *e); int ethr_event_destroy(ethr_event *e); int ethr_event_wait(ethr_event *e); int ethr_event_swait(ethr_event *e, int spincount); diff --git a/erts/lib_src/common/erl_misc_utils.c b/erts/lib_src/common/erl_misc_utils.c index 1262c50718..053217304b 100644 --- a/erts/lib_src/common/erl_misc_utils.c +++ b/erts/lib_src/common/erl_misc_utils.c @@ -160,8 +160,6 @@ erts_milli_sleep(long ms) if (ms > 0) { #ifdef __WIN32__ Sleep((DWORD) ms); -#elif defined(__OSE__) - delay(ms); #else struct timeval tv; tv.tv_sec = ms / 1000; @@ -320,10 +318,6 @@ erts_cpu_info_update(erts_cpu_info_t *cpuinfo) online = 0; #endif } -#elif defined(__OSE__) - online = ose_num_cpus(); - configured = ose_num_cpus(); - available = ose_num_cpus(); #endif if (online > configured) diff --git a/erts/lib_src/common/erl_printf_format.c b/erts/lib_src/common/erl_printf_format.c index 307680505c..e7d5d4413e 100644 --- a/erts/lib_src/common/erl_printf_format.c +++ b/erts/lib_src/common/erl_printf_format.c @@ -78,15 +78,7 @@ #endif #ifndef ERTS_SIZEOF_ETERM -# ifdef HALFWORD_HEAP_EMULATOR -# if SIZEOF_VOID_P == 8 -# define ERTS_SIZEOF_ETERM 4 -# else -# error "HALFWORD_HEAP_EMULATOR only allowed on 64-bit architecture" -# endif -# else -# define ERTS_SIZEOF_ETERM SIZEOF_VOID_P -# endif +#define ERTS_SIZEOF_ETERM SIZEOF_VOID_P #endif #if defined(__GNUC__) @@ -102,7 +94,7 @@ #endif #define FMTC_d 0x0000 -#define FMTC_R 0x0001 +/*empty 0x0001 was RELATIVE */ #define FMTC_o 0x0002 #define FMTC_u 0x0003 #define FMTC_x 0x0004 @@ -166,7 +158,7 @@ static char heX[] = "0123456789ABCDEF"; #define SIGN(X) ((X) > 0 ? 1 : ((X) < 0 ? -1 : 0)) #define USIGN(X) ((X) == 0 ? 0 : 1) -int (*erts_printf_eterm_func)(fmtfn_t, void*, ErlPfEterm, long, ErlPfEterm*) = NULL; +int (*erts_printf_eterm_func)(fmtfn_t, void*, ErlPfEterm, long) = NULL; static int noop_fn(void *vfp, char* buf, size_t len) @@ -645,7 +637,6 @@ int erts_printf_format(fmtfn_t fn, void* arg, char* fmt, va_list ap) case 'p': ptr++; fmt |= FMTC_p; break; case 'n': ptr++; fmt |= FMTC_n; break; case 'T': ptr++; fmt |= FMTC_T; break; - case 'R': ptr++; fmt |= FMTC_R; break; case '%': FMT(fn,arg,ptr,1,count); ptr++; @@ -820,11 +811,9 @@ int erts_printf_format(fmtfn_t fn, void* arg, char* fmt, va_list ap) default: *va_arg(ap,int*) = count; break; } break; - case FMTC_T: /* Eterm */ - case FMTC_R: { /* Eterm, Eterm* base (base ignored if !HALFWORD_HEAP) */ + case FMTC_T: { /* Eterm */ long prec; ErlPfEterm eterm; - ErlPfEterm* eterm_base; if (!erts_printf_eterm_func) return -EINVAL; @@ -835,16 +824,14 @@ int erts_printf_format(fmtfn_t fn, void* arg, char* fmt, va_list ap) else prec = (long) precision; eterm = va_arg(ap, ErlPfEterm); - eterm_base = ((fmt & FMTC_MASK) == FMTC_R) ? - va_arg(ap, ErlPfEterm*) : NULL; if (width > 0 && !(fmt & FMTF_adj)) { - res = (*erts_printf_eterm_func)(noop_fn, NULL, eterm, prec, eterm_base); + res = (*erts_printf_eterm_func)(noop_fn, NULL, eterm, prec); if (res < 0) return res; if (width > res) BLANKS(fn, arg, width - res, count); } - res = (*erts_printf_eterm_func)(fn, arg, eterm, prec, eterm_base); + res = (*erts_printf_eterm_func)(fn, arg, eterm, prec); if (res < 0) return res; count += res; diff --git a/erts/lib_src/common/ethr_aux.c b/erts/lib_src/common/ethr_aux.c index 0cbb1b2fb8..56fecf81b8 100644 --- a/erts/lib_src/common/ethr_aux.c +++ b/erts/lib_src/common/ethr_aux.c @@ -207,18 +207,7 @@ ethr_init_common__(ethr_init_data *id) ethr_min_stack_size__ = ETHR_B2KW(ethr_min_stack_size__); -#ifdef __OSE__ - /* For supervisor processes, OSE adds a number of bytes to the requested stack. With this - * addition, the resulting size must not exceed the largest available stack size. The number - * of bytes that will be added is configured in the monolith and can therefore not be - * specified here. We simply assume that it is less than 0x1000. The available stack sizes - * are configured in the .lmconf file and the largest one is usually 65536 bytes. - * Consequently, the requested stack size is limited to 0xF000. - */ - ethr_max_stack_size__ = 0xF000; -#else ethr_max_stack_size__ = 32*1024*1024; -#endif #if SIZEOF_VOID_P == 8 ethr_max_stack_size__ *= 2; #endif @@ -664,10 +653,6 @@ ETHR_IMPL_NORETURN__ ethr_fatal_error__(const char *file, int ethr_assert_failed(const char *file, int line, const char *func, char *a) { fprintf(stderr, "%s:%d: %s(): Assertion failed: %s\n", file, line, func, a); -#ifdef __OSE__ - ramlog_printf("%d: %s:%d: %s(): Assertion failed: %s\n", - current_process(),file, line, func, a); -#endif ethr_abort__(); return 0; } diff --git a/erts/lib_src/common/ethr_mutex.c b/erts/lib_src/common/ethr_mutex.c index 72aa34ec1c..a596e6c31c 100644 --- a/erts/lib_src/common/ethr_mutex.c +++ b/erts/lib_src/common/ethr_mutex.c @@ -1250,7 +1250,7 @@ ethr_cond_wait(ethr_cond *cnd, ethr_mutex *mtx) return 0; } -#elif (defined(ETHR_PTHREADS) || defined(ETHR_OSE_THREADS)) && !defined(ETHR_DBG_WIN_MTX_WITH_PTHREADS) +#elif defined(ETHR_PTHREADS) && !defined(ETHR_DBG_WIN_MTX_WITH_PTHREADS) /* -- pthread mutex and condition variables -------------------------------- */ int diff --git a/erts/lib_src/ose/ethr_event.c b/erts/lib_src/ose/ethr_event.c deleted file mode 100644 index 24ea191c4b..0000000000 --- a/erts/lib_src/ose/ethr_event.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2009-2010. 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% - */ - -/* - * Author: Rickard Green - */ - -#define ETHR_INLINE_FUNC_NAME_(X) X ## __ -#define ETHR_EVENT_IMPL__ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "ethread.h" - -#ifdef USE_PTHREAD_API - -int -ethr_event_init(ethr_event *e) -{ - int res; - ethr_atomic32_init(&e->state, ETHR_EVENT_OFF__); - res = pthread_mutex_init(&e->mtx, NULL); - if (res != 0) - return res; - res = pthread_cond_init(&e->cnd, NULL); - if (res != 0) { - pthread_mutex_destroy(&e->mtx); - return res; - } - return 0; -} - -int -ethr_event_destroy(ethr_event *e) -{ - int res; - res = pthread_mutex_destroy(&e->mtx); - if (res != 0) - return res; - res = pthread_cond_destroy(&e->cnd); - if (res != 0) - return res; - return 0; -} - -static ETHR_INLINE int -wait__(ethr_event *e, int spincount) -{ - int sc = spincount; - ethr_sint32_t val; - int res, ulres; - int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS; - - if (spincount < 0) - ETHR_FATAL_ERROR__(EINVAL); - - while (1) { - val = ethr_atomic32_read(&e->state); - if (val == ETHR_EVENT_ON__) - return 0; - if (sc == 0) - break; - sc--; - ETHR_SPIN_BODY; - if (--until_yield == 0) { - until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS; - res = ETHR_YIELD(); - if (res != 0) - ETHR_FATAL_ERROR__(res); - } - } - - if (val != ETHR_EVENT_OFF_WAITER__) { - val = ethr_atomic32_cmpxchg(&e->state, - ETHR_EVENT_OFF_WAITER__, - ETHR_EVENT_OFF__); - if (val == ETHR_EVENT_ON__) - return 0; - ETHR_ASSERT(val == ETHR_EVENT_OFF__); - } - - ETHR_ASSERT(val == ETHR_EVENT_OFF_WAITER__ - || val == ETHR_EVENT_OFF__); - - res = pthread_mutex_lock(&e->mtx); - if (res != 0) - ETHR_FATAL_ERROR__(res); - - while (1) { - - val = ethr_atomic32_read(&e->state); - if (val == ETHR_EVENT_ON__) - break; - - res = pthread_cond_wait(&e->cnd, &e->mtx); - if (res == EINTR) - break; - if (res != 0) - ETHR_FATAL_ERROR__(res); - } - - ulres = pthread_mutex_unlock(&e->mtx); - if (ulres != 0) - ETHR_FATAL_ERROR__(ulres); - - return res; /* 0 || EINTR */ -} - -#else -/* --- OSE implementation of events ---------------------------- */ - -#ifdef DEBUG -union SIGNAL { - SIGSELECT signo; -}; -#endif - -int -ethr_event_init(ethr_event *e) -{ - ethr_atomic32_init(&e->state, ETHR_EVENT_OFF__); - e->proc = current_process(); - return 0; -} - -int -ethr_event_destroy(ethr_event *e) -{ - return 0; -} - -static ETHR_INLINE int -wait__(ethr_event *e, int spincount) -{ - int sc = spincount; - int res; - int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS; - - if (spincount < 0) - ETHR_FATAL_ERROR__(EINVAL); - - ETHR_ASSERT(e->proc == current_process()); - ETHR_ASSERT(get_fsem(current_process()) == 0); - - while (1) { - ethr_sint32_t val; - while (1) { - val = ethr_atomic32_read(&e->state); - if (val == ETHR_EVENT_ON__) - return 0; - if (sc == 0) - break; - sc--; - ETHR_SPIN_BODY; - if (--until_yield == 0) { - until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS; - res = ETHR_YIELD(); - if (res != 0) - ETHR_FATAL_ERROR__(res); - } - } - if (val != ETHR_EVENT_OFF_WAITER__) { - val = ethr_atomic32_cmpxchg(&e->state, - ETHR_EVENT_OFF_WAITER__, - ETHR_EVENT_OFF__); - if (val == ETHR_EVENT_ON__) - return 0; - ETHR_ASSERT(val == ETHR_EVENT_OFF__); - } - - wait_fsem(1); - - ETHR_ASSERT(get_fsem(current_process()) == 0); - } -} - -#endif - -void -ethr_event_reset(ethr_event *e) -{ - ethr_event_reset__(e); -} - -void -ethr_event_set(ethr_event *e) -{ - ethr_event_set__(e); -} - -int -ethr_event_wait(ethr_event *e) -{ - return wait__(e, 0); -} - -int -ethr_event_swait(ethr_event *e, int spincount) -{ - return wait__(e, spincount); -} diff --git a/erts/lib_src/ose/ethread.c b/erts/lib_src/ose/ethread.c deleted file mode 100644 index dc16acdd08..0000000000 --- a/erts/lib_src/ose/ethread.c +++ /dev/null @@ -1,833 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2010-2011. 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% - */ - -/* - * Description: OSE implementation of the ethread library - * Author: Lukas Larsson - */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "stdio.h" -#ifdef ETHR_TIME_WITH_SYS_TIME -# include "time.h" -# include "sys/time.h" -#else -# ifdef ETHR_HAVE_SYS_TIME_H -# include "sys/time.h" -# else -# include "time.h" -# endif -#endif -#include "sys/types.h" -#include "unistd.h" - -#include "limits.h" - -#define ETHR_INLINE_FUNC_NAME_(X) X ## __ -#define ETHREAD_IMPL__ - -#include "ethread.h" -#include "ethr_internal.h" - -#include "erl_printf.h" -#include "efs.h" -#include "ose.h" - -#include "ose_spi.h" - -#include "string.h" -#include "ctype.h" -#include "stdlib.h" - -#ifndef ETHR_HAVE_ETHREAD_DEFINES -#error Missing configure defines -#endif - -#define ETHR_INVALID_TID_ID -1 - -#define DEFAULT_PRIO_NAME "ERTS_ETHR_DEFAULT_PRIO" - -/* Set the define to 1 to get some logging */ -#if 0 -#include "ramlog.h" -#define LOG(output) ramlog_printf output -#else -#define LOG(output) -#endif - -static ethr_tid main_thr_tid; -static const char* own_tid_key = "ethread_own_tid"; -ethr_tsd_key ethr_ts_event_key__; - -#define ETHREADWRAPDATASIG 1 - -/* Init data sent to thr_wrapper() */ -typedef struct { - SIGSELECT sig_no; - ethr_ts_event *tse; - ethr_tid *tid; - ethr_sint32_t result; - void *(*thr_func)(void *); - void *arg; - void *prep_func_res; - const char *name; -} ethr_thr_wrap_data__; - -union SIGNAL { - SIGSELECT sig_no; - ethr_thr_wrap_data__ data; -}; - -#define ETHR_GET_OWN_TID__ ((ethr_tid *) get_envp(current_process(),\ - own_tid_key)) - -/* - * -------------------------------------------------------------------------- - * Static functions - * -------------------------------------------------------------------------- - */ - -/* Will retrive the instrinsic name by removing the 'prefix' and the - * suffix from 'name'. - * The 'prefix' is given as an inparameter. If NULL or an empty string no - * prefix will be removed. - * If 'strip_suffix' is 1 suffixes in the form of '_123' will be removed. - * Will return a pointer to a newly allocated buffer containing the intrinsic - * name in uppercase characters. - * The caller must remember to free this buffer when no lnger needed. - */ -static char * -ethr_intrinsic_name(const char *name, const char *prefix, int strip_suffix) -{ - const char *start = name; - const char *end = name + strlen(name); - char *intrinsic_name = NULL; - int i; - - if (name == NULL) { - LOG(("ERTS - ethr_intrinsic_namNo input name.\n")); - return NULL; - } - - /* take care of the prefix */ - if ((prefix != NULL) && (*prefix != '\0')) { - const char *found = strstr(name, prefix); - - if (found == name) { - /* found the prefix at the beginning */ - start += strlen(prefix); - } - } - - /* take care of the suffix */ - if (strip_suffix) { - const char *suffix_start = strrchr(start, '_'); - - if (suffix_start != NULL) { - const char *ch; - int only_numbers = 1; - - for (ch = suffix_start + 1; *ch != '\0'; ch++) { - if (strchr("0123456789", *ch) == NULL) { - only_numbers = 0; - break; - } - } - - if (only_numbers) { - end = suffix_start; - } - } - } - - intrinsic_name = malloc(end - start + 1); - for (i = 0; (start + i) < end; i++) { - intrinsic_name[i] = toupper(start[i]); - } - intrinsic_name[i] = '\0'; - - return intrinsic_name; -} - -static char * -ethr_get_amended_env(const char *name, const char *prefix, const char *suffix) -{ - unsigned len; - char *env_name = NULL; - char *env_value = NULL; - - if (name == NULL) { - return NULL; - } - - len = strlen(name); - - if (prefix != NULL) { - len += strlen(prefix); - } - - if (suffix != NULL) { - len += strlen(suffix); - } - - env_name = malloc(len + 1); - sprintf(env_name, "%s%s%s", (prefix != NULL) ? prefix : "", - name, - (suffix != NULL) ? suffix : ""); - env_value = get_env(get_bid(current_process()), env_name); - - if (env_value == NULL) { - LOG(("ERTS - ethr_get_amended_env(): %s environment variable not present\n", env_name)); - } else { - LOG(("ERTS - ethr_get_amended_env(): Found %s environment variable: %s.\n", env_name, env_value)); - } - free(env_name); - - return env_value; -} - -/* Reads the environment variable derived from 'name' and interprets it as as an - * OSE priority. If successfull it will update 'out_prio'. - * Returns: 0 if successfull - * -1 orherwise. - */ -static int -ethr_get_prio(const char *name, OSPRIORITY *out_prio) -{ - int rc = -1; - char *intrinsic_name = NULL; - char *prio_env = NULL; - long prio; - char *endptr = NULL; - - LOG(("ERTS - ethr_get_prio(): name: %s.\n", name)); - - intrinsic_name = ethr_intrinsic_name(name, NULL, 1); - LOG(("ERTS - ethr_get_prio(): Intrinsic name: %s.\n", intrinsic_name)); - - prio_env = ethr_get_amended_env(intrinsic_name, "ERTS_", "_PRIO"); - if (prio_env == NULL) { - goto fini; - } - - prio = efs_str_to_long(prio_env, (const char **)&endptr); - if (endptr != NULL) { - LOG(("ERTS - ethr_get_prio(): Environment varible for '%s' includes " - "non-numerical characters: '%s'.\n", intrinsic_name, prio_env)); - goto fini; - } - - if ((prio < 0) || (prio > 32)) { - LOG(("ERTS - ethr_get_prio(): prio for '%s' (%d) is out of bounds (0-32).\n", - intrinsic_name, prio)); - goto fini; - } - - /* Success */ - *out_prio = (OSPRIORITY)prio; - rc = 0; - -fini: - if (intrinsic_name != NULL) { - free(intrinsic_name); - } - if (prio_env != NULL) { - free_buf((union SIGNAL **) &prio_env); - } - - return rc; -} - -static PROCESS blockId(void) { - static PROCESS bid = (PROCESS)0; - - /* For now we only use the same block. */ - /* if (bid == 0) { - bid = create_block("Erlang-VM", 0, 0, 0, 0); - } - return bid; */ - return 0; -} - -static void thr_exit_cleanup(ethr_tid *tid, void *res) -{ - - ETHR_ASSERT(tid == ETHR_GET_OWN_TID__); - - tid->res = res; - - ethr_run_exit_handlers__(); - ethr_ts_event_destructor__((void *) ethr_get_tse__()); -} - -//static OS_PROCESS(thr_wrapper); -static OS_PROCESS(thr_wrapper) -{ - ethr_tid my_tid; - ethr_sint32_t result; - void *res; - void *(*thr_func)(void *); - void *arg; - ethr_ts_event *tsep = NULL; - -#ifdef DEBUG - { - PROCESS pid = current_process(); - - const char *execMode; - - PROCESS bid = get_bid(pid); - - /* In the call below, 16 is a secret number provided by frbr that makes - * the function return current domain. */ - OSADDRESS domain = get_pid_info(current_process(), 16); - -#ifdef HAVE_OSE_SPI_H - execMode = get_pid_info(pid, OSE_PI_SUPERVISOR) - ? "Supervisor" - : "User"; -#else - execMode = "unknown"; -#endif - - fprintf(stderr,"[0x%x] New process. Bid:0x%x, domain:%d, exec mode:%s\n", - current_process(), bid, domain, execMode); - } -#endif - - { - SIGSELECT sigsel[] = {1,ETHREADWRAPDATASIG}; - union SIGNAL *init_msg = receive(sigsel); - - thr_func = init_msg->data.thr_func; - arg = init_msg->data.arg; - - result = (ethr_sint32_t) ethr_make_ts_event__(&tsep); - - if (result == 0) { - tsep->iflgs |= ETHR_TS_EV_ETHREAD; - my_tid = *init_msg->data.tid; - set_envp(current_process(), own_tid_key, (OSADDRESS)&my_tid); - if (ethr_thr_child_func__) - ethr_thr_child_func__(init_msg->data.prep_func_res); - } - - init_msg->data.result = result; - - send(&init_msg,sender(&init_msg)); - } - - /* pthread mutex api says we have to do this */ - signal_fsem(current_process()); - ETHR_ASSERT(get_fsem(current_process()) == 0); - - res = result == 0 ? (*thr_func)(arg) : NULL; - - ethr_thr_exit(&res); -} - -/* internal exports */ - -int ethr_set_tse__(ethr_ts_event *tsep) -{ - return ethr_tsd_set(ethr_ts_event_key__,(void *) tsep); -} - -ethr_ts_event *ethr_get_tse__(void) -{ - return (ethr_ts_event *) ethr_tsd_get(ethr_ts_event_key__); -} - -#if defined(ETHR_PPC_RUNTIME_CONF__) - -static int -ppc_init__(void) -{ - int pid; - - - ethr_runtime__.conf.have_lwsync = 0; - - return 0; -} - -#endif - -#if defined(ETHR_X86_RUNTIME_CONF__) - -void -ethr_x86_cpuid__(int *eax, int *ebx, int *ecx, int *edx) -{ -#if ETHR_SIZEOF_PTR == 4 - int have_cpuid; - /* - * If it is possible to toggle eflags bit 21, - * we have the cpuid instruction. - */ - __asm__ ("pushf\n\t" - "popl %%eax\n\t" - "movl %%eax, %%ecx\n\t" - "xorl $0x200000, %%eax\n\t" - "pushl %%eax\n\t" - "popf\n\t" - "pushf\n\t" - "popl %%eax\n\t" - "movl $0x0, %0\n\t" - "xorl %%ecx, %%eax\n\t" - "jz no_cpuid\n\t" - "movl $0x1, %0\n\t" - "no_cpuid:\n\t" - : "=r"(have_cpuid) - : - : "%eax", "%ecx", "cc"); - if (!have_cpuid) { - *eax = *ebx = *ecx = *edx = 0; - return; - } -#endif -#if ETHR_SIZEOF_PTR == 4 && defined(__PIC__) && __PIC__ - /* - * When position independet code is used in 32-bit mode, the B register - * is used for storage of global offset table address, and we may not - * use it as input or output in an asm. We need to save and restore the - * B register explicitly (for some reason gcc doesn't provide this - * service to us). - */ - __asm__ ("pushl %%ebx\n\t" - "cpuid\n\t" - "movl %%ebx, %1\n\t" - "popl %%ebx\n\t" - : "=a"(*eax), "=r"(*ebx), "=c"(*ecx), "=d"(*edx) - : "0"(*eax) - : "cc"); -#else - __asm__ ("cpuid\n\t" - : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) - : "0"(*eax) - : "cc"); -#endif -} - -#endif /* ETHR_X86_RUNTIME_CONF__ */ - -/* - * -------------------------------------------------------------------------- - * Exported functions - * -------------------------------------------------------------------------- - */ - -int -ethr_init(ethr_init_data *id) -{ - int res; - - if (!ethr_not_inited__) - return EINVAL; - - -#if defined(ETHR_PPC_RUNTIME_CONF__) - res = ppc_init__(); - if (res != 0) - goto error; -#endif - - res = ethr_init_common__(id); - if (res != 0) - goto error; - - main_thr_tid.id = current_process(); - main_thr_tid.tsd_key_index = 0; - - set_envp(current_process(),own_tid_key,(OSADDRESS)&main_thr_tid); - signal_fsem(current_process()); - - - ETHR_ASSERT(&main_thr_tid == ETHR_GET_OWN_TID__); - - ethr_not_inited__ = 0; - - ethr_tsd_key_create(ðr_ts_event_key__,"ethread_tse"); - - return 0; - error: - ethr_not_inited__ = 1; - return res; - -} - -int -ethr_late_init(ethr_late_init_data *id) -{ - int res = ethr_late_init_common__(id); - if (res != 0) - return res; - ethr_not_completely_inited__ = 0; - return res; -} - -int -ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg, - ethr_thr_opts *opts) -{ - int res; - int use_stack_size = (opts && opts->suggested_stack_size >= 0 - ? opts->suggested_stack_size - : 0x200 /* Use system default */); - OSPRIORITY use_prio; - char *use_name; - char default_thr_name[20]; - static int no_of_thr = 0; - cpuid_t use_core; - - union SIGNAL *init_msg; - SIGSELECT sigsel[] = {1,ETHREADWRAPDATASIG}; - void *prep_func_res; - - - if (opts != NULL) { - LOG(("ERTS - ethr_thr_create(): opts supplied: name: %s, coreNo: %u.\n", - opts->name, opts->coreNo)); - use_name = opts->name; - use_core = opts->coreNo; - if (0 != ethr_get_prio(use_name, &use_prio)) { - if (0 != ethr_get_prio("DEFAULT", &use_prio)) { - use_prio = get_pri(current_process()); - LOG(("ERTS - ethr_thr_create(): Using current process' prio: %d.\n", use_prio)); - } else { - LOG(("ERTS - ethr_thr_create(): Using default prio: %d.\n", use_prio)); - } - } else { - LOG(("ERTS - ethr_thr_create(): Using configured prio: %d.\n", use_prio)); - } - } else { - LOG(("ERTS - ethr_thr_create(): opts not supplied. Using defaults.\n")); - no_of_thr++; - sprintf(default_thr_name, "ethread_%d", no_of_thr); - use_name = default_thr_name; - use_core = ose_cpu_id(); - - if (0 != ethr_get_prio("DEFAULT", &use_prio)) { - use_prio = get_pri(current_process()); - LOG(("ERTS - ethr_thr_create(): Using current process' prio: %d.\n", use_prio)); - } - } - -#ifdef ETHR_MODIFIED_DEFAULT_STACK_SIZE - if (use_stack_size < 0) - use_stack_size = ETHR_MODIFIED_DEFAULT_STACK_SIZE; -#endif - -#if ETHR_XCHK - if (ethr_not_completely_inited__) { - ETHR_ASSERT(0); - return EACCES; - } - if (!tid || !func) { - ETHR_ASSERT(0); - return EINVAL; - } -#endif - - if (use_stack_size >= 0) { - size_t suggested_stack_size = (size_t) use_stack_size; - size_t stack_size; -#ifdef ETHR_DEBUG - suggested_stack_size /= 2; /* Make sure we got margin */ -#endif -#ifdef ETHR_STACK_GUARD_SIZE - /* The guard is at least on some platforms included in the stack size - passed when creating threads */ - suggested_stack_size += ETHR_B2KW(ETHR_STACK_GUARD_SIZE); -#endif - - if (suggested_stack_size < ethr_min_stack_size__) - stack_size = ETHR_KW2B(ethr_min_stack_size__); - else if (suggested_stack_size > ethr_max_stack_size__) - stack_size = ETHR_KW2B(ethr_max_stack_size__); - else - stack_size = ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size)); - use_stack_size = stack_size; - } - - init_msg = alloc(sizeof(ethr_thr_wrap_data__), ETHREADWRAPDATASIG); - - /* Call prepare func if it exist */ - if (ethr_thr_prepare_func__) - init_msg->data.prep_func_res = ethr_thr_prepare_func__(); - else - init_msg->data.prep_func_res = NULL; - - LOG(("ERTS - ethr_thr_create(): Process [0x%x] is creating '%s', coreNo = %u, prio:%u\n", - current_process(), use_name, use_core, use_prio)); - - tid->id = create_process(OS_PRI_PROC, use_name, thr_wrapper, - use_stack_size, use_prio, 0, - get_bid(current_process()), NULL, 0, 0); - if (ose_bind_process(tid->id, use_core)) { - LOG(("ERTS - ethr_thr_create(): Bound pid 0x%x (%s) to core no %u.\n", - tid->id, use_name, use_core)); - } else { - LOG(("ERTS - ethr_thr_create(): Failed binding pid 0x%x (%s) to core no %u.\n", - tid->id, use_name, use_core)); - } - - /*FIXME!!! Normally this shouldn't be used in shared mode. Still there is - * a problem with stdin fd in fd_ processes which should be further - * investigated */ - efs_clone(tid->id); - - tid->tsd_key_index = 0; - tid->res = NULL; - - init_msg->data.tse = ethr_get_ts_event(); - init_msg->data.thr_func = func; - init_msg->data.arg = arg; - init_msg->data.tid = tid; - init_msg->data.name = opts->name; - - send(&init_msg, tid->id); - - start(tid->id); - init_msg = receive(sigsel); - - res = init_msg->data.result; - prep_func_res = init_msg->data.prep_func_res; - - free_buf(&init_msg); - /* Cleanup... */ - - if (ethr_thr_parent_func__) - ethr_thr_parent_func__(prep_func_res); - - LOG(("ERTS - ethr_thr_create(): Exiting.\n")); - return res; -} - -int -ethr_thr_join(ethr_tid tid, void **res) -{ - SIGSELECT sigsel[] = {1,OS_ATTACH_SIG}; -#if ETHR_XCHK - if (ethr_not_inited__) { - ETHR_ASSERT(0); - return EACCES; - } -#endif - - if (tid.id == ETHR_INVALID_TID_ID) - return EINVAL; - - attach(NULL,tid.id); - receive(sigsel); - - if (res) - *res = tid.res; - - return 0; -} - -int -ethr_thr_detach(ethr_tid tid) -{ -#if ETHR_XCHK - if (ethr_not_inited__) { - ETHR_ASSERT(0); - return EACCES; - } -#endif - return 0; -} - -void -ethr_thr_exit(void *res) -{ - ethr_tid *tid; -#if ETHR_XCHK - if (ethr_not_inited__) { - ETHR_ASSERT(0); - return; - } -#endif - tid = ETHR_GET_OWN_TID__; - if (!tid) { - ETHR_ASSERT(0); - kill_proc(current_process()); - } - thr_exit_cleanup(tid, res); - /* Harakiri possible? */ - kill_proc(current_process()); -} - -ethr_tid -ethr_self(void) -{ - ethr_tid *tid; -#if ETHR_XCHK - if (ethr_not_inited__) { - ethr_tid dummy_tid = {ETHR_INVALID_TID_ID, 0, NULL}; - ETHR_ASSERT(0); - return dummy_tid; - } -#endif - tid = ETHR_GET_OWN_TID__; - if (!tid) { - ethr_tid dummy_tid = {ETHR_INVALID_TID_ID, 0, NULL}; - return dummy_tid; - } - return *tid; -} - -int -ethr_equal_tids(ethr_tid tid1, ethr_tid tid2) -{ - return tid1.id == tid2.id && tid1.id != ETHR_INVALID_TID_ID; -} - - -/* - * Thread specific events - */ - -ethr_ts_event * -ethr_get_ts_event(void) -{ - return ethr_get_ts_event__(); -} - -void -ethr_leave_ts_event(ethr_ts_event *tsep) -{ - ethr_leave_ts_event__(tsep); -} - -/* - * Thread specific data - */ - -int -ethr_tsd_key_create(ethr_tsd_key *keyp, char *keyname) -{ - -#if ETHR_XCHK - if (ethr_not_inited__) { - ETHR_ASSERT(0); - return EACCES; - } - if (!keyp) { - ETHR_ASSERT(0); - return EINVAL; - } -#endif - - ose_create_ppdata(keyname,keyp); - - return 0; -} - -int -ethr_tsd_key_delete(ethr_tsd_key key) -{ -#if ETHR_XCHK - if (ethr_not_inited__) { - ETHR_ASSERT(0); - return EACCES; - } -#endif - /* Not possible to delete ppdata */ - - return 0; -} - -int -ethr_tsd_set(ethr_tsd_key key, void *value) -{ - void **ppdp; -#if ETHR_XCHK - if (ethr_not_inited__) { - ETHR_ASSERT(0); - return EACCES; - } -#endif - ppdp = (void **)ose_get_ppdata(key); - *ppdp = value; - return 0; -} - -void * -ethr_tsd_get(ethr_tsd_key key) -{ -#if ETHR_XCHK - if (ethr_not_inited__) { - ETHR_ASSERT(0); - return NULL; - } -#endif - return *(void**)ose_get_ppdata(key); -} - -/* - * Signal functions - */ - -#if ETHR_HAVE_ETHR_SIG_FUNCS - -int ethr_sigmask(int how, const sigset_t *set, sigset_t *oset) -{ -#if ETHR_XCHK - if (ethr_not_inited__) { - ETHR_ASSERT(0); - return EACCES; - } - if (!set && !oset) { - ETHR_ASSERT(0); - return EINVAL; - } -#endif - return pthread_sigmask(how, set, oset); -} - -int ethr_sigwait(const sigset_t *set, int *sig) -{ -#if ETHR_XCHK - if (ethr_not_inited__) { - ETHR_ASSERT(0); - return EACCES; - } - if (!set || !sig) { - ETHR_ASSERT(0); - return EINVAL; - } -#endif - if (sigwait(set, sig) < 0) - return errno; - return 0; -} - -#endif /* #if ETHR_HAVE_ETHR_SIG_FUNCS */ - -ETHR_IMPL_NORETURN__ -ethr_abort__(void) -{ - abort(); -} diff --git a/erts/lib_src/pthread/ethr_event.c b/erts/lib_src/pthread/ethr_event.c index ba664236f6..0629b4dfcd 100644 --- a/erts/lib_src/pthread/ethr_event.c +++ b/erts/lib_src/pthread/ethr_event.c @@ -29,6 +29,13 @@ #include "config.h" #endif +#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) +# define __DARWIN__ 1 +#endif +#ifdef __DARWIN__ +# define _DARWIN_UNLIMITED_SELECT +#endif + #include "ethread.h" #undef ETHR_INCLUDE_MONOTONIC_CLOCK__ #define ETHR_INCLUDE_MONOTONIC_CLOCK__ @@ -56,6 +63,12 @@ ethr_event_init(ethr_event *e) } int +ethr_event_prepare_timed(ethr_event *e) +{ + return 0; +} + +int ethr_event_destroy(ethr_event *e) { return 0; @@ -171,6 +184,17 @@ return_event_on: #include <errno.h> #include <string.h> +#ifdef __DARWIN__ + +struct ethr_event_fdsets___ { + fd_set *rsetp; + fd_set *esetp; + size_t mem_size; + fd_mask mem[1]; +}; + +#endif + static void setup_nonblocking_pipe(ethr_event *e) { @@ -188,6 +212,35 @@ setup_nonblocking_pipe(ethr_event *e) flgs = fcntl(e->fd[1], F_GETFL, 0); fcntl(e->fd[1], F_SETFL, flgs | O_NONBLOCK); + +#ifndef __DARWIN__ + if (e->fd[0] >= FD_SETSIZE) + ETHR_FATAL_ERROR__(ENOTSUP); +#else + { + int nmasks; + ethr_event_fdsets__ *fdsets; + size_t mem_size; + + nmasks = (e->fd[0]+NFDBITS)/NFDBITS; + mem_size = 2*nmasks*sizeof(fd_mask); + if (mem_size < 2*sizeof(fd_set)) { + mem_size = 2*sizeof(fd_set); + nmasks = mem_size/(2*sizeof(fd_mask)); + } + + fdsets = malloc(sizeof(ethr_event_fdsets__) + + mem_size + - sizeof(fd_mask)); + if (!fdsets) + ETHR_FATAL_ERROR__(ENOMEM); + fdsets->rsetp = (fd_set *) (char *) &fdsets->mem[0]; + fdsets->esetp = (fd_set *) (char *) &fdsets->mem[nmasks]; + fdsets->mem_size = mem_size; + e->fdsets = fdsets; + } +#endif + ETHR_MEMBAR(ETHR_StoreStore); } @@ -252,6 +305,19 @@ ethr_event_init(ethr_event *e) e->fd[0] = e->fd[1] = ETHR_EVENT_INVALID_FD__; +#ifdef __DARWIN__ + e->fdsets = NULL; +#endif + + return 0; +} + +int +ethr_event_prepare_timed(ethr_event *e) +{ + if (e->fd[0] == ETHR_EVENT_INVALID_FD__) + setup_nonblocking_pipe(e); + return 0; } @@ -263,13 +329,14 @@ ethr_event_destroy(ethr_event *e) close(e->fd[0]); close(e->fd[1]); } +#ifdef __DARWIN__ + if (e->fdsets) + free(e->fdsets); +#endif res = pthread_mutex_destroy(&e->mtx); if (res != 0) return res; - res = pthread_cond_destroy(&e->cnd); - if (res != 0) - return res; - return 0; + return pthread_cond_destroy(&e->cnd); } static ETHR_INLINE int @@ -403,8 +470,10 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) int fd; int sres; ssize_t rres; - fd_set rset; - fd_set eset; +#ifndef __DARWIN__ + fd_set rset, eset; +#endif + fd_set *rsetp, *esetp; struct timeval select_timeout; #ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME @@ -457,12 +526,22 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) ETHR_ASSERT(act == val); } + +#ifdef __DARWIN__ + rsetp = e->fdsets->rsetp; + esetp = e->fdsets->esetp; + memset((void *) &e->fdsets->mem[0], 0, e->fdsets->mem_size); +#else FD_ZERO(&rset); - FD_SET(fd, &rset); FD_ZERO(&eset); - FD_SET(fd, &eset); + rsetp = &rset; + esetp = &eset; +#endif + + FD_SET(fd, rsetp); + FD_SET(fd, esetp); - sres = select(fd + 1, &rset, NULL, &eset, &select_timeout); + sres = select(fd + 1, rsetp, NULL, esetp, &select_timeout); if (sres == 0) res = ETIMEDOUT; else { diff --git a/erts/lib_src/win/ethr_event.c b/erts/lib_src/win/ethr_event.c index c88c8784a2..6951a216c5 100644 --- a/erts/lib_src/win/ethr_event.c +++ b/erts/lib_src/win/ethr_event.c @@ -47,6 +47,12 @@ ethr_event_init(ethr_event *e) } int +ethr_event_prepare_timed(ethr_event *e) +{ + return 0; +} + +int ethr_event_destroy(ethr_event *e) { BOOL res = CloseHandle(e->handle); diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam Binary files differindex 5a188be3ba..357bcd3d9a 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 291356c7b1..7280b43502 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1974,6 +1974,7 @@ localtime_to_universaltime(_Localtime, _IsDst) -> %% CHECK! Why the strange very thorough specification of the error %% condition with disallowed arity in erl_bif_types? %% Not documented +%% Shadowed by erl_bif_types: erlang:make_fun/3 -spec erlang:make_fun(Module, Function, Arity) -> function() when Module :: atom(), Function :: atom(), @@ -2423,7 +2424,7 @@ tuple_to_list(_Tuple) -> MinBinVHeapSize :: pos_integer()}; (modified_timing_level) -> integer() | undefined; (multi_scheduling) -> disabled | blocked | enabled; - (multi_scheduling_blockers) -> [PID :: pid()]; + (multi_scheduling_blockers) -> [Pid :: pid()]; (nif_version) -> string(); (otp_release) -> string(); (os_monotonic_time_source) -> [{atom(),term()}]; diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 4d04e1dacb..d5c8fd4268 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1147,6 +1147,7 @@ enc_opt(packet_size) -> ?INET_LOPT_PACKET_SIZE; enc_opt(read_packets) -> ?INET_LOPT_READ_PACKETS; enc_opt(netns) -> ?INET_LOPT_NETNS; enc_opt(show_econnreset) -> ?INET_LOPT_TCP_SHOW_ECONNRESET; +enc_opt(line_delimiter) -> ?INET_LOPT_LINE_DELIM; enc_opt(raw) -> ?INET_OPT_RAW; % Names of SCTP opts: enc_opt(sctp_rtoinfo) -> ?SCTP_OPT_RTOINFO; @@ -1205,6 +1206,7 @@ dec_opt(?INET_LOPT_PACKET_SIZE) -> packet_size; dec_opt(?INET_LOPT_READ_PACKETS) -> read_packets; dec_opt(?INET_LOPT_NETNS) -> netns; dec_opt(?INET_LOPT_TCP_SHOW_ECONNRESET) -> show_econnreset; +dec_opt(?INET_LOPT_LINE_DELIM) -> line_delimiter; dec_opt(?INET_OPT_RAW) -> raw; dec_opt(I) when is_integer(I) -> undefined. @@ -1287,6 +1289,7 @@ type_opt_1(packet) -> {httph_bin,?TCP_PB_HTTPH_BIN}, {ssl, ?TCP_PB_SSL_TLS}, % obsolete {ssl_tls, ?TCP_PB_SSL_TLS}]}; +type_opt_1(line_delimiter) -> int; type_opt_1(mode) -> {enum,[{list, ?INET_MODE_LIST}, {binary, ?INET_MODE_BINARY}]}; diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl index 69a0d19719..87d620b180 100644 --- a/erts/test/otp_SUITE.erl +++ b/erts/test/otp_SUITE.erl @@ -290,7 +290,7 @@ call_to_deprecated(Config) when is_list(Config) -> call_to_size_1(Config) when is_list(Config) -> %% Applications that do not call erlang:size/1: Apps = [asn1,compiler,debugger,kernel,observer,parsetools, - runtime_tools,stdlib,tools,webtool], + runtime_tools,stdlib,tools], not_recommended_calls(Config, Apps, {erlang,size,1}). call_to_now_0(Config) when is_list(Config) -> @@ -298,12 +298,14 @@ call_to_now_0(Config) when is_list(Config) -> Apps = [asn1,common_test,compiler,debugger,dialyzer, gs,kernel,mnesia,observer,parsetools,reltool, runtime_tools,sasl,stdlib,syntax_tools, - test_server,tools,webtool], + test_server,tools], not_recommended_calls(Config, Apps, {erlang,now,0}). -not_recommended_calls(Config, Apps, MFA) -> +not_recommended_calls(Config, Apps0, MFA) -> Server = ?config(xref_server, Config), + Apps = [App || App <- Apps0, is_present_application(App, Server)], + Fs = [MFA], Q1 = io_lib:format("E || ~p : Fun", [Fs]), @@ -337,11 +339,28 @@ not_recommended_calls(Config, Apps, MFA) -> end, case CallsToMFA of [] -> - ok; + SkippedApps = ordsets:subtract(ordsets:from_list(Apps0), + ordsets:from_list(Apps)), + case SkippedApps of + [] -> + ok; + _ -> + AppStrings = [atom_to_list(A) || A <- SkippedApps], + Mess = io_lib:format("Application(s) not present: ~s\n", + [string:join(AppStrings, ", ")]), + {comment, Mess} + end; _ -> ?t:fail({length(CallsToMFA),calls_to_size_1}) end. +is_present_application(Name, Server) -> + Q = io_lib:format("~w : App", [Name]), + case xref:q(Server, lists:flatten(Q)) of + {ok,[Name]} -> true; + {error,_,_} -> false + end. + strong_components(Config) when is_list(Config) -> Server = ?config(xref_server, Config), ?line {ok,Cs} = xref:q(Server, "components AE"), diff --git a/erts/test/upgrade_SUITE.erl b/erts/test/upgrade_SUITE.erl index 8a91cf5b7e..83cd2359d8 100644 --- a/erts/test/upgrade_SUITE.erl +++ b/erts/test/upgrade_SUITE.erl @@ -40,7 +40,7 @@ %% - typer requires hipe (in the .app file) %% - erl_interface, jinterface support no upgrade -define(appup_exclude, - [dialyzer,hipe,typer,erl_interface,jinterface]). + [dialyzer,hipe,typer,erl_interface,jinterface,ose]). init_per_suite(Config) -> %% Check that a real release is running, not e.g. cerl diff --git a/erts/vsn.mk b/erts/vsn.mk index 38b9a13e63..9e4248a668 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% # -VSN = 7.0.3 +VSN = 8.0 # Port number 4365 in 4.2 # Port number 4366 in 4.3 |