aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rwxr-xr-xerts/autoconf/config.guess541
-rwxr-xr-xerts/autoconf/config.sub367
-rw-r--r--erts/configure.in11
-rw-r--r--erts/doc/src/erl_driver.xml62
-rw-r--r--erts/doc/src/erl_nif.xml37
-rw-r--r--erts/doc/src/erlang.xml102
-rw-r--r--erts/doc/src/erts_alloc.xml2
-rw-r--r--erts/doc/src/notes.xml4
-rw-r--r--erts/emulator/Makefile.in10
-rw-r--r--erts/emulator/beam/atom.names1
-rw-r--r--erts/emulator/beam/beam_emu.c11
-rw-r--r--erts/emulator/beam/bif.c269
-rw-r--r--erts/emulator/beam/bif.h7
-rw-r--r--erts/emulator/beam/bif.tab8
-rw-r--r--erts/emulator/beam/big.c247
-rw-r--r--erts/emulator/beam/big.h3
-rw-r--r--erts/emulator/beam/binary.c92
-rw-r--r--erts/emulator/beam/dist.c2
-rw-r--r--erts/emulator/beam/erl_alloc_util.c10
-rw-r--r--erts/emulator/beam/erl_async.c4
-rw-r--r--erts/emulator/beam/erl_bif_ddll.c2
-rwxr-xr-xerts/emulator/beam/erl_bif_info.c4
-rw-r--r--erts/emulator/beam/erl_driver.h5
-rw-r--r--erts/emulator/beam/erl_init.c53
-rw-r--r--erts/emulator/beam/erl_nif.c13
-rw-r--r--erts/emulator/beam/erl_nif.h5
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h2
-rw-r--r--erts/emulator/beam/erl_port.h141
-rw-r--r--erts/emulator/beam/erl_port_task.c114
-rw-r--r--erts/emulator/beam/erl_unicode.c63
-rw-r--r--erts/emulator/beam/io.c214
-rw-r--r--erts/emulator/beam/ops.tab2
-rw-r--r--erts/emulator/beam/sys.h14
-rw-r--r--erts/emulator/drivers/common/efile_drv.c11
-rw-r--r--erts/emulator/sys/common/erl_check_io.c42
-rw-r--r--erts/emulator/sys/common/erl_mseg.c315
-rw-r--r--erts/emulator/sys/common/erl_mseg.h9
-rw-r--r--erts/emulator/sys/common/erl_sys_common_misc.c204
-rw-r--r--erts/emulator/sys/common/erl_util_queue.h77
-rw-r--r--erts/emulator/sys/unix/sys.c8
-rw-r--r--erts/emulator/sys/win32/erl_win_dyn_driver.h8
-rwxr-xr-xerts/emulator/sys/win32/sys.c86
-rw-r--r--erts/emulator/test/driver_SUITE.erl325
-rw-r--r--erts/emulator/test/driver_SUITE_data/Makefile.src3
-rw-r--r--erts/emulator/test/driver_SUITE_data/consume_timeslice_drv.c172
-rw-r--r--erts/emulator/test/hash_SUITE.erl88
-rw-r--r--erts/emulator/test/nif_SUITE.erl107
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c24
-rw-r--r--erts/emulator/test/num_bif_SUITE.erl535
-rwxr-xr-xerts/emulator/utils/gen_git_version39
-rw-r--r--erts/lib_src/common/erl_printf_format.c10
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin54120 -> 54360 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin92996 -> 93456 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin41128 -> 44092 bytes
-rw-r--r--erts/preloaded/src/erl_prim_loader.erl16
-rw-r--r--erts/preloaded/src/erlang.erl133
-rw-r--r--erts/preloaded/src/prim_file.erl208
-rw-r--r--erts/test/otp_SUITE.erl2
58 files changed, 3493 insertions, 1351 deletions
diff --git a/erts/autoconf/config.guess b/erts/autoconf/config.guess
index 38a833903b..f475ceb413 100755
--- a/erts/autoconf/config.guess
+++ b/erts/autoconf/config.guess
@@ -1,14 +1,12 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
-# Inc.
+# Copyright 1992-2013 Free Software Foundation, Inc.
-timestamp='2007-05-17'
+timestamp='2013-02-12'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
+# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
@@ -17,26 +15,22 @@ timestamp='2007-05-17'
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-
-# Originally written by Per Bothner <[email protected]>.
-# Please send patches to <[email protected]>. Submit a context
-# diff and a properly formatted ChangeLog entry.
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner.
#
-# This script attempts to guess a canonical system name similar to
-# config.sub. If it succeeds, it prints the system name on stdout, and
-# exits with 0. Otherwise, it exits with 1.
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
#
-# The plan is that this can be called by configure scripts if you
-# don't specify an explicit build system type.
+# Please send patches with a ChangeLog entry to [email protected].
+
me=`echo "$0" | sed -e 's,.*/,,'`
@@ -56,8 +50,7 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-Free Software Foundation, Inc.
+Copyright 1992-2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -144,7 +137,7 @@ UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:NetBSD:*:*)
# NetBSD (nbsd) targets should (where applicable) match one or
- # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
# *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
# switched to ELF, *-*-netbsd* would select the old
# object file format. This provides both forward
@@ -170,7 +163,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
arm*|i386|m68k|ns32k|sh3*|sparc|vax)
eval $set_cc_for_build
if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
- | grep __ELF__ >/dev/null
+ | grep -q __ELF__
then
# Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
# Return netbsd for either. FIX?
@@ -180,7 +173,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
fi
;;
*)
- os=netbsd
+ os=netbsd
;;
esac
# The OS release
@@ -201,6 +194,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
echo "${machine}-${os}${release}"
exit ;;
+ *:Bitrig:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+ exit ;;
*:OpenBSD:*:*)
UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
@@ -223,7 +220,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
;;
*5.*)
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
;;
esac
# According to Compaq, /usr/sbin/psrinfo has been available on
@@ -269,7 +266,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# A Xn.n version is an unreleased experimental baselevel.
# 1.2 uses "1.2" for uname -r.
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- exit ;;
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
Alpha\ *:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# Should we change UNAME_MACHINE based on the output of uname instead
@@ -295,12 +295,12 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
echo s390-ibm-zvmoe
exit ;;
*:OS400:*:*)
- echo powerpc-ibm-os400
+ echo powerpc-ibm-os400
exit ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
echo arm-acorn-riscix${UNAME_RELEASE}
exit ;;
- arm:riscos:*:*|arm:RISCOS:*:*)
+ arm*:riscos:*:*|arm*:RISCOS:*:*)
echo arm-unknown-riscos
exit ;;
SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
@@ -324,14 +324,33 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
case `/usr/bin/uname -p` in
sparc) echo sparc-icl-nx7; exit ;;
esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
sun4H:SunOS:5.*:*)
echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
- i86pc:SunOS:5.*:* | ix86xen:SunOS:5.*:*)
- echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit ;;
sun4*:SunOS:6*:*)
# According to config.sub, this is the proper way to canonicalize
@@ -375,23 +394,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
# MiNT. But MiNT is downward compatible to TOS, so this should
# be no problem.
atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
+ echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
+ exit ;;
*falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
+ echo m68k-atari-mint${UNAME_RELEASE}
exit ;;
milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
- echo m68k-milan-mint${UNAME_RELEASE}
- exit ;;
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
- echo m68k-hades-mint${UNAME_RELEASE}
- exit ;;
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
- echo m68k-unknown-mint${UNAME_RELEASE}
- exit ;;
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
m68k:machten:*:*)
echo m68k-apple-machten${UNAME_RELEASE}
exit ;;
@@ -461,8 +480,8 @@ EOF
echo m88k-motorola-sysv3
exit ;;
AViiON:dgux:*:*)
- # DG/UX returns AViiON for all architectures
- UNAME_PROCESSOR=`/usr/bin/uname -p`
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
then
if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
@@ -475,7 +494,7 @@ EOF
else
echo i586-dg-dgux${UNAME_RELEASE}
fi
- exit ;;
+ exit ;;
M88*:DolphinOS:*:*) # DolphinOS (SVR3)
echo m88k-dolphin-sysv3
exit ;;
@@ -532,7 +551,7 @@ EOF
echo rs6000-ibm-aix3.2
fi
exit ;;
- *:AIX:*:[45])
+ *:AIX:*:[4567])
IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
IBM_ARCH=rs6000
@@ -575,52 +594,52 @@ EOF
9000/[678][0-9][0-9])
if [ -x /usr/bin/getconf ]; then
sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
- sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
- case "${sc_cpu_version}" in
- 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
- 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
- 532) # CPU_PA_RISC2_0
- case "${sc_kernel_bits}" in
- 32) HP_ARCH="hppa2.0n" ;;
- 64) HP_ARCH="hppa2.0w" ;;
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
'') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
- esac ;;
- esac
+ esac ;;
+ esac
fi
if [ "${HP_ARCH}" = "" ]; then
eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
+ sed 's/^ //' << EOF >$dummy.c
- #define _HPUX_SOURCE
- #include <stdlib.h>
- #include <unistd.h>
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
- int main ()
- {
- #if defined(_SC_KERNEL_BITS)
- long bits = sysconf(_SC_KERNEL_BITS);
- #endif
- long cpu = sysconf (_SC_CPU_VERSION);
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
- case CPU_PA_RISC2_0:
- #if defined(_SC_KERNEL_BITS)
- switch (bits)
- {
- case 64: puts ("hppa2.0w"); break;
- case 32: puts ("hppa2.0n"); break;
- default: puts ("hppa2.0"); break;
- } break;
- #else /* !defined(_SC_KERNEL_BITS) */
- puts ("hppa2.0"); break;
- #endif
- default: puts ("hppa1.0"); break;
- }
- exit (0);
- }
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
EOF
(CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
test -z "$HP_ARCH" && HP_ARCH=hppa
@@ -640,7 +659,7 @@ EOF
# => hppa64-hp-hpux11.23
if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
- grep __LP64__ >/dev/null
+ grep -q __LP64__
then
HP_ARCH="hppa2.0w"
else
@@ -711,22 +730,22 @@ EOF
exit ;;
C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
echo c1-convex-bsd
- exit ;;
+ exit ;;
C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
if getsysinfo -f scalar_acc
then echo c32-convex-bsd
else echo c2-convex-bsd
fi
- exit ;;
+ exit ;;
C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
echo c34-convex-bsd
- exit ;;
+ exit ;;
C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
echo c38-convex-bsd
- exit ;;
+ exit ;;
C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
echo c4-convex-bsd
- exit ;;
+ exit ;;
CRAY*Y-MP:*:*:*)
echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit ;;
@@ -750,14 +769,14 @@ EOF
exit ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
5000:UNIX_System_V:4.*:*)
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
- echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
@@ -769,40 +788,51 @@ EOF
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
exit ;;
*:FreeBSD:*:*)
- case ${UNAME_MACHINE} in
- pc98)
- echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case ${UNAME_PROCESSOR} in
amd64)
echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
*)
- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
esac
exit ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
exit ;;
+ *:MINGW64*:*)
+ echo ${UNAME_MACHINE}-pc-mingw64
+ exit ;;
*:MINGW*:*)
echo ${UNAME_MACHINE}-pc-mingw32
exit ;;
+ i*:MSYS*:*)
+ echo ${UNAME_MACHINE}-pc-msys
+ exit ;;
i*:windows32*:*)
- # uname -m includes "-pc" on this system.
- echo ${UNAME_MACHINE}-mingw32
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
exit ;;
i*:PW*:*)
echo ${UNAME_MACHINE}-pc-pw32
exit ;;
- *:Interix*:[3456]*)
- case ${UNAME_MACHINE} in
- x86)
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
echo i586-pc-interix${UNAME_RELEASE}
exit ;;
- EM64T | authenticamd)
+ authenticamd | genuineintel | EM64T)
echo x86_64-unknown-interix${UNAME_RELEASE}
exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
esac ;;
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
echo i${UNAME_MACHINE}-pc-mks
exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
# How do we know it's Interix rather than the generic POSIX subsystem?
# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
@@ -832,20 +862,68 @@ EOF
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
exit ;;
- arm*:Linux:*:*)
+ aarch64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
+ fi
+ fi
+ exit ;;
avr32*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
cris:Linux:*:*)
- echo cris-axis-linux-gnu
+ echo ${UNAME_MACHINE}-axis-linux-gnu
exit ;;
crisv32:Linux:*:*)
- echo crisv32-axis-linux-gnu
+ echo ${UNAME_MACHINE}-axis-linux-gnu
exit ;;
frv:Linux:*:*)
- echo frv-unknown-linux-gnu
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ hexagon:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ LIBC=gnu
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
exit ;;
ia64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
@@ -856,74 +934,36 @@ EOF
m68*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
- mips:Linux:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #undef CPU
- #undef mips
- #undef mipsel
- #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=mipsel
- #else
- #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=mips
- #else
- CPU=
- #endif
- #endif
-EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^CPU/{
- s: ::g
- p
- }'`"
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
- ;;
- mips64:Linux:*:*)
+ mips:Linux:*:* | mips64:Linux:*:*)
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
#undef CPU
- #undef mips64
- #undef mips64el
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=mips64el
+ CPU=${UNAME_MACHINE}el
#else
#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=mips64
+ CPU=${UNAME_MACHINE}
#else
CPU=
#endif
#endif
EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^CPU/{
- s: ::g
- p
- }'`"
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
;;
- or32:Linux:*:*)
- echo or32-unknown-linux-gnu
+ or1k:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
- ppc:Linux:*:*)
- echo powerpc-unknown-linux-gnu
+ or32:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
- ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-gnu
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-gnu
exit ;;
- alpha:Linux:*:*)
- case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
- EV5) UNAME_MACHINE=alphaev5 ;;
- EV56) UNAME_MACHINE=alphaev56 ;;
- PCA56) UNAME_MACHINE=alphapca56 ;;
- PCA57) UNAME_MACHINE=alphapca56 ;;
- EV6) UNAME_MACHINE=alphaev6 ;;
- EV67) UNAME_MACHINE=alphaev67 ;;
- EV68*) UNAME_MACHINE=alphaev68 ;;
- esac
- objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
- if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
- echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
@@ -933,14 +973,17 @@ EOF
*) echo hppa-unknown-linux-gnu ;;
esac
exit ;;
- parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-gnu
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-ibm-linux
exit ;;
sh64*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
sh*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
@@ -948,81 +991,18 @@ EOF
sparc:Linux:*:* | sparc64:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
- tile:Linux:*:*)
- echo tile-unknown-linux-gnu
+ tile*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
vax:Linux:*:*)
echo ${UNAME_MACHINE}-dec-linux-gnu
exit ;;
x86_64:Linux:*:*)
- echo x86_64-unknown-linux-gnu
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
- xtensa:Linux:*:*)
- echo xtensa-unknown-linux-gnu
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
- i*86:Linux:*:*)
- # The BFD linker knows what the default object file format is, so
- # first see if it will tell us. cd to the root directory to prevent
- # problems with other programs or directories called `ld' in the path.
- # Set LC_ALL=C to ensure ld outputs messages in English.
- ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
- | sed -ne '/supported targets:/!d
- s/[ ][ ]*/ /g
- s/.*supported targets: *//
- s/ .*//
- p'`
- case "$ld_supported_targets" in
- elf32-i386)
- TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
- ;;
- a.out-i386-linux)
- echo "${UNAME_MACHINE}-pc-linux-gnuaout"
- exit ;;
- coff-i386)
- echo "${UNAME_MACHINE}-pc-linux-gnucoff"
- exit ;;
- "")
- # Either a pre-BFD a.out linker (linux-gnuoldld) or
- # one that does not give us useful --help.
- echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
- exit ;;
- esac
- # Determine whether the default compiler is a.out or elf
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <features.h>
- #ifdef __ELF__
- # ifdef __GLIBC__
- # if __GLIBC__ >= 2
- LIBC=gnu
- # else
- LIBC=gnulibc1
- # endif
- # else
- LIBC=gnulibc1
- # endif
- #else
- #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
- LIBC=gnu
- #else
- LIBC=gnuaout
- #endif
- #endif
- #ifdef __dietlibc__
- LIBC=dietlibc
- #endif
-EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^LIBC/{
- s: ::g
- p
- }'`"
- test x"${LIBC}" != x && {
- echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
- exit
- }
- test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
- ;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
# earlier versions are messed up and put the nodename in both
@@ -1030,11 +1010,11 @@ EOF
echo i386-sequent-sysv4
exit ;;
i*86:UNIX_SV:4.2MP:2.*)
- # Unixware is an offshoot of SVR4, but it has its own version
- # number series starting with 2...
- # I am not positive that other SVR4 systems won't match this,
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
# I just have to hope. -- rms.
- # Use sysv4.2uw... so that sysv4* matches it.
+ # Use sysv4.2uw... so that sysv4* matches it.
echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
exit ;;
i*86:OS/2:*:*)
@@ -1051,7 +1031,7 @@ EOF
i*86:syllable:*:*)
echo ${UNAME_MACHINE}-pc-syllable
exit ;;
- i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
echo i386-unknown-lynxos${UNAME_RELEASE}
exit ;;
i*86:*DOS:*:*)
@@ -1066,7 +1046,7 @@ EOF
fi
exit ;;
i*86:*:5:[678]*)
- # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
case `/bin/uname -X | grep "^Machine"` in
*486*) UNAME_MACHINE=i486 ;;
*Pentium) UNAME_MACHINE=i586 ;;
@@ -1094,10 +1074,13 @@ EOF
exit ;;
pc:*:*:*)
# Left here for compatibility:
- # uname -m prints for DJGPP always 'pc', but it prints nothing about
- # the processor, so we play safe by assuming i386.
- echo i386-pc-msdosdjgpp
- exit ;;
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
Intel:Mach:3*:*)
echo i386-pc-mach3
exit ;;
@@ -1132,8 +1115,18 @@ EOF
/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
&& { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4; exit; } ;;
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
echo m68k-unknown-lynxos${UNAME_RELEASE}
exit ;;
@@ -1146,7 +1139,7 @@ EOF
rs6000:LynxOS:2.*:*)
echo rs6000-unknown-lynxos${UNAME_RELEASE}
exit ;;
- PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
echo powerpc-unknown-lynxos${UNAME_RELEASE}
exit ;;
SM[BE]S:UNIX_SV:*:*)
@@ -1166,10 +1159,10 @@ EOF
echo ns32k-sni-sysv
fi
exit ;;
- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
- echo i586-unisys-sysv4
- exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ echo i586-unisys-sysv4
+ exit ;;
*:UNIX_System_V:4*:FTX*)
# From Gerald Hewes <[email protected]>.
# How about differentiating between stratus architectures? -djm
@@ -1195,11 +1188,11 @@ EOF
exit ;;
R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
if [ -d /usr/nec ]; then
- echo mips-nec-sysv${UNAME_RELEASE}
+ echo mips-nec-sysv${UNAME_RELEASE}
else
- echo mips-unknown-sysv${UNAME_RELEASE}
+ echo mips-unknown-sysv${UNAME_RELEASE}
fi
- exit ;;
+ exit ;;
BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
echo powerpc-be-beos
exit ;;
@@ -1209,6 +1202,12 @@ EOF
BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
echo i586-pc-beos
exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ x86_64:Haiku:*:*)
+ echo x86_64-unknown-haiku
+ exit ;;
SX-4:SUPER-UX:*:*)
echo sx4-nec-superux${UNAME_RELEASE}
exit ;;
@@ -1236,6 +1235,16 @@ EOF
*:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
case $UNAME_PROCESSOR in
+ i386)
+ eval $set_cc_for_build
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ UNAME_PROCESSOR="x86_64"
+ fi
+ fi ;;
unknown) UNAME_PROCESSOR=powerpc ;;
esac
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
@@ -1251,7 +1260,10 @@ EOF
*:QNX:*:4*)
echo i386-pc-qnx
exit ;;
- NSE-?:NONSTOP_KERNEL:*:*)
+ NEO-?:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSE-*:NONSTOP_KERNEL:*:*)
echo nse-tandem-nsk${UNAME_RELEASE}
exit ;;
NSR-?:NONSTOP_KERNEL:*:*)
@@ -1296,13 +1308,13 @@ EOF
echo pdp10-unknown-its
exit ;;
SEI:*:*:SEIUX)
- echo mips-sei-seiux${UNAME_RELEASE}
+ echo mips-sei-seiux${UNAME_RELEASE}
exit ;;
*:DragonFly:*:*)
echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
exit ;;
*:*VMS:*:*)
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
case "${UNAME_MACHINE}" in
A*) echo alpha-dec-vms ; exit ;;
I*) echo ia64-dec-vms ; exit ;;
@@ -1317,11 +1329,14 @@ EOF
i*86:rdos:*:*)
echo ${UNAME_MACHINE}-pc-rdos
exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo ${UNAME_MACHINE}-unknown-esx
+ exit ;;
esac
-#echo '(No uname command or uname output not recognized.)' 1>&2
-#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
-
eval $set_cc_for_build
cat >$dummy.c <<EOF
#ifdef _SEQUENT_
@@ -1339,11 +1354,11 @@ main ()
#include <sys/param.h>
printf ("m68k-sony-newsos%s\n",
#ifdef NEWSOS4
- "4"
+ "4"
#else
- ""
+ ""
#endif
- ); exit (0);
+ ); exit (0);
#endif
#endif
@@ -1477,9 +1492,9 @@ This script, last modified $timestamp, has failed to recognize
the operating system you are using. It is advised that you
download the most up to date version of the config scripts from
- http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
and
- http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
If the version you run ($0) is already up to date, please
send the following data and any information you think might be
diff --git a/erts/autoconf/config.sub b/erts/autoconf/config.sub
index f43233b104..bb6edbdb47 100755
--- a/erts/autoconf/config.sub
+++ b/erts/autoconf/config.sub
@@ -1,44 +1,40 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
-# Inc.
+# Copyright 1992-2013 Free Software Foundation, Inc.
-timestamp='2007-04-29'
+timestamp='2013-02-12'
-# This file is (in principle) common to ALL GNU software.
-# The presence of a machine in this file suggests that SOME GNU software
-# can handle that machine. It does not imply ALL GNU software can.
-#
-# This file is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
-# Please send patches to <[email protected]>. Submit a context
-# diff and a properly formatted ChangeLog entry.
+# Please send patches with a ChangeLog entry to [email protected].
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
# If it is invalid, we print an error message on stderr and exit with code 1.
# Otherwise, we print the canonical config type on stdout and succeed.
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
# that are meaningful with *any* GNU software.
@@ -72,8 +68,7 @@ Report bugs and patches to <[email protected]>."
version="\
GNU config.sub ($timestamp)
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
-Free Software Foundation, Inc.
+Copyright 1992-2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -120,12 +115,18 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
- nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
- uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
+ android-linux)
+ os=-linux-android
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+ ;;
*)
basic_machine=`echo $1 | sed 's/-[^-]*$//'`
if [ $basic_machine != $1 ]
@@ -148,10 +149,13 @@ case $os in
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
- -apple | -axis | -knuth | -cray)
+ -apple | -axis | -knuth | -cray | -microblaze*)
os=
basic_machine=$1
;;
+ -bluegene*)
+ os=-cnk
+ ;;
-sim | -cisco | -oki | -wec | -winbond)
os=
basic_machine=$1
@@ -166,10 +170,10 @@ case $os in
os=-chorusos
basic_machine=$1
;;
- -chorusrdb)
- os=-chorusrdb
+ -chorusrdb)
+ os=-chorusrdb
basic_machine=$1
- ;;
+ ;;
-hiux*)
os=-hiuxwe2
;;
@@ -214,6 +218,12 @@ case $os in
-isc*)
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
+ -lynx*178)
+ os=-lynxos178
+ ;;
+ -lynx*5)
+ os=-lynxos5
+ ;;
-lynx*)
os=-lynxos
;;
@@ -238,24 +248,34 @@ case $basic_machine in
# Some are omitted here because they have special meanings below.
1750a | 580 \
| a29k \
+ | aarch64 | aarch64_be \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| am33_2.0 \
- | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | arc \
+ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+ | avr | avr32 \
+ | be32 | be64 \
| bfin \
| c4x | clipper \
| d10v | d30v | dlx | dsp16xx \
+ | epiphany \
| fido | fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
+ | le32 | le64 \
+ | lm32 \
| m32c | m32r | m32rle | m68000 | m68k | m88k \
- | maxq | mb | microblaze | mcore | mep \
+ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
| mips64 | mips64el \
- | mips64vr | mips64vrel \
+ | mips64octeon | mips64octeonel \
| mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
| mips64vr4100 | mips64vr4100el \
| mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \
@@ -266,31 +286,45 @@ case $basic_machine in
| mipsisa64r2 | mipsisa64r2el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
+ | mipsr5900 | mipsr5900el \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
+ | moxie \
| mt \
| msp430 \
- | nios | nios2 \
+ | nds32 | nds32le | nds32be \
+ | nios | nios2 | nios2eb | nios2el \
| ns16k | ns32k \
- | or32 \
+ | open8 \
+ | or1k | or32 \
| pdp10 | pdp11 | pj | pjl \
- | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | powerpc | powerpc64 | powerpc64le | powerpcle \
| pyramid \
+ | rl78 | rx \
| score \
- | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
- | spu | strongarm \
- | tahoe | thumb | tic4x | tic80 | tron \
- | v850 | v850e \
+ | spu \
+ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
| we32k \
- | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
- | z8k)
+ | x86 | xc16x | xstormy16 | xtensa \
+ | z8k | z80)
basic_machine=$basic_machine-unknown
;;
- m6811 | m68hc11 | m6812 | m68hc12)
- # Motorola 68HC11/12.
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
+ ;;
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
basic_machine=$basic_machine-unknown
os=-none
;;
@@ -300,6 +334,21 @@ case $basic_machine in
basic_machine=mt-unknown
;;
+ strongarm | thumb | xscale)
+ basic_machine=arm-unknown
+ ;;
+ xgate)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ xscaleeb)
+ basic_machine=armeb-unknown
+ ;;
+
+ xscaleel)
+ basic_machine=armel-unknown
+ ;;
+
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
# (2) the word "unknown" tends to confuse beginning users.
@@ -314,29 +363,37 @@ case $basic_machine in
# Recognize the basic CPU types with company name.
580-* \
| a29k-* \
+ | aarch64-* | aarch64_be-* \
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
+ | be32-* | be64-* \
| bfin-* | bs2000-* \
- | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
| clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
| elxsi-* \
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | hexagon-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* | iq2000-* \
+ | le32-* | le64-* \
+ | lm32-* \
| m32c-* | m32r-* | m32rle-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
- | m88110-* | m88k-* | maxq-* | mcore-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+ | microblaze-* | microblazeel-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \
| mips64-* | mips64el-* \
- | mips64vr-* | mips64vrel-* \
+ | mips64octeon-* | mips64octeonel-* \
| mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
| mips64vr4100-* | mips64vr4100el-* \
| mips64vr4300-* | mips64vr4300el-* \
| mips64vr5000-* | mips64vr5000el-* \
@@ -347,31 +404,41 @@ case $basic_machine in
| mipsisa64r2-* | mipsisa64r2el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipsr5900-* | mipsr5900el-* \
| mipstx39-* | mipstx39el-* \
| mmix-* \
| mt-* \
| msp430-* \
- | nios-* | nios2-* \
+ | nds32-* | nds32le-* | nds32be-* \
+ | nios-* | nios2-* | nios2eb-* | nios2el-* \
| none-* | np1-* | ns16k-* | ns32k-* \
+ | open8-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pyramid-* \
- | romp-* | rs6000-* \
- | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | rl78-* | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparclite-* \
- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
- | tahoe-* | thumb-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+ | tahoe-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile*-* \
| tron-* \
- | v850-* | v850e-* | vax-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+ | vax-* \
| we32k-* \
- | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
- | xstormy16-* | xtensa-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* \
+ | xstormy16-* | xtensa*-* \
| ymp-* \
- | z8k-*)
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
@@ -389,7 +456,7 @@ case $basic_machine in
basic_machine=a29k-amd
os=-udi
;;
- abacus)
+ abacus)
basic_machine=abacus-unknown
;;
adobe68k)
@@ -435,6 +502,10 @@ case $basic_machine in
basic_machine=m68k-apollo
os=-bsd
;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
aux)
basic_machine=m68k-apple
os=-aux
@@ -443,10 +514,35 @@ case $basic_machine in
basic_machine=ns32k-sequent
os=-dynix
;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
c90)
basic_machine=c90-cray
os=-unicos
;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
convex-c1)
basic_machine=c1-convex
os=-bsd
@@ -475,8 +571,8 @@ case $basic_machine in
basic_machine=craynv-cray
os=-unicosmp
;;
- cr16c)
- basic_machine=cr16c-unknown
+ cr16 | cr16-*)
+ basic_machine=cr16-unknown
os=-elf
;;
crds | unos)
@@ -514,6 +610,10 @@ case $basic_machine in
basic_machine=m88k-motorola
os=-sysv3
;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
djgpp)
basic_machine=i586-pc
os=-msdosdjgpp
@@ -629,7 +729,6 @@ case $basic_machine in
i370-ibm* | ibm*)
basic_machine=i370-ibm
;;
-# I'm not sure what "Sysv32" means. Should this be sysv3.2?
i*86v32)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv32
@@ -668,6 +767,14 @@ case $basic_machine in
basic_machine=m68k-isi
os=-sysv
;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
m88k-omron*)
basic_machine=m88k-omron
;;
@@ -679,6 +786,13 @@ case $basic_machine in
basic_machine=ns32k-utek
os=-sysv
;;
+ microblaze*)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ os=-mingw64
+ ;;
mingw32)
basic_machine=i386-pc
os=-mingw32
@@ -715,10 +829,18 @@ case $basic_machine in
ms1-*)
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
;;
+ msys)
+ basic_machine=i386-pc
+ os=-msys
+ ;;
mvs)
basic_machine=i370-ibm
os=-mvs
;;
+ nacl)
+ basic_machine=le32-unknown
+ os=-nacl
+ ;;
ncr3000)
basic_machine=i486-ncr
os=-sysv4
@@ -783,6 +905,12 @@ case $basic_machine in
np1)
basic_machine=np1-gould
;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
nsr-tandem)
basic_machine=nsr-tandem
;;
@@ -813,6 +941,14 @@ case $basic_machine in
basic_machine=i860-intel
os=-osf
;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
pbd)
basic_machine=sparc-tti
;;
@@ -857,9 +993,10 @@ case $basic_machine in
;;
power) basic_machine=power-ibm
;;
- ppc) basic_machine=powerpc-unknown
+ ppc | ppcbe) basic_machine=powerpc-unknown
;;
- ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ppc-* | ppcbe-*)
+ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ppcle | powerpclittle | ppc-le | powerpc-little)
basic_machine=powerpcle-unknown
@@ -884,7 +1021,11 @@ case $basic_machine in
basic_machine=i586-unknown
os=-pw32
;;
- rdos)
+ rdos | rdos64)
+ basic_machine=x86_64-pc
+ os=-rdos
+ ;;
+ rdos32)
basic_machine=i386-pc
os=-rdos
;;
@@ -953,6 +1094,9 @@ case $basic_machine in
basic_machine=i860-stratus
os=-sysv4
;;
+ strongarm-* | thumb-*)
+ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
sun2)
basic_machine=m68000-sun
;;
@@ -1009,17 +1153,9 @@ case $basic_machine in
basic_machine=t90-cray
os=-unicos
;;
- tic54x | c54x*)
- basic_machine=tic54x-unknown
- os=-coff
- ;;
- tic55x | c55x*)
- basic_machine=tic55x-unknown
- os=-coff
- ;;
- tic6x | c6x*)
- basic_machine=tic6x-unknown
- os=-coff
+ tile*)
+ basic_machine=$basic_machine-unknown
+ os=-linux-gnu
;;
tx39)
basic_machine=mipstx39-unknown
@@ -1027,10 +1163,6 @@ case $basic_machine in
tx39el)
basic_machine=mipstx39el-unknown
;;
- tile*)
- basic_machine=tile-tilera
- os=-linux-gnu
- ;;
toad1)
basic_machine=pdp10-xkl
os=-tops20
@@ -1092,6 +1224,9 @@ case $basic_machine in
xps | xps100)
basic_machine=xps100-honeywell
;;
+ xscale-* | xscalee[bl]-*)
+ basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+ ;;
ymp)
basic_machine=ymp-cray
os=-unicos
@@ -1100,6 +1235,10 @@ case $basic_machine in
basic_machine=z8k-unknown
os=-sim
;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
none)
basic_machine=none-none
os=-none
@@ -1138,7 +1277,7 @@ case $basic_machine in
we32k)
basic_machine=we32k-att
;;
- sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
basic_machine=sh-unknown
;;
sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
@@ -1185,9 +1324,12 @@ esac
if [ x"$os" != x"" ]
then
case $os in
- # First match some system type aliases
- # that might get confused with valid system types.
+ # First match some system type aliases
+ # that might get confused with valid system types.
# -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
-solaris1 | -solaris1.*)
os=`echo $os | sed -e 's|solaris1|sunos4|'`
;;
@@ -1208,21 +1350,23 @@ case $os in
# Each alternative MUST END IN A *, to match a version number.
# -sysv* is not here because it comes later, after sysvr4.
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
- | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
- | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* | -plan9* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
- | -aos* \
+ | -aos* | -aros* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
- | -openbsd* | -solidbsd* \
+ | -bitrig* | -openbsd* | -solidbsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
- | -chorusos* | -chorusrdb* \
- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-musl* | -linux-uclibc* \
| -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
@@ -1230,7 +1374,7 @@ case $os in
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
- | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
@@ -1269,7 +1413,7 @@ case $os in
-opened*)
os=-openedition
;;
- -os400*)
+ -os400*)
os=-os400
;;
-wince*)
@@ -1318,7 +1462,7 @@ case $os in
-sinix*)
os=-sysv4
;;
- -tpf*)
+ -tpf*)
os=-tpf
;;
-triton*)
@@ -1354,12 +1498,14 @@ case $os in
-aros*)
os=-aros
;;
- -kaos*)
- os=-kaos
- ;;
-zvmoe)
os=-zvmoe
;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -nacl*)
+ ;;
-none)
;;
*)
@@ -1382,10 +1528,10 @@ else
# system, and we'll never get to this point.
case $basic_machine in
- score-*)
+ score-*)
os=-elf
;;
- spu-*)
+ spu-*)
os=-elf
;;
*-acorn)
@@ -1397,8 +1543,20 @@ case $basic_machine in
arm*-semi)
os=-aout
;;
- c4x-* | tic4x-*)
- os=-coff
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ hexagon-*)
+ os=-elf
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
;;
# This must come before the *-dec entry.
pdp10-*)
@@ -1418,14 +1576,11 @@ case $basic_machine in
;;
m68000-sun)
os=-sunos3
- # This also exists in the configure program, but was not the
- # default.
- # os=-sunos4
;;
m68*-cisco)
os=-aout
;;
- mep-*)
+ mep-*)
os=-elf
;;
mips*-cisco)
@@ -1434,6 +1589,9 @@ case $basic_machine in
mips*-*)
os=-elf
;;
+ or1k-*)
+ os=-elf
+ ;;
or32-*)
os=-coff
;;
@@ -1452,7 +1610,7 @@ case $basic_machine in
*-ibm)
os=-aix
;;
- *-knuth)
+ *-knuth)
os=-mmixware
;;
*-wec)
@@ -1557,7 +1715,7 @@ case $basic_machine in
-sunos*)
vendor=sun
;;
- -aix*)
+ -cnk*|-aix*)
vendor=ibm
;;
-beos*)
@@ -1628,3 +1786,4 @@ exit
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:
+
diff --git a/erts/configure.in b/erts/configure.in
index 1e3a607a6f..7257751068 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -1923,12 +1923,21 @@ fi
AC_CHECK_FUNCS([getipnodebyname getipnodebyaddr gethostbyname2])
AC_CHECK_FUNCS([ieee_handler fpsetmask finite isnan isinf res_gethostbyname dlopen \
- pread pwrite writev memmove strerror strerror_r strncasecmp \
+ pread pwrite memmove strerror strerror_r strncasecmp \
gethrtime localtime_r gmtime_r inet_pton mmap mremap memcpy mallopt \
sbrk _sbrk __sbrk brk _brk __brk \
flockfile fstat strlcpy strlcat setsid posix2time time2posix \
setlocale nl_langinfo poll])
+dnl writev on OS X snow leopard is broken for files > 4GB
+case $host_os in
+ darwin10.8.0)
+ AC_MSG_CHECKING([for writev])
+ AC_MSG_RESULT(no, not stable on OS X Snow Leopard) ;;
+ *)
+ AC_CHECK_FUNCS([writev]) ;;
+esac
+
AC_CHECK_DECLS([posix2time, time2posix],,,[#include <time.h>])
disable_vfork=false
diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml
index 1212c34586..636326e4e1 100644
--- a/erts/doc/src/erl_driver.xml
+++ b/erts/doc/src/erl_driver.xml
@@ -170,10 +170,13 @@
callback, the best approach is to divide the work into multiple chunks of
work and trigger multiple calls to the
<seealso marker="driver_entry#timeout">timeout callback</seealso> using
- zero timeouts. This might, however, not always be possible, e.g. when
- calling third party libraries. In this case you typically want to dispatch
- the work to another thread. Information about thread primitives can be
- found below.</p>
+ zero timeouts. The
+ <seealso marker="#erl_drv_consume_timeslice"><c>erl_drv_consume_timeslice()</c></seealso>
+ function can be useful in order to determine when to trigger such
+ timeout callback calls. It might, however, not always be possible to
+ implement it this way, e.g. when calling third party libraries. In this
+ case you typically want to dispatch the work to another thread.
+ Information about thread primitives can be found below.</p>
</description>
<section>
@@ -1960,9 +1963,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
emulator thread. This enables the driver to perform
time-consuming, blocking operations without blocking the
emulator.</p>
- <p>Erlang is by default started without an async thread pool. The
- number of async threads that the runtime system should use
- is specified by the
+ <p>The async thread pool size can be set with the
<seealso marker="erl#async_thread_pool_size">+A</seealso>
command line argument of <seealso marker="erl">erl(1)</seealso>.
If no async thread pool is available, the call is made
@@ -2807,7 +2808,6 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
<p>This function is thread-safe.</p>
</desc>
</func>
-
<func>
<name><ret>int</ret><nametext>erl_drv_getenv(char *key, char *value, size_t *value_size)</nametext></name>
<fsummary>Get the value of an environment variable</fsummary>
@@ -2843,6 +2843,52 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len
<p>This function is thread-safe.</p>
</desc>
</func>
+ <func>
+ <name><ret>int</ret><nametext>erl_drv_consume_timeslice(ErlDrvPort port, int percent)</nametext></name>
+ <fsummary>Give the runtime system a hint about how much CPU time the
+ current driver callback call has consumed</fsummary>
+ <desc>
+ <marker id="erl_drv_consume_timeslice"></marker>
+ <p>Arguments:</p>
+ <taglist>
+ <tag><c>port</c></tag>
+ <item>Port handle of the executing port.</item>
+ <tag><c>percent</c></tag>
+ <item>Approximate consumed fraction of a full
+ time-slice in percent.</item>
+ </taglist>
+ <p>Give the runtime system a hint about how much CPU time the
+ current driver callback call has consumed since last hint, or
+ since the start of the callback if no previous hint has been given.
+ The time is given as a fraction, in percent, of a full time-slice
+ that a port is allowed to execute before it should surrender the
+ CPU to other runnable ports or processes. Valid range is
+ <c>[1, 100]</c>. The scheduling time-slice is not an exact entity,
+ but can usually be approximated to about 1 millisecond.</p>
+
+ <p>Note that it is up to the runtime system to determine if and
+ how to use this information. Implementations on some platforms
+ may use other means in order to determine the consumed fraction
+ of the time-slice. Lengthy driver callbacks should regardless of
+ this frequently call the <c>erl_drv_consume_timeslice()</c>
+ function in order to determine if it is allowed to continue
+ execution or not.</p>
+
+ <p><c>erl_drv_consume_timeslice()</c> returns a non-zero value
+ if the time-slice has been exhausted, and zero if the callback is
+ allowed to continue execution. If a non-zero value is
+ returned the driver callback should return as soon as possible in
+ order for the port to be able to yield.</p>
+
+ <p>This function is provided to better support co-operative scheduling,
+ improve system responsiveness, and to make it easier to prevent
+ misbehaviors of the VM due to a port monopolizing a scheduler thread.
+ It can be used when dividing length work into a number of repeated
+ driver callback calls without the need to use threads. Also see the
+ important <seealso marker="#WARNING">warning</seealso> text at the
+ beginning of this document.</p>
+ </desc>
+ </func>
</funcs>
<section>
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index f00f7b9f46..18193d1150 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -174,9 +174,11 @@ ok
millisecond has passed. This can be achieved using different approaches.
If you have full control over the code that are to execute in the native
function, the best approach is to divide the work into multiple chunks of
- work and call the native function multiple times. This might, however,
- not always be possible, e.g. when calling third party libraries. In this
- case you typically want to dispatch the work to another thread, return
+ work and call the native function multiple times. Function
+ <seealso marker="#enif_consume_timeslice">enif_consume_timeslice</seealso> can be
+ used this facilitate such work division. In some cases, however, this might not
+ be possible, e.g. when calling third party libraries. Then you typically want
+ to dispatch the work to another thread, return
from the native function, and wait for the result. The thread can send
the result back to the calling thread using message passing. Information
about thread primitives can be found below.</p>
@@ -227,8 +229,8 @@ ok
bit length have no support yet.</p>
</item>
<tag>Resource objects</tag>
- <item><p>The use of resource objects is a way to return pointers to
- native data structures from a NIF in a safe way. A resource object is
+ <item><p>The use of resource objects is a safe way to return pointers to
+ native data structures from a NIF. A resource object is
just a block of memory allocated with
<seealso marker="#enif_alloc_resource">enif_alloc_resource</seealso>.
A handle ("safe pointer") to this memory block can then be returned to Erlang by the use of
@@ -581,6 +583,31 @@ typedef enum {
<desc><p>Same as <seealso marker="erl_driver#erl_drv_cond_wait">erl_drv_cond_wait</seealso>.
</p></desc>
</func>
+ <func><name><ret>int</ret><nametext>enif_consume_timeslice(ErlNifEnv *env, int percent)</nametext></name>
+ <fsummary></fsummary>
+ <desc><p>Give the runtime system a hint about how much CPU time the current NIF call has consumed
+ since last hint, or since the start of the NIF if no previous hint has been given.
+ The time is given as a <c>percent</c> of the timeslice that a process is allowed to execute Erlang
+ code until it may be suspended to give time for other runnable processes.
+ The scheduling timeslice is not an exact entity, but can usually be
+ approximated to about 1 millisecond.</p>
+ <p>Note that it is up to the runtime system to determine if and how to use this information.
+ Implementations on some platforms may use other means in order to determine consumed
+ CPU time. Lengthy NIFs should regardless of this frequently call <c>enif_consume_timeslice</c>
+ in order to determine if it is allowed to continue execution or not.</p>
+
+ <p>Returns 1 if the timeslice is exhausted, or 0 otherwise. If 1 is returned the NIF should return
+ as soon as possible in order for the process to yield.</p>
+ <p>Argument <c>percent</c> must be an integer between 1 and 100. This function
+ must only be called from a NIF-calling thread and argument <c>env</c> must be
+ the environment of the calling process.</p>
+ <p>This function is provided to better support co-operative scheduling, improve system responsiveness,
+ and make it easier to prevent misbehaviors of the VM due to a NIF monopolizing a scheduler thread.
+ It can be used to divide <seealso marker="#lengthy_work">length work</seealso> into
+ a number of repeated NIF-calls without the need to create threads.
+ See also the <seealso marker="#WARNING">warning</seealso> text at the beginning of this document.</p>
+ </desc>
+ </func>
<func><name><ret>int</ret><nametext>enif_equal_tids(ErlNifTid tid1, ErlNifTid tid2)</nametext></name>
<fsummary></fsummary>
<desc><p>Same as <seealso marker="erl_driver#erl_drv_equal_tids">erl_drv_equal_tids</seealso>.
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 7804a7498e..06fefa8efb 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -300,6 +300,44 @@
</desc>
</func>
<func>
+ <name name="binary_to_float" arity="1"/>
+ <fsummary>Convert from text representation to a float</fsummary>
+ <desc>
+ <p>Returns the float whose text representation is <c><anno>Binary</anno></c>.</p>
+ <pre>
+> <input>binary_to_float(&lt;&lt;"2.2017764e+0">>).</input>
+2.2017764</pre>
+ <p>Failure: <c>badarg</c> if <c><anno>Binary</anno></c> contains a bad
+ representation of a float.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="binary_to_integer" arity="1"/>
+ <fsummary>Convert from text representation to an integer</fsummary>
+ <desc>
+ <p>Returns an integer whose text representation is
+ <c><anno>Binary</anno></c>.</p>
+ <pre>
+> <input>binary_to_integer(&lt;&lt;"123"&gt;&gt;).</input>
+123</pre>
+ <p>Failure: <c>badarg</c> if <c><anno>Binary</anno></c> contains a bad
+ representation of an integer.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="binary_to_integer" arity="2"/>
+ <fsummary>Convert 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>
+ <pre>
+> <input>binary_to_integer(&lt;&lt;"3FF"&gt;&gt;, 16).</input>
+1023</pre>
+ <p>Failure: <c>badarg</c> if <c><anno>Binary</anno></c> contains a bad
+ representation of an integer.</p>
+ </desc>
+ </func>
+ <func>
<name name="binary_to_list" arity="1"/>
<fsummary>Convert a binary to a list</fsummary>
<desc>
@@ -961,26 +999,38 @@ true
</desc>
</func>
<func>
- <name name="float_to_list" arity="1"/>
+ <name name="float_to_binary" arity="1"/>
<fsummary>Text representation of a float</fsummary>
<desc>
- <p>Returns a string which corresponds to the text
- representation of <c><anno>Float</anno></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>
+ <desc>
+ <p>Returns a binary which corresponds 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>
<pre>
-> <input>float_to_list(7.0).</input>
-"7.00000000000000000000e+00"</pre>
+> <input>float_to_binary(7.12, [{decimals, 4}]).</input>
+&lt;&lt;"7.1200">>
+> <input>float_to_binary(7.12, [{decimals, 4}, compact]).</input>
+&lt;&lt;"7.12">></pre>
</desc>
</func>
<func>
- <name>float_to_list(Float, Options) -> string()</name>
+ <name name="float_to_list" arity="1"/>
+ <fsummary>Text representation of a float</fsummary>
+ <desc>
+ <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>
- <type>
- <v>Float = float()</v>
- <v>Options = [Option]</v>
- <v>Option = {decimals, Decimals::0..249} |
- {scientific, Decimals::0..249} |
- compact</v>
- </type>
<desc>
<p>Returns a string which corresponds to the text
representation of <c>Float</c> using fixed decimal point formatting.
@@ -993,7 +1043,8 @@ true
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>float_to_list/1</c>.
+ <c>Options</c> is <c>[]</c> the function behaves like
+ <c><seealso marker="#float_to_list/1">float_to_list/1</seealso></c>.
</p>
<pre>
> <input>float_to_list(7.12, [{decimals, 4}]).</input>
@@ -1429,7 +1480,28 @@ os_prompt% </pre>
{one,new,two,three}</pre>
</desc>
</func>
-
+ <func>
+ <name name="integer_to_binary" arity="1"/>
+ <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>
+ <pre>
+> <input>integer_to_binary(77).</input>
+&lt;&lt;"77">></pre>
+ </desc>
+ </func>
+ <func>
+ <name name="integer_to_binary" arity="2"/>
+ <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>
+ <pre>
+> <input>integer_to_binary(1023, 16).</input>
+&lt;&lt;"3FF">></pre>
+ </desc>
+ </func>
<func>
<name name="integer_to_list" arity="1"/>
<fsummary>Text representation of an integer</fsummary>
diff --git a/erts/doc/src/erts_alloc.xml b/erts/doc/src/erts_alloc.xml
index f0bde600ad..c73cdfd290 100644
--- a/erts/doc/src/erts_alloc.xml
+++ b/erts/doc/src/erts_alloc.xml
@@ -276,7 +276,7 @@
<item>
Max cached segments. The maximum number of memory segments
stored in the memory segment cache. Valid range is
- 0-30. Default value is 5.</item>
+ 0-30. Default value is 10.</item>
</taglist>
<p>The following flags are available for configuration of
<c>sys_alloc</c>:</p>
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index 42298e4824..0363f0237e 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -144,7 +144,7 @@
spawning processes, terminating processes, sending
messages, etc.</item> <item>Optimizations of run queue
management reducing contention.</item>
- <item>Optimizations of process state changes reducing
+ <item>Optimizations of process internal state changes reducing
contention.</item> </list> <p>These changes imply changes
of the characteristics the system. Most notable: changed
timing in the system.</p>
@@ -403,7 +403,7 @@
</item>
<item>
<p>
- The <seealso marker="#+stbt">+stbt</seealso> command line
+ The <seealso marker="erl#+stbt">+stbt</seealso> command line
argument of <c>erl</c> was added. This argument can be
used for trying to set scheduler bind type. Upon failure
unbound schedulers will be used.</p>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 3e44bbb8db..2877e58cdf 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -20,6 +20,8 @@
include $(ERL_TOP)/make/target.mk
include ../vsn.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
+-include $(TARGET)/gen_git_version.mk
+
ENABLE_ALLOC_TYPE_VARS = @ENABLE_ALLOC_TYPE_VARS@
HIPE_ENABLED=@HIPE_ENABLED@
@@ -196,7 +198,7 @@ else
EMU_CC = @EMU_CC@
endif
WFLAGS = @WFLAGS@
-CFLAGS = @STATIC_CFLAGS@ $(TYPE_FLAGS) $(FLAVOR_FLAGS) $(DEFS) $(WFLAGS) $(THR_DEFS) $(ARCHCFLAGS)
+CFLAGS = @STATIC_CFLAGS@ $(TYPE_FLAGS) $(FLAVOR_FLAGS) $(DEFS) $(WFLAGS) $(THR_DEFS) $(ARCHCFLAGS) $(GIT_VSN)
HCC = @HCC@
LD = @LD@
DEXPORT = @DEXPORT@
@@ -1006,6 +1008,12 @@ DEP_FLAGS=-MM $(MG_FLAG) $(CFLAGS) $(INCLUDES) -Idrivers/common -Idrivers/$(ERLA
SYS_SRC=$(ALL_SYS_SRC)
endif
+.PHONY: $(TARGET)/gen_git_version.mk
+$(TARGET)/gen_git_version.mk:
+# We touch beam/erl_bif.info.c if we regenerated the git version to force a
+# rebuild.
+ if $(gen_verbose)utils/gen_git_version $@; then touch beam/erl_bif_info.c; fi
+
.PHONY: depend
ifdef VOID_EMULATOR
depend:
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index f138324e1f..ce60bb9bbc 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -269,6 +269,7 @@ atom hipe_architecture
atom http httph https http_response http_request http_header http_eoh http_error http_bin httph_bin
atom id
atom if_clause
+atom ignore
atom imports
atom in
atom in_exiting
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 0e9d140908..e2c3bf292f 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -1070,17 +1070,6 @@ init_emulator(void)
#endif /* USE_VM_PROBES */
-#ifdef USE_VM_PROBES
-void
-dtrace_drvport_str(ErlDrvPort drvport, char *port_buf)
-{
- Port *port = erts_drvport2port(drvport, NULL);
-
- erts_snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>",
- port_channel_no(port->common.id),
- port_number(port->common.id));
-}
-#endif
/*
* process_main() is called twice:
* The first call performs some initialisation, including exporting
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 46f76624a5..9c438679ea 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -39,6 +39,7 @@
#include "erl_thr_progress.h"
#define ERTS_PTAB_WANT_BIF_IMPL__
#include "erl_ptab.h"
+#include "erl_bits.h"
static Export* flush_monitor_message_trap = NULL;
static Export* set_cpu_topology_trap = NULL;
@@ -2069,11 +2070,16 @@ BIF_RETTYPE send_3(BIF_ALIST_3)
result = do_send(p, to, msg, suspend, &ref);
if (result > 0) {
ERTS_VBUMP_REDS(p, result);
+ if (ERTS_IS_PROC_OUT_OF_REDS(p))
+ goto yield_return;
BIF_RET(am_ok);
}
switch (result) {
case 0:
+ /* May need to yield even though we do not bump reds here... */
+ if (ERTS_IS_PROC_OUT_OF_REDS(p))
+ goto yield_return;
BIF_RET(am_ok);
break;
case SEND_TRAP:
@@ -2091,10 +2097,10 @@ BIF_RETTYPE send_3(BIF_ALIST_3)
}
break;
case SEND_YIELD_RETURN:
- if (suspend)
- ERTS_BIF_YIELD_RETURN(p, am_ok);
- else
+ if (!suspend)
BIF_RET(am_nosuspend);
+ yield_return:
+ ERTS_BIF_YIELD_RETURN(p, am_ok);
case SEND_AWAIT_RESULT:
ASSERT(is_internal_ref(ref));
BIF_TRAP3(await_port_send_result_trap, p, ref, am_nosuspend, am_ok);
@@ -2133,11 +2139,16 @@ Eterm erl_send(Process *p, Eterm to, Eterm msg)
if (result > 0) {
ERTS_VBUMP_REDS(p, result);
+ if (ERTS_IS_PROC_OUT_OF_REDS(p))
+ goto yield_return;
BIF_RET(msg);
}
switch (result) {
case 0:
+ /* May need to yield even though we do not bump reds here... */
+ if (ERTS_IS_PROC_OUT_OF_REDS(p))
+ goto yield_return;
BIF_RET(msg);
break;
case SEND_TRAP:
@@ -2147,6 +2158,7 @@ Eterm erl_send(Process *p, Eterm to, Eterm msg)
ERTS_BIF_YIELD2(bif_export[BIF_send_2], p, to, msg);
break;
case SEND_YIELD_RETURN:
+ yield_return:
ERTS_BIF_YIELD_RETURN(p, msg);
case SEND_AWAIT_RESULT:
ASSERT(is_internal_ref(ref));
@@ -2895,45 +2907,69 @@ BIF_RETTYPE string_to_integer_1(BIF_ALIST_1)
BIF_RET(TUPLE2(hp, res, tail));
}
}
-
BIF_RETTYPE list_to_integer_1(BIF_ALIST_1)
-{
+ {
+ /* Using do_list_to_integer is about twice as fast as using
+ erts_chars_to_integer because we do not have to copy the
+ entire list */
Eterm res;
Eterm dummy;
/* must be a list */
-
if (do_list_to_integer(BIF_P,BIF_ARG_1,&res,&dummy) != LTI_ALL_INTEGER) {
BIF_ERROR(BIF_P,BADARG);
}
BIF_RET(res);
}
-/**********************************************************************/
+BIF_RETTYPE list_to_integer_2(BIF_ALIST_2)
+{
-/* convert a float to a list of ascii characters */
+ /* Bif implementation is about 50% faster than pure erlang,
+ and since we have erts_chars_to_integer now it is simpler
+ as well. This could be optmized further if we did not have to
+ copy the list to buf. */
+ int i;
+ Eterm res;
+ char *buf = NULL;
+ int base;
-BIF_RETTYPE float_to_list_1(BIF_ALIST_1)
-{
- int i;
- Uint need;
- Eterm* hp;
- FloatDef f;
- char fbuf[30];
+ i = list_length(BIF_ARG_1);
+ if (i < 0)
+ BIF_ERROR(BIF_P, BADARG);
+
+ base = signed_val(BIF_ARG_2);
+
+ if (base < 2 || base > 36)
+ BIF_ERROR(BIF_P, BADARG);
+
+ /* Take fast path if base it 10 */
+ if (base == 10)
+ return list_to_integer_1(BIF_P,&BIF_ARG_1);
+
+ buf = (char *) erts_alloc(ERTS_ALC_T_TMP, i + 1);
+
+ if (intlist_to_buf(BIF_ARG_1, buf, i) < 0)
+ goto list_to_integer_1_error;
+ buf[i] = '\0'; /* null terminal */
+
+ if ((res = erts_chars_to_integer(BIF_P,buf,i,base)) == THE_NON_VALUE)
+ goto list_to_integer_1_error;
+
+ erts_free(ERTS_ALC_T_TMP, (void *) buf);
+ BIF_RET(res);
+
+ list_to_integer_1_error:
+ erts_free(ERTS_ALC_T_TMP, (void *) buf);
+ BIF_ERROR(BIF_P, BADARG);
- /* check the arguments */
- if (is_not_float(BIF_ARG_1))
- BIF_ERROR(BIF_P, BADARG);
- GET_DOUBLE(BIF_ARG_1, f);
- if ((i = sys_double_to_chars(f.fd, fbuf, sizeof(fbuf))) <= 0)
- BIF_ERROR(BIF_P, EXC_INTERNAL_ERROR);
- need = i*2;
- hp = HAlloc(BIF_P, need);
- BIF_RET(buf_to_intlist(&hp, fbuf, i, NIL));
-}
+ }
+
+/**********************************************************************/
+
+static int do_float_to_charbuf(Process *p, Eterm efloat, Eterm list,
+ char *fbuf, int sizeof_fbuf) {
-BIF_RETTYPE float_to_list_2(BIF_ALIST_2)
-{
const static int arity_two = make_arityval(2);
int decimals = SYS_DEFAULT_FLOAT_DECIMALS;
int compact = 0;
@@ -2942,16 +2978,11 @@ BIF_RETTYPE float_to_list_2(BIF_ALIST_2)
FMT_FIXED,
FMT_SCIENTIFIC
} fmt_type = FMT_LEGACY;
- Eterm list = BIF_ARG_2;
Eterm arg;
- int i;
- Uint need;
- Eterm* hp;
FloatDef f;
- char fbuf[256];
/* check the arguments */
- if (is_not_float(BIF_ARG_1))
+ if (is_not_float(efloat))
goto badarg;
for(; is_list(list); list = CDR(list_val(list))) {
@@ -2963,15 +2994,14 @@ BIF_RETTYPE float_to_list_2(BIF_ALIST_2)
Eterm* tp = tuple_val(arg);
if (*tp == arity_two && is_small(tp[2])) {
decimals = signed_val(tp[2]);
- if (decimals > 0 && decimals < sizeof(fbuf) - 6 /* "X." ++ "e+YY" */)
- switch (tp[1]) {
- case am_decimals:
- fmt_type = FMT_FIXED;
- continue;
- case am_scientific:
- fmt_type = FMT_SCIENTIFIC;
- continue;
- }
+ switch (tp[1]) {
+ case am_decimals:
+ fmt_type = FMT_FIXED;
+ continue;
+ case am_scientific:
+ fmt_type = FMT_SCIENTIFIC;
+ continue;
+ }
}
}
goto badarg;
@@ -2980,22 +3010,64 @@ BIF_RETTYPE float_to_list_2(BIF_ALIST_2)
goto badarg;
}
- GET_DOUBLE(BIF_ARG_1, f);
+ GET_DOUBLE(efloat, f);
if (fmt_type == FMT_FIXED) {
- if ((i = sys_double_to_chars_fast(f.fd, fbuf, sizeof(fbuf),
- decimals, compact)) <= 0)
- goto badarg;
+ return sys_double_to_chars_fast(f.fd, fbuf, sizeof_fbuf,
+ decimals, compact);
} else {
- if ((i = sys_double_to_chars_ext(f.fd, fbuf, sizeof(fbuf), decimals)) <= 0)
- goto badarg;
+ return sys_double_to_chars_ext(f.fd, fbuf, sizeof_fbuf, decimals);
}
- need = i*2;
- hp = HAlloc(BIF_P, need);
- BIF_RET(buf_to_intlist(&hp, fbuf, i, NIL));
badarg:
+ return -1;
+}
+
+/* convert a float to a list of ascii characters */
+
+static BIF_RETTYPE do_float_to_list(Process *BIF_P, Eterm arg, Eterm opts) {
+ int used;
+ Eterm* hp;
+ char fbuf[256];
+
+ if ((used = do_float_to_charbuf(BIF_P,arg,opts,fbuf,sizeof(fbuf))) <= 0) {
BIF_ERROR(BIF_P, BADARG);
+ }
+ hp = HAlloc(BIF_P, (Uint)used*2);
+ BIF_RET(buf_to_intlist(&hp, fbuf, (Uint)used, NIL));
+}
+
+
+BIF_RETTYPE float_to_list_1(BIF_ALIST_1)
+{
+ return do_float_to_list(BIF_P,BIF_ARG_1,NIL);
+}
+
+BIF_RETTYPE float_to_list_2(BIF_ALIST_2)
+{
+ return do_float_to_list(BIF_P,BIF_ARG_1,BIF_ARG_2);
+}
+
+/* convert a float to a binary of ascii characters */
+
+static BIF_RETTYPE do_float_to_binary(Process *BIF_P, Eterm arg, Eterm opts) {
+ int used;
+ char fbuf[256];
+
+ if ((used = do_float_to_charbuf(BIF_P,arg,opts,fbuf,sizeof(fbuf))) <= 0) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+ BIF_RET(new_binary(BIF_P, (byte*)fbuf, (Uint)used));
+}
+
+BIF_RETTYPE float_to_binary_1(BIF_ALIST_1)
+{
+ return do_float_to_binary(BIF_P,BIF_ARG_1,NIL);
+}
+
+BIF_RETTYPE float_to_binary_2(BIF_ALIST_2)
+{
+ return do_float_to_binary(BIF_P,BIF_ARG_1,BIF_ARG_2);
}
/**********************************************************************/
@@ -3180,36 +3252,101 @@ BIF_RETTYPE string_to_float_1(BIF_ALIST_1)
BIF_RET(tup);
}
+static BIF_RETTYPE do_charbuf_to_float(Process *BIF_P,char *buf) {
+ FloatDef f;
+ Eterm res;
+ Eterm* hp;
+
+ if (sys_chars_to_double(buf, &f.fd) != 0)
+ BIF_ERROR(BIF_P, BADARG);
+
+ hp = HAlloc(BIF_P, FLOAT_SIZE_OBJECT);
+ res = make_float(hp);
+ PUT_DOUBLE(f, hp);
+ BIF_RET(res);
+
+}
BIF_RETTYPE list_to_float_1(BIF_ALIST_1)
{
int i;
- FloatDef f;
Eterm res;
- Eterm* hp;
char *buf = NULL;
i = list_length(BIF_ARG_1);
- if (i < 0) {
- badarg:
- if (buf)
- erts_free(ERTS_ALC_T_TMP, (void *) buf);
- BIF_ERROR(BIF_P, BADARG);
- }
-
+ if (i < 0)
+ BIF_ERROR(BIF_P, BADARG);
+
buf = (char *) erts_alloc(ERTS_ALC_T_TMP, i + 1);
if (intlist_to_buf(BIF_ARG_1, buf, i) < 0)
- goto badarg;
+ goto list_to_float_1_error;
buf[i] = '\0'; /* null terminal */
+
+ if ((res = do_charbuf_to_float(BIF_P,buf)) == THE_NON_VALUE)
+ goto list_to_float_1_error;
+
+ erts_free(ERTS_ALC_T_TMP, (void *) buf);
+ BIF_RET(res);
+
+ list_to_float_1_error:
+ erts_free(ERTS_ALC_T_TMP, (void *) buf);
+ BIF_ERROR(BIF_P, BADARG);
+
+}
+
+BIF_RETTYPE binary_to_float_1(BIF_ALIST_1)
+{
+ Eterm res;
+ Eterm binary = BIF_ARG_1;
+ Sint size;
+ byte* bytes, *buf;
+ Eterm* real_bin;
+ Uint offs = 0;
+ Uint bit_offs = 0;
+
+ if (is_not_binary(binary) || (size = binary_size(binary)) == 0)
+ BIF_ERROR(BIF_P, BADARG);
+
+ /*
+ * Unfortunately we have to copy the binary because we have to insert
+ * the '\0' at the end of the binary for strtod to work
+ * (there is no nstrtod :( )
+ */
+
+ buf = erts_alloc(ERTS_ALC_T_TMP, size + 1);
+
+ real_bin = binary_val(binary);
+ if (*real_bin == HEADER_SUB_BIN) {
+ ErlSubBin* sb = (ErlSubBin *) real_bin;
+ if (sb->bitsize) {
+ goto binary_to_float_1_error;
+ }
+ offs = sb->offs;
+ bit_offs = sb->bitoffs;
+ real_bin = binary_val(sb->orig);
+ }
+ if (*real_bin == HEADER_PROC_BIN) {
+ bytes = ((ProcBin *) real_bin)->bytes + offs;
+ } else {
+ bytes = (byte *)(&(((ErlHeapBin *) real_bin)->data)) + offs;
+ }
+ if (bit_offs)
+ erts_copy_bits(bytes, bit_offs, 1, buf, 0, 1, size*8);
+ else
+ memcpy(buf, bytes, size);
+
+ buf[size] = '\0';
+
+ if ((res = do_charbuf_to_float(BIF_P,(char*)buf)) == THE_NON_VALUE)
+ goto binary_to_float_1_error;
- if (sys_chars_to_double(buf, &f.fd) != 0)
- goto badarg;
- hp = HAlloc(BIF_P, FLOAT_SIZE_OBJECT);
- res = make_float(hp);
- PUT_DOUBLE(f, hp);
erts_free(ERTS_ALC_T_TMP, (void *) buf);
BIF_RET(res);
+
+ binary_to_float_1_error:
+ erts_free(ERTS_ALC_T_TMP, (void *) buf);
+ BIF_ERROR(BIF_P, BADARG);
}
/**********************************************************************/
diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h
index ceaf747875..51b77a95ed 100644
--- a/erts/emulator/beam/bif.h
+++ b/erts/emulator/beam/bif.h
@@ -35,6 +35,13 @@ extern Export* erts_format_cpu_topology_trap;
#define BIF_ARG_2 (BIF__ARGS[1])
#define BIF_ARG_3 (BIF__ARGS[2])
+#define ERTS_IS_PROC_OUT_OF_REDS(p) \
+ ((p)->fcalls > 0 \
+ ? 0 \
+ : (!ERTS_PROC_GET_SAVED_CALLS_BUF((p)) \
+ ? (p)->fcalls == 0 \
+ : ((p)->fcalls == -CONTEXT_REDS)))
+
#define BUMP_ALL_REDS(p) do { \
if (!ERTS_PROC_GET_SAVED_CALLS_BUF((p))) \
(p)->fcalls = 0; \
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index 4aaf466008..b74dc5c3fe 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -522,6 +522,7 @@ bif erlang:nif_error/2
bif prim_file:internal_name2native/1
bif prim_file:internal_native2name/1
bif prim_file:internal_normalize_utf8/1
+bif prim_file:is_translatable/1
bif file:native_name_encoding/0
#
@@ -560,6 +561,13 @@ bif erlang:prepare_loading/2
bif erlang:finish_loading/1
bif erlang:insert_element/3
bif erlang:delete_element/2
+bif erlang:binary_to_integer/1
+bif erlang:binary_to_integer/2
+bif erlang:integer_to_binary/1
+bif erlang:list_to_integer/2
+bif erlang:float_to_binary/1
+bif erlang:float_to_binary/2
+bif erlang:binary_to_float/1
#
# Obsolete
diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c
index 5a5b162b9c..acfcc845e4 100644
--- a/erts/emulator/beam/big.c
+++ b/erts/emulator/beam/big.c
@@ -1674,26 +1674,26 @@ int big_decimal_estimate(Wterm x)
** Convert a bignum into a string of decimal numbers
*/
-static void write_big(Wterm x, void (*write_func)(void *, char), void *arg)
+static Uint write_big(Wterm x, void (*write_func)(void *, char), void *arg)
{
Eterm* xp = big_val(x);
ErtsDigit* dx = BIG_V(xp);
dsize_t xl = BIG_SIZE(xp);
short sign = BIG_SIGN(xp);
ErtsDigit rem;
+ Uint n = 0;
if (xl == 1 && *dx < D_DECIMAL_BASE) {
rem = *dx;
- if (rem == 0)
- (*write_func)(arg, '0');
- else {
+ if (rem == 0) {
+ (*write_func)(arg, '0'); n++;
+ } else {
while(rem) {
- (*write_func)(arg, (rem % 10) + '0');
+ (*write_func)(arg, (rem % 10) + '0'); n++;
rem /= 10;
}
}
- }
- else {
+ } else {
ErtsDigit* tmp = (ErtsDigit*) erts_alloc(ERTS_ALC_T_TMP,
sizeof(ErtsDigit)*xl);
dsize_t tmpl = xl;
@@ -1704,15 +1704,14 @@ static void write_big(Wterm x, void (*write_func)(void *, char), void *arg)
tmpl = D_div(tmp, tmpl, D_DECIMAL_BASE, tmp, &rem);
if (tmpl == 1 && *tmp == 0) {
while(rem) {
- (*write_func)(arg, (rem % 10)+'0');
+ (*write_func)(arg, (rem % 10)+'0'); n++;
rem /= 10;
}
break;
- }
- else {
+ } else {
int i = D_DECIMAL_EXP;
while(i--) {
- (*write_func)(arg, (rem % 10)+'0');
+ (*write_func)(arg, (rem % 10)+'0'); n++;
rem /= 10;
}
}
@@ -1720,8 +1719,10 @@ static void write_big(Wterm x, void (*write_func)(void *, char), void *arg)
erts_free(ERTS_ALC_T_TMP, (void *) tmp);
}
- if (sign)
- (*write_func)(arg, '-');
+ if (sign) {
+ (*write_func)(arg, '-'); n++;
+ }
+ return n;
}
struct big_list__ {
@@ -1762,6 +1763,20 @@ char *erts_big_to_string(Wterm x, char *buf, Uint buf_sz)
return big_str;
}
+/* Bignum to binary bytes
+ * e.g. 1 bsl 64 -> "18446744073709551616"
+ */
+
+Uint erts_big_to_binary_bytes(Eterm x, char *buf, Uint buf_sz)
+{
+ char *big_str = buf + buf_sz;
+ Uint n;
+ n = write_big(x, write_string, (void *) &big_str);
+ ASSERT(buf <= big_str && big_str <= buf + buf_sz);
+ return n;
+}
+
+
/*
** Normalize a bignum given thing pointer length in digits and a sign
** patch zero if odd length
@@ -2467,3 +2482,209 @@ int term_equals_2pow32(Eterm x)
return 0;
}
}
+
+
+#define IS_VALID_CHARACTER(CHAR,BASE) \
+ (CHAR < '0' \
+ || (CHAR > ('0' + BASE - 1) \
+ && !(BASE > 10 \
+ && ((CHAR >= 'a' && CHAR < ('a' + BASE - 10)) \
+ || (CHAR >= 'A' && CHAR < ('A' + BASE - 10))))))
+#define CHARACTER_FROM_BASE(CHAR) \
+ ((CHAR <= '9') ? CHAR - '0' : 10 + ((CHAR <= 'Z') ? CHAR - 'A' : CHAR - 'a'))
+#define D_BASE_EXP(BASE) (d_base_exp_lookup[BASE-2])
+#define D_BASE_BASE(BASE) (d_base_base_lookup[BASE-2])
+#define LG2_LOOKUP(BASE) (lg2_lookup[base-2])
+
+/*
+ * for i in 2..64 do
+ * lg2_lookup[i-2] = log2(i)
+ * end
+ * How many bits are needed to store string of size n
+ */
+const double lg2_lookup[] = { 1.0, 1.58496, 2, 2.32193, 2.58496, 2.80735, 3.0,
+ 3.16993, 3.32193, 3.45943, 3.58496, 3.70044, 3.80735, 3.90689, 4.0,
+ 4.08746, 4.16993, 4.24793, 4.32193, 4.39232, 4.45943, 4.52356, 4.58496,
+ 4.64386, 4.70044, 4.75489, 4.80735, 4.85798, 4.90689, 4.9542, 5.0,
+ 5.04439, 5.08746, 5.12928, 5.16993, 5.20945, 5.24793, 5.2854, 5.32193,
+ 5.35755, 5.39232, 5.42626, 5.45943, 5.49185, 5.52356, 5.55459, 5.58496,
+ 5.61471, 5.64386, 5.67243, 5.70044, 5.72792, 5.75489, 5.78136, 5.80735,
+ 5.83289, 5.85798, 5.88264, 5.90689, 5.93074, 5.9542, 5.97728, 6.0 };
+
+/*
+ * for i in 2..64 do
+ * d_base_exp_lookup[i-2] = 31 / lg2_lookup[i-2];
+ * end
+ * How many characters can fit in 31 bits
+ */
+const byte d_base_exp_lookup[] = { 31, 19, 15, 13, 11, 11, 10, 9, 9, 8, 8, 8, 8,
+ 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5 };
+
+/*
+ * for i in 2..64 do
+ * d_base_base_lookup[i-2] = pow(i,d_base_exp_lookup[i-2]);
+ * end
+ * How much can the characters which fit in 31 bit represent
+ */
+const Uint d_base_base_lookup[] = { 2147483648, 1162261467, 1073741824,
+ 1220703125, 362797056, 1977326743, 1073741824, 387420489, 1000000000,
+ 214358881, 429981696, 815730721, 1475789056, 170859375, 268435456,
+ 410338673, 612220032, 893871739, 1280000000, 1801088541, 113379904,
+ 148035889, 191102976, 244140625, 308915776, 387420489, 481890304,
+ 594823321, 729000000, 887503681, 1073741824, 1291467969, 1544804416,
+ 1838265625, 60466176, 69343957, 79235168, 90224199, 102400000,
+ 115856201, 130691232, 147008443, 164916224, 184528125, 205962976,
+ 229345007, 254803968, 282475249, 312500000, 345025251, 380204032,
+ 418195493, 459165024, 503284375, 550731776, 601692057, 656356768,
+ 714924299, 777600000, 844596301, 916132832, 992436543, 1073741824 };
+
+Eterm erts_chars_to_integer(Process *BIF_P, char *bytes,
+ Uint size, const int base) {
+ Eterm res;
+ Sint i = 0;
+ int n = 0;
+ int neg = 0;
+ byte b;
+ Eterm *hp, *hp_end;
+ int m;
+ int lg2;
+
+ if (size == 0)
+ goto bytebuf_to_integer_1_error;
+
+ if (bytes[0] == '-') {
+ neg = 1;
+ bytes++;
+ size--;
+
+ } else if (bytes[0] == '+') {
+ bytes++;
+ size--;
+ }
+
+ if (size < SMALL_DIGITS && base <= 10) {
+ /* *
+ * Take shortcut if we know that all chars are '0' < b < '9' and
+ * fit in a small. This improves speed by about 10% over the generic
+ * small case.
+ * */
+ while (size--) {
+ b = *bytes++;
+
+ if (b < '0' || b > ('0'+base-1))
+ goto bytebuf_to_integer_1_error;
+
+ i = i * base + b - '0';
+ }
+
+ if (neg)
+ i = -i;
+ res = make_small(i);
+ goto bytebuf_to_integer_1_done;
+ }
+
+ /*
+ * Calculate the maximum number of bits which will
+ * be needed to represent the binary
+ */
+ lg2 = ((size+2)*LG2_LOOKUP(base)+1);
+
+ if (lg2 < SMALL_BITS) {
+ /* Take shortcut if we know it will fit in a small.
+ * This improves speed by about 30%.
+ */
+ while (size) {
+ b = *bytes++;
+ size--;
+
+ if (IS_VALID_CHARACTER(b,base))
+ goto bytebuf_to_integer_1_error;
+
+ i = i * base + CHARACTER_FROM_BASE(b);
+
+ }
+
+ if (neg)
+ i = -i;
+ res = make_small(i);
+ goto bytebuf_to_integer_1_done;
+
+ }
+
+ /* Start calculating bignum */
+ m = (lg2 + D_EXP-1)/D_EXP;
+ m = BIG_NEED_SIZE(m);
+
+ hp = HAlloc(BIF_P, m);
+ hp_end = hp + m;
+
+ if ((i = (size % D_BASE_EXP(base))) == 0)
+ i = D_BASE_EXP(base);
+
+ n = size - i;
+ m = 0;
+
+ while (i--) {
+ b = *bytes++;
+
+ if (IS_VALID_CHARACTER(b,base)) {
+ HRelease(BIF_P, hp_end, hp);
+ goto bytebuf_to_integer_1_error;
+ }
+
+ m = base * m + CHARACTER_FROM_BASE(b);
+ }
+
+ res = small_to_big(m, hp);
+
+ while (n) {
+ i = D_BASE_EXP(base);
+ n -= D_BASE_EXP(base);
+ m = 0;
+ while (i--) {
+ b = *bytes++;
+
+ if (IS_VALID_CHARACTER(b,base)) {
+ HRelease(BIF_P, hp_end, hp);
+ goto bytebuf_to_integer_1_error;
+ }
+
+ m = base * m + CHARACTER_FROM_BASE(b);
+ }
+ if (is_small(res)) {
+ res = small_to_big(signed_val(res), hp);
+ }
+ res = big_times_small(res, D_BASE_BASE(base), hp);
+ if (is_small(res)) {
+ res = small_to_big(signed_val(res), hp);
+ }
+ res = big_plus_small(res, m, hp);
+ }
+
+ if (is_big(res)) /* check if small */
+ res = big_plus_small(res, 0, hp); /* includes conversion to small */
+
+ if (neg) {
+ if (is_small(res))
+ res = make_small(-signed_val(res));
+ else {
+ Uint *big = big_val(res); /* point to thing */
+ *big = bignum_header_neg(*big);
+ }
+ }
+
+ if (is_big(res)) {
+ hp += (big_arity(res) + 1);
+ }
+ HRelease(BIF_P, hp_end, hp);
+ goto bytebuf_to_integer_1_done;
+
+bytebuf_to_integer_1_error:
+ return THE_NON_VALUE;
+
+bytebuf_to_integer_1_done:
+ return res;
+
+}
diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h
index 7eb1e5afe2..c74283b9e5 100644
--- a/erts/emulator/beam/big.h
+++ b/erts/emulator/beam/big.h
@@ -117,6 +117,7 @@ typedef Uint dsize_t; /* Vector size type */
int big_decimal_estimate(Wterm);
Eterm erts_big_to_list(Eterm, Eterm**);
char *erts_big_to_string(Wterm x, char *buf, Uint buf_sz);
+Uint erts_big_to_binary_bytes(Eterm x, char *buf, Uint buf_sz);
Eterm small_times(Sint, Sint, Eterm*);
@@ -165,5 +166,7 @@ int term_equals_2pow32(Eterm);
Eterm erts_uint64_to_big(Uint64, Eterm **);
Eterm erts_sint64_to_big(Sint64, Eterm **);
+Eterm erts_chars_to_integer(Process *, char*, Uint, const int);
+
#endif
diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c
index dad13f1067..33abac2f3d 100644
--- a/erts/emulator/beam/binary.c
+++ b/erts/emulator/beam/binary.c
@@ -240,6 +240,98 @@ erts_bin_bytes_to_list(Eterm previous, Eterm* hp, byte* bytes, Uint size, Uint b
return previous;
}
+BIF_RETTYPE binary_to_integer_1(BIF_ALIST_1)
+{
+ byte *temp_alloc = NULL;
+ char *bytes;
+ Uint size;
+ Eterm res;
+
+ if ((bytes = (char*)erts_get_aligned_binary_bytes(BIF_ARG_1, &temp_alloc))
+ == NULL )
+ goto binary_to_integer_1_error;
+
+ size = binary_size(BIF_ARG_1);
+
+ if ((res = erts_chars_to_integer(BIF_P,bytes,size,10)) != THE_NON_VALUE) {
+ erts_free_aligned_binary_bytes(temp_alloc);
+ return res;
+ }
+
+ binary_to_integer_1_error:
+ erts_free_aligned_binary_bytes(temp_alloc);
+ BIF_ERROR(BIF_P, BADARG);
+}
+
+BIF_RETTYPE binary_to_integer_2(BIF_ALIST_2)
+{
+ byte *temp_alloc = NULL;
+ char *bytes;
+ Uint size;
+ int base;
+ Eterm res;
+
+ if (!is_small(BIF_ARG_2))
+ BIF_ERROR(BIF_P, BADARG);
+
+ base = signed_val(BIF_ARG_2);
+
+ if (base < 2 || base > 36)
+ BIF_ERROR(BIF_P, BADARG);
+
+ if ((bytes = (char*)erts_get_aligned_binary_bytes(BIF_ARG_1, &temp_alloc))
+ == NULL )
+ goto binary_to_integer_2_error;
+
+ size = binary_size(BIF_ARG_1);
+
+ if ((res = erts_chars_to_integer(BIF_P,bytes,size,base)) != THE_NON_VALUE) {
+ erts_free_aligned_binary_bytes(temp_alloc);
+ return res;
+ }
+
+ binary_to_integer_2_error:
+
+ erts_free_aligned_binary_bytes(temp_alloc);
+ BIF_ERROR(BIF_P, BADARG);
+
+}
+
+BIF_RETTYPE integer_to_binary_1(BIF_ALIST_1)
+{
+ Uint size;
+ Eterm res;
+
+ if (is_not_integer(BIF_ARG_1)) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
+ if (is_small(BIF_ARG_1)) {
+ char *c;
+ struct Sint_buf ibuf;
+
+ /* Enhancement: If we can calculate the buffer size exactly
+ * we could avoid an unnecessary copy of buffers.
+ * Useful if size determination is faster than a copy.
+ */
+ c = Sint_to_buf(signed_val(BIF_ARG_1), &ibuf);
+ size = sys_strlen(c);
+ res = new_binary(BIF_P, (byte *)c, size);
+ } else {
+ byte* bytes;
+ Uint n = 0;
+
+ /* Here we also have multiple copies of buffers
+ * due to new_binary interface
+ */
+ size = big_decimal_estimate(BIF_ARG_1) - 1; /* remove null */
+ bytes = (byte*) erts_alloc(ERTS_ALC_T_TMP, sizeof(byte)*size);
+ n = erts_big_to_binary_bytes(BIF_ARG_1, (char *)bytes, size);
+ res = new_binary(BIF_P, bytes + size - n, n);
+ erts_free(ERTS_ALC_T_TMP, (void *) bytes);
+ }
+ BIF_RET(res);
+}
BIF_RETTYPE binary_to_list_1(BIF_ALIST_1)
{
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index 59fe7ea418..0781665f05 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -2698,7 +2698,7 @@ BIF_RETTYPE setnode_3(BIF_ALIST_3)
*/
{
ErlDrvSizeT disable = ERL_DRV_BUSY_MSGQ_DISABLED;
- erl_drv_busy_msgq_limits((ErlDrvPort) pp, &disable, NULL);
+ erl_drv_busy_msgq_limits(ERTS_Port2ErlDrvPort(pp), &disable, NULL);
}
pp->dist_entry = dep;
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c
index 187bc2b48b..ac7f420708 100644
--- a/erts/emulator/beam/erl_alloc_util.c
+++ b/erts/emulator/beam/erl_alloc_util.c
@@ -643,9 +643,9 @@ alcu_mseg_realloc(Allctr_t *allctr, void *seg, Uint old_size, Uint *new_size_p)
}
static ERTS_INLINE void
-alcu_mseg_dealloc(Allctr_t *allctr, void *seg, Uint size)
+alcu_mseg_dealloc(Allctr_t *allctr, void *seg, Uint size, Uint flags)
{
- erts_mseg_dealloc_opt(allctr->alloc_no, seg, size, &allctr->mseg_opt);
+ erts_mseg_dealloc_opt(allctr->alloc_no, seg, size, flags, &allctr->mseg_opt);
INC_CC(allctr->calls.mseg_dealloc);
}
@@ -2276,7 +2276,7 @@ resize_carrier(Allctr_t *allctr, Block_t *old_blk, Uint umem_sz, UWord flags)
(void *) BLK2UMEM(old_blk),
MIN(new_blk_sz, old_blk_sz) - ABLK_HDR_SZ);
unlink_carrier(&allctr->sbc_list, old_crr);
- alcu_mseg_dealloc(allctr, old_crr, old_crr_sz);
+ alcu_mseg_dealloc(allctr, old_crr, old_crr_sz, ERTS_MSEG_FLG_NONE);
}
else {
/* Old carrier unchanged; restore stat */
@@ -2352,6 +2352,7 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk)
Carrier_t *crr;
#if HAVE_ERTS_MSEG
Uint is_mseg = 0;
+ Uint mseg_flags = ERTS_MSEG_FLG_NONE;
#endif
if (IS_SBC_BLK(blk)) {
@@ -2398,6 +2399,7 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk)
is_mseg++;
ASSERT(crr_sz % MSEG_UNIT_SZ == 0);
STAT_MSEG_MBC_FREE(allctr, crr_sz);
+ mseg_flags = ERTS_MSEG_FLG_2POW;
}
else
#endif
@@ -2411,7 +2413,7 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk)
#if HAVE_ERTS_MSEG
if (is_mseg) {
- alcu_mseg_dealloc(allctr, crr, crr_sz);
+ alcu_mseg_dealloc(allctr, crr, crr_sz, mseg_flags);
}
else
#endif
diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c
index f2ca193ace..831e29d8a2 100644
--- a/erts/emulator/beam/erl_async.c
+++ b/erts/emulator/beam/erl_async.c
@@ -612,8 +612,8 @@ long driver_async(ErlDrvPort ix, unsigned int* key,
sched_id = 1;
#endif
- prt = erts_drvport2port(ix, NULL);
- if (!prt)
+ prt = erts_drvport2port(ix);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c
index 7cea0bc2eb..1c3e955f47 100644
--- a/erts/emulator/beam/erl_bif_ddll.c
+++ b/erts/emulator/beam/erl_bif_ddll.c
@@ -141,7 +141,7 @@ kill_ports_driver_unloaded(DE_Handle *dh)
state = erts_atomic32_read_nob(&prt->state);
if (!(state & ERTS_PORT_SFLGS_DEAD) && prt->drv_ptr->handle == dh)
- driver_failure_atom((ErlDrvPort) prt, "driver_unloaded");
+ driver_failure_atom(ERTS_Port2ErlDrvPort(prt), "driver_unloaded");
erts_port_release(prt);
}
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index a601e4fb39..8582a8954b 100755
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -69,7 +69,11 @@ static char erts_system_version[] = ("Erlang " ERLANG_OTP_RELEASE
" [no-c-stack-objects]"
#endif
#ifndef OTP_RELEASE
+#ifdef ERLANG_GIT_VERSION
+ " [source-" ERLANG_GIT_VERSION "]"
+#else
" [source]"
+#endif
#endif
#ifdef ARCH_64
#if HALFWORD_HEAP
diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h
index a9a50a10bf..e280563de1 100644
--- a/erts/emulator/beam/erl_driver.h
+++ b/erts/emulator/beam/erl_driver.h
@@ -408,6 +408,11 @@ EXTERN int driver_cancel_timer(ErlDrvPort port);
EXTERN int driver_read_timer(ErlDrvPort port, unsigned long *time_left);
/*
+ * Inform runtime system about lengthy work.
+ */
+EXTERN int erl_drv_consume_timeslice(ErlDrvPort port, int percent);
+
+/*
* Get plain-text error message from within a driver
*/
EXTERN char* erl_errno_id(int error);
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index 223c9c4d7e..ec3e0d54cb 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -981,19 +981,64 @@ erl_start(int argc, char **argv)
break;
case 'f':
if (!strncmp(argv[i],"-fn",3)) {
+ int warning_type = ERL_FILENAME_WARNING_WARNING;
arg = get_arg(argv[i]+3, argv[i+1], &i);
switch (*arg) {
case 'u':
- erts_set_user_requested_filename_encoding(ERL_FILENAME_UTF8);
+ switch (*(argv[i]+4)) {
+ case 'w':
+ case 0:
+ break;
+ case 'i':
+ warning_type = ERL_FILENAME_WARNING_IGNORE;
+ break;
+ case 'e':
+ warning_type = ERL_FILENAME_WARNING_ERROR;
+ break;
+ default:
+ erts_fprintf(stderr, "bad type of warnings for "
+ "wrongly coded filename: %s\n", argv[i]+4);
+ erts_usage();
+ }
+ erts_set_user_requested_filename_encoding
+ (
+ ERL_FILENAME_UTF8,
+ warning_type
+ );
break;
case 'l':
- erts_set_user_requested_filename_encoding(ERL_FILENAME_LATIN1);
+ erts_set_user_requested_filename_encoding
+ (
+ ERL_FILENAME_LATIN1,
+ warning_type
+ );
break;
case 'a':
- erts_set_user_requested_filename_encoding(ERL_FILENAME_UNKNOWN);
+ switch (*(argv[i]+4)) {
+ case 'w':
+ case 0:
+ break;
+ case 'i':
+ warning_type = ERL_FILENAME_WARNING_IGNORE;
+ break;
+ case 'e':
+ warning_type = ERL_FILENAME_WARNING_ERROR;
+ break;
+ default:
+ erts_fprintf(stderr, "bad type of warnings for "
+ "wrongly coded filename: %s\n", argv[i]+4);
+ erts_usage();
+ }
+ erts_set_user_requested_filename_encoding
+ (
+ ERL_FILENAME_UNKNOWN,
+ warning_type
+ );
break;
default:
- erts_fprintf(stderr, "bad filename encoding %s, can be (l,u or a)\n", arg);
+ erts_fprintf(stderr, "bad filename encoding %s, can be "
+ "(l,u or a, optionally followed by w, "
+ "i or e)\n", arg);
erts_usage();
}
break;
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 068f904b76..d4c2b5bdcc 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -1443,6 +1443,19 @@ void* enif_dlsym(void* handle, const char* symbol,
return ret;
}
+int enif_consume_timeslice(ErlNifEnv* env, int percent)
+{
+ Sint reds;
+
+ ASSERT(is_proc_bound(env) && percent >= 1 && percent <= 100);
+ if (percent < 1) percent = 1;
+ else if (percent > 100) percent = 100;
+
+ reds = ((CONTEXT_REDS+99) / 100) * percent;
+ ASSERT(reds > 0 && reds <= CONTEXT_REDS);
+ BUMP_REDS(env->proc, reds);
+ return ERTS_BIF_REDS_LEFT(env->proc) == 0;
+}
/***************************************************************************
** load_nif/2 **
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index 93e56332e1..62aebcab6c 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -32,10 +32,11 @@
** 2.0: R14A
** 2.1: R14B02 "vm_variant"
** 2.2: R14B03 enif_is_exception
-** 2.3: R15 enif_make_reverse_list
+** 2.3: R15 enif_make_reverse_list, enif_is_number
+** 2.4: R16 enif_consume_timeslice
*/
#define ERL_NIF_MAJOR_VERSION 2
-#define ERL_NIF_MINOR_VERSION 3
+#define ERL_NIF_MINOR_VERSION 4
#include <stdlib.h>
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index af27573433..2f841645e1 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -140,6 +140,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_make_reverse_list,(ErlNifEnv*, ERL_NIF_TERM term,
ERL_NIF_API_FUNC_DECL(int,enif_is_number,(ErlNifEnv*, ERL_NIF_TERM term));
ERL_NIF_API_FUNC_DECL(void*,enif_dlopen,(const char* lib, void (*err_handler)(void*,const char*), void* err_arg));
ERL_NIF_API_FUNC_DECL(void*,enif_dlsym,(void* handle, const char* symbol, void (*err_handler)(void*,const char*), void* err_arg));
+ERL_NIF_API_FUNC_DECL(int,enif_consume_timeslice,(ErlNifEnv*, int percent));
/*
** Add new entries here to keep compatibility on Windows!!!
@@ -264,6 +265,7 @@ ERL_NIF_API_FUNC_DECL(void*,enif_dlsym,(void* handle, const char* symbol, void (
# define enif_is_number ERL_NIF_API_FUNC_MACRO(enif_is_number)
# define enif_dlopen ERL_NIF_API_FUNC_MACRO(enif_dlopen)
# define enif_dlsym ERL_NIF_API_FUNC_MACRO(enif_dlsym)
+# define enif_consume_timeslice ERL_NIF_API_FUNC_MACRO(enif_consume_timeslice)
/*
** Add new entries here
diff --git a/erts/emulator/beam/erl_port.h b/erts/emulator/beam/erl_port.h
index 65b4cd0bfe..ac4f7af5a7 100644
--- a/erts/emulator/beam/erl_port.h
+++ b/erts/emulator/beam/erl_port.h
@@ -40,7 +40,29 @@ extern int erts_port_parallelism;
typedef struct erts_driver_t_ erts_driver_t;
-#define ERTS_INVALID_ERL_DRV_PORT ((ErlDrvPort) (SWord) -1)
+/*
+ * It would have been preferred to use NULL as value of
+ * ERTS_INVALID_ERL_DRV_PORT. That would, however, not be
+ * backward compatible. In pre-R16 systems, 0 was a valid
+ * port handle and -1 was used as invalid handle, so we
+ * are stuck with it.
+ */
+#define ERTS_INVALID_ERL_DRV_PORT ((struct _erl_drv_port *) ((SWord) -1))
+#ifdef DEBUG
+/* Make sure we use this api, and do not cast directly */
+#define ERTS_ErlDrvPort2Port(PH) \
+ ((PH) == ERTS_INVALID_ERL_DRV_PORT \
+ ? ERTS_INVALID_ERL_DRV_PORT \
+ : ((Port *) ((PH) - 4711)))
+#define ERTS_Port2ErlDrvPort(PH) \
+ ((PH) == ERTS_INVALID_ERL_DRV_PORT \
+ ? ERTS_INVALID_ERL_DRV_PORT \
+ : ((ErlDrvPort) ((PH) + 4711)))
+#else
+#define ERTS_ErlDrvPort2Port(PH) ((Port *) (PH))
+#define ERTS_Port2ErlDrvPort(PH) ((ErlDrvPort) (PH))
+#endif
+
#define SMALL_IO_QUEUE 5 /* Number of fixed elements */
typedef struct {
@@ -153,6 +175,7 @@ struct _erl_drv_port {
ErlDrvPDL port_data_lock;
ErtsPrtSD *psd; /* Port specific data */
+ int reds; /* Only used while executing driver callbacks */
};
#define ERTS_PORT_GET_CONNECTED(PRT) \
@@ -429,16 +452,16 @@ ERTS_GLB_INLINE void erts_port_release(Port *);
ERTS_GLB_INLINE Port *erts_thr_id2port_sflgs(Eterm id, Uint32 invalid_sflgs);
ERTS_GLB_INLINE void erts_thr_port_release(Port *prt);
#endif
-ERTS_GLB_INLINE Port *erts_thr_drvport2port_raw(ErlDrvPort, int);
-ERTS_GLB_INLINE Port *erts_drvport2port_raw(ErlDrvPort drvport);
-ERTS_GLB_INLINE Port *erts_drvport2port(ErlDrvPort, erts_aint32_t *);
-ERTS_GLB_INLINE Port *erts_drvportid2port(Eterm);
+ERTS_GLB_INLINE Port *erts_thr_drvport2port(ErlDrvPort, int);
+ERTS_GLB_INLINE Port *erts_drvport2port_state(ErlDrvPort, erts_aint32_t *);
ERTS_GLB_INLINE Eterm erts_drvport2id(ErlDrvPort);
ERTS_GLB_INLINE Uint32 erts_portid2status(Eterm);
ERTS_GLB_INLINE int erts_is_port_alive(Eterm);
ERTS_GLB_INLINE int erts_is_valid_tracer_port(Eterm);
ERTS_GLB_INLINE int erts_port_driver_callback_epilogue(Port *, erts_aint32_t *);
+#define erts_drvport2port(Prt) erts_drvport2port_state((Prt), NULL)
+
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
ERTS_GLB_INLINE Port *erts_pix2port(int ix)
@@ -620,90 +643,72 @@ erts_thr_port_release(Port *prt)
#endif
-ERTS_GLB_INLINE Port*
-erts_thr_drvport2port_raw(ErlDrvPort drvport, int lock_pdl)
+ERTS_GLB_INLINE Port *
+erts_thr_drvport2port(ErlDrvPort drvport, int lock_pdl)
{
+ Port *prt = ERTS_ErlDrvPort2Port(drvport);
+ ASSERT(prt != NULL);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
+ return ERTS_INVALID_ERL_DRV_PORT;
+
+ if (lock_pdl && prt->port_data_lock)
+ driver_pdl_lock(prt->port_data_lock);
+
#if ERTS_ENABLE_LOCK_CHECK
- int emu_thread = erts_lc_is_emu_thr();
-#endif
- if (drvport == ERTS_INVALID_ERL_DRV_PORT)
- return NULL;
- else {
- Port *prt = (Port *) drvport;
- if (lock_pdl && prt->port_data_lock)
- driver_pdl_lock(prt->port_data_lock);
-#if ERTS_ENABLE_LOCK_CHECK
- if (!ERTS_IS_CRASH_DUMPING) {
- if (emu_thread) {
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- ERTS_LC_ASSERT(!prt->port_data_lock
- || erts_lc_mtx_is_locked(&prt->port_data_lock->mtx));
- }
- else {
- ERTS_LC_ASSERT(prt->port_data_lock);
- ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&prt->port_data_lock->mtx));
- }
+ if (!ERTS_IS_CRASH_DUMPING) {
+ if (erts_lc_is_emu_thr()) {
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
+ ERTS_LC_ASSERT(!prt->port_data_lock
+ || erts_lc_mtx_is_locked(&prt->port_data_lock->mtx));
+ }
+ else {
+ ERTS_LC_ASSERT(prt->port_data_lock);
+ ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&prt->port_data_lock->mtx));
}
-#endif
- return prt;
}
-}
+#endif
-ERTS_GLB_INLINE Port*
-erts_drvport2port_raw(ErlDrvPort drvport)
-{
- ERTS_LC_ASSERT(erts_lc_is_emu_thr());
- if (drvport == ERTS_INVALID_ERL_DRV_PORT)
- return NULL;
- else {
- Port *prt = (Port *) drvport;
- ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)
- || ERTS_IS_CRASH_DUMPING);
- return prt;
+ if (erts_atomic32_read_nob(&prt->state)
+ & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) {
+ if (lock_pdl && prt->port_data_lock)
+ driver_pdl_unlock(prt->port_data_lock);
+ return ERTS_INVALID_ERL_DRV_PORT;
}
-}
-
-ERTS_GLB_INLINE Port*
-erts_drvport2port(ErlDrvPort drvport, erts_aint32_t *statep)
-{
- Port *prt = erts_drvport2port_raw(drvport);
- erts_aint32_t state;
- if (!prt)
- return NULL;
- state = erts_atomic32_read_nob(&prt->state);
- if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
- return NULL;
- if (statep)
- *statep = state;
return prt;
}
-ERTS_GLB_INLINE Port*
-erts_drvportid2port(Eterm id)
+ERTS_GLB_INLINE Port *
+erts_drvport2port_state(ErlDrvPort drvport, erts_aint32_t *statep)
{
- Port *prt;
+ Port *prt = ERTS_ErlDrvPort2Port(drvport);
erts_aint32_t state;
- if (is_not_internal_port(id))
- return NULL;
- prt = (Port *) erts_ptab_pix2intptr_nob(&erts_port,
- internal_port_index(id));
- if (!prt)
- return NULL;
+ ASSERT(prt);
+ ERTS_LC_ASSERT(erts_lc_is_emu_thr());
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
+ return ERTS_INVALID_ERL_DRV_PORT;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)
|| ERTS_IS_CRASH_DUMPING);
- if (prt->common.id != id)
- return NULL;
+ /*
+ * This state check is only needed since a driver callback
+ * might terminate the port, and then call back into the
+ * emulator. Drivers should preferably have been forbidden
+ * to call into the emulator after terminating the port,
+ * but it has been like this for ages. Perhaps forbid this
+ * in some future major release?
+ */
state = erts_atomic32_read_nob(&prt->state);
if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
- return NULL;
+ return ERTS_INVALID_ERL_DRV_PORT;
+ if (statep)
+ *statep = state;
return prt;
}
ERTS_GLB_INLINE Eterm
erts_drvport2id(ErlDrvPort drvport)
{
- Port *prt = erts_drvport2port_raw(drvport);
- if (!prt)
+ Port *prt = erts_drvport2port(drvport);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return am_undefined;
else
return prt->common.id;
diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c
index dbc4a06c2d..ce045ec94e 100644
--- a/erts/emulator/beam/erl_port_task.c
+++ b/erts/emulator/beam/erl_port_task.c
@@ -685,12 +685,12 @@ enqueue_proc2port_data(Port *pp,
void
erl_drv_busy_msgq_limits(ErlDrvPort dport, ErlDrvSizeT *lowp, ErlDrvSizeT *highp)
{
- Port *pp = erts_drvport2port(dport, NULL);
- ErtsPortTaskBusyPortQ *bpq = pp->sched.taskq.bpq;
+ Port *pp = erts_drvport2port(dport);
+ ErtsPortTaskBusyPortQ *bpq;
int written = 0, resume_procs = 0;
ErlDrvSizeT low, high;
- if (!pp || !bpq) {
+ if (pp == ERTS_INVALID_ERL_DRV_PORT || !(bpq = pp->sched.taskq.bpq)) {
if (lowp)
*lowp = ERL_DRV_BUSY_MSGQ_DISABLED;
if (highp)
@@ -1160,6 +1160,27 @@ select_task_for_exec(Port *pp,
}
/*
+ * Cut time slice
+ */
+
+int
+erl_drv_consume_timeslice(ErlDrvPort dprt, int percent)
+{
+ Port *pp = erts_drvport2port(dprt);
+ if (pp == ERTS_INVALID_ERL_DRV_PORT)
+ return -1;
+ if (percent < 1)
+ percent = 1;
+ else if (100 < percent)
+ percent = 100;
+ pp->reds += percent*((CONTEXT_REDS+99)/100);
+ if (pp->reds < CONTEXT_REDS)
+ return 0;
+ pp->reds = CONTEXT_REDS;
+ return 1;
+}
+
+/*
* Abort a scheduled task.
*/
@@ -1509,7 +1530,6 @@ fail:
void
erts_port_task_free_port(Port *pp)
{
- ErtsProcList *suspended;
erts_aint32_t flags;
ErtsRunQueue *runq;
@@ -1522,19 +1542,16 @@ erts_port_task_free_port(Port *pp)
erts_port_task_sched_lock(&pp->sched);
flags = erts_smp_atomic32_read_bor_relb(&pp->sched.flags,
ERTS_PTS_FLG_EXIT);
- suspended = pp->suspended;
- pp->suspended = NULL;
erts_port_task_sched_unlock(&pp->sched);
erts_atomic32_read_bset_relb(&pp->state,
- (ERTS_PORT_SFLG_CLOSING
+ (ERTS_PORT_SFLG_CONNECTED
+ | ERTS_PORT_SFLG_EXITING
+ | ERTS_PORT_SFLG_CLOSING
| ERTS_PORT_SFLG_FREE),
ERTS_PORT_SFLG_FREE);
erts_smp_runq_unlock(runq);
- if (erts_proclist_fetch(&suspended, NULL))
- erts_resume_processes(suspended);
-
if (!(flags & (ERTS_PTS_FLG_IN_RUNQ|ERTS_PTS_FLG_EXEC)))
begin_port_cleanup(pp, NULL, NULL);
}
@@ -1554,7 +1571,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
int processing_busy_q;
int res = 0;
int vreds = 0;
- int reds = ERTS_PORT_REDS_EXECUTE;
+ int reds = 0;
erts_aint_t io_tasks_executed = 0;
int fpe_was_unmasked;
erts_aint32_t state;
@@ -1599,6 +1616,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
fpe_was_unmasked = erts_block_fpe();
state = erts_atomic32_read_nob(&pp->state);
+ pp->reds = ERTS_PORT_REDS_EXECUTE;
goto begin_handle_tasks;
while (1) {
@@ -1625,14 +1643,14 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
switch (ptp->type) {
case ERTS_PORT_TASK_TIMEOUT:
- reds += ERTS_PORT_REDS_TIMEOUT;
+ reds = ERTS_PORT_REDS_TIMEOUT;
if (!(state & ERTS_PORT_SFLGS_DEAD)) {
DTRACE_DRIVER(driver_timeout, pp);
(*pp->drv_ptr->timeout)((ErlDrvData) pp->drv_data);
}
break;
case ERTS_PORT_TASK_INPUT:
- reds += ERTS_PORT_REDS_INPUT;
+ reds = ERTS_PORT_REDS_INPUT;
ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0);
DTRACE_DRIVER(driver_ready_input, pp);
/* NOTE some windows drivers use ->ready_input for input and output */
@@ -1641,7 +1659,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
io_tasks_executed++;
break;
case ERTS_PORT_TASK_OUTPUT:
- reds += ERTS_PORT_REDS_OUTPUT;
+ reds = ERTS_PORT_REDS_OUTPUT;
ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0);
DTRACE_DRIVER(driver_ready_output, pp);
(*pp->drv_ptr->ready_output)((ErlDrvData) pp->drv_data,
@@ -1649,7 +1667,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
io_tasks_executed++;
break;
case ERTS_PORT_TASK_EVENT:
- reds += ERTS_PORT_REDS_EVENT;
+ reds = ERTS_PORT_REDS_EVENT;
ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0);
DTRACE_DRIVER(driver_event, pp);
(*pp->drv_ptr->event)((ErlDrvData) pp->drv_data,
@@ -1661,22 +1679,22 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
ErtsProc2PortSigData *sigdp = &ptp->u.alive.td.psig.data;
ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0);
if (!pp->sched.taskq.bpq)
- reds += ptp->u.alive.td.psig.callback(pp,
- state,
- ERTS_PROC2PORT_SIG_EXEC,
- sigdp);
+ reds = ptp->u.alive.td.psig.callback(pp,
+ state,
+ ERTS_PROC2PORT_SIG_EXEC,
+ sigdp);
else {
ErlDrvSizeT size = erts_proc2port_sig_command_data_size(sigdp);
- reds += ptp->u.alive.td.psig.callback(pp,
- state,
- ERTS_PROC2PORT_SIG_EXEC,
- sigdp);
+ reds = ptp->u.alive.td.psig.callback(pp,
+ state,
+ ERTS_PROC2PORT_SIG_EXEC,
+ sigdp);
dequeued_proc2port_data(pp, size);
}
break;
}
case ERTS_PORT_TASK_DIST_CMD:
- reds += erts_dist_command(pp, CONTEXT_REDS-reds);
+ reds = erts_dist_command(pp, CONTEXT_REDS - pp->reds);
break;
default:
erl_exit(ERTS_ABORT_EXIT,
@@ -1701,7 +1719,10 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
vreds += ERTS_PORT_CALLBACK_VREDS;
reds += ERTS_PORT_CALLBACK_VREDS;
- if (reds >= CONTEXT_REDS)
+ pp->reds += reds;
+ reds = 0;
+
+ if (pp->reds >= CONTEXT_REDS)
break;
}
@@ -1725,6 +1746,8 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
active = finalize_exec(pp, &execq, processing_busy_q);
+ reds = pp->reds - vreds;
+
erts_port_release(pp);
*curr_port_pp = NULL;
@@ -1770,7 +1793,6 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
res = (erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks)
!= (erts_aint_t) 0);
- reds -= vreds;
runq->scheduler->reductions += reds;
ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq));
@@ -1793,10 +1815,11 @@ begin_port_cleanup(Port *pp, ErtsPortTask **execqp, int *processing_busy_q_p)
int i, max;
ErtsPortTaskBusyCallerTable *tabp;
ErtsPortTask *qs[3];
+ ErtsPortTaskHandleList *free_nshp = NULL;
+ ErtsProcList *plp;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
-
/*
* Abort remaining tasks...
*
@@ -1935,7 +1958,42 @@ begin_port_cleanup(Port *pp, ErtsPortTask **execqp, int *processing_busy_q_p)
erts_smp_atomic32_read_band_nob(&pp->sched.flags,
~(ERTS_PTS_FLG_HAVE_BUSY_TASKS
- |ERTS_PTS_FLG_HAVE_TASKS));
+ |ERTS_PTS_FLG_HAVE_TASKS
+ |ERTS_PTS_FLGS_BUSY));
+
+ erts_port_task_sched_lock(&pp->sched);
+
+ /* Cleanup nosuspend handles... */
+ free_nshp = (pp->sched.taskq.local.busy.nosuspend
+ ? get_free_nosuspend_handles(pp)
+ : NULL);
+ ASSERT(!pp->sched.taskq.local.busy.nosuspend);
+
+ /* Make sure not to leave any processes suspended on the port... */
+ plp = pp->suspended;
+ pp->suspended = NULL;
+
+ erts_port_task_sched_unlock(&pp->sched);
+
+ if (free_nshp)
+ free_nosuspend_handles(free_nshp);
+
+ if (erts_proclist_fetch(&plp, NULL)) {
+#ifdef USE_VM_PROBES
+ if (DTRACE_ENABLED(process_port_unblocked)) {
+ DTRACE_CHARBUF(port_str, 16);
+ DTRACE_CHARBUF(pid_str, 16);
+ ErtsProcList* plp2 = plp;
+
+ erts_snprintf(port_str, sizeof(port_str), "%T", pp->common.id);
+ while (plp2 != NULL) {
+ erts_snprintf(pid_str, sizeof(pid_str), "%T", plp2->pid);
+ DTRACE2(process_port_unblocked, pid_str, port_str);
+ }
+ }
+#endif
+ erts_resume_processes(plp);
+ }
/*
* Schedule cleanup of port structure...
diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c
index 99108af937..80982f3760 100644
--- a/erts/emulator/beam/erl_unicode.c
+++ b/erts/emulator/beam/erl_unicode.c
@@ -2573,8 +2573,20 @@ BIF_RETTYPE prim_file_internal_native2name_1(BIF_ALIST_1)
case ERL_FILENAME_UTF8:
bytes = erts_get_aligned_binary_bytes(BIF_ARG_1, &temp_alloc);
if (erts_analyze_utf8(bytes,size,&err_pos,&num_chars,NULL) != ERTS_UTF8_OK) {
+ Eterm *hp = HAlloc(BIF_P,3);
+ Eterm warn_type = NIL;
erts_free_aligned_binary_bytes(temp_alloc);
- goto noconvert;
+ switch (erts_get_filename_warning_type()) {
+ case ERL_FILENAME_WARNING_IGNORE:
+ warn_type = am_ignore;
+ break;
+ case ERL_FILENAME_WARNING_ERROR:
+ warn_type = am_error;
+ break;
+ default:
+ warn_type = am_warning;
+ }
+ BIF_RET(TUPLE2(hp,am_error,warn_type));
}
num_built = 0;
num_eaten = 0;
@@ -2607,9 +2619,8 @@ BIF_RETTYPE prim_file_internal_native2name_1(BIF_ALIST_1)
erts_free_aligned_binary_bytes(temp_alloc);
BIF_RET(ret);
default:
- goto noconvert;
+ break;
}
- noconvert:
BIF_RET(BIF_ARG_1);
}
@@ -2646,6 +2657,52 @@ BIF_RETTYPE prim_file_internal_normalize_utf8_1(BIF_ALIST_1)
BIF_RET(ret);
}
+BIF_RETTYPE prim_file_is_translatable_1(BIF_ALIST_1)
+{
+ ERTS_DECLARE_DUMMY(Eterm real_bin);
+ ERTS_DECLARE_DUMMY(Uint offset);
+ Uint size;
+ Uint num_chars;
+ Uint bitsize;
+ ERTS_DECLARE_DUMMY(Uint bitoffs);
+ byte *temp_alloc = NULL;
+ byte *bytes;
+ byte *err_pos;
+ int status;
+
+ if (is_not_binary(BIF_ARG_1)) {
+ BIF_ERROR(BIF_P,BADARG);
+ }
+ size = binary_size(BIF_ARG_1);
+ ERTS_GET_REAL_BIN(BIF_ARG_1, real_bin, offset, bitoffs, bitsize);
+ if (bitsize != 0) {
+ BIF_ERROR(BIF_P,BADARG);
+ }
+ if (size == 0) {
+ BIF_RET(am_true);
+ }
+
+ /*
+ * If the encoding is latin1, the pathname is always translatable.
+ */
+ switch (erts_get_native_filename_encoding()) {
+ case ERL_FILENAME_LATIN1:
+ BIF_RET(am_true);
+ case ERL_FILENAME_WIN_WCHAR:
+ if (erts_get_user_requested_filename_encoding() == ERL_FILENAME_LATIN1) {
+ BIF_RET(am_true);
+ }
+ }
+
+ /*
+ * Check whether the binary contains legal UTF-8 sequences.
+ */
+ bytes = erts_get_aligned_binary_bytes(BIF_ARG_1, &temp_alloc);
+ status = erts_analyze_utf8(bytes, size, &err_pos, &num_chars, NULL);
+ erts_free_aligned_binary_bytes(temp_alloc);
+ BIF_RET(status == ERTS_UTF8_OK ? am_true : am_false);
+}
+
BIF_RETTYPE file_native_name_encoding_0(BIF_ALIST_0)
{
switch (erts_get_native_filename_encoding()) {
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 3ea4b24848..b73c883658 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -82,11 +82,11 @@ static void pdl_init(void);
#ifdef ERTS_SMP
static void driver_monitor_lock_pdl(Port *p);
static void driver_monitor_unlock_pdl(Port *p);
-#define DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(Port) erts_thr_drvport2port_raw((Port), 1)
+#define DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(Port) erts_thr_drvport2port((Port), 1)
#define DRV_MONITOR_LOCK_PDL(Port) driver_monitor_lock_pdl(Port)
#define DRV_MONITOR_UNLOCK_PDL(Port) driver_monitor_unlock_pdl(Port)
#else
-#define DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(Port) erts_thr_drvport2port_raw((Port), 0)
+#define DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(Port) erts_thr_drvport2port((Port), 0)
#define DRV_MONITOR_LOCK_PDL(Port) /* nothing */
#define DRV_MONITOR_UNLOCK_PDL(Port) /* nothing */
#endif
@@ -97,12 +97,10 @@ static void driver_monitor_unlock_pdl(Port *p);
static ERTS_INLINE ErlIOQueue*
drvport2ioq(ErlDrvPort drvport)
{
- Port *prt = erts_thr_drvport2port_raw(drvport, 0);
- erts_aint32_t state = erts_atomic32_read_nob(&prt->state);
- if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
+ Port *prt = erts_thr_drvport2port(drvport, 0);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return NULL;
- else
- return &prt->ioq;
+ return &prt->ioq;
}
static ERTS_INLINE int
@@ -178,6 +176,22 @@ typedef struct line_buf_context {
\
dtrace_proc_str((PID), process_str); \
dtrace_port_str((PORT), port_str);
+
+void
+dtrace_drvport_str(ErlDrvPort drvport, char *port_buf)
+{
+ Port *port = erts_drvport2port(drvport);
+
+ if (port != ERTS_INVALID_ERL_DRV_PORT)
+ erts_snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>",
+ port_channel_no(port->common.id),
+ port_number(port->common.id));
+ else
+ erts_snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<INVALID>",
+ port_channel_no(port->common.id),
+ port_number(port->common.id));
+}
+
#endif
static ERTS_INLINE void
@@ -683,7 +697,7 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */
}
#endif
fpe_was_unmasked = erts_block_fpe();
- drv_data = (*driver->start)((ErlDrvPort) port, name, opts);
+ drv_data = (*driver->start)(ERTS_Port2ErlDrvPort(port), name, opts);
if (((SWord) drv_data) == -1)
error_type = -1;
else if (((SWord) drv_data) == -2) {
@@ -777,8 +791,8 @@ driver_create_port(ErlDrvPort creator_port_ix, /* Creating port */
if (!erts_get_scheduler_id())
return ERTS_INVALID_ERL_DRV_PORT;
- creator_port = erts_drvport2port(creator_port_ix, NULL);
- if (!creator_port)
+ creator_port = erts_drvport2port(creator_port_ix);
+ if (creator_port == ERTS_INVALID_ERL_DRV_PORT)
return ERTS_INVALID_ERL_DRV_PORT;
rp = erts_proc_lookup(pid);
@@ -849,7 +863,7 @@ driver_create_port(ErlDrvPort creator_port_ix, /* Creating port */
port->drv_data = (UWord) drv_data;
- return (ErlDrvPort) port;
+ return ERTS_Port2ErlDrvPort(port);
}
#ifdef ERTS_SMP
@@ -1185,6 +1199,7 @@ typedef struct {
int async; /* Asynchronous operation */
int pre_chk_sched_flags; /* Check sched flags before lock? */
int fpe_was_unmasked;
+ int reds_left_in;
} ErtsTryImmDrvCallState;
#define ERTS_INIT_TRY_IMM_DRV_CALL_STATE(C_P, PRT, SFLGS, PTS_FLGS, A, PRT_OP) \
@@ -1199,6 +1214,7 @@ static ERTS_INLINE ErtsTryImmDrvCallResult
try_imm_drv_call(ErtsTryImmDrvCallState *sp)
{
ErtsTryImmDrvCallResult res;
+ int reds_left_in;
erts_aint32_t invalid_state, invalid_sched_flags;
Port *prt = sp->port;
Process *c_p = sp->c_p;
@@ -1232,16 +1248,24 @@ try_imm_drv_call(ErtsTryImmDrvCallState *sp)
goto locked_fail;
}
- if (c_p) {
+
+ if (!c_p)
+ reds_left_in = CONTEXT_REDS/10;
+ else {
if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS))
trace_virtual_sched(c_p, am_out);
if (erts_system_profile_flags.runnable_procs
&& erts_system_profile_flags.exclusive)
profile_runnable_proc(c_p, am_inactive);
+ reds_left_in = ERTS_BIF_REDS_LEFT(c_p);
erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN);
}
+ ASSERT(0 <= reds_left_in && reds_left_in <= CONTEXT_REDS);
+ sp->reds_left_in = reds_left_in;
+ prt->reds = CONTEXT_REDS - reds_left_in;
+
ERTS_SMP_CHK_NO_PROC_LOCKS;
if (IS_TRACED_FL(prt, F_TRACE_SCHED_PORTS))
@@ -1262,10 +1286,12 @@ locked_fail:
static ERTS_INLINE void
finalize_imm_drv_call(ErtsTryImmDrvCallState *sp)
{
+ int reds;
Port *prt = sp->port;
Process *c_p = sp->c_p;
- erts_port_driver_callback_epilogue(prt, NULL);
+ reds = prt->reds;
+ reds += erts_port_driver_callback_epilogue(prt, NULL);
erts_unblock_fpe(sp->fpe_was_unmasked);
@@ -1280,6 +1306,12 @@ finalize_imm_drv_call(ErtsTryImmDrvCallState *sp)
if (c_p) {
erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
+ if (reds != (CONTEXT_REDS - sp->reds_left_in)) {
+ int bump_reds = reds - (CONTEXT_REDS - sp->reds_left_in);
+ ASSERT(bump_reds > 0);
+ BUMP_REDS(c_p, bump_reds);
+ }
+
if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS))
trace_virtual_sched(c_p, am_in);
if (erts_system_profile_flags.runnable_procs
@@ -3470,7 +3502,7 @@ erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed)
{
ErtsLink *lnk;
Eterm rreason;
- erts_aint32_t state;
+ erts_aint32_t state, set_state_flags;
ERTS_SMP_CHK_NO_PROC_LOCKS;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p));
@@ -3499,9 +3531,12 @@ erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed)
if (reason == am_normal && from != ERTS_PORT_GET_CONNECTED(p) && from != p->common.id)
return 0;
+ set_state_flags = ERTS_PORT_SFLG_EXITING;
if (send_closed)
- erts_atomic32_read_bor_relb(&p->state,
- ERTS_PORT_SFLG_SEND_CLOSED);
+ set_state_flags |= ERTS_PORT_SFLG_SEND_CLOSED;
+
+ state = erts_atomic32_read_bor_mb(&p->state, set_state_flags);
+ state |= set_state_flags;
if (IS_TRACED_FL(p, F_TRACE_PORTS)) {
trace_port(p, am_closed, reason);
@@ -3509,17 +3544,11 @@ erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed)
erts_trace_check_exiting(p->common.id);
- /*
- * Setting the port to not busy here, frees the list of pending
- * processes and makes them runnable.
- */
- set_busy_port((ErlDrvPort) p, 0);
+ set_busy_port(ERTS_Port2ErlDrvPort(p), 0);
if (p->common.u.alive.reg != NULL)
(void) erts_unregister_name(NULL, 0, p, p->common.u.alive.reg->name);
- state = erts_atomic32_read_bor_relb(&p->state, ERTS_PORT_SFLG_EXITING);
-
{
SweepContext sc = {p->common.id, rreason};
lnk = ERTS_P_LINKS(p);
@@ -4759,8 +4788,8 @@ set_busy_port(ErlDrvPort dprt, int on)
ERTS_SMP_CHK_NO_PROC_LOCKS;
- prt = erts_drvport2port_raw(dprt);
- if (!prt)
+ prt = erts_drvport2port(dprt);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return;
if (on) {
@@ -4859,8 +4888,8 @@ erts_port_resume_procs(Port *prt)
void set_port_control_flags(ErlDrvPort port_num, int flags)
{
- Port *prt = erts_drvport2port_raw(port_num);
- if (prt)
+ Port *prt = erts_drvport2port(port_num);
+ if (prt != ERTS_INVALID_ERL_DRV_PORT)
prt->control_flags = flags;
}
@@ -4870,8 +4899,8 @@ int get_port_flags(ErlDrvPort ix)
Port *prt;
erts_aint32_t state;
- prt = erts_drvport2port(ix, &state);
- if (!prt)
+ prt = erts_drvport2port_state(ix, &state);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return 0;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
@@ -4960,7 +4989,7 @@ erts_stale_drv_select(Eterm port,
int deselect)
{
char *type;
- ErlDrvPort drv_port = (ErlDrvPort) erts_port_lookup_raw(port);
+ ErlDrvPort drv_port = ERTS_Port2ErlDrvPort(erts_port_lookup_raw(port));
ErtsPortNames *pnp = erts_get_port_names(port);
erts_dsprintf_buf_t *dsbufp;
@@ -5082,7 +5111,6 @@ ErlDrvTermData driver_mk_term_nil(void)
void driver_report_exit(ErlDrvPort ix, int status)
{
- Port* prt = erts_drvport2port(ix, NULL);
Eterm* hp;
Eterm tuple;
Process *rp;
@@ -5091,6 +5119,10 @@ void driver_report_exit(ErlDrvPort ix, int status)
ErlOffHeap *ohp;
ErtsProcLocks rp_locks = 0;
int scheduler = erts_get_scheduler_id() != 0;
+ Port* prt = erts_drvport2port(ix);
+
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
+ return;
ERTS_SMP_CHK_NO_PROC_LOCKS;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
@@ -5687,8 +5719,18 @@ deliver_term_check_port(ErlDrvTermData port_id, Eterm *connected_p)
#ifdef ERTS_SMP
ErtsThrPrgrDelayHandle dhndl = erts_thr_progress_unmanaged_delay();
#endif
+ erts_aint32_t state;
Port *prt = erts_port_lookup_raw((Eterm) port_id);
- erts_aint32_t state = erts_atomic32_read_nob(&prt->state);
+ if (!prt)
+ return -1;
+ state = erts_atomic32_read_nob(&prt->state);
+ if (state & (ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP
+ | ERTS_PORT_SFLG_CLOSING)) {
+ if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
+ return -1;
+ else
+ return 0;
+ }
if (connected_p) {
#ifdef ERTS_SMP
if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED)
@@ -5705,9 +5747,7 @@ deliver_term_check_port(ErlDrvTermData port_id, Eterm *connected_p)
ERTS_SMP_LC_ASSERT(dhndl == ERTS_THR_PRGR_DHANDLE_MANAGED
? erts_lc_is_port_locked(prt)
: !erts_lc_is_port_locked(prt));
- return ((state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
- ? -1
- : ((state & ERTS_PORT_SFLG_CLOSING) ? 0 : 1));
+ return 1;
}
int erl_drv_output_term(ErlDrvTermData port_id, ErlDrvTermData* data, int len)
@@ -5733,14 +5773,12 @@ driver_output_term(ErlDrvPort drvport, ErlDrvTermData* data, int len)
ERTS_SMP_CHK_NO_PROC_LOCKS;
/* NOTE! It *not* safe to access 'drvport' from unmanaged threads. */
- prt = erts_drvport2port(drvport, &state);
- if (!prt)
+ prt = erts_drvport2port_state(drvport, &state);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1; /* invalid (dead) */
ERTS_SMP_CHK_NO_PROC_LOCKS;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
- return -1;
- else if (state & ERTS_PORT_SFLG_CLOSING)
+ if (state & ERTS_PORT_SFLG_CLOSING)
return 0;
return driver_deliver_term(ERTS_PORT_GET_CONNECTED(prt), data, len);
@@ -5780,13 +5818,11 @@ driver_send_term(ErlDrvPort drvport,
#endif
{
erts_aint32_t state;
- Port* prt = erts_drvport2port(drvport, &state);
- if (!prt)
+ Port* prt = erts_drvport2port_state(drvport, &state);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1; /* invalid (dead) */
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
- if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP)
- return -1;
- else if (state & ERTS_PORT_SFLG_CLOSING)
+ if (state & ERTS_PORT_SFLG_CLOSING)
return 0;
}
return driver_deliver_term(to, data, len);
@@ -5802,11 +5838,11 @@ int driver_output_binary(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
ErlDrvBinary* bin, ErlDrvSizeT offs, ErlDrvSizeT len)
{
erts_aint32_t state;
- Port* prt = erts_drvport2port(ix, &state);
+ Port* prt = erts_drvport2port_state(ix, &state);
ERTS_SMP_CHK_NO_PROC_LOCKS;
- if (prt == NULL)
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
if (state & ERTS_PORT_SFLG_CLOSING)
@@ -5837,15 +5873,14 @@ int driver_output2(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
char* buf, ErlDrvSizeT len)
{
erts_aint32_t state;
- Port* prt = erts_drvport2port(ix, &state);
+ Port* prt = erts_drvport2port_state(ix, &state);
ERTS_SMP_CHK_NO_PROC_LOCKS;
- if (prt == NULL)
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
-
if (state & ERTS_PORT_SFLG_CLOSING)
return 0;
@@ -5902,8 +5937,8 @@ int driver_outputv(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
if (hlen < 0)
hlen = 0;
- prt = erts_drvport2port(ix, &state);
- if (prt == NULL)
+ prt = erts_drvport2port_state(ix, &state);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
@@ -6179,8 +6214,8 @@ ErlDrvPDL
driver_pdl_create(ErlDrvPort dp)
{
ErlDrvPDL pdl;
- Port *pp = erts_drvport2port(dp, NULL);
- if (!pp || pp->port_data_lock)
+ Port *pp = erts_drvport2port(dp);
+ if (pp == ERTS_INVALID_ERL_DRV_PORT || pp->port_data_lock)
return NULL;
pdl = erts_alloc(ERTS_ALC_T_PORT_DATA_LOCK,
sizeof(struct erl_drv_port_data_lock));
@@ -6638,11 +6673,11 @@ drv_cancel_timer(Port *prt)
int driver_set_timer(ErlDrvPort ix, unsigned long t)
{
- Port* prt = erts_drvport2port(ix, NULL);
+ Port* prt = erts_drvport2port(ix);
ERTS_SMP_CHK_NO_PROC_LOCKS;
- if (prt == NULL)
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
if (prt->drv_ptr->timeout == NULL)
@@ -6665,8 +6700,8 @@ int driver_set_timer(ErlDrvPort ix, unsigned long t)
int driver_cancel_timer(ErlDrvPort ix)
{
- Port* prt = erts_drvport2port(ix, NULL);
- if (prt == NULL)
+ Port* prt = erts_drvport2port(ix);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
drv_cancel_timer(prt);
@@ -6677,11 +6712,11 @@ int driver_cancel_timer(ErlDrvPort ix)
int
driver_read_timer(ErlDrvPort ix, unsigned long* t)
{
- Port* prt = erts_drvport2port(ix, NULL);
+ Port* prt = erts_drvport2port(ix);
ERTS_SMP_CHK_NO_PROC_LOCKS;
- if (prt == NULL)
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
#ifdef ERTS_SMP
@@ -6757,19 +6792,13 @@ int driver_monitor_process(ErlDrvPort drvport,
{
Port *prt;
int ret;
- erts_aint32_t state;
#if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK))
ErtsSchedulerData *sched = erts_get_scheduler_data();
#endif
prt = DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(drvport);
-
- state = erts_atomic32_read_nob(&prt->state);
-
- if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) {
- DRV_MONITOR_UNLOCK_PDL(prt);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
- }
/* 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) */
@@ -6836,19 +6865,13 @@ int driver_demonitor_process(ErlDrvPort drvport,
{
Port *prt;
int ret;
- erts_aint32_t state;
#if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK))
ErtsSchedulerData *sched = erts_get_scheduler_data();
#endif
prt = DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(drvport);
-
- state = erts_atomic32_read_nob(&prt->state);
-
- if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) {
- DRV_MONITOR_UNLOCK_PDL(prt);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
- }
/* Now we should have either the port lock (if we have a scheduler) or the port data lock
(if we're a driver thread) */
@@ -6897,18 +6920,13 @@ ErlDrvTermData driver_get_monitored_process(ErlDrvPort drvport,
{
Port *prt;
ErlDrvTermData ret;
- erts_aint32_t state;
#if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK))
ErtsSchedulerData *sched = erts_get_scheduler_data();
#endif
prt = DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(drvport);
-
- state = erts_atomic32_read_nob(&prt->state);
- if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) {
- DRV_MONITOR_UNLOCK_PDL(prt);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return driver_term_nil;
- }
/* Now we should have either the port lock (if we have a scheduler) or the port data lock
(if we're a driver thread) */
@@ -6981,11 +6999,11 @@ static int
driver_failure_term(ErlDrvPort ix, Eterm term, int eof)
{
erts_aint32_t state;
- Port* prt = erts_drvport2port(ix, &state);
+ Port* prt = erts_drvport2port_state(ix, &state);
ERTS_SMP_CHK_NO_PROC_LOCKS;
- if (prt == NULL)
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
if (eof)
@@ -7014,14 +7032,14 @@ driver_failure_term(ErlDrvPort ix, Eterm term, int eof)
*/
int driver_exit(ErlDrvPort ix, int err)
{
- Port* prt = erts_drvport2port(ix, NULL);
+ Port* prt = erts_drvport2port(ix);
Process* rp;
ErtsLink *lnk, *rlnk = NULL;
Eterm connected;
ERTS_SMP_CHK_NO_PROC_LOCKS;
- if (prt == NULL)
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
connected = ERTS_PORT_GET_CONNECTED(prt);
@@ -7095,16 +7113,18 @@ ErlDrvTermData driver_mk_atom(char* string)
ErlDrvTermData driver_mk_port(ErlDrvPort ix)
{
- Port* prt = erts_drvport2port(ix, NULL);
+ Port* prt = erts_drvport2port(ix);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
+ return (ErlDrvTermData) NIL;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
return (ErlDrvTermData) prt->common.id;
}
ErlDrvTermData driver_connected(ErlDrvPort ix)
{
- Port* prt = erts_drvport2port(ix, NULL);
+ Port* prt = erts_drvport2port(ix);
ERTS_SMP_CHK_NO_PROC_LOCKS;
- if (prt == NULL)
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return NIL;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
return ERTS_PORT_GET_CONNECTED(prt);
@@ -7112,9 +7132,9 @@ ErlDrvTermData driver_connected(ErlDrvPort ix)
ErlDrvTermData driver_caller(ErlDrvPort ix)
{
- Port* prt = erts_drvport2port(ix, NULL);
+ Port* prt = erts_drvport2port(ix);
ERTS_SMP_CHK_NO_PROC_LOCKS;
- if (prt == NULL)
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return NIL;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
return prt->caller;
@@ -7122,17 +7142,15 @@ ErlDrvTermData driver_caller(ErlDrvPort ix)
int driver_lock_driver(ErlDrvPort ix)
{
- Port* prt = erts_drvport2port(ix, NULL);
+ Port* prt = erts_drvport2port(ix);
DE_Handle* dh;
ERTS_SMP_CHK_NO_PROC_LOCKS;
- erts_smp_rwmtx_rwlock(&erts_driver_list_lock);
-
- if (prt == NULL) {
- erts_smp_rwmtx_rwunlock(&erts_driver_list_lock);
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
- }
+
+ erts_smp_rwmtx_rwlock(&erts_driver_list_lock);
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
if ((dh = (DE_Handle*)prt->drv_ptr->handle ) == NULL) {
@@ -7327,7 +7345,7 @@ no_event_callback(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_
{
Port *prt = get_current_port();
report_missing_drv_callback(prt, "Event", "event()");
- driver_event((ErlDrvPort) prt, event, NULL);
+ driver_event(ERTS_Port2ErlDrvPort(prt), event, NULL);
}
static void
@@ -7335,7 +7353,7 @@ no_ready_input_callback(ErlDrvData drv_data, ErlDrvEvent event)
{
Port *prt = get_current_port();
report_missing_drv_callback(prt, "Input", "ready_input()");
- driver_select((ErlDrvPort) prt, event,
+ driver_select(ERTS_Port2ErlDrvPort(prt), event,
(ERL_DRV_READ | ERL_DRV_USE_NO_CALLBACK), 0);
}
@@ -7344,7 +7362,7 @@ no_ready_output_callback(ErlDrvData drv_data, ErlDrvEvent event)
{
Port *prt = get_current_port();
report_missing_drv_callback(prt, "Output", "ready_output()");
- driver_select((ErlDrvPort) prt, event,
+ driver_select(ERTS_Port2ErlDrvPort(prt), event,
(ERL_DRV_WRITE | ERL_DRV_USE_NO_CALLBACK), 0);
}
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index 6764e88c81..8a79b4910e 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -1021,7 +1021,7 @@ 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=s Dst=d => gen_element(Jump, S1, S2, Dst)
+bif2 Jump=j u$bif:erlang:element/2 S1=s S2=rxy 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
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index 249a9c05c2..9416a91480 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -1029,10 +1029,22 @@ char* win32_errorstr(int);
#define ERL_FILENAME_UTF8_MAC (3)
#define ERL_FILENAME_WIN_WCHAR (4)
+/************************************************************************
+ * If a filename in for example list_dir is not in the right encoding, it
+ * will be skipped in the resulting list, but depending on a startup setting
+ * we will inform the user in different ways. These macros define the
+ * different reactions to wrongly coded filenames. In the error case an
+ * exception will be thrown by prim_file.
+ ************************************************************************/
+#define ERL_FILENAME_WARNING_WARNING (0)
+#define ERL_FILENAME_WARNING_IGNORE (1)
+#define ERL_FILENAME_WARNING_ERROR (2)
+
int erts_get_native_filename_encoding(void);
/* The set function is only to be used by erl_init! */
-void erts_set_user_requested_filename_encoding(int encoding);
+void erts_set_user_requested_filename_encoding(int encoding, int warning);
int erts_get_user_requested_filename_encoding(void);
+int erts_get_filename_warning_type(void);
void erts_init_sys_common_misc(void);
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index fda6cf2e53..22328fcd11 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -1160,7 +1160,14 @@ static void invoke_read_line(void *data)
/* Need more place */
ErlDrvSizeT need = (d->c.read_line.read_size >= DEFAULT_LINEBUF_SIZE) ?
d->c.read_line.read_size + DEFAULT_LINEBUF_SIZE : DEFAULT_LINEBUF_SIZE;
- ErlDrvBinary *newbin = driver_alloc_binary(need);
+ ErlDrvBinary *newbin;
+#if !ALWAYS_READ_LINE_AHEAD
+ /* Use read_ahead size if need does not exceed it */
+ if (need < (d->c.read_line.binp)->orig_size &&
+ d->c.read_line.read_ahead)
+ need = (d->c.read_line.binp)->orig_size;
+#endif
+ newbin = driver_alloc_binary(need);
if (newbin == NULL) {
d->result_ok = 0;
d->errInfo.posix_errno = ENOMEM;
@@ -2263,6 +2270,8 @@ file_stop(ErlDrvData e)
desc->fd = FILE_FD_INVALID;
desc->flags = 0;
cq_execute(desc);
+ } else {
+ EF_FREE(desc);
}
} else {
if (desc->fd != FILE_FD_INVALID) {
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index 474408ae7c..c16831a07d 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -481,6 +481,7 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix,
int on)
{
void (*stop_select_fn)(ErlDrvEvent, void*) = NULL;
+ Port *prt = erts_drvport2port(ix);
Eterm id = erts_drvport2id(ix);
ErtsSysFdType fd = (ErtsSysFdType) e;
ErtsPollEvents ctl_events = (ErtsPollEvents) 0;
@@ -491,9 +492,11 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix,
#ifdef USE_VM_PROBES
DTRACE_CHARBUF(name, 64);
#endif
-
- ERTS_SMP_LC_ASSERT(erts_drvport2port(ix, NULL)
- && erts_lc_is_port_locked(erts_drvport2port(ix, NULL)));
+
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
+ return -1;
+
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
#ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS
if ((unsigned)fd >= (unsigned)erts_smp_atomic_read_nob(&drv_ev_state_len)) {
@@ -519,9 +522,9 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix,
if (!on && (mode&ERL_DRV_USE_NO_CALLBACK) == ERL_DRV_USE) {
if (IS_FD_UNKNOWN(state)) {
/* fast track to stop_select callback */
- stop_select_fn = erts_drvport2port(ix, NULL)->drv_ptr->stop_select;
+ stop_select_fn = prt->drv_ptr->stop_select;
#ifdef USE_VM_PROBES
- strncpy(name, erts_drvport2port(ix, NULL)->drv_ptr->name, sizeof(name)-1);
+ strncpy(name, prt->drv_ptr->name, sizeof(name)-1);
name[sizeof(name)-1] = '\0';
#endif
ret = 0;
@@ -654,14 +657,14 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix,
}
}
if ((mode & ERL_DRV_USE_NO_CALLBACK) == ERL_DRV_USE) {
- erts_driver_t* drv_ptr = erts_drvport2port(ix, NULL)->drv_ptr;
+ erts_driver_t* drv_ptr = prt->drv_ptr;
ASSERT(new_events==0);
if (state->remove_cnt == 0 || !wake_poller) {
/* Safe to close fd now as it is not in pollset
or there was no need to eject fd (kernel poll) */
stop_select_fn = drv_ptr->stop_select;
#ifdef USE_VM_PROBES
- strncpy(name, erts_drvport2port(ix, NULL)->drv_ptr->name, sizeof(name)-1);
+ strncpy(name, prt->drv_ptr->name, sizeof(name)-1);
name[sizeof(name)-1] = '\0';
#endif
}
@@ -712,9 +715,12 @@ ERTS_CIO_EXPORT(driver_event)(ErlDrvPort ix,
ErtsDrvEventState *state;
int do_wake = 0;
int ret;
+ Port *prt = erts_drvport2port(ix);
+
+ if (prt == ERTS_INVALID_ERL_DRV_PORT)
+ return -1;
- ERTS_SMP_LC_ASSERT(erts_drvport2port(ix, NULL)
- && erts_lc_is_port_locked(erts_drvport2port(ix, NULL)));
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
#ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS
if ((unsigned)fd >= (unsigned)erts_smp_atomic_read_nob(&drv_ev_state_len)) {
@@ -949,7 +955,7 @@ static void
print_select_op(erts_dsprintf_buf_t *dsbufp,
ErlDrvPort ix, ErtsSysFdType fd, int mode, int on)
{
- Port *pp = erts_drvport2port(ix, NULL);
+ Port *pp = erts_drvport2port(ix);
erts_dsprintf(dsbufp,
"driver_select(%p, %d,%s%s%s%s, %d) "
"by ",
@@ -960,8 +966,8 @@ print_select_op(erts_dsprintf_buf_t *dsbufp,
mode & ERL_DRV_USE ? " ERL_DRV_USE" : "",
mode & (ERL_DRV_USE_NO_CALLBACK & ~ERL_DRV_USE) ? "_NO_CALLBACK" : "",
on);
- print_driver_name(dsbufp, pp->common.id);
- erts_dsprintf(dsbufp, "driver %T ", pp ? pp->common.id : NIL);
+ print_driver_name(dsbufp, pp != ERTS_INVALID_ERL_DRV_PORT ? pp->common.id : NIL);
+ erts_dsprintf(dsbufp, "driver %T ", pp != ERTS_INVALID_ERL_DRV_PORT ? pp->common.id : NIL);
}
static void
@@ -1020,8 +1026,9 @@ steal_pending_stop_select(erts_dsprintf_buf_t *dsbufp, ErlDrvPort ix,
state->driver.drv_ptr = NULL;
}
else if ((mode & ERL_DRV_USE_NO_CALLBACK) == ERL_DRV_USE) {
- erts_driver_t* drv_ptr = erts_drvport2port(ix, NULL)->drv_ptr;
- if (drv_ptr != state->driver.drv_ptr) {
+ Port *prt = erts_drvport2port(ix);
+ erts_driver_t* drv_ptr = prt != ERTS_INVALID_ERL_DRV_PORT ? prt->drv_ptr : NULL;
+ if (drv_ptr && drv_ptr != state->driver.drv_ptr) {
/* Some other driver wants the stop_select callback */
if (state->driver.drv_ptr->handle) {
erts_ddll_dereference_driver(state->driver.drv_ptr->handle);
@@ -1042,7 +1049,7 @@ static void
print_event_op(erts_dsprintf_buf_t *dsbufp,
ErlDrvPort ix, ErtsSysFdType fd, ErlDrvEventData event_data)
{
- Port *pp = erts_drvport2port(ix, NULL);
+ Port *pp = erts_drvport2port(ix);
erts_dsprintf(dsbufp, "driver_event(%p, %d, ", ix, (int) fd);
if (!event_data)
erts_dsprintf(dsbufp, "NULL");
@@ -1051,8 +1058,9 @@ print_event_op(erts_dsprintf_buf_t *dsbufp,
(unsigned int) event_data->events,
(unsigned int) event_data->revents);
erts_dsprintf(dsbufp, ") by ");
- print_driver_name(dsbufp, pp->common.id);
- erts_dsprintf(dsbufp, "driver %T ", pp ? pp->common.id : NIL);
+ if (pp != ERTS_INVALID_ERL_DRV_PORT)
+ print_driver_name(dsbufp, pp->common.id);
+ erts_dsprintf(dsbufp, "driver %T ", pp != ERTS_INVALID_ERL_DRV_PORT ? pp->common.id : NIL);
}
static void
diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c
index 538eea88d1..bd8ba82a5f 100644
--- a/erts/emulator/sys/common/erl_mseg.c
+++ b/erts/emulator/sys/common/erl_mseg.c
@@ -39,6 +39,7 @@
#include "erl_alloc.h"
#include "big.h"
#include "erl_thr_progress.h"
+#include "erl_util_queue.h"
#if HAVE_ERTS_MSEG
@@ -175,6 +176,7 @@ struct cache_t_ {
Uint size;
void *seg;
cache_t *next;
+ cache_t *prev;
};
@@ -183,9 +185,9 @@ typedef struct ErtsMsegAllctr_t_ ErtsMsegAllctr_t;
struct mem_kind_t {
cache_t cache[MAX_CACHE_SIZE];
- cache_t *cache_unpowered;
- cache_t *cache_area[CACHE_AREAS];
- cache_t *cache_free;
+ cache_t cache_unpowered_node;
+ cache_t cache_powered_node[CACHE_AREAS];
+ cache_t cache_free;
Sint cache_size;
Uint cache_hits;
@@ -516,67 +518,94 @@ do { \
#define ERTS_DBG_MK_CHK_THR_ACCESS(MK)
#endif
-/* NEW CACHE interface */
+/* Cache interface */
-static ERTS_INLINE cache_t *mseg_cache_alloc_descriptor(MemKind *mk) {
- cache_t *c = mk->cache_free;
- ERTS_DBG_MK_CHK_THR_ACCESS(mk);
- if (c)
- mk->cache_free = c->next;
-
- return c;
-}
-
-static ERTS_INLINE void mseg_cache_free_descriptor(MemKind *mk, cache_t *c) {
- ERTS_DBG_MK_CHK_THR_ACCESS(mk);
- ASSERT(c);
-
- c->seg = NULL;
+static ERTS_INLINE void mseg_cache_clear_node(cache_t *c) {
+ c->seg = NULL;
c->size = 0;
- c->next = mk->cache_free;
- mk->cache_free = c;
+ c->next = c;
+ c->prev = c;
}
-static ERTS_INLINE int cache_bless_segment(MemKind *mk, void *seg, Uint size) {
+static ERTS_INLINE int cache_bless_segment(MemKind *mk, void *seg, Uint size, Uint flags) {
cache_t *c;
ERTS_DBG_MK_CHK_THR_ACCESS(mk);
- if (mk->cache_free && MAP_IS_ALIGNED(seg)) {
- if (IS_2POW(size)) {
+ ASSERT(!MSEG_FLG_IS_2POW(flags) || (MSEG_FLG_IS_2POW(flags) && MAP_IS_ALIGNED(seg) && IS_2POW(size)));
+
+ /* The idea is that sbc caching is prefered over mbc caching.
+ * Blocks are normally allocated in mb carriers and thus cached there.
+ * 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))) {
+
+ /* We have free slots, use one to cache the segment */
+
+ c = erts_circleq_head(&(mk->cache_free));
+ erts_circleq_remove(c);
+
+ c->seg = seg;
+ c->size = size;
+
+ if (MSEG_FLG_IS_2POW(flags)) {
int ix = SIZE_TO_CACHE_AREA_IDX(size);
ASSERT(ix < CACHE_AREAS);
ASSERT((1 << (ix + MSEG_ALIGN_BITS)) == size);
- /* unlink from free cache list */
- c = mseg_cache_alloc_descriptor(mk);
+ erts_circleq_push_head(&(mk->cache_powered_node[ix]), c);
- /* link to cache area */
- c->seg = seg;
- c->size = size;
- c->next = mk->cache_area[ix];
+ } else
+ erts_circleq_push_head(&(mk->cache_unpowered_node), c);
- mk->cache_area[ix] = c;
- mk->cache_size++;
+ mk->cache_size++;
+ ASSERT(mk->cache_size <= mk->ma->max_cache_size);
- ASSERT(mk->cache_size <= mk->ma->max_cache_size);
+ return 1;
+ } else if (!MSEG_FLG_IS_2POW(flags) && !erts_circleq_is_empty(&(mk->cache_unpowered_node))) {
- return 1;
- } else {
- /* unlink from free cache list */
- c = mseg_cache_alloc_descriptor(mk);
+ /* 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));
+ erts_circleq_remove(c);
+
+ mseg_destroy(mk->ma, mk, c->seg, c->size);
+ mseg_cache_clear_node(c);
+
+ c->seg = seg;
+ c->size = size;
+
+ erts_circleq_push_head(&(mk->cache_unpowered_node), c);
+
+ return 1;
+ } else if (!MSEG_FLG_IS_2POW(flags)) {
+
+ /* No free slots and no unpowered (sbc) slots.
+ * Evict smallest slot from powered cache so we can cache an unpowered (sbc) segment.
+ * Note: Though this is the wanted policy I don't think it is used significantly.
+ * This branch could probably be removed without serious impact.
+ */
+
+ int i;
+
+ for( i = 0; i < CACHE_AREAS; i++) {
+ if (erts_circleq_is_empty(&(mk->cache_powered_node[i])))
+ continue;
+
+ c = erts_circleq_tail(&(mk->cache_powered_node[i]));
+ erts_circleq_remove(c);
+
+ mseg_destroy(mk->ma, mk, c->seg, c->size);
+ mseg_cache_clear_node(c);
- /* link to cache area */
c->seg = seg;
c->size = size;
- c->next = mk->cache_unpowered;
-
- mk->cache_unpowered = c;
- mk->cache_size++;
- ASSERT(mk->cache_size <= mk->ma->max_cache_size);
+ erts_circleq_push_head(&(mk->cache_unpowered_node), c);
return 1;
}
@@ -585,90 +614,110 @@ static ERTS_INLINE int cache_bless_segment(MemKind *mk, void *seg, Uint size) {
return 0;
}
-static ERTS_INLINE void *cache_get_segment(MemKind *mk, Uint *size_p) {
+static ERTS_INLINE void *cache_get_segment(MemKind *mk, Uint *size_p, Uint flags) {
Uint size = *size_p;
ERTS_DBG_MK_CHK_THR_ACCESS(mk);
- if (IS_2POW(size)) {
+
+ if (MSEG_FLG_IS_2POW(flags)) {
int i, ix = SIZE_TO_CACHE_AREA_IDX(size);
void *seg;
cache_t *c;
Uint csize;
+ ASSERT(IS_2POW(size));
+
for( i = ix; i < CACHE_AREAS; i++) {
- if ((c = mk->cache_area[i]) == NULL)
+ if (erts_circleq_is_empty(&(mk->cache_powered_node[i])))
continue;
+ c = erts_circleq_head(&(mk->cache_powered_node[i]));
+ erts_circleq_remove(c);
+
ASSERT(IS_2POW(c->size));
+ ASSERT(MAP_IS_ALIGNED(c->seg));
+
+ csize = c->size;
+ seg = c->seg;
- /* unlink from cache area */
- csize = c->size;
- seg = c->seg;
- mk->cache_area[i] = c->next;
- c->next = NULL;
mk->cache_size--;
mk->cache_hits++;
/* link to free cache list */
- mseg_cache_free_descriptor(mk, c);
+ mseg_cache_clear_node(c);
+ erts_circleq_push_head(&(mk->cache_free), c);
ASSERT(!(mk->cache_size < 0));
- /* divvy up the cache - if needed */
- while( i > ix) {
- csize = csize >> 1;
- /* try to cache half of it */
- if (!cache_bless_segment(mk, (char *)seg + csize, csize)) {
- /* wouldn't cache .. destroy it instead */
- mseg_destroy(mk->ma, mk, (char *)seg + csize, csize);
- }
- i--;
+ if (csize != size) {
+ mseg_destroy(mk->ma, mk, (char *)seg + size, csize - size);
}
- ASSERT(csize == size);
+
return seg;
}
}
- else if (mk->cache_unpowered) {
+ else if (!erts_circleq_is_empty(&(mk->cache_unpowered_node))) {
void *seg;
- cache_t *c, *pc;
+ cache_t *c;
+ cache_t *best = NULL;
+ Uint bdiff = 0;
Uint csize;
Uint bad_max_abs = mk->ma->abs_max_cache_bad_fit;
Uint bad_max_rel = mk->ma->rel_max_cache_bad_fit;
- c = mk->cache_unpowered;
- pc = c;
-
- while (c) {
+ erts_circleq_foreach(c, &(mk->cache_unpowered_node)) {
csize = c->size;
- if (csize >= size &&
- ((csize - size)*100 < bad_max_rel*size) &&
- (csize - size) < bad_max_abs ) {
+ if (csize >= size) {
+ if (((csize - size)*100 < bad_max_rel*size) && (csize - size) < bad_max_abs ) {
- /* unlink from cache area */
- seg = c->seg;
+ seg = c->seg;
- if (pc == c) {
- mk->cache_unpowered = c->next;
- } else {
- pc->next = c->next;
- }
+ erts_circleq_remove(c);
+
+ mk->cache_size--;
+ mk->cache_hits++;
- c->next = NULL;
- mk->cache_size--;
- mk->cache_hits++;
+ mseg_cache_clear_node(c);
+ erts_circleq_push_head(&(mk->cache_free), c);
- /* link to free cache list */
- mseg_cache_free_descriptor(mk, c);
- *size_p = csize;
+ *size_p = csize;
- return seg;
+ return seg;
+
+ } else if (!best || (csize - size) < bdiff) {
+ best = c;
+ bdiff = csize - size;
+ }
}
+ }
+
+ /* No cached segment met our criteria, use the best one found and trim it */
+
+ if (best) {
+
+ seg = best->seg;
+ csize = best->size;
+
+ ASSERT(best->seg);
+ ASSERT(best->size > 0);
+
+ mk->cache_hits++;
+
+ /* Use current cache placement for remaining segment space */
+
+ best->seg = seg + size;
+ best->size = csize - size;
+
+ ASSERT((size % GET_PAGE_SIZE) == 0);
+ ASSERT((best->size % GET_PAGE_SIZE) == 0);
+
+ *size_p = size;
+
+ return seg;
- pc = c;
- c = c->next;
}
}
return NULL;
@@ -679,20 +728,18 @@ static ERTS_INLINE void *cache_get_segment(MemKind *mk, Uint *size_p) {
* using callbacks from aux-work in the scheduler.
*/
-static ERTS_INLINE Uint mseg_drop_one_memkind_cache_size(MemKind *mk, cache_t **head) {
+static ERTS_INLINE Uint mseg_drop_one_memkind_cache_size(MemKind *mk, cache_t *head) {
cache_t *c = NULL;
- c = *head;
-
- ASSERT( c != NULL );
-
- *head = c->next;
+ c = erts_circleq_tail(head);
+ erts_circleq_remove(c);
if (erts_mtrace_enabled)
erts_mtrace_crr_free(SEGTYPE, SEGTYPE, c->seg);
mseg_destroy(mk->ma, mk, c->seg, c->size);
- mseg_cache_free_descriptor(mk, c);
+ mseg_cache_clear_node(c);
+ erts_circleq_push_head(&(mk->cache_free), c);
mk->segments.current.watermark--;
mk->cache_size--;
@@ -702,30 +749,27 @@ static ERTS_INLINE Uint mseg_drop_one_memkind_cache_size(MemKind *mk, cache_t **
return mk->cache_size;
}
-static ERTS_INLINE Uint mseg_drop_memkind_cache_size(MemKind *mk, cache_t **head) {
- cache_t *c = NULL, *next = NULL;
-
- c = *head;
- ASSERT( c != NULL );
+static ERTS_INLINE Uint mseg_drop_memkind_cache_size(MemKind *mk, cache_t *head) {
+ cache_t *c = NULL;
- while (c) {
+ while (!erts_circleq_is_empty(head)) {
- next = c->next;
+ c = erts_circleq_tail(head);
+ erts_circleq_remove(c);
if (erts_mtrace_enabled)
erts_mtrace_crr_free(SEGTYPE, SEGTYPE, c->seg);
mseg_destroy(mk->ma, mk, c->seg, c->size);
- mseg_cache_free_descriptor(mk, c);
+
+ mseg_cache_clear_node(c);
+ erts_circleq_push_head(&(mk->cache_free), c);
mk->segments.current.watermark--;
mk->cache_size--;
- c = next;
}
- *head = NULL;
-
ASSERT( mk->cache_size >= 0 );
return mk->cache_size;
@@ -743,12 +787,12 @@ static Uint mseg_check_memkind_cache(MemKind *mk) {
ERTS_DBG_MK_CHK_THR_ACCESS(mk);
for (i = 0; i < CACHE_AREAS; i++) {
- if (mk->cache_area[i] != NULL)
- return mseg_drop_one_memkind_cache_size(mk, &(mk->cache_area[i]));
+ if (!erts_circleq_is_empty(&(mk->cache_powered_node[i])))
+ return mseg_drop_one_memkind_cache_size(mk, &(mk->cache_powered_node[i]));
}
- if (mk->cache_unpowered)
- return mseg_drop_one_memkind_cache_size(mk, &(mk->cache_unpowered));
+ if (!erts_circleq_is_empty(&(mk->cache_unpowered_node)))
+ return mseg_drop_one_memkind_cache_size(mk, &(mk->cache_unpowered_node));
return 0;
}
@@ -804,17 +848,17 @@ static void mseg_clear_memkind_cache(MemKind *mk) {
/* drop pow2 caches */
for (i = 0; i < CACHE_AREAS; i++) {
- if (mk->cache_area[i] == NULL)
+ if (erts_circleq_is_empty(&(mk->cache_powered_node[i])))
continue;
- mseg_drop_memkind_cache_size(mk, &(mk->cache_area[i]));
- ASSERT(mk->cache_area[i] == NULL);
+ mseg_drop_memkind_cache_size(mk, &(mk->cache_powered_node[i]));
+ ASSERT(erts_circleq_is_empty(&(mk->cache_powered_node[i])));
}
/* drop varied caches */
- if(mk->cache_unpowered)
- mseg_drop_memkind_cache_size(mk, &(mk->cache_unpowered));
+ if (!erts_circleq_is_empty(&(mk->cache_unpowered_node)))
+ mseg_drop_memkind_cache_size(mk, &(mk->cache_unpowered_node));
- ASSERT(mk->cache_unpowered == NULL);
+ ASSERT(erts_circleq_is_empty(&(mk->cache_unpowered_node)));
ASSERT(mk->cache_size == 0);
}
@@ -873,7 +917,7 @@ mseg_alloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, Uint *size_p,
ma->min_seg_size = size;
#endif
- if (opt->cache && mk->cache_size > 0 && (seg = cache_get_segment(mk, &size)) != NULL)
+ if (opt->cache && mk->cache_size > 0 && (seg = cache_get_segment(mk, &size, flags)) != NULL)
goto done;
if ((seg = mseg_create(ma, mk, size)) == NULL)
@@ -894,14 +938,13 @@ done:
static void
mseg_dealloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg, Uint size,
- const ErtsMsegOpt_t *opt)
+ Uint flags, const ErtsMsegOpt_t *opt)
{
MemKind* mk = memkind(ma, opt);
-
ERTS_MSEG_DEALLOC_STAT(mk,size);
- if (opt->cache && cache_bless_segment(mk, seg, size)) {
+ if (opt->cache && cache_bless_segment(mk, seg, size, flags)) {
schedule_cache_check(ma);
goto done;
}
@@ -934,7 +977,7 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg,
/* Dealloc old segment if new segment is of size 0 */
if (!(*new_size_p)) {
- mseg_dealloc(ma, atype, seg, old_size, opt);
+ mseg_dealloc(ma, atype, seg, old_size, flags, opt);
DEC_CC(ma, dealloc);
return NULL;
}
@@ -993,7 +1036,7 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg,
else {
if (!opt->preserv) {
- mseg_dealloc(ma, atype, seg, old_size, opt);
+ mseg_dealloc(ma, atype, seg, old_size, flags, opt);
new_seg = mseg_alloc(ma, atype, &new_size, flags, opt);
ASSERT(MAP_IS_ALIGNED(new_seg) || !new_seg);
}
@@ -1020,7 +1063,7 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg,
new_size = old_size;
else {
sys_memcpy(((char *) new_seg), ((char *) seg), MIN(new_size, old_size));
- mseg_dealloc(ma, atype, seg, old_size, opt);
+ mseg_dealloc(ma, atype, seg, old_size, flags, opt);
}
#endif
}
@@ -1497,19 +1540,19 @@ erts_mseg_alloc(ErtsAlcType_t atype, Uint *size_p, Uint flags)
void
erts_mseg_dealloc_opt(ErtsAlcType_t atype, void *seg,
- Uint size, const ErtsMsegOpt_t *opt)
+ Uint size, Uint flags, const ErtsMsegOpt_t *opt)
{
ErtsMsegAllctr_t *ma = ERTS_MSEG_ALLCTR_OPT(opt);
ERTS_MSEG_LOCK(ma);
ERTS_DBG_MA_CHK_THR_ACCESS(ma);
- mseg_dealloc(ma, atype, seg, size, opt);
+ mseg_dealloc(ma, atype, seg, size, flags, opt);
ERTS_MSEG_UNLOCK(ma);
}
void
-erts_mseg_dealloc(ErtsAlcType_t atype, void *seg, Uint size)
+erts_mseg_dealloc(ErtsAlcType_t atype, void *seg, Uint size, Uint flags)
{
- erts_mseg_dealloc_opt(atype, seg, size, &erts_mseg_default_opt);
+ erts_mseg_dealloc_opt(atype, seg, size, flags, &erts_mseg_default_opt);
}
void *
@@ -1556,27 +1599,28 @@ erts_mseg_unit_size(void)
return MSEG_ALIGNED_SIZE;
}
+
static void mem_kind_init(ErtsMsegAllctr_t *ma, MemKind* mk, const char* name)
{
int i;
+ /* Clear all cache headers */
+ mseg_cache_clear_node(&(mk->cache_free));
+ mseg_cache_clear_node(&(mk->cache_unpowered_node));
+
for (i = 0; i < CACHE_AREAS; i++) {
- mk->cache_area[i] = NULL;
+ mseg_cache_clear_node(&(mk->cache_powered_node[i]));
}
- mk->cache_free = NULL;
+ /* Populate cache free list */
ASSERT(ma->max_cache_size <= MAX_CACHE_SIZE);
for (i = 0; i < ma->max_cache_size; i++) {
- mk->cache[i].seg = NULL;
- mk->cache[i].size = 0;
- mk->cache[i].next = mk->cache_free;
- mk->cache_free = &(mk->cache[i]);
+ mseg_cache_clear_node(&(mk->cache[i]));
+ erts_circleq_push_head(&(mk->cache_free), &(mk->cache[i]));
}
- mk->cache_unpowered = NULL;
-
mk->cache_size = 0;
mk->cache_hits = 0;
@@ -1594,9 +1638,6 @@ static void mem_kind_init(ErtsMsegAllctr_t *ma, MemKind* mk, const char* name)
ma->mk_list = mk;
}
-
-
-
void
erts_mseg_init(ErtsMsegInit_t *init)
{
@@ -1721,7 +1762,7 @@ erts_mseg_test(unsigned long op,
case 0x401:
return (unsigned long) erts_mseg_alloc(ERTS_ALC_A_INVALID, (Uint *) a1, (Uint) 0);
case 0x402:
- erts_mseg_dealloc(ERTS_ALC_A_INVALID, (void *) a1, (Uint) a2);
+ erts_mseg_dealloc(ERTS_ALC_A_INVALID, (void *) a1, (Uint) a2, (Uint) 0);
return (unsigned long) 0;
case 0x403:
return (unsigned long) erts_mseg_realloc(ERTS_ALC_A_INVALID,
diff --git a/erts/emulator/sys/common/erl_mseg.h b/erts/emulator/sys/common/erl_mseg.h
index 3d0b0f0355..3cab9e18da 100644
--- a/erts/emulator/sys/common/erl_mseg.h
+++ b/erts/emulator/sys/common/erl_mseg.h
@@ -74,7 +74,7 @@ typedef struct {
{ \
4*1024*1024, /* amcbf: Absolute max cache bad fit */ \
20, /* rmcbf: Relative max cache bad fit */ \
- 5, /* mcs: Max cache size */ \
+ 10, /* mcs: Max cache size */ \
1000 /* cci: Cache check interval */ \
}
@@ -93,11 +93,10 @@ extern const ErtsMsegOpt_t erts_mseg_default_opt;
void *erts_mseg_alloc(ErtsAlcType_t, Uint *, Uint);
void *erts_mseg_alloc_opt(ErtsAlcType_t, Uint *, Uint, const ErtsMsegOpt_t *);
-void erts_mseg_dealloc(ErtsAlcType_t, void *, Uint);
-void erts_mseg_dealloc_opt(ErtsAlcType_t, void *, Uint, const ErtsMsegOpt_t *);
+void erts_mseg_dealloc(ErtsAlcType_t, void *, Uint, Uint);
+void erts_mseg_dealloc_opt(ErtsAlcType_t, void *, Uint, Uint, const ErtsMsegOpt_t *);
void *erts_mseg_realloc(ErtsAlcType_t, void *, Uint, Uint *, Uint);
-void *erts_mseg_realloc_opt(ErtsAlcType_t, void *, Uint, Uint *,
- Uint, const ErtsMsegOpt_t *);
+void *erts_mseg_realloc_opt(ErtsAlcType_t, void *, Uint, Uint *, Uint, const ErtsMsegOpt_t *);
void erts_mseg_clear_cache(void);
void erts_mseg_cache_check(void);
Uint erts_mseg_no( const ErtsMsegOpt_t *);
diff --git a/erts/emulator/sys/common/erl_sys_common_misc.c b/erts/emulator/sys/common/erl_sys_common_misc.c
index 1bf5fa89f4..0b31c125e5 100644
--- a/erts/emulator/sys/common/erl_sys_common_misc.c
+++ b/erts/emulator/sys/common/erl_sys_common_misc.c
@@ -47,14 +47,16 @@
/* Written once and only once */
static int filename_encoding = ERL_FILENAME_UNKNOWN;
+static int filename_warning = ERL_FILENAME_WARNING_WARNING;
#if defined(__WIN32__) || defined(__DARWIN__)
static int user_filename_encoding = ERL_FILENAME_UTF8; /* Default unicode on windows */
#else
static int user_filename_encoding = ERL_FILENAME_LATIN1;
#endif
-void erts_set_user_requested_filename_encoding(int encoding)
+void erts_set_user_requested_filename_encoding(int encoding, int warning)
{
user_filename_encoding = encoding;
+ filename_warning = warning;
}
int erts_get_user_requested_filename_encoding(void)
@@ -62,6 +64,11 @@ int erts_get_user_requested_filename_encoding(void)
return user_filename_encoding;
}
+int erts_get_filename_warning_type(void)
+{
+ return filename_warning;
+}
+
void erts_init_sys_common_misc(void)
{
#if defined(__WIN32__)
@@ -107,9 +114,9 @@ int erts_get_native_filename_encoding(void)
}
/* For internal use by sys_double_to_chars_fast() */
-static char* float_first_trailing_zero(char* p)
+static char* find_first_trailing_zero(char* p)
{
- for (--p; *p == '0' && *(p-1) == '0'; --p);
+ for (; *(p-1) == '0'; --p);
if (*(p-1) == '.') ++p;
return p;
}
@@ -120,34 +127,83 @@ sys_double_to_chars(double fp, char *buffer, size_t buffer_size)
return sys_double_to_chars_ext(fp, buffer, buffer_size, SYS_DEFAULT_FLOAT_DECIMALS);
}
+/* Convert float to string using fixed point notation.
+ * decimals must be >= 0
+ * if compact != 0, the trailing 0's will be truncated
+ */
int
-sys_double_to_chars_fast(double f, char *outbuf, int maxlen, int decimals, int compact)
+sys_double_to_chars_fast(double f, char *buffer, int buffer_size, int decimals,
+ int compact)
{
- enum {
- FRAC_SIZE = 52
- , EXP_SIZE = 11
- , EXP_MASK = (1ll << EXP_SIZE) - 1
- , FRAC_MASK = (1ll << FRAC_SIZE) - 1
- , FRAC_MASK2 = (1ll << (FRAC_SIZE + 1)) - 1
- , MAX_FLOAT = 1ll << (FRAC_SIZE+1)
+ /* Note that some C compilers don't support "static const" propagation
+ * so we use a defines */
+ #define SYS_DOUBLE_RND_CONST 0.55555555555555555
+ #define FRAC_SIZE 52
+ #define EXP_SIZE 11
+ #define EXP_MASK ((1ll << EXP_SIZE) - 1)
+ #define MAX_DECIMALS (sizeof(cs_sys_double_pow10) \
+ / sizeof(cs_sys_double_pow10[0]))
+ #define FRAC_MASK ((1ll << FRAC_SIZE) - 1)
+ #define FRAC_MASK2 ((1ll << (FRAC_SIZE + 1)) - 1)
+ #define MAX_FLOAT (1ll << (FRAC_SIZE+1))
+
+ static const double cs_sys_double_pow10[] = {
+ SYS_DOUBLE_RND_CONST / 1ll,
+ SYS_DOUBLE_RND_CONST / 10ll,
+ SYS_DOUBLE_RND_CONST / 100ll,
+ SYS_DOUBLE_RND_CONST / 1000ll,
+ SYS_DOUBLE_RND_CONST / 10000ll,
+ SYS_DOUBLE_RND_CONST / 100000ll,
+ SYS_DOUBLE_RND_CONST / 1000000ll,
+ SYS_DOUBLE_RND_CONST / 10000000ll,
+ SYS_DOUBLE_RND_CONST / 100000000ll,
+ SYS_DOUBLE_RND_CONST / 1000000000ll,
+ SYS_DOUBLE_RND_CONST / 10000000000ll,
+ SYS_DOUBLE_RND_CONST / 100000000000ll,
+ SYS_DOUBLE_RND_CONST / 1000000000000ll,
+ SYS_DOUBLE_RND_CONST / 10000000000000ll,
+ SYS_DOUBLE_RND_CONST / 100000000000000ll,
+ SYS_DOUBLE_RND_CONST / 1000000000000000ll,
+ SYS_DOUBLE_RND_CONST / 10000000000000000ll,
+ SYS_DOUBLE_RND_CONST / 100000000000000000ll,
+ SYS_DOUBLE_RND_CONST / 1000000000000000000ll
};
- long long mantissa, int_part, int_part2, frac_part;
+ long long mantissa, int_part = 0, frac_part = 0;
short exp;
- int sign, i, n, m, max;
- double absf;
+ int max;
+ int neg;
+ double fr;
union { long long L; double F; } x;
- char c, *p = outbuf;
- int digit, roundup;
+ char *p = buffer;
+
+ if (decimals < 0)
+ return -1;
- x.F = f;
+ /* Round the number to given decimal places. The number of 5's in the
+ * SYS_DOUBLE_RND_CONST constant is chosen such that adding any more 5's doesn't
+ * change the double precision of the number, i.e.:
+ * 1> term_to_binary(0.55555555555555555, [{minor_version, 1}]).
+ * <<131,70,63,225,199,28,113,199,28,114>>
+ * 2> term_to_binary(0.5555555555555555555, [{minor_version, 1}]).
+ * <<131,70,63,225,199,28,113,199,28,114>>
+ */
+ if (f >= 0) {
+ neg = 0;
+ fr = decimals < MAX_DECIMALS ? (f + cs_sys_double_pow10[decimals]) : f;
+ x.F = fr;
+ } else {
+ neg = 1;
+ fr = decimals < MAX_DECIMALS ? (f - cs_sys_double_pow10[decimals]) : f;
+ x.F = -fr;
+ }
exp = (x.L >> FRAC_SIZE) & EXP_MASK;
mantissa = x.L & FRAC_MASK;
- sign = x.L >= 0 ? 1 : -1;
+
if (exp == EXP_MASK) {
if (mantissa == 0) {
- if (sign == -1)
+ if (neg)
*p++ = '-';
*p++ = 'i';
*p++ = 'n';
@@ -158,101 +214,79 @@ sys_double_to_chars_fast(double f, char *outbuf, int maxlen, int decimals, int c
*p++ = 'n';
}
*p = '\0';
- return p - outbuf;
+ return p - buffer;
}
exp -= EXP_MASK >> 1;
mantissa |= (1ll << FRAC_SIZE);
- frac_part = 0;
- int_part = 0;
- absf = f * sign;
-
- /* Don't bother with optimizing too large numbers and decimals */
- if (absf > MAX_FLOAT || decimals > maxlen-17) {
- int len = erts_snprintf(outbuf, maxlen, "%.*f", decimals, f);
- if (len >= maxlen)
+
+ /* Don't bother with optimizing too large numbers or too large precision */
+ if (x.F > MAX_FLOAT || decimals >= MAX_DECIMALS) {
+ int len = erts_snprintf(buffer, buffer_size, "%.*f", decimals, f);
+ char* p = buffer + len;
+ if (len >= buffer_size)
return -1;
- p = outbuf + len;
/* Delete trailing zeroes */
if (compact)
- p = float_first_trailing_zero(outbuf + len);
+ p = find_first_trailing_zero(p);
*p = '\0';
- return p - outbuf;
- }
-
- if (exp >= FRAC_SIZE)
+ return p - buffer;
+ } else if (exp >= FRAC_SIZE) {
int_part = mantissa << (exp - FRAC_SIZE);
- else if (exp >= 0) {
+ } else if (exp >= 0) {
int_part = mantissa >> (FRAC_SIZE - exp);
frac_part = (mantissa << (exp + 1)) & FRAC_MASK2;
- }
- else /* if (exp < 0) */
+ } else /* if (exp < 0) */ {
frac_part = (mantissa & FRAC_MASK2) >> -(exp + 1);
+ }
- if (int_part == 0) {
- if (sign == -1)
+ if (!int_part) {
+ if (neg)
*p++ = '-';
*p++ = '0';
} else {
- int ret;
+ int ret, i, n;
while (int_part != 0) {
- int_part2 = int_part / 10;
- *p++ = (char)(int_part - ((int_part2 << 3) + (int_part2 << 1)) + '0');
- int_part = int_part2;
+ long long j = int_part / 10;
+ *p++ = (char)(int_part - ((j << 3) + (j << 1)) + '0');
+ int_part = j;
}
- if (sign == -1)
+ if (neg)
*p++ = '-';
/* Reverse string */
- ret = p - outbuf;
+ ret = p - buffer;
for (i = 0, n = ret/2; i < n; i++) {
- int j = ret - i - 1;
- c = outbuf[i];
- outbuf[i] = outbuf[j];
- outbuf[j] = c;
+ int j = ret - i - 1;
+ char c = buffer[i];
+ buffer[i] = buffer[j];
+ buffer[j] = c;
}
}
- if (decimals != 0)
+
+ if (decimals > 0) {
+ int i;
*p++ = '.';
- max = maxlen - (p - outbuf) - 1 /* leave room for trailing '\0' */;
- if (max > decimals)
+ max = buffer_size - (p - buffer) - 1 /* leave room for trailing '\0' */;
+
+ if (decimals > max)
+ return -1; /* the number is not large enough to fit in the buffer */
+
max = decimals;
- for (m = 0; m < max; m++) {
- /* frac_part *= 10; */
- frac_part = (frac_part << 3) + (frac_part << 1);
- *p++ = (char)((frac_part >> (FRAC_SIZE + 1)) + '0');
- frac_part &= FRAC_MASK2;
- }
+ for (i = 0; i < max; i++) {
+ /* frac_part *= 10; */
+ frac_part = (frac_part << 3) + (frac_part << 1);
- roundup = 0;
- /* Rounding - look at the next digit */
- frac_part = (frac_part << 3) + (frac_part << 1);
- digit = (frac_part >> (FRAC_SIZE + 1));
- if (digit > 5)
- roundup = 1;
- else if (digit == 5) {
- frac_part &= FRAC_MASK2;
- if (frac_part != 0) roundup = 1;
- }
- if (roundup) {
- char d;
- int pos = p - outbuf - 1;
- do {
- d = outbuf[pos];
- if (d == '-') break;
- if (d == '.') continue;
- if (++d != ':') {
- outbuf[pos] = d;
- break;
- }
- outbuf[pos] = '0';
- } while (--pos);
+ *p++ = (char)((frac_part >> (FRAC_SIZE + 1)) + '0');
+ frac_part &= FRAC_MASK2;
+ }
+
+ /* Delete trailing zeroes */
+ if (compact)
+ p = find_first_trailing_zero(p);
}
- /* Delete trailing zeroes */
- if (compact && *(p - 1) == '0')
- p = float_first_trailing_zero(--p);
*p = '\0';
- return p - outbuf;
+ return p - buffer;
}
diff --git a/erts/emulator/sys/common/erl_util_queue.h b/erts/emulator/sys/common/erl_util_queue.h
new file mode 100644
index 0000000000..47925e2264
--- /dev/null
+++ b/erts/emulator/sys/common/erl_util_queue.h
@@ -0,0 +1,77 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2013. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef ERL_UTIL_QUEUE_H_
+#define ERL_UTIL_QUEUE_H_
+
+#define erts_circleq_head(Q) ((Q)->next)
+#define erts_circleq_tail(Q) ((Q)->prev)
+#define erts_circleq_next(Q) ((Q)->next)
+#define erts_circleq_prev(Q) ((Q)->prev)
+#define erts_circleq_is_empty(Q) ((Q)->next == (void *)(Q))
+
+#define erts_circleq_remove(N) \
+ do { \
+ (N)->next->prev = (N)->prev; \
+ (N)->prev->next = (N)->next; \
+ (N)->next = (N); \
+ (N)->prev = (N); \
+ } while(0)
+
+#define erts_circleq_pop_head(Q, N) \
+ do { \
+ (N) = (Q)->next; \
+ (N)->next->prev = (N)->prev; \
+ (N)->prev->next = (N)->next; \
+ (N)->next = (N); \
+ (N)->prev = (N); \
+ } while(0)
+
+#define erts_circleq_pop_tail(Q, N) \
+ do { \
+ (N) = (Q)->prev; \
+ (N)->next->prev = (N)->prev; \
+ (N)->prev->next = (N)->next; \
+ (N)->next = (N); \
+ (N)->prev = (N); \
+ } while(0)
+
+#define erts_circleq_push_head(Q, N) \
+ do { \
+ (N)->next = (Q)->next; \
+ (N)->prev = (void *)(Q); \
+ (Q)->next->prev = (N); \
+ (Q)->next = (N); \
+ } while(0)
+
+#define erts_circleq_push_tail(Q, N) \
+ do { \
+ (N)->prev = (Q)->prev; \
+ (N)->next = (void *)(Q); \
+ (Q)->prev->next = (N); \
+ (Q)->prev = (N); \
+ } while(0)
+
+#define erts_circleq_foreach(V, Q) \
+ for ((V) = (Q)->next; (V) != (const void *)(Q); (V) = (V)->next)
+
+#define erts_circleq_foreach_reverse(V, Q) \
+ for ((V) = (Q)->prev; (V) != (const void *)(Q); (V) = (V)->prev)
+
+#endif
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index 0b96eded76..dbc163bac1 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -1211,8 +1211,8 @@ static int set_driver_data(ErlDrvPort port_num,
report_exit_list = report_exit;
}
- prt = erts_drvport2port(port_num, NULL);
- if (prt)
+ prt = erts_drvport2port(port_num);
+ if (prt != ERTS_INVALID_ERL_DRV_PORT)
prt->os_pid = pid;
if (read_write & DO_READ) {
@@ -2650,7 +2650,7 @@ report_exit_status(ErtsSysReportExit *rep, int status)
if (rep->ifd >= 0) {
driver_data[rep->ifd].alive = 0;
driver_data[rep->ifd].status = status;
- (void) driver_select((ErlDrvPort) pp,
+ (void) driver_select(ERTS_Port2ErlDrvPort(pp),
rep->ifd,
(ERL_DRV_READ|ERL_DRV_USE),
1);
@@ -2658,7 +2658,7 @@ report_exit_status(ErtsSysReportExit *rep, int status)
if (rep->ofd >= 0) {
driver_data[rep->ofd].alive = 0;
driver_data[rep->ofd].status = status;
- (void) driver_select((ErlDrvPort) pp,
+ (void) driver_select(ERTS_Port2ErlDrvPort(pp),
rep->ofd,
(ERL_DRV_WRITE|ERL_DRV_USE),
1);
diff --git a/erts/emulator/sys/win32/erl_win_dyn_driver.h b/erts/emulator/sys/win32/erl_win_dyn_driver.h
index ae3228ff28..a7c53c904d 100644
--- a/erts/emulator/sys/win32/erl_win_dyn_driver.h
+++ b/erts/emulator/sys/win32/erl_win_dyn_driver.h
@@ -37,6 +37,7 @@ WDD_TYPEDEF(int, driver_failure_posix,(ErlDrvPort, int));
WDD_TYPEDEF(int, driver_failure,(ErlDrvPort, int));
WDD_TYPEDEF(int, driver_exit, (ErlDrvPort, int));
WDD_TYPEDEF(int, driver_failure_eof, (ErlDrvPort));
+WDD_TYPEDEF(void, erl_drv_busy_msgq_limits, (ErlDrvPort, ErlDrvSizeT *, ErlDrvSizeT *));
WDD_TYPEDEF(int, driver_select, (ErlDrvPort, ErlDrvEvent, int, int));
WDD_TYPEDEF(int, driver_event, (ErlDrvPort, ErlDrvEvent,ErlDrvEventData));
WDD_TYPEDEF(int, driver_output, (ErlDrvPort, char *, ErlDrvSizeT));
@@ -47,6 +48,7 @@ WDD_TYPEDEF(ErlDrvSizeT, driver_vec_to_buf, (ErlIOVec *, char *, ErlDrvSizeT));
WDD_TYPEDEF(int, driver_set_timer, (ErlDrvPort, unsigned long));
WDD_TYPEDEF(int, driver_cancel_timer, (ErlDrvPort));
WDD_TYPEDEF(int, driver_read_timer, (ErlDrvPort, unsigned long *));
+WDD_TYPEDEF(int, erl_drv_consume_timeslice, (ErlDrvPort, int));
WDD_TYPEDEF(char *, erl_errno_id, (int));
WDD_TYPEDEF(void, set_busy_port, (ErlDrvPort, int));
WDD_TYPEDEF(void, set_port_control_flags, (ErlDrvPort, int));
@@ -152,6 +154,7 @@ typedef struct {
WDD_FTYPE(driver_failure) *driver_failure;
WDD_FTYPE(driver_exit) *driver_exit;
WDD_FTYPE(driver_failure_eof) *driver_failure_eof;
+ WDD_FTYPE(erl_drv_busy_msgq_limits) *erl_drv_busy_msgq_limits;
WDD_FTYPE(driver_select) *driver_select;
WDD_FTYPE(driver_event) *driver_event;
WDD_FTYPE(driver_output) *driver_output;
@@ -162,6 +165,7 @@ typedef struct {
WDD_FTYPE(driver_set_timer) *driver_set_timer;
WDD_FTYPE(driver_cancel_timer) *driver_cancel_timer;
WDD_FTYPE(driver_read_timer) *driver_read_timer;
+ WDD_FTYPE(erl_drv_consume_timeslice) *erl_drv_consume_timeslice;
WDD_FTYPE(erl_errno_id) *erl_errno_id;
WDD_FTYPE(set_busy_port)* set_busy_port;
WDD_FTYPE(set_port_control_flags) *set_port_control_flags;
@@ -261,6 +265,7 @@ extern TWinDynDriverCallbacks WinDynDriverCallbacks;
#define driver_failure (WinDynDriverCallbacks.driver_failure)
#define driver_exit (WinDynDriverCallbacks.driver_exit)
#define driver_failure_eof (WinDynDriverCallbacks.driver_failure_eof)
+#define erl_drv_busy_msgq_limits (WinDynDriverCallbacks.erl_drv_busy_msgq_limits)
#define driver_select (WinDynDriverCallbacks.driver_select)
#define driver_event (WinDynDriverCallbacks.driver_event)
#define driver_output (WinDynDriverCallbacks.driver_output)
@@ -271,6 +276,7 @@ extern TWinDynDriverCallbacks WinDynDriverCallbacks;
#define driver_set_timer (WinDynDriverCallbacks.driver_set_timer)
#define driver_cancel_timer (WinDynDriverCallbacks.driver_cancel_timer)
#define driver_read_timer (WinDynDriverCallbacks.driver_read_timer)
+#define erl_drv_consume_timeslice (WinDynDriverCallbacks.erl_drv_consume_timeslice)
#define erl_errno_id (WinDynDriverCallbacks.erl_errno_id)
#define set_busy_port (WinDynDriverCallbacks.set_busy_port)
#define set_port_control_flags (WinDynDriverCallbacks.set_port_control_flags)
@@ -394,6 +400,7 @@ do { \
((W).driver_failure) = driver_failure; \
((W).driver_exit) = driver_exit; \
((W).driver_failure_eof) = driver_failure_eof; \
+((W).erl_drv_busy_msgq_limits) = erl_drv_busy_msgq_limits;\
((W).driver_select) = driver_select; \
((W).driver_event) = driver_event; \
((W).driver_output) = driver_output; \
@@ -404,6 +411,7 @@ do { \
((W).driver_set_timer) = driver_set_timer; \
((W).driver_cancel_timer) = driver_cancel_timer; \
((W).driver_read_timer) = driver_read_timer; \
+((W).erl_drv_consume_timeslice) = erl_drv_consume_timeslice;\
((W).erl_errno_id) = erl_errno_id; \
((W).set_busy_port) = set_busy_port; \
((W).set_port_control_flags) = set_port_control_flags; \
diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c
index 1cd9072cea..19dffd0ea4 100755
--- a/erts/emulator/sys/win32/sys.c
+++ b/erts/emulator/sys/win32/sys.c
@@ -57,11 +57,13 @@ extern void _dosmaperr(DWORD);
#define __argv e_argv
#endif
+typedef struct driver_data DriverData;
+
static void init_console();
static int get_and_remove_option(int* argc, char** argv, const char* option);
static char *get_and_remove_option2(int *argc, char **argv,
const char *option);
-static int init_async_io(struct async_io* aio, int use_threads);
+static int init_async_io(DriverData *dp, struct async_io* aio, int use_threads);
static void release_async_io(struct async_io* aio, ErlDrvPort);
static void async_read_file(struct async_io* aio, LPVOID buf, DWORD numToRead);
static int async_write_file(struct async_io* aio, LPVOID buf, DWORD numToWrite);
@@ -96,7 +98,7 @@ static erts_smp_atomic_t pipe_creation_counter;
static int driver_write(long, HANDLE, byte*, int);
static int create_file_thread(struct async_io* aio, int mode);
#ifdef ERTS_SMP
-static void close_active_handle(ErlDrvPort, HANDLE handle);
+static void close_active_handle(DriverData *, HANDLE handle);
static DWORD WINAPI threaded_handle_closer(LPVOID param);
#endif
static DWORD WINAPI threaded_reader(LPVOID param);
@@ -440,6 +442,8 @@ typedef struct async_io {
DWORD bytesTransferred; /* Bytes read or write in the last operation.
* Valid only when DF_OVR_READY is set.
*/
+ DriverData *dp; /* Pointer to driver data struct which
+ this struct is part of */
} AsyncIo;
@@ -458,7 +462,7 @@ static BOOL (WINAPI *fpSetHandleInformation)(HANDLE,DWORD,DWORD);
* none of the file handles.
*/
-typedef struct driver_data {
+struct driver_data {
int totalNeeded; /* Total number of bytes needed to fill
* up the packet header or packet. */
int bytesInBuffer; /* Number of bytes read so far in
@@ -476,7 +480,8 @@ typedef struct driver_data {
AsyncIo in; /* Control block for overlapped reading. */
AsyncIo out; /* Control block for overlapped writing. */
int report_exit; /* Do report exit status for the port */
-} DriverData;
+ erts_atomic32_t refc; /* References to this struct */
+};
/* Driver interfaces */
static ErlDrvData spawn_start(ErlDrvPort, char*, SysDriverOpts*);
@@ -581,6 +586,26 @@ struct erl_drv_entry vanilla_driver_entry = {
stop_select
};
+static ERTS_INLINE void
+refer_driver_data(DriverData *dp)
+{
+#ifdef DEBUG
+ erts_aint32_t refc = erts_atomic32_inc_read_nob(&dp->refc);
+ ASSERT(refc > 1);
+#else
+ erts_atomic32_inc_nob(&dp->refc);
+#endif
+}
+
+static ERTS_INLINE void
+unrefer_driver_data(DriverData *dp)
+{
+ erts_aint32_t refc = erts_atomic32_dec_read_mb(&dp->refc);
+ ASSERT(refc >= 0);
+ if (refc == 0)
+ driver_free(dp);
+}
+
/*
* Initialises a DriverData structure.
*
@@ -604,6 +629,7 @@ new_driver_data(ErlDrvPort port_num, int packet_bytes, int wait_objs_required, i
* any more, since driver_select() can't fail.
*/
+ erts_atomic32_init_nob(&dp->refc, 1);
dp->bytesInBuffer = 0;
dp->totalNeeded = packet_bytes;
dp->inBufSize = PORT_BUFSIZ;
@@ -616,9 +642,9 @@ new_driver_data(ErlDrvPort port_num, int packet_bytes, int wait_objs_required, i
dp->port_num = port_num;
dp->packet_bytes = packet_bytes;
dp->port_pid = INVALID_HANDLE_VALUE;
- if (init_async_io(&dp->in, use_threads) == -1)
+ if (init_async_io(dp, &dp->in, use_threads) == -1)
goto async_io_error1;
- if (init_async_io(&dp->out, use_threads) == -1)
+ if (init_async_io(dp, &dp->out, use_threads) == -1)
goto async_io_error2;
return dp;
@@ -662,7 +688,7 @@ release_driver_data(DriverData* dp)
dp->in.fd = INVALID_HANDLE_VALUE;
DEBUGF(("Waiting for the in event thingie"));
if (WaitForSingleObject(dp->in.ov.hEvent,timeout) == WAIT_TIMEOUT) {
- close_active_handle(dp->port_num, dp->in.ov.hEvent);
+ close_active_handle(dp, dp->in.ov.hEvent);
dp->in.ov.hEvent = NULL;
timeout = 0;
}
@@ -673,7 +699,7 @@ release_driver_data(DriverData* dp)
dp->out.fd = INVALID_HANDLE_VALUE;
DEBUGF(("Waiting for the out event thingie"));
if (WaitForSingleObject(dp->out.ov.hEvent,timeout) == WAIT_TIMEOUT) {
- close_active_handle(dp->port_num, dp->out.ov.hEvent);
+ close_active_handle(dp, dp->out.ov.hEvent);
dp->out.ov.hEvent = NULL;
}
DEBUGF(("...done\n"));
@@ -719,7 +745,7 @@ release_driver_data(DriverData* dp)
* the exit thread.
*/
- driver_free(dp);
+ unrefer_driver_data(dp);
}
#ifdef ERTS_SMP
@@ -727,11 +753,12 @@ release_driver_data(DriverData* dp)
struct handles_to_be_closed {
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
unsigned cnt;
+ DriverData *dp;
};
static struct handles_to_be_closed* htbc_curr = NULL;
CRITICAL_SECTION htbc_lock;
-static void close_active_handle(ErlDrvPort port_num, HANDLE handle)
+static void close_active_handle(DriverData *dp, HANDLE handle)
{
struct handles_to_be_closed* htbc;
int i;
@@ -745,11 +772,14 @@ static void close_active_handle(ErlDrvPort port_num, HANDLE handle)
sizeof(*htbc));
htbc->handles[0] = CreateAutoEvent(FALSE);
htbc->cnt = 1;
+ htbc->dp = dp;
+ refer_driver_data(dp); /* Need to keep driver data until we have
+ closed the event; outstanding operation
+ might write into it.. */
thread = (HANDLE *) _beginthreadex(NULL, 0, threaded_handle_closer, htbc, 0, &tid);
CloseHandle(thread);
}
htbc->handles[htbc->cnt++] = handle;
- driver_select(port_num, (ErlDrvEvent)handle, ERL_DRV_USE_NO_CALLBACK, 0);
SetEvent(htbc->handles[0]);
htbc_curr = htbc;
LeaveCriticalSection(&htbc_lock);
@@ -798,6 +828,7 @@ threaded_handle_closer(LPVOID param)
}
LeaveCriticalSection(&htbc_lock);
CloseHandle(htbc->handles[0]);
+ unrefer_driver_data(htbc->dp);
erts_free(ERTS_ALC_T_DRV_TAB, htbc);
DEBUGF(("threaded_handle_closer %p terminating\r\n", htbc));
return 0;
@@ -864,8 +895,9 @@ reuse_driver_data(DriverData *dp, HANDLE ifd, HANDLE ofd, int read_write, ErlDrv
*/
static int
-init_async_io(AsyncIo* aio, int use_threads)
+init_async_io(DriverData *dp, AsyncIo* aio, int use_threads)
{
+ aio->dp = dp;
aio->flags = 0;
aio->thread = (HANDLE) -1;
aio->fd = INVALID_HANDLE_VALUE;
@@ -884,6 +916,8 @@ init_async_io(AsyncIo* aio, int use_threads)
if (aio->ov.hEvent == NULL)
return -1;
if (use_threads) {
+ OV_BUFFER_PTR(aio) = NULL;
+ OV_NUM_TO_READ(aio) = 0;
aio->ioAllowed = CreateAutoEvent(FALSE);
if (aio->ioAllowed == NULL)
return -1;
@@ -914,12 +948,8 @@ release_async_io(AsyncIo* aio, ErlDrvPort port_num)
CloseHandle(aio->fd);
aio->fd = INVALID_HANDLE_VALUE;
- if (aio->ov.hEvent != NULL) {
- (void) driver_select(port_num,
- (ErlDrvEvent)aio->ov.hEvent,
- ERL_DRV_USE, 0);
- /* was CloseHandle(aio->ov.hEvent); */
- }
+ if (aio->ov.hEvent != NULL)
+ CloseHandle(aio->ov.hEvent);
aio->ov.hEvent = NULL;
@@ -1260,9 +1290,9 @@ spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts)
retval = set_driver_data(dp, hFromChild, hToChild, opts->read_write,
opts->exit_status);
if (retval != ERL_DRV_ERROR_GENERAL && retval != ERL_DRV_ERROR_ERRNO) {
- Port *prt = erts_drvport2port_raw(port_num);
+ Port *prt = erts_drvport2port(port_num);
/* We assume that this cannot generate a negative number */
- ASSERT(prt);
+ ASSERT(prt != ERTS_INVALID_ERL_DRV_PORT);
prt->os_pid = (SWord) pid;
}
}
@@ -1287,12 +1317,15 @@ create_file_thread(AsyncIo* aio, int mode)
{
DWORD tid; /* Id for thread. */
+ refer_driver_data(aio->dp);
aio->thread = (HANDLE)
_beginthreadex(NULL, 0,
(mode & DO_WRITE) ? threaded_writer : threaded_reader,
aio, 0, &tid);
-
- return aio->thread != (HANDLE) -1;
+ if (aio->thread != (HANDLE) -1)
+ return 1;
+ unrefer_driver_data(aio->dp);
+ return 0;
}
/*
@@ -2078,6 +2111,7 @@ threaded_reader(LPVOID param)
if (aio->flags & DF_EXIT_THREAD)
break;
}
+ unrefer_driver_data(aio->dp);
return 0;
}
@@ -2157,6 +2191,7 @@ threaded_writer(LPVOID param)
}
CloseHandle(aio->fd);
aio->fd = INVALID_HANDLE_VALUE;
+ unrefer_driver_data(aio->dp);
return 0;
}
@@ -2297,6 +2332,7 @@ static void fd_stop(ErlDrvData data)
(void) driver_select(dp->port_num,
(ErlDrvEvent)dp->out.ov.hEvent,
ERL_DRV_WRITE, 0);
+ ASSERT(dp->out.flushEvent);
SetEvent(dp->out.flushEvent);
WaitForSingleObject(dp->out.flushReplyEvent, INFINITE);
}
@@ -2349,12 +2385,12 @@ stop(ErlDrvData data)
if (dp->in.ov.hEvent != NULL) {
(void) driver_select(dp->port_num,
(ErlDrvEvent)dp->in.ov.hEvent,
- ERL_DRV_READ, 0);
+ ERL_DRV_READ|ERL_DRV_USE_NO_CALLBACK, 0);
}
if (dp->out.ov.hEvent != NULL) {
(void) driver_select(dp->port_num,
(ErlDrvEvent)dp->out.ov.hEvent,
- ERL_DRV_WRITE, 0);
+ ERL_DRV_WRITE|ERL_DRV_USE_NO_CALLBACK, 0);
}
if (dp->out.thread == (HANDLE) -1 && dp->in.thread == (HANDLE) -1) {
@@ -2366,6 +2402,8 @@ stop(ErlDrvData data)
*/
HANDLE thread;
DWORD tid;
+
+ /* threaded_exiter implicitly takes over refc from us... */
thread = (HANDLE *) _beginthreadex(NULL, 0, threaded_exiter, dp, 0, &tid);
CloseHandle(thread);
}
diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl
index dae36fed8f..dfba7d098f 100644
--- a/erts/emulator/test/driver_SUITE.erl
+++ b/erts/emulator/test/driver_SUITE.erl
@@ -78,7 +78,8 @@
otp_9302/1,
thr_free_drv/1,
async_blast/1,
- thr_msg_blast/1]).
+ thr_msg_blast/1,
+ consume_timeslice/1]).
-export([bin_prefix/2]).
@@ -149,7 +150,8 @@ all() ->
otp_9302,
thr_free_drv,
async_blast,
- thr_msg_blast].
+ thr_msg_blast,
+ consume_timeslice].
groups() ->
[{timer, [],
@@ -2073,10 +2075,329 @@ thr_msg_blast(Config) when is_list(Config) ->
Res
end.
+consume_timeslice(Config) when is_list(Config) ->
+ %%
+ %% Verify that erl_drv_consume_timeslice() works.
+ %%
+ %% The first four cases expect that the command signal is
+ %% delivered immediately, i.e., isn't scheduled. Since there
+ %% are no conflicts these signals should normally be delivered
+ %% immediately. However some builds and configurations may
+ %% schedule these ops anyway, in these cases we do not verify
+ %% scheduling counts.
+ %%
+ %% When signal is delivered immediately we must take into account
+ %% that process and port are "virtualy" scheduled out and in
+ %% in the trace generated.
+ %%
+ %% Port ! {_, {command, _}, and port_command() differs. The send
+ %% instruction needs to check if the caller is out of reductions
+ %% at the end of the instruction, since no erlang function call
+ %% is involved. Otherwise, a sequence of send instructions would
+ %% not be scheduled out even when out of reductions. port_commond()
+ %% doesn't do that since it will always (since R16A) be called via
+ %% the erlang wrappers in the erlang module.
+ %%
+ %% The last two cases tests scheduled operations. We create
+ %% a conflict by executing at the same time on different
+ %% schedulers. When only one scheduler we enable parallelism on
+ %% the port instead.
+ %%
+
+ Path = ?config(data_dir, Config),
+ erl_ddll:start(),
+ ok = load_driver(Path, consume_timeslice_drv),
+ Port = open_port({spawn, consume_timeslice_drv}, [{parallelism, false}]),
+
+ Parent = self(),
+ Go = make_ref(),
+
+ "enabled" = port_control(Port, $E, ""),
+ Proc1 = spawn_link(fun () ->
+ receive Go -> ok end,
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}}
+ end),
+ receive after 100 -> ok end,
+ count_pp_sched_start(),
+ Proc1 ! Go,
+ wait_command_msgs(Port, 10),
+ [{Port, Sprt1}, {Proc1, Sproc1}] = count_pp_sched_stop([Port, Proc1]),
+ case Sprt1 of
+ 10 ->
+ true = in_range(5, Sproc1-10, 7);
+ _ ->
+ case erlang:system_info(lock_checking) of
+ true -> ?t:format("Ignore bad sched count due to lock checking", []);
+ false -> ?t:fail({unexpected_sched_counts, Sprt1, Sproc1})
+ end
+ end,
+
+ "disabled" = port_control(Port, $D, ""),
+ Proc2 = spawn_link(fun () ->
+ receive Go -> ok end,
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}},
+ Port ! {Parent, {command, ""}}
+ end),
+ receive after 100 -> ok end,
+ count_pp_sched_start(),
+ Proc2 ! Go,
+ wait_command_msgs(Port, 10),
+ [{Port, Sprt2}, {Proc2, Sproc2}] = count_pp_sched_stop([Port, Proc2]),
+ case Sprt2 of
+ 10 ->
+ true = in_range(1, Sproc2-10, 2);
+ _ ->
+ case erlang:system_info(lock_checking) of
+ true -> ?t:format("Ignore bad sched count due to lock checking", []);
+ false -> ?t:fail({unexpected_sched_counts, Sprt2, Sproc2})
+ end
+ end,
+
+ "enabled" = port_control(Port, $E, ""),
+ Proc3 = spawn_link(fun () ->
+ receive Go -> ok end,
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, "")
+ end),
+ count_pp_sched_start(),
+ Proc3 ! Go,
+ wait_command_msgs(Port, 10),
+ [{Port, Sprt3}, {Proc3, Sproc3}] = count_pp_sched_stop([Port, Proc3]),
+ case Sprt3 of
+ 10 ->
+ true = in_range(5, Sproc3-10, 7);
+ _ ->
+ case erlang:system_info(lock_checking) of
+ true -> ?t:format("Ignore bad sched count due to lock checking", []);
+ false -> ?t:fail({unexpected_sched_counts, Sprt3, Sproc3})
+ end
+ end,
+
+ "disabled" = port_control(Port, $D, ""),
+ Proc4 = spawn_link(fun () ->
+ receive Go -> ok end,
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, ""),
+ port_command(Port, "")
+ end),
+ count_pp_sched_start(),
+ Proc4 ! Go,
+ wait_command_msgs(Port, 10),
+ [{Port, Sprt4}, {Proc4, Sproc4}] = count_pp_sched_stop([Port, Proc4]),
+ case Sprt4 of
+ 10 ->
+ true = in_range(1, Sproc4-10, 2);
+ _ ->
+ case erlang:system_info(lock_checking) of
+ true -> ?t:format("Ignore bad sched count due to lock checking", []);
+ false -> ?t:fail({unexpected_sched_counts, Sprt4, Sproc4})
+ end
+ end,
+
+ SOnl = erlang:system_info(schedulers_online),
+ %% If only one scheduler use port with parallelism set to true,
+ %% in order to trigger scheduling of command signals
+ Port2 = case SOnl of
+ 1 ->
+ Port ! {self(), close},
+ receive {Port, closed} -> ok end,
+ open_port({spawn, consume_timeslice_drv},
+ [{parallelism, true}]);
+ _ ->
+ process_flag(scheduler, 1),
+ 1 = erlang:system_info(scheduler_id),
+ Port
+ end,
+ count_pp_sched_start(),
+ "enabled" = port_control(Port2, $E, ""),
+ W5 = case SOnl of
+ 1 ->
+ false;
+ _ ->
+ W1= spawn_opt(fun () ->
+ 2 = erlang:system_info(scheduler_id),
+ "sleeped" = port_control(Port2, $S, "")
+ end, [link,{scheduler,2}]),
+ receive after 100 -> ok end,
+ W1
+ end,
+ Proc5 = spawn_opt(fun () ->
+ receive Go -> ok end,
+ 1 = erlang:system_info(scheduler_id),
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}}
+ end, [link,{scheduler,1}]),
+ receive after 100 -> ok end,
+ Proc5 ! Go,
+ wait_procs_exit([W5, Proc5]),
+ wait_command_msgs(Port2, 10),
+ [{Port2, Sprt5}, {Proc5, Sproc5}] = count_pp_sched_stop([Port2, Proc5]),
+ true = in_range(2, Sproc5, 3),
+ true = in_range(7, Sprt5, 20),
+
+ count_pp_sched_start(),
+ "disabled" = port_control(Port2, $D, ""),
+ W6 = case SOnl of
+ 1 ->
+ false;
+ _ ->
+ W2= spawn_opt(fun () ->
+ 2 = erlang:system_info(scheduler_id),
+ "sleeped" = port_control(Port2, $S, "")
+ end, [link,{scheduler,2}]),
+ receive after 100 -> ok end,
+ W2
+ end,
+ Proc6 = spawn_opt(fun () ->
+ receive Go -> ok end,
+ 1 = erlang:system_info(scheduler_id),
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}},
+ Port2 ! {Parent, {command, ""}}
+ end, [link,{scheduler,1}]),
+ receive after 100 -> ok end,
+ Proc6 ! Go,
+ wait_procs_exit([W6, Proc6]),
+ wait_command_msgs(Port2, 10),
+ [{Port2, Sprt6}, {Proc6, Sproc6}] = count_pp_sched_stop([Port2, Proc6]),
+ true = in_range(2, Sproc6, 3),
+ true = in_range(3, Sprt6, 6),
+
+ process_flag(scheduler, 0),
+
+ Port2 ! {self(), close},
+ receive {Port2, closed} -> ok end,
+ ok.
+
+wait_command_msgs(_, 0) ->
+ ok;
+wait_command_msgs(Port, N) ->
+ receive
+ {Port, command} ->
+ wait_command_msgs(Port, N-1)
+ end.
+
+in_range(Low, Val, High) when is_integer(Low),
+ is_integer(Val),
+ is_integer(High),
+ Low =< Val,
+ Val =< High ->
+ true;
+in_range(Low, Val, High) when is_integer(Low),
+ is_integer(Val),
+ is_integer(High) ->
+ false.
+
+count_pp_sched_start() ->
+ erlang:trace(all, true, [running_procs, running_ports, {tracer, self()}]),
+ ok.
+
+count_pp_sched_stop(Ps) ->
+ Td = erlang:trace_delivered(all),
+ erlang:trace(all, false, [running_procs, running_ports, {tracer, self()}]),
+ PNs = lists:map(fun (P) -> {P, 0} end, Ps),
+ receive {trace_delivered, all, Td} -> ok end,
+ Res = count_proc_sched(Ps, PNs),
+ ?t:format("Scheduling counts: ~p~n", [Res]),
+ erlang:display({scheduling_counts, Res}),
+ Res.
+
+do_inc_pn(_P, []) ->
+ throw(undefined);
+do_inc_pn(P, [{P,N}|PNs]) ->
+ [{P,N+1}|PNs];
+do_inc_pn(P, [PN|PNs]) ->
+ [PN|do_inc_pn(P, PNs)].
+
+inc_pn(P, PNs) ->
+ try
+ do_inc_pn(P, PNs)
+ catch
+ throw:undefined -> PNs
+ end.
+
+count_proc_sched(Ps, PNs) ->
+ receive
+ TT when element(1, TT) == trace, element(3, TT) == in ->
+% erlang:display(TT),
+ count_proc_sched(Ps, inc_pn(element(2, TT), PNs));
+ TT when element(1, TT) == trace, element(3, TT) == out ->
+ count_proc_sched(Ps, PNs)
+ after 0 ->
+ PNs
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Utilities
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%flush_msgs() ->
+% receive
+% M ->
+% erlang:display(M),
+% flush_msgs()
+% after 0 ->
+% ok
+% end.
+
+wait_procs_exit([]) ->
+ ok;
+wait_procs_exit([P|Ps]) when is_pid(P) ->
+ Mon = erlang:monitor(process, P),
+ receive
+ {'DOWN', Mon, process, P, _} ->
+ wait_procs_exit(Ps)
+ end;
+wait_procs_exit([_|Ps]) ->
+ wait_procs_exit(Ps).
+
get_port_msg(Port, Timeout) ->
receive
{Port, What} ->
diff --git a/erts/emulator/test/driver_SUITE_data/Makefile.src b/erts/emulator/test/driver_SUITE_data/Makefile.src
index b667dff6b6..1fedd72200 100644
--- a/erts/emulator/test/driver_SUITE_data/Makefile.src
+++ b/erts/emulator/test/driver_SUITE_data/Makefile.src
@@ -15,7 +15,8 @@ MISC_DRVS = outputv_drv@dll@ \
otp_9302_drv@dll@ \
thr_free_drv@dll@ \
async_blast_drv@dll@ \
- thr_msg_blast_drv@dll@
+ thr_msg_blast_drv@dll@ \
+ consume_timeslice_drv@dll@
SYS_INFO_DRVS = sys_info_base_drv@dll@ \
sys_info_prev_drv@dll@ \
diff --git a/erts/emulator/test/driver_SUITE_data/consume_timeslice_drv.c b/erts/emulator/test/driver_SUITE_data/consume_timeslice_drv.c
new file mode 100644
index 0000000000..6b0c4cf37d
--- /dev/null
+++ b/erts/emulator/test/driver_SUITE_data/consume_timeslice_drv.c
@@ -0,0 +1,172 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2012. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include "erl_driver.h"
+#ifdef __WIN32__
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+
+static void stop(ErlDrvData drv_data);
+static ErlDrvData start(ErlDrvPort port,
+ char *command);
+static void output(ErlDrvData drv_data,
+ char *buf, ErlDrvSizeT len);
+static ErlDrvSSizeT control(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen);
+
+static ErlDrvEntry consume_timeslice_drv_entry = {
+ NULL /* init */,
+ start,
+ stop,
+ output,
+ NULL /* ready_input */,
+ NULL /* ready_output */,
+ "consume_timeslice_drv",
+ NULL /* finish */,
+ NULL /* handle */,
+ control,
+ 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,
+ ERL_DRV_FLAG_USE_PORT_LOCKING,
+ NULL /* handle2 */,
+ NULL /* handle_monitor */
+};
+
+typedef struct {
+ ErlDrvPort port;
+ ErlDrvTermData tport;
+ ErlDrvTermData cmd_msg[6];
+ int consume_timeslice;
+} consume_timeslice_data_t;
+
+
+DRIVER_INIT(consume_timeslice_drv)
+{
+ return &consume_timeslice_drv_entry;
+}
+
+static void stop(ErlDrvData drv_data)
+{
+ driver_free((void *) drv_data);
+}
+
+static ErlDrvData start(ErlDrvPort port,
+ char *command)
+{
+ consume_timeslice_data_t *ctsd;
+
+ ctsd = driver_alloc(sizeof(consume_timeslice_data_t));
+ if (!ctsd)
+ return ERL_DRV_ERROR_GENERAL;
+
+ ctsd->port = port;
+ ctsd->tport = driver_mk_port(port);
+ ctsd->consume_timeslice = 0;
+
+ ctsd->cmd_msg[0] = ERL_DRV_PORT;
+ ctsd->cmd_msg[1] = ctsd->tport;
+ ctsd->cmd_msg[2] = ERL_DRV_ATOM;
+ ctsd->cmd_msg[3] = driver_mk_atom("command");
+ ctsd->cmd_msg[4] = ERL_DRV_TUPLE;
+ ctsd->cmd_msg[5] = (ErlDrvTermData) 2;
+
+ return (ErlDrvData) ctsd;
+}
+
+static void output(ErlDrvData drv_data,
+ char *buf, ErlDrvSizeT len)
+{
+ consume_timeslice_data_t *ctsd = (consume_timeslice_data_t *) drv_data;
+ int res;
+
+ if (ctsd->consume_timeslice) {
+ int res = erl_drv_consume_timeslice(ctsd->port, 50);
+ if (res < 0) {
+ driver_failure_atom(ctsd->port, "erl_drv_consume_timeslice() failed");
+ return;
+ }
+ }
+
+ res = erl_drv_output_term(ctsd->tport,
+ ctsd->cmd_msg,
+ sizeof(ctsd->cmd_msg)/sizeof(ErlDrvTermData));
+ if (res <= 0) {
+ driver_failure_atom(ctsd->port, "erl_drv_output_term() failed");
+ return;
+ }
+}
+static ErlDrvSSizeT control(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen)
+{
+ consume_timeslice_data_t *ctsd = (consume_timeslice_data_t *) drv_data;
+ int res;
+ char *res_str;
+ ErlDrvSSizeT res_len;
+
+ switch (command) {
+ case 'E':
+ ctsd->consume_timeslice = 1;
+ res_str = "enabled";
+ break;
+ case 'D':
+ ctsd->consume_timeslice = 0;
+ res_str = "disabled";
+ break;
+ case 'S':
+#ifdef __WIN32__
+ Sleep((DWORD) 1000);
+#else
+ sleep(1);
+#endif
+ res_str = "sleeped";
+ break;
+ default:
+ res_str = "what?";
+ break;
+ }
+
+ res_len = strlen(res_str);
+ if (res_len > rlen) {
+ char *abuf = driver_alloc(sizeof(char)*res_len);
+ if (!abuf) {
+ driver_failure_atom(ctsd->port, "driver_alloc() failed");
+ return 0;
+ }
+ *rbuf = abuf;
+ }
+
+ memcpy((void *) *rbuf, (void *) res_str, res_len);
+
+ return res_len;
+}
diff --git a/erts/emulator/test/hash_SUITE.erl b/erts/emulator/test/hash_SUITE.erl
index 830ed91da9..898eae8c15 100644
--- a/erts/emulator/test/hash_SUITE.erl
+++ b/erts/emulator/test/hash_SUITE.erl
@@ -75,7 +75,7 @@ config(priv_dir,_) ->
test_phash2/1,otp_5292/1,bit_level_binaries/1,otp_7127/1,
end_per_testcase/2,init_per_testcase/2]).
init_per_testcase(_Case, Config) ->
- ?line Dog=test_server:timetrap(test_server:minutes(10)),
+ Dog=test_server:timetrap(test_server:minutes(10)),
[{watchdog, Dog}|Config].
end_per_testcase(_Case, Config) ->
@@ -169,24 +169,24 @@ otp_7127(Config) when is_list(Config) ->
%% define -DSTANDALONE when compiling.
%%
basic_test() ->
- ?line 685556714 = erlang:phash({a,b,c},16#FFFFFFFF),
- ?line 14468079 = erlang:hash({a,b,c},16#7FFFFFF),
- ?line 37442646 = erlang:phash([a,b,c,{1,2,3},c:pid(0,2,3),
+ 685556714 = erlang:phash({a,b,c},16#FFFFFFFF),
+ 14468079 = erlang:hash({a,b,c},16#7FFFFFF),
+ 37442646 = erlang:phash([a,b,c,{1,2,3},c:pid(0,2,3),
16#77777777777777],16#FFFFFFFF),
- ?line Comment = case erlang:hash([a,b,c,{1,2,3},c:pid(0,2,3),
+ Comment = case erlang:hash([a,b,c,{1,2,3},c:pid(0,2,3),
16#77777777777777],16#7FFFFFF) of
102727602 ->
- ?line big = erlang:system_info(endian),
+ big = erlang:system_info(endian),
"Big endian machine";
105818829 ->
- ?line little = erlang:system_info(endian),
+ little = erlang:system_info(endian),
"Little endian machine"
end,
ExternalReference = <<131,114,0,3,100,0,13,110,111,110,111,100,101,64,
110,111,104,111,115,116,0,0,0,0,122,0,0,0,0,0,0,0,0>>,
- ?line 1113403635 = erlang:phash(binary_to_term(ExternalReference),
+ 1113403635 = erlang:phash(binary_to_term(ExternalReference),
16#FFFFFFFF),
- ?line 123 = erlang:hash(binary_to_term(ExternalReference),
+ 123 = erlang:hash(binary_to_term(ExternalReference),
16#7FFFFFF),
ExternalFun = <<131,117,0,0,0,3,103,100,0,13,110,111,110,111,100,101,64,
110,111,104,111,115,116,0,0,0,38,0,0,0,0,0,100,0,8,101,
@@ -204,9 +204,9 @@ basic_test() ->
104,101,108,108,100,0,10,108,111,99,97,108,95,102,117,
110,99,108,0,0,0,1,103,100,0,13,110,111,110,111,100,101,
64,110,111,104,111,115,116,0,0,0,22,0,0,0,0,0,106>>,
- ?line 170987488 = erlang:phash(binary_to_term(ExternalFun),
+ 170987488 = erlang:phash(binary_to_term(ExternalFun),
16#FFFFFFFF),
- ?line 124460689 = erlang:hash(binary_to_term(ExternalFun),
+ 124460689 = erlang:hash(binary_to_term(ExternalFun),
16#7FFFFFF),
case (catch erlang:phash(1,0)) of
{'EXIT',{badarg, _}} ->
@@ -237,23 +237,23 @@ range_test() ->
spread_test(N) ->
- ?line test_fun(N,{erlang,phash},16#50000000000,fun(X) ->
+ test_fun(N,{erlang,phash},16#50000000000,fun(X) ->
X
end),
- ?line test_fun(N,{erlang,phash},0,fun(X) ->
+ test_fun(N,{erlang,phash},0,fun(X) ->
X
end),
- ?line test_fun(N,{erlang,phash},16#123456789ABCDEF123456789ABCDEF,fun(X) ->
+ test_fun(N,{erlang,phash},16#123456789ABCDEF123456789ABCDEF,fun(X) ->
X
end),
- ?line test_fun(N,{erlang,phash},16#50000000000,fun(X) ->
+ test_fun(N,{erlang,phash},16#50000000000,fun(X) ->
integer_to_list(X)
end),
- ?line test_fun(N,{erlang,phash},16#50000000000,fun(X) ->
+ test_fun(N,{erlang,phash},16#50000000000,fun(X) ->
integer_to_bytelist(X,[])
end),
- ?line test_fun(N,{erlang,phash},16#50000000000,fun(X) ->
- integer_to_binary(X)
+ test_fun(N,{erlang,phash},16#50000000000,fun(X) ->
+ integer_to_binary_value(X)
end).
@@ -265,14 +265,14 @@ cmp_test(N) ->
do_cmp_hashes(0,_) ->
ok;
do_cmp_hashes(N,Steps) ->
- ?line R0 = random:uniform(1 bsl Steps - 1) + random:uniform(16#FFFFFFFF),
- ?line R = case random:uniform(2) of
+ R0 = random:uniform(1 bsl Steps - 1) + random:uniform(16#FFFFFFFF),
+ R = case random:uniform(2) of
1 ->
R0;
_ ->
-R0
end,
- ?line NSteps = case N rem 10 of
+ NSteps = case N rem 10 of
0 ->
case (Steps + 8) rem 1024 of
0 ->
@@ -283,9 +283,9 @@ do_cmp_hashes(N,Steps) ->
_ ->
Steps
end,
- ?line X = erlang:phash(R,16#FFFFFFFF),
- ?line Y = make_hash(R,16#FFFFFFFF),
- ?line case X =:= Y of
+ X = erlang:phash(R,16#FFFFFFFF),
+ Y = make_hash(R,16#FFFFFFFF),
+ case X =:= Y of
true ->
do_cmp_hashes(N - 1, NSteps);
_ ->
@@ -469,8 +469,8 @@ phash2_test() ->
SpecFun = fun(S) -> sofs:no_elements(S) > 1 end,
F = sofs:relation_to_family(sofs:converse(sofs:relation(L))),
D = sofs:to_external(sofs:family_specification(SpecFun, F)),
- ?line [] = D,
- ?line [] = [{E,H,H2} || {E,H} <- L, (H2 = erlang:phash2(E, Max)) =/= H],
+ [] = D,
+ [] = [{E,H,H2} || {E,H} <- L, (H2 = erlang:phash2(E, Max)) =/= H],
ok.
-ifdef(FALSE).
@@ -497,17 +497,17 @@ otp_5292_test() ->
end,
S2 = md5([md5(hash_int(S, E, PH)) || {Start, N, Sz} <- d(),
{S, E} <- int(Start, N, Sz)]),
- ?line Comment = case S1 of
+ Comment = case S1 of
<<4,248,208,156,200,131,7,1,173,13,239,173,112,81,16,174>> ->
- ?line big = erlang:system_info(endian),
+ big = erlang:system_info(endian),
"Big endian machine";
<<180,28,33,231,239,184,71,125,76,47,227,241,78,184,176,233>> ->
- ?line little = erlang:system_info(endian),
+ little = erlang:system_info(endian),
"Little endian machine"
end,
- ?line <<124,81,198,121,174,233,19,137,10,83,33,80,226,111,238,99>> = S2,
- ?line 2 = erlang:hash(1, (1 bsl 27) -1),
- ?line {'EXIT', _} = (catch erlang:hash(1, (1 bsl 27))),
+ <<124,81,198,121,174,233,19,137,10,83,33,80,226,111,238,99>> = S2,
+ 2 = erlang:hash(1, (1 bsl 27) -1),
+ {'EXIT', _} = (catch erlang:hash(1, (1 bsl 27))),
{comment, Comment}.
d() ->
@@ -528,21 +528,21 @@ md5(T) ->
erlang:md5(term_to_binary(T)).
bit_level_binaries() ->
- ?line [3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] =
+ [3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] =
bit_level_all_different(fun erlang:hash/2),
- ?line [3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] =
+ [3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] =
bit_level_all_different(fun erlang:phash/2),
- ?line [102233154,19716,102133857,4532024,123369135,24565730,109558721|_] =
+ [102233154,19716,102133857,4532024,123369135,24565730,109558721|_] =
bit_level_all_different(fun erlang:phash2/2),
- ?line 13233341 = test_hash_phash(<<42:7>>, 16#7FFFFFF),
- ?line 79121243 = test_hash_phash(<<99:7>>, 16#7FFFFFF),
- ?line 95517726 = test_hash_phash(<<16#378ABF73:31>>, 16#7FFFFFF),
+ 13233341 = test_hash_phash(<<42:7>>, 16#7FFFFFF),
+ 79121243 = test_hash_phash(<<99:7>>, 16#7FFFFFF),
+ 95517726 = test_hash_phash(<<16#378ABF73:31>>, 16#7FFFFFF),
- ?line 64409098 = test_phash2(<<99:7>>, 16#7FFFFFF),
- ?line 55555814 = test_phash2(<<123,19:2>>, 16#7FFFFFF),
- ?line 83868582 = test_phash2(<<123,45,6:3>>, 16#7FFFFFF),
- ?line 2123204 = test_phash2(<<123,45,7:3>>, 16#7FFFFFF),
+ 64409098 = test_phash2(<<99:7>>, 16#7FFFFFF),
+ 55555814 = test_phash2(<<123,19:2>>, 16#7FFFFFF),
+ 83868582 = test_phash2(<<123,45,6:3>>, 16#7FFFFFF),
+ 2123204 = test_phash2(<<123,45,7:3>>, 16#7FFFFFF),
ok.
@@ -579,7 +579,7 @@ test_phash2(Bitstr, Rem) ->
otp_7127_test() ->
%% Used to return 2589127136.
- ?line 38990304 = erlang:phash2(<<"Scott9">>),
+ 38990304 = erlang:phash2(<<"Scott9">>),
ok.
%%
@@ -711,7 +711,7 @@ collect_hits() ->
init_table(),
N.
-integer_to_binary(N) ->
+integer_to_binary_value(N) ->
list_to_binary(lists:reverse(integer_to_bytelist(N,[]))).
integer_to_bytelist(0,Acc) ->
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 6bd7361612..0a9d997c3b 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -36,7 +36,7 @@
threading/1, send/1, send2/1, send3/1, send_threaded/1, neg/1,
is_checks/1,
get_length/1, make_atom/1, make_string/1, reverse_list_test/1,
- otp_9668/1
+ otp_9668/1, consume_timeslice/1
]).
-export([many_args_100/100]).
@@ -63,7 +63,7 @@ all() ->
resource_takeover, threading, send, send2, send3,
send_threaded, neg, is_checks, get_length, make_atom,
make_string,reverse_list_test,
- otp_9668
+ otp_9668, consume_timeslice
].
groups() ->
@@ -1259,6 +1259,108 @@ otp_9668(Config) ->
?line verify_tmpmem(TmpMem),
ok.
+consume_timeslice(Config) when is_list(Config) ->
+ CONTEXT_REDS = 2000,
+ Me = self(),
+ Go = make_ref(),
+ RedDiff = make_ref(),
+ Done = make_ref(),
+ DummyMFA = {?MODULE,dummy_call,1},
+ P = spawn(fun () ->
+ receive Go -> ok end,
+ {reductions, R1} = process_info(self(), reductions),
+ 1 = consume_timeslice_nif(100, false),
+ dummy_call(111),
+ 0 = consume_timeslice_nif(90, false),
+ dummy_call(222),
+ 1 = consume_timeslice_nif(10, false),
+ dummy_call(333),
+ 0 = consume_timeslice_nif(25, false),
+ 0 = consume_timeslice_nif(25, false),
+ 0 = consume_timeslice_nif(25, false),
+ 1 = consume_timeslice_nif(25, false),
+ 0 = consume_timeslice_nif(25, false),
+
+ ok = case consume_timeslice_nif(1, true) of
+ Cnt when Cnt > 70, Cnt < 80 -> ok;
+ Other -> Other
+ end,
+ dummy_call(444),
+
+ {reductions, R2} = process_info(self(), reductions),
+ Me ! {RedDiff, R2 - R1},
+ exit(Done)
+ end),
+ erlang:yield(),
+
+ erlang:trace_pattern(DummyMFA, [], [local]),
+ ?line 1 = erlang:trace(P, true, [call, running, procs, {tracer, self()}]),
+
+ P ! Go,
+
+ %% receive Go -> ok end,
+ ?line {trace, P, in, _} = next_tmsg(P),
+
+ %% consume_timeslice_nif(100),
+ %% dummy_call(111)
+ ?line {trace, P, out, _} = next_tmsg(P),
+ ?line {trace, P, in, _} = next_tmsg(P),
+ ?line {trace, P, call, {?MODULE,dummy_call,[111]}} = next_tmsg(P),
+
+ %% consume_timeslice_nif(90),
+ %% dummy_call(222)
+ ?line {trace, P, call, {?MODULE,dummy_call,[222]}} = next_tmsg(P),
+
+ %% consume_timeslice_nif(10),
+ %% dummy_call(333)
+ ?line {trace, P, out, _} = next_tmsg(P),
+ ?line {trace, P, in, _} = next_tmsg(P),
+ ?line {trace, P, call, {?MODULE,dummy_call,[333]}} = next_tmsg(P),
+
+ %% 25,25,25,25, 25
+ ?line {trace, P, out, {?MODULE,consume_timeslice_nif,2}} = next_tmsg(P),
+ ?line {trace, P, in, {?MODULE,consume_timeslice_nif,2}} = next_tmsg(P),
+
+ %% consume_timeslice(1,true)
+ %% dummy_call(444)
+ ?line {trace, P, out, DummyMFA} = next_tmsg(P),
+ ?line {trace, P, in, DummyMFA} = next_tmsg(P),
+ ?line {trace, P, call, {?MODULE,dummy_call,[444]}} = next_tmsg(P),
+
+ %% exit(Done)
+ ?line {trace, P, exit, Done} = next_tmsg(P),
+
+ ExpReds = (100 + 90 + 10 + 25*5 + 75) * CONTEXT_REDS div 100,
+ receive
+ {RedDiff, Reductions} when Reductions < (ExpReds + 10), Reductions > (ExpReds - 10) ->
+ io:format("Reductions = ~p~n", [Reductions]),
+ ok;
+ {RedDiff, Reductions} ->
+ ?t:fail({unexpected_reduction_count, Reductions})
+ end,
+
+ none = next_msg(P),
+
+ ok.
+
+next_msg(Pid) ->
+ receive
+ M -> M
+ after 100 ->
+ none
+ end.
+
+next_tmsg(Pid) ->
+ receive TMsg when is_tuple(TMsg),
+ element(1, TMsg) == trace,
+ element(2, TMsg) == Pid ->
+ TMsg
+ after 100 ->
+ none
+ end.
+
+dummy_call(_) ->
+ ok.
tmpmem() ->
case erlang:system_info({allocator,temp_alloc}) of
@@ -1370,6 +1472,7 @@ reverse_list(_) -> ?nif_stub.
echo_int(_) -> ?nif_stub.
type_sizes() -> ?nif_stub.
otp_9668_nif(_) -> ?nif_stub.
+consume_timeslice_nif(_,_) -> ?nif_stub.
nif_stub_error(Line) ->
exit({nif_not_loaded,module,?MODULE,line,Line}).
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index 03092fef5e..2504d24b51 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -1456,6 +1456,27 @@ static ERL_NIF_TERM otp_9668_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
return atom_ok;
}
+static ERL_NIF_TERM consume_timeslice_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int percent;
+ char atom[10];
+ int do_repeat;
+
+ if (!enif_get_int(env, argv[0], &percent) ||
+ !enif_get_atom(env, argv[1], atom, sizeof(atom), ERL_NIF_LATIN1)) {
+ return enif_make_badarg(env);
+ }
+ if (strcmp(atom , "true") == 0) {
+ int cnt = 1;
+ while (enif_consume_timeslice(env, percent) == 0 && cnt < 200)
+ cnt++;
+ return enif_make_int(env, cnt);
+ }
+ else {
+ return enif_make_int(env, enif_consume_timeslice(env, percent));
+ }
+}
+
static ErlNifFunc nif_funcs[] =
{
{"lib_version", 0, lib_version},
@@ -1504,7 +1525,8 @@ static ErlNifFunc nif_funcs[] =
{"reverse_list",1, reverse_list},
{"echo_int", 1, echo_int},
{"type_sizes", 0, type_sizes},
- {"otp_9668_nif", 1, otp_9668_nif}
+ {"otp_9668_nif", 1, otp_9668_nif},
+ {"consume_timeslice_nif", 2, consume_timeslice_nif}
};
ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload)
diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl
index bf33c337ee..b92a0e2059 100644
--- a/erts/emulator/test/num_bif_SUITE.erl
+++ b/erts/emulator/test/num_bif_SUITE.erl
@@ -31,24 +31,28 @@
%% list_to_integer/1
%% round/1
%% trunc/1
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2, t_abs/1, t_float/1,
- t_float_to_list/1, t_integer_to_list/1,
- t_list_to_integer/1,
- t_list_to_float_safe/1, t_list_to_float_risky/1,
- t_round/1, t_trunc/1]).
+%% integer_to_binary/1
+%% integer_to_binary/2
+%% binary_to_integer/1
+
+-export([all/0, suite/0, groups/0, init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2, t_abs/1, t_float/1,
+ t_float_to_string/1, t_integer_to_string/1,
+ t_string_to_integer/1,
+ t_string_to_float_safe/1, t_string_to_float_risky/1,
+ t_round/1, t_trunc/1
+ ]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [t_abs, t_float, t_float_to_list, t_integer_to_list,
- {group, t_list_to_float}, t_list_to_integer, t_round,
+ [t_abs, t_float, t_float_to_string, t_integer_to_string,
+ {group, t_string_to_float}, t_string_to_integer, t_round,
t_trunc].
groups() ->
- [{t_list_to_float, [],
- [t_list_to_float_safe, t_list_to_float_risky]}].
+ [{t_string_to_float, [],
+ [t_string_to_float_safe, t_string_to_float_risky]}].
init_per_suite(Config) ->
Config.
@@ -65,257 +69,382 @@ end_per_group(_GroupName, Config) ->
t_abs(Config) when is_list(Config) ->
%% Floats.
- ?line 5.5 = abs(id(5.5)),
- ?line 0.0 = abs(id(0.0)),
- ?line 100.0 = abs(id(-100.0)),
+ 5.5 = abs(id(5.5)),
+ 0.0 = abs(id(0.0)),
+ 100.0 = abs(id(-100.0)),
%% Integers.
- ?line 5 = abs(id(5)),
- ?line 0 = abs(id(0)),
- ?line 100 = abs(id(-100)),
+ 5 = abs(id(5)),
+ 0 = abs(id(0)),
+ 100 = abs(id(-100)),
%% The largest smallnum. OTP-3190.
- ?line X = id((1 bsl 27) - 1),
- ?line X = abs(X),
- ?line X = abs(X-1)+1,
- ?line X = abs(X+1)-1,
- ?line X = abs(-X),
- ?line X = abs(-X-1)-1,
- ?line X = abs(-X+1)+1,
+ X = id((1 bsl 27) - 1),
+ X = abs(X),
+ X = abs(X-1)+1,
+ X = abs(X+1)-1,
+ X = abs(-X),
+ X = abs(-X-1)-1,
+ X = abs(-X+1)+1,
%% Bignums.
BigNum = id(13984792374983749),
- ?line BigNum = abs(BigNum),
- ?line BigNum = abs(-BigNum),
+ BigNum = abs(BigNum),
+ BigNum = abs(-BigNum),
ok.
t_float(Config) when is_list(Config) ->
- ?line 0.0 = float(id(0)),
- ?line 2.5 = float(id(2.5)),
- ?line 0.0 = float(id(0.0)),
- ?line -100.55 = float(id(-100.55)),
- ?line 42.0 = float(id(42)),
- ?line -100.0 = float(id(-100)),
+ 0.0 = float(id(0)),
+ 2.5 = float(id(2.5)),
+ 0.0 = float(id(0.0)),
+ -100.55 = float(id(-100.55)),
+ 42.0 = float(id(42)),
+ -100.0 = float(id(-100)),
%% Bignums.
- ?line 4294967305.0 = float(id(4294967305)),
- ?line -4294967305.0 = float(id(-4294967305)),
+ 4294967305.0 = float(id(4294967305)),
+ -4294967305.0 = float(id(-4294967305)),
%% Extremly big bignums.
- ?line Big = id(list_to_integer(id(lists:duplicate(2000, $1)))),
- ?line {'EXIT', {badarg, _}} = (catch float(Big)),
-
- %% Invalid types and lists.
- ?line {'EXIT', {badarg, _}} = (catch list_to_integer(id(atom))),
- ?line {'EXIT', {badarg, _}} = (catch list_to_integer(id(123))),
- ?line {'EXIT', {badarg, _}} = (catch list_to_integer(id([$1,[$2]]))),
- ?line {'EXIT', {badarg, _}} = (catch list_to_integer(id("1.2"))),
- ?line {'EXIT', {badarg, _}} = (catch list_to_integer(id("a"))),
- ?line {'EXIT', {badarg, _}} = (catch list_to_integer(id(""))),
+ Big = id(list_to_integer(id(lists:duplicate(2000, $1)))),
+ {'EXIT', {badarg, _}} = (catch float(Big)),
+
ok.
-%% Tests float_to_list/1, float_to_list/2.
-
-t_float_to_list(Config) when is_list(Config) ->
- test_ftl("0.0e+0", 0.0),
- test_ftl("2.5e+1", 25.0),
- test_ftl("2.5e+0", 2.5),
- test_ftl("2.5e-1", 0.25),
- test_ftl("-3.5e+17", -350.0e15),
- "1.00000000000000000000e+00" = float_to_list(1.0),
- "1.00000000000000000000e+00" = float_to_list(1.0, []),
- "-1.00000000000000000000e+00" = float_to_list(-1.0, []),
- "-1.00000000000000000000" = float_to_list(-1.0, [{decimals, 20}]),
- {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{decimals, -1}])),
- {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{decimals, 250}])),
- {'EXIT', {badarg, _}} = (catch float_to_list(1.0e+300, [{decimals, 1}])),
- "1.0e+300" = float_to_list(1.0e+300, [{scientific, 1}]),
- "1.0" = float_to_list(1.0, [{decimals, 249}, compact]),
- Expected = "1." ++ string:copies("0", 249) ++ "e+00",
- Expected = float_to_list(1.0, [{scientific, 249}, compact]),
+%% Tests float_to_list/1, float_to_list/2, float_to_binary/1, float_to_binary/2
+
+t_float_to_string(Config) when is_list(Config) ->
+ test_fts("0.00000000000000000000e+00", 0.0),
+ test_fts("2.50000000000000000000e+01", 25.0),
+ test_fts("2.50000000000000000000e+00", 2.5),
+ test_fts("2.50000000000000000000e-01", 0.25),
+ test_fts("-3.50000000000000000000e+17", -350.0e15),
+ test_fts("1.00000000000000000000e+00",1.0),
+ test_fts("1.00000000000000000000e+00",1.0, []),
+ test_fts("-1.00000000000000000000e+00",-1.0, []),
+ test_fts("-1.00000000000000000000",-1.0, [{decimals, 20}]),
+ {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{decimals, -1}])),
+ {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{decimals, 254}])),
+ {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{scientific, 250}])),
+ {'EXIT', {badarg, _}} = (catch float_to_list(1.0e+300, [{decimals, 1}])),
+ {'EXIT', {badarg, _}} = (catch float_to_binary(1.0, [{decimals, -1}])),
+ {'EXIT', {badarg, _}} = (catch float_to_binary(1.0, [{decimals, 254}])),
+ {'EXIT', {badarg, _}} = (catch float_to_binary(1.0, [{scientific, 250}])),
+ {'EXIT', {badarg, _}} = (catch float_to_binary(1.0e+300, [{decimals, 1}])),
+ test_fts("1.0e+300",1.0e+300, [{scientific, 1}]),
+ test_fts("1.0",1.0, [{decimals, 249}, compact]),
+ test_fts("1",1.0,[{decimals,0}]),
+ test_fts("2",1.9,[{decimals,0}]),
+ test_fts("123456789012345680.0",123456789012345678.0,
+ [{decimals, 236}, compact]),
+ {'EXIT', {badarg, _}} = (catch float_to_list(
+ 123456789012345678.0, [{decimals, 237}])),
+ {'EXIT', {badarg, _}} = (catch float_to_binary(
+ 123456789012345678.0, [{decimals, 237}])),
+ test_fts("1." ++ string:copies("0", 249) ++ "e+00",
+ 1.0, [{scientific, 249}, compact]),
X1 = float_to_list(1.0),
X2 = float_to_list(1.0, [{scientific, 20}]),
X1 = X2,
- "1.000e+00" = float_to_list(1.0, [{scientific, 3}]),
- "1.000" = float_to_list(1.0, [{decimals, 3}]),
- "1.0" = float_to_list(1.0, [{decimals, 3}, compact]),
- "1.12" = float_to_list(1.123, [{decimals, 2}]),
- "1.123" = float_to_list(1.123, [{decimals, 3}]),
- "1.123" = float_to_list(1.123, [{decimals, 3}, compact]),
- "1.1230" = float_to_list(1.123, [{decimals, 4}]),
- "1.12300" = float_to_list(1.123, [{decimals, 5}]),
- "1.123" = float_to_list(1.123, [{decimals, 5}, compact]),
- "1.1234" = float_to_list(1.1234,[{decimals, 6}, compact]),
+
+ Y1 = float_to_binary(1.0),
+ Y2 = float_to_binary(1.0, [{scientific, 20}]),
+ Y1 = Y2,
+
+ test_fts("1.000e+00",1.0, [{scientific, 3}]),
+ test_fts("1.000",1.0, [{decimals, 3}]),
+ test_fts("1.0",1.0, [{decimals, 1}]),
+ test_fts("1.0",1.0, [{decimals, 3}, compact]),
+ test_fts("1.12",1.123, [{decimals, 2}]),
+ test_fts("1.123",1.123, [{decimals, 3}]),
+ test_fts("1.123",1.123, [{decimals, 3}, compact]),
+ test_fts("1.1230",1.123, [{decimals, 4}]),
+ test_fts("1.12300",1.123, [{decimals, 5}]),
+ test_fts("1.123",1.123, [{decimals, 5}, compact]),
+ test_fts("1.1234",1.1234,[{decimals, 6}, compact]),
+ test_fts("1.01",1.005, [{decimals, 2}]),
+ test_fts("-1.01",-1.005,[{decimals, 2}]),
+ test_fts("0.999",0.999, [{decimals, 3}]),
+ test_fts("-0.999",-0.999,[{decimals, 3}]),
+ test_fts("1.0",0.999, [{decimals, 2}, compact]),
+ test_fts("-1.0",-0.999,[{decimals, 2}, compact]),
+ test_fts("0.5",0.5, [{decimals, 1}]),
+ test_fts("-0.5",-0.5, [{decimals, 1}]),
"2.333333" = erlang:float_to_list(7/3, [{decimals, 6}, compact]),
"2.333333" = erlang:float_to_list(7/3, [{decimals, 6}]),
- "0.00000000000000000000e+00" = float_to_list(0.0, [compact]),
- "0.0" = float_to_list(0.0, [{decimals, 10}, compact]),
- "123000000000000000000.0" = float_to_list(1.23e20, [{decimals, 10}, compact]),
- "1.2300000000e+20" = float_to_list(1.23e20, [{scientific, 10}, compact]),
- "1.23000000000000000000e+20" = float_to_list(1.23e20, []),
+ <<"2.333333">> = erlang:float_to_binary(7/3, [{decimals, 6}, compact]),
+ <<"2.333333">> = erlang:float_to_binary(7/3, [{decimals, 6}]),
+ test_fts("0.00000000000000000000e+00",0.0, [compact]),
+ test_fts("0.0",0.0, [{decimals, 10}, compact]),
+ test_fts("123000000000000000000.0",1.23e20, [{decimals, 10}, compact]),
+ test_fts("1.2300000000e+20",1.23e20, [{scientific, 10}, compact]),
+ test_fts("1.23000000000000000000e+20",1.23e20, []),
ok.
-test_ftl(Expect, Float) ->
- %% No ?line on the next line -- we want the line number from t_float_to_list.
- Expect = remove_zeros(lists:reverse(float_to_list(Float)), []).
-
-%% Removes any non-significant zeros in a floating point number.
-%% Example: 2.500000e+01 -> 2.5e+1
-
-remove_zeros([$+, $e|Rest], [$0, X|Result]) ->
- remove_zeros([$+, $e|Rest], [X|Result]);
-remove_zeros([$-, $e|Rest], [$0, X|Result]) ->
- remove_zeros([$-, $e|Rest], [X|Result]);
-remove_zeros([$0, $.|Rest], [$e|Result]) ->
- remove_zeros(Rest, [$., $0, $e|Result]);
-remove_zeros([$0|Rest], [$e|Result]) ->
- remove_zeros(Rest, [$e|Result]);
-remove_zeros([Char|Rest], Result) ->
- remove_zeros(Rest, [Char|Result]);
-remove_zeros([], Result) ->
- Result.
-
-%% Tests integer_to_list/1.
-
-t_integer_to_list(Config) when is_list(Config) ->
- ?line "0" = integer_to_list(id(0)),
- ?line "42" = integer_to_list(id(42)),
- ?line "-42" = integer_to_list(id(-42)),
- ?line "32768" = integer_to_list(id(32768)),
- ?line "268435455" = integer_to_list(id(268435455)),
- ?line "-268435455" = integer_to_list(id(-268435455)),
- ?line "123456932798748738738" = integer_to_list(id(123456932798748738738)),
- ?line Big_List = id(lists:duplicate(2000, id($1))),
- ?line Big = list_to_integer(Big_List),
- ?line Big_List = integer_to_list(Big),
- ok.
+test_fts(Expect, Float) ->
+ Expect = float_to_list(Float),
+ BinExpect = list_to_binary(Expect),
+ BinExpect = float_to_binary(Float).
-%% Tests list_to_float/1.
+test_fts(Expect, Float, Args) ->
+ Expect = float_to_list(Float,Args),
+ BinExpect = list_to_binary(Expect),
+ BinExpect = float_to_binary(Float,Args).
-t_list_to_float_safe(Config) when is_list(Config) ->
- ?line 0.0 = list_to_float(id("0.0")),
- ?line 0.0 = list_to_float(id("-0.0")),
- ?line 0.5 = list_to_float(id("0.5")),
- ?line -0.5 = list_to_float(id("-0.5")),
- ?line 100.0 = list_to_float(id("1.0e2")),
- ?line 127.5 = list_to_float(id("127.5")),
- ?line -199.5 = list_to_float(id("-199.5")),
+%% Tests list_to_float/1.
- ?line {'EXIT',{badarg,_}} = (catch list_to_float(id("0"))),
- ?line {'EXIT',{badarg,_}} = (catch list_to_float(id("0..0"))),
- ?line {'EXIT',{badarg,_}} = (catch list_to_float(id("0e12"))),
- ?line {'EXIT',{badarg,_}} = (catch list_to_float(id("--0.0"))),
+t_string_to_float_safe(Config) when is_list(Config) ->
+ test_stf(0.0,"0.0"),
+ test_stf(0.0,"-0.0"),
+ test_stf(0.5,"0.5"),
+ test_stf(-0.5,"-0.5"),
+ test_stf(100.0,"1.0e2"),
+ test_stf(127.5,"127.5"),
+ test_stf(-199.5,"-199.5"),
+
+ {'EXIT',{badarg,_}} = (catch list_to_float(id("0"))),
+ {'EXIT',{badarg,_}} = (catch list_to_float(id("0..0"))),
+ {'EXIT',{badarg,_}} = (catch list_to_float(id("0e12"))),
+ {'EXIT',{badarg,_}} = (catch list_to_float(id("--0.0"))),
+ {'EXIT',{badarg,_}} = (catch binary_to_float(id(<<"0">>))),
+ {'EXIT',{badarg,_}} = (catch binary_to_float(id(<<"0..0">>))),
+ {'EXIT',{badarg,_}} = (catch binary_to_float(id(<<"0e12">>))),
+ {'EXIT',{badarg,_}} = (catch binary_to_float(id(<<"--0.0">>))),
+
+ UBin = <<0:3,(id(<<"0.0">>))/binary,0:5>>,
+ <<_:3,UnAlignedBin:3/binary,0:5>> = id(UBin),
+ 0.0 = binary_to_float(UnAlignedBin),
+
+ ABin = <<0:8,(id(<<"1.0">>))/binary,0:8>>,
+ <<_:8,AlignedBin:3/binary,0:8>> = id(ABin),
+ 1.0 = binary_to_float(AlignedBin),
ok.
%% This might crash the emulator...
%% (Known to crash the Unix version of Erlang 4.4.1)
-t_list_to_float_risky(Config) when is_list(Config) ->
- ?line Many_Ones = lists:duplicate(25000, id($1)),
- ?line id(list_to_float("2."++Many_Ones)),
- ?line {'EXIT', {badarg, _}} = (catch list_to_float("2"++Many_Ones)),
- ok.
-
-%% Tests list_to_integer/1.
+t_string_to_float_risky(Config) when is_list(Config) ->
+ Many_Ones = lists:duplicate(25000, id($1)),
+ id(list_to_float("2."++Many_Ones)),
+ {'EXIT', {badarg, _}} = (catch list_to_float("2"++Many_Ones)),
-t_list_to_integer(Config) when is_list(Config) ->
- ?line 0 = list_to_integer(id("0")),
- ?line 0 = list_to_integer(id("00")),
- ?line 0 = list_to_integer(id("-0")),
- ?line 1 = list_to_integer(id("1")),
- ?line -1 = list_to_integer(id("-1")),
- ?line 42 = list_to_integer(id("42")),
- ?line -12 = list_to_integer(id("-12")),
- ?line 32768 = list_to_integer(id("32768")),
- ?line 268435455 = list_to_integer(id("268435455")),
- ?line -268435455 = list_to_integer(id("-268435455")),
-
- %% Bignums.
- ?line 123456932798748738738 = list_to_integer(id("123456932798748738738")),
- ?line id(list_to_integer(lists:duplicate(2000, id($1)))),
+ id(binary_to_float(list_to_binary("2."++Many_Ones))),
+ {'EXIT', {badarg, _}} = (catch binary_to_float(
+ list_to_binary("2"++Many_Ones))),
ok.
+test_stf(Expect,List) ->
+ Expect = list_to_float(List),
+ Bin = list_to_binary(List),
+ Expect = binary_to_float(Bin).
+
%% Tests round/1.
t_round(Config) when is_list(Config) ->
- ?line 0 = round(id(0.0)),
- ?line 0 = round(id(0.4)),
- ?line 1 = round(id(0.5)),
- ?line 0 = round(id(-0.4)),
- ?line -1 = round(id(-0.5)),
- ?line 255 = round(id(255.3)),
- ?line 256 = round(id(255.6)),
- ?line -1033 = round(id(-1033.3)),
- ?line -1034 = round(id(-1033.6)),
+ 0 = round(id(0.0)),
+ 0 = round(id(0.4)),
+ 1 = round(id(0.5)),
+ 0 = round(id(-0.4)),
+ -1 = round(id(-0.5)),
+ 255 = round(id(255.3)),
+ 256 = round(id(255.6)),
+ -1033 = round(id(-1033.3)),
+ -1034 = round(id(-1033.6)),
% OTP-3722:
- ?line X = id((1 bsl 27) - 1),
- ?line MX = -X,
- ?line MXm1 = -X-1,
- ?line MXp1 = -X+1,
- ?line F = id(X + 0.0),
- ?line X = round(F),
- ?line X = round(F+1)-1,
- ?line X = round(F-1)+1,
- ?line MX = round(-F),
- ?line MXm1 = round(-F-1),
- ?line MXp1 = round(-F+1),
-
- ?line X = round(F+0.1),
- ?line X = round(F+1+0.1)-1,
- ?line X = round(F-1+0.1)+1,
- ?line MX = round(-F+0.1),
- ?line MXm1 = round(-F-1+0.1),
- ?line MXp1 = round(-F+1+0.1),
-
- ?line X = round(F-0.1),
- ?line X = round(F+1-0.1)-1,
- ?line X = round(F-1-0.1)+1,
- ?line MX = round(-F-0.1),
- ?line MXm1 = round(-F-1-0.1),
- ?line MXp1 = round(-F+1-0.1),
-
- ?line 0.5 = abs(round(F+0.5)-(F+0.5)),
- ?line 0.5 = abs(round(F-0.5)-(F-0.5)),
- ?line 0.5 = abs(round(-F-0.5)-(-F-0.5)),
- ?line 0.5 = abs(round(-F+0.5)-(-F+0.5)),
+ X = id((1 bsl 27) - 1),
+ MX = -X,
+ MXm1 = -X-1,
+ MXp1 = -X+1,
+ F = id(X + 0.0),
+ X = round(F),
+ X = round(F+1)-1,
+ X = round(F-1)+1,
+ MX = round(-F),
+ MXm1 = round(-F-1),
+ MXp1 = round(-F+1),
+
+ X = round(F+0.1),
+ X = round(F+1+0.1)-1,
+ X = round(F-1+0.1)+1,
+ MX = round(-F+0.1),
+ MXm1 = round(-F-1+0.1),
+ MXp1 = round(-F+1+0.1),
+
+ X = round(F-0.1),
+ X = round(F+1-0.1)-1,
+ X = round(F-1-0.1)+1,
+ MX = round(-F-0.1),
+ MXm1 = round(-F-1-0.1),
+ MXp1 = round(-F+1-0.1),
+
+ 0.5 = abs(round(F+0.5)-(F+0.5)),
+ 0.5 = abs(round(F-0.5)-(F-0.5)),
+ 0.5 = abs(round(-F-0.5)-(-F-0.5)),
+ 0.5 = abs(round(-F+0.5)-(-F+0.5)),
%% Bignums.
- ?line 4294967296 = round(id(4294967296.1)),
- ?line 4294967297 = round(id(4294967296.9)),
- ?line -4294967296 = -round(id(4294967296.1)),
- ?line -4294967297 = -round(id(4294967296.9)),
+ 4294967296 = round(id(4294967296.1)),
+ 4294967297 = round(id(4294967296.9)),
+ -4294967296 = -round(id(4294967296.1)),
+ -4294967297 = -round(id(4294967296.9)),
ok.
t_trunc(Config) when is_list(Config) ->
- ?line 0 = trunc(id(0.0)),
- ?line 5 = trunc(id(5.3333)),
- ?line -10 = trunc(id(-10.978987)),
+ 0 = trunc(id(0.0)),
+ 5 = trunc(id(5.3333)),
+ -10 = trunc(id(-10.978987)),
% The largest smallnum, converted to float (OTP-3722):
- ?line X = id((1 bsl 27) - 1),
- ?line F = id(X + 0.0),
+ X = id((1 bsl 27) - 1),
+ F = id(X + 0.0),
io:format("X = ~p/~w/~w, F = ~p/~w/~w, trunc(F) = ~p/~w/~w~n",
[X, X, binary_to_list(term_to_binary(X)),
F, F, binary_to_list(term_to_binary(F)),
trunc(F), trunc(F), binary_to_list(term_to_binary(trunc(F)))]),
- ?line X = trunc(F),
- ?line X = trunc(F+1)-1,
- ?line X = trunc(F-1)+1,
- ?line X = -trunc(-F),
- ?line X = -trunc(-F-1)-1,
- ?line X = -trunc(-F+1)+1,
+ X = trunc(F),
+ X = trunc(F+1)-1,
+ X = trunc(F-1)+1,
+ X = -trunc(-F),
+ X = -trunc(-F-1)-1,
+ X = -trunc(-F+1)+1,
%% Bignums.
- ?line 4294967305 = trunc(id(4294967305.7)),
- ?line -4294967305 = trunc(id(-4294967305.7)),
+ 4294967305 = trunc(id(4294967305.7)),
+ -4294967305 = trunc(id(-4294967305.7)),
ok.
+
+%% Tests integer_to_binary/1.
+
+t_integer_to_string(Config) when is_list(Config) ->
+ test_its("0",0),
+ test_its("42",42),
+ test_its("-42",-42),
+ test_its("32768",32768),
+ test_its("268435455",268435455),
+ test_its("-268435455",-268435455),
+ test_its("123456932798748738738",123456932798748738738),
+
+ %% 1 bsl 33, just beyond 32 bit
+ test_its("8589934592",8589934592),
+ test_its("-8589934592",-8589934592),
+ %% 1 bsl 65, just beyond 64 bit
+ test_its("36893488147419103232",36893488147419103232),
+ test_its("-36893488147419103232",-36893488147419103232),
+
+ %% Bignums.
+ BigBin = id(list_to_binary(lists:duplicate(2000, id($1)))),
+ Big = erlang:binary_to_integer(BigBin),
+ BigBin = erlang:integer_to_binary(Big),
+
+ %% Invalid types
+ lists:foreach(fun(Value) ->
+ {'EXIT', {badarg, _}} =
+ (catch erlang:integer_to_binary(Value)),
+ {'EXIT', {badarg, _}} =
+ (catch erlang:integer_to_list(Value))
+ end,[atom,1.2,0.0,[$1,[$2]]]),
+
+ ok.
+
+test_its(List,Int) ->
+ Int = list_to_integer(List),
+ Int = binary_to_integer(list_to_binary(List)).
+
+%% Tests binary_to_integer/1.
+
+t_string_to_integer(Config) when is_list(Config) ->
+ 0 = erlang:binary_to_integer(id(<<"00">>)),
+ 0 = erlang:binary_to_integer(id(<<"-0">>)),
+ 0 = erlang:binary_to_integer(id(<<"+0">>)),
+
+ test_sti(0),
+ test_sti(1),
+ test_sti(-1),
+ test_sti(42),
+ test_sti(-12),
+ test_sti(32768),
+ test_sti(268435455),
+ test_sti(-268435455),
+
+ %% 1 bsl 28 - 1, just before 32 bit bignum
+ test_sti(1 bsl 28 - 1),
+ %% 1 bsl 28, just beyond 32 bit small
+ test_sti(1 bsl 28),
+ %% 1 bsl 33, just beyond 32 bit
+ test_sti(1 bsl 33),
+ %% 1 bsl 60 - 1, just before 64 bit bignum
+ test_sti(1 bsl 60 - 1),
+ %% 1 bsl 60, just beyond 64 bit small
+ test_sti(1 bsl 60),
+ %% 1 bsl 65, just beyond 64 bit
+ test_sti(1 bsl 65),
+ %% Bignums.
+ test_sti(123456932798748738738,16),
+ test_sti(list_to_integer(lists:duplicate(2000, $1))),
+
+ %% unalign string
+ Str = <<"10">>,
+ UnalignStr = <<0:3, (id(Str))/binary, 0:5>>,
+ <<_:3, SomeStr:2/binary, _:5>> = id(UnalignStr),
+ 10 = erlang:binary_to_integer(SomeStr),
+
+ %% Invalid types
+ lists:foreach(fun(Value) ->
+ {'EXIT', {badarg, _}} =
+ (catch binary_to_integer(Value)),
+ {'EXIT', {badarg, _}} =
+ (catch erlang:list_to_integer(Value))
+ end,[atom,1.2,0.0,[$1,[$2]]]),
+
+ % Default base error cases
+ lists:foreach(fun(Value) ->
+ {'EXIT', {badarg, _}} =
+ (catch erlang:binary_to_integer(
+ list_to_binary(Value))),
+ {'EXIT', {badarg, _}} =
+ (catch erlang:list_to_integer(Value))
+ end,["1.0"," 1"," -1",""]),
+
+ % Custom base error cases
+ lists:foreach(fun({Value,Base}) ->
+ {'EXIT', {badarg, _}} =
+ (catch binary_to_integer(
+ list_to_binary(Value),Base)),
+ {'EXIT', {badarg, _}} =
+ (catch erlang:list_to_integer(Value,Base))
+ end,[{" 1",1},{" 1",37},{"2",2},{"C",11},
+ {"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111z",16},
+ {"1z111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",16},
+ {"111z11111111",16}]),
+
+ ok.
+
+test_sti(Num) ->
+ [begin
+ io:format("Testing ~p:~p",[Num,Base]),
+ test_sti(Num,Base)
+ end|| Base <- lists:seq(2,36)].
+
+test_sti(Num,Base) ->
+ Num = list_to_integer(int2list(Num,Base),Base),
+ Num = -1*list_to_integer(int2list(Num*-1,Base),Base),
+ Num = binary_to_integer(int2bin(Num,Base),Base),
+ Num = -1*binary_to_integer(int2bin(Num*-1,Base),Base).
+
% Calling this function (which is not supposed to be inlined) prevents
% the compiler from calculating the answer, so we don't test the compiler
% instead of the newest runtime system.
id(X) -> X.
+
+%% Uses the printing library to to integer_to_binary conversions.
+int2bin(Int,Base) when Base < 37 ->
+ iolist_to_binary(int2list(Int,Base)).
+
+int2list(Int,Base) when Base < 37 ->
+ lists:flatten(io_lib:format("~."++integer_to_list(Base)++"B",[Int])).
diff --git a/erts/emulator/utils/gen_git_version b/erts/emulator/utils/gen_git_version
new file mode 100755
index 0000000000..ef06a4b8e2
--- /dev/null
+++ b/erts/emulator/utils/gen_git_version
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+OUTPUT_FILE=$1
+
+if command -v git 2>&1 >/dev/null &&
+ test -d $ERL_TOP/.git -o -f $ERL_TOP/.git
+then
+ VSN=`git describe --match "OTP_R[0-9][0-9][A-B]*" HEAD`
+ case "$VSN" in
+ OTP_R*-g*)
+ VSN=`echo $VSN | sed -e 's/.*-g\\(.*\\)/\\1/g'` ;;
+ *) VSN="na" ;;
+ esac
+else
+ VSN="na"
+fi
+
+
+# Only update the file if there has been a change to
+# the version number.
+if test -r $OUTPUT_FILE
+then
+ VC=`sed -n -e 's/^.*"\\\\"\\(.*\\)\\\\"".*/\\1/p' < $OUTPUT_FILE`
+else
+ VC=unset
+fi
+
+if test "$VSN" != "$VC"
+then
+ echo "# Automatically generated by $0 - DO NOT EDIT." > $OUTPUT_FILE
+ if test "$VSN" = "na"
+ then
+ echo "# GIT_VSN=-DERLANG_GIT_VERSION=\"\\\"$VSN\\\"\"" >> $OUTPUT_FILE
+ else
+ echo "GIT_VSN=-DERLANG_GIT_VERSION=\"\\\"$VSN\\\"\"" >> $OUTPUT_FILE
+ fi
+ exit 0
+fi
+exit 1 \ No newline at end of file
diff --git a/erts/lib_src/common/erl_printf_format.c b/erts/lib_src/common/erl_printf_format.c
index 384b1b1ad7..00df3f068f 100644
--- a/erts/lib_src/common/erl_printf_format.c
+++ b/erts/lib_src/common/erl_printf_format.c
@@ -335,7 +335,7 @@ static int fmt_double(fmtfn_t fn,void*arg,double val,
int fi = 0;
char format_str[7];
char sbuf[32];
- char *bufp;
+ char *bufp = sbuf;
double dexp;
int exp;
size_t max_size = 1;
@@ -425,12 +425,12 @@ static int fmt_double(fmtfn_t fn,void*arg,double val,
max_size++; /* '\0' */
- if (max_size < sizeof(sbuf))
- bufp = sbuf;
- else {
+ if (max_size >= sizeof(sbuf)) {
bufp = (char *) malloc(sizeof(char)*max_size);
if (!bufp) {
res = -ENOMEM;
+ /* Make sure not to trigger free */
+ bufp = sbuf;
goto out;
}
}
@@ -448,10 +448,10 @@ static int fmt_double(fmtfn_t fn,void*arg,double val,
res = fmt_fld(fn, arg, bufp, size, 0, width, 0, new_fmt, count);
+ out:
if (bufp != sbuf)
free((void *) bufp);
- out:
if (erts_printf_unblock_fpe)
(*erts_printf_unblock_fpe)(fpe_was_unmasked);
return res;
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index f8c2df3a5a..4a3af265c1 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 5b288ecc5c..50e87b3550 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index ca93edbe25..f7b3aac376 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl
index d36fdeba3f..7490954f2d 100644
--- a/erts/preloaded/src/erl_prim_loader.erl
+++ b/erts/preloaded/src/erl_prim_loader.erl
@@ -149,8 +149,18 @@ start_it("inet", Id, Pid, Hosts) ->
start_it("efile", Id, Pid, _Hosts) ->
process_flag(trap_exit, true),
- {ok, Port} = prim_file:open([binary]),
- init_ack(Pid),
+ {ok, Port} = prim_file:start(),
+ %% Check that we started in a valid directory.
+ case prim_file:get_cwd(Port) of
+ {error, _} ->
+ %% At this point in the startup, we have no error_logger at all.
+ Report = "Invalid current directory or invalid filename "
+ "mode: loader cannot read current directory\n",
+ erlang:display(Report),
+ exit({error, invalid_current_directory});
+ _ ->
+ init_ack(Pid)
+ end,
MultiGet = case erlang:system_info(thread_pool_size) of
0 -> false;
_ -> true
@@ -434,7 +444,7 @@ efile_multi_get_file_from_port2(_MFs, 0, _Max, State, _Paths, _Fun, _Ref, Ret) -
efile_par_get_file(Ref, State, {Mod,File} = MF, Paths, Pid, Fun) ->
%% One port for each file read in "parallel":
- case prim_file:open([binary]) of
+ case prim_file:start() of
{ok, Port} ->
Port0 = State#state.data,
State1 = State#state{data = Port},
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 115e1b03c4..8e4a471a82 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -36,7 +36,8 @@
-export([set_cookie/2, get_cookie/0]).
-export([nodes/0]).
--export([list_to_integer/2,integer_to_list/2]).
+-export([integer_to_list/2]).
+-export([integer_to_binary/2]).
-export([flush_monitor_message/2]).
-export([set_cpu_topology/1, format_cpu_topology/1]).
-export([await_proc_exit/3]).
@@ -73,7 +74,9 @@
-export([adler32/1, adler32/2, adler32_combine/3, append_element/2]).
-export([atom_to_binary/2, atom_to_list/1, binary_part/2, binary_part/3]).
--export([binary_to_atom/2, binary_to_existing_atom/2, binary_to_list/1]).
+-export([binary_to_atom/2, binary_to_existing_atom/2, binary_to_float/1]).
+-export([binary_to_integer/1,binary_to_integer/2]).
+-export([binary_to_list/1]).
-export([binary_to_list/3, binary_to_term/1, binary_to_term/2]).
-export([bit_size/1, bitsize/1, bitstr_to_list/1, bitstring_to_list/1]).
-export([bump_reductions/1, byte_size/1, call_on_load_function/1]).
@@ -84,18 +87,21 @@
-export([display_nl/0, display_string/1, dist_exit/3, erase/0, erase/1]).
-export([error/1, error/2, exit/1, exit/2, external_size/1]).
-export([external_size/2, finish_after_on_load/2, finish_loading/1, float/1]).
--export([float_to_list/1, float_to_list/2]).
+-export([float_to_binary/1, float_to_binary/2,
+ float_to_list/1, float_to_list/2]).
-export([fun_info/2, fun_to_list/1, function_exported/3]).
-export([garbage_collect/0, garbage_collect/1]).
-export([garbage_collect_message_area/0, get/0, get/1, get_keys/1]).
-export([get_module_info/1, get_stacktrace/0, group_leader/0]).
-export([group_leader/2, halt/0, halt/1, halt/2, hash/2, hibernate/3]).
-export([insert_element/3]).
--export([integer_to_list/1, iolist_size/1, iolist_to_binary/1]).
+-export([integer_to_binary/1, integer_to_list/1]).
+-export([iolist_size/1, iolist_to_binary/1]).
-export([is_alive/0, is_builtin/3, is_process_alive/1, length/1, link/1]).
-export([list_to_atom/1, list_to_binary/1, list_to_bitstr/1]).
-export([list_to_bitstring/1, list_to_existing_atom/1, list_to_float/1]).
--export([list_to_integer/1, list_to_pid/1, list_to_tuple/1, loaded/0]).
+-export([list_to_integer/1, list_to_integer/2]).
+-export([list_to_pid/1, list_to_tuple/1, loaded/0]).
-export([localtime/0, make_ref/0, match_spec_test/3, md5/1, md5_final/1]).
-export([md5_init/0, md5_update/2, module_loaded/1, monitor/2]).
-export([monitor_node/2, monitor_node/3, nif_error/1, nif_error/2
@@ -317,6 +323,25 @@ binary_to_atom(_Binary, _Encoding) ->
binary_to_existing_atom(_Binary, _Encoding) ->
erlang:nif_error(undefined).
+%% binary_to_float/1
+-spec binary_to_float(Binary) -> float() when
+ Binary :: binary().
+binary_to_float(_Binary) ->
+ erlang:nif_error(undefined).
+
+%% binary_to_integer/1
+-spec binary_to_integer(Binary) -> integer() when
+ Binary :: binary().
+binary_to_integer(_Binary) ->
+ erlang:nif_error(undefined).
+
+%% binary_to_integer/2
+-spec binary_to_integer(Binary,Base) -> integer() when
+ Binary :: binary(),
+ Base :: 2..36.
+binary_to_integer(_Binary,_Base) ->
+ erlang:nif_error(undefined).
+
%% binary_to_list/1
-spec binary_to_list(Binary) -> [byte()] when
Binary :: binary().
@@ -706,6 +731,22 @@ finish_after_on_load(_P1, _P2) ->
float(_Number) ->
erlang:nif_error(undefined).
+%% float_to_binary/1
+-spec float_to_binary(Float) -> binary() when
+ Float :: float().
+float_to_binary(_Float) ->
+ erlang:nif_error(undefined).
+
+%% float_to_binary/2
+-spec float_to_binary(Float, Options) -> binary() when
+ Float :: float(),
+ Options :: [Option],
+ Option :: {decimals, Decimals :: 0..253} |
+ {scientific, Decimals :: 0..249} |
+ compact.
+float_to_binary(_Float, _Options) ->
+ erlang:nif_error(undefined).
+
%% float_to_list/1
-spec float_to_list(Float) -> string() when
Float :: float().
@@ -716,8 +757,8 @@ float_to_list(_Float) ->
-spec float_to_list(Float, Options) -> string() when
Float :: float(),
Options :: [Option],
- Option :: {decimals, non_neg_integer()} |
- {scientific, non_neg_integer()} |
+ Option :: {decimals, Decimals :: 0..253} |
+ {scientific, Decimals :: 0..249} |
compact.
float_to_list(_Float, _Options) ->
erlang:nif_error(undefined).
@@ -850,6 +891,12 @@ hibernate(_Module, _Function, _Args) ->
insert_element(_Index, _Tuple1, _Term) ->
erlang:nif_error(undefined).
+%% integer_to_binary/1
+-spec integer_to_binary(Integer) -> binary() when
+ Integer :: integer().
+integer_to_binary(_Integer) ->
+ erlang:nif_error(undefined).
+
%% integer_to_list/1
-spec integer_to_list(Integer) -> string() when
Integer :: integer().
@@ -942,6 +989,13 @@ list_to_float(_String) ->
list_to_integer(_String) ->
erlang:nif_error(undefined).
+%% list_to_integer/2
+-spec list_to_integer(String, Base) -> integer() when
+ String :: string(),
+ Base :: 2..36.
+list_to_integer(_String,_Base) ->
+ erlang:nif_error(undefined).
+
%% list_to_pid/1
-spec list_to_pid(String) -> pid() when
String :: string().
@@ -2838,51 +2892,32 @@ integer_to_list(I0, Base, R0) ->
integer_to_list(I1, Base, R1)
end.
-
--spec list_to_integer(String, Base) -> integer() when
- String :: string(),
+-spec integer_to_binary(Integer, Base) -> binary() when
+ Integer :: integer(),
Base :: 2..36.
-list_to_integer(L, 10) ->
- erlang:list_to_integer(L);
-list_to_integer(L, Base)
- when erlang:is_list(L), erlang:is_integer(Base),
+integer_to_binary(I, 10) ->
+ erlang:integer_to_binary(I);
+integer_to_binary(I, Base)
+ when erlang:is_integer(I), erlang:is_integer(Base),
Base >= 2, Base =< 1+$Z-$A+10 ->
- case list_to_integer_sign(L, Base) of
- I when erlang:is_integer(I) ->
- I;
- Fault ->
- erlang:error(Fault, [L,Base])
- end;
-list_to_integer(L, Base) ->
- erlang:error(badarg, [L,Base]).
-
-list_to_integer_sign([$-|[_|_]=L], Base) ->
- case list_to_integer(L, Base, 0) of
- I when erlang:is_integer(I) ->
- -I;
- I ->
- I
+ if I < 0 ->
+ <<"$-",(integer_to_binary(-I, Base, []))/binary>>;
+ true ->
+ integer_to_binary(I, Base, <<>>)
end;
-list_to_integer_sign([$+|[_|_]=L], Base) ->
- list_to_integer(L, Base, 0);
-list_to_integer_sign([_|_]=L, Base) ->
- list_to_integer(L, Base, 0);
-list_to_integer_sign(_, _) ->
- badarg.
-
-list_to_integer([D|L], Base, I)
- when erlang:is_integer(D), D >= $0, D =< $9, D < Base+$0 ->
- list_to_integer(L, Base, I*Base + D-$0);
-list_to_integer([D|L], Base, I)
- when erlang:is_integer(D), D >= $A, D < Base+$A-10 ->
- list_to_integer(L, Base, I*Base + D-$A+10);
-list_to_integer([D|L], Base, I)
- when erlang:is_integer(D), D >= $a, D < Base+$a-10 ->
- list_to_integer(L, Base, I*Base + D-$a+10);
-list_to_integer([], _, I) ->
- I;
-list_to_integer(_, _, _) ->
- badarg.
+integer_to_binary(I, Base) ->
+ erlang:error(badarg, [I, Base]).
+
+integer_to_binary(0, _Base, R0) ->
+ R0;
+integer_to_binary(I0, Base, R0) ->
+ D = I0 rem Base,
+ I1 = I0 div Base,
+ if D >= 10 ->
+ integer_to_binary(I1,Base,<<(D-10+$A),R0/binary>>);
+ true ->
+ integer_to_binary(I1,Base,<<(D+$0),R0/binary>>)
+ end.
%% erlang:flush_monitor_message/2 is for internal use only!
%%
diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl
index 50adf9c89d..bf8879c2a0 100644
--- a/erts/preloaded/src/prim_file.erl
+++ b/erts/preloaded/src/prim_file.erl
@@ -50,9 +50,9 @@
write_file_info/2, write_file_info/3, write_file_info/4,
make_link/2, make_link/3,
make_symlink/2, make_symlink/3,
- read_link/1, read_link/2,
+ read_link/1, read_link/2, read_link_all/1, read_link_all/2,
read_link_info/1, read_link_info/2, read_link_info/3,
- list_dir/1, list_dir/2]).
+ list_dir/1, list_dir/2, list_dir_all/1, list_dir_all/2]).
%% How to start and stop the ?DRV port.
-export([start/0, stop/1]).
@@ -152,16 +152,19 @@
-export([internal_name2native/1,
internal_native2name/1,
- internal_normalize_utf8/1]).
+ internal_normalize_utf8/1,
+ is_translatable/1]).
-type prim_file_name() :: string() | unicode:unicode_binary().
+-type prim_file_name_error() :: 'error' | 'ignore' | 'warning'.
-spec internal_name2native(prim_file_name()) -> binary().
internal_name2native(_) ->
erlang:nif_error(undefined).
--spec internal_native2name(binary()) -> prim_file_name().
+-spec internal_native2name(binary()) ->
+ prim_file_name() | {'error',prim_file_name_error()}.
internal_native2name(_) ->
erlang:nif_error(undefined).
@@ -171,6 +174,11 @@ internal_native2name(_) ->
internal_normalize_utf8(_) ->
erlang:nif_error(undefined).
+-spec is_translatable(prim_file_name()) -> boolean().
+
+is_translatable(_) ->
+ erlang:nif_error(undefined).
+
%%% End of BIFs
%%%-----------------------------------------------------------------
@@ -210,12 +218,7 @@ open(_, _) ->
%% Opens a port that can be used for open/3 or read_file/2.
%% Returns {ok, Port} | {error, Reason}.
open(Portopts) when is_list(Portopts) ->
- case drv_open(?FD_DRV, Portopts) of
- {error, _} = Error ->
- Error;
- Other ->
- Other
- end;
+ drv_open(?FD_DRV, [binary|Portopts]);
open(_) ->
{error, badarg}.
@@ -607,13 +610,7 @@ sendfile(#file_descriptor{module = ?MODULE, data = {Port, _}},
%% Returns {ok, Port}, the Port should be used as first argument in all
%% the following functions. Returns {error, Reason} upon failure.
start() ->
- try erlang:open_port({spawn, ?DRV}, [binary]) of
- Port ->
- {ok, Port}
- catch
- error:Reason ->
- {error, Reason}
- end.
+ drv_open(?DRV, [binary]).
stop(Port) when is_port(Port) ->
try erlang:port_close(Port) of
@@ -667,7 +664,8 @@ get_cwd_int(Drive) ->
get_cwd_int({?DRV, [binary]}, Drive).
get_cwd_int(Port, Drive) ->
- drv_command(Port, <<?FILE_PWD, Drive>>).
+ drv_command(Port, <<?FILE_PWD, Drive>>,
+ fun handle_fname_response/1).
@@ -679,10 +677,17 @@ set_cwd(Dir) ->
set_cwd(Port, Dir) when is_port(Port) ->
set_cwd_int(Port, Dir).
-set_cwd_int(Port, Dir) ->
- %% Dir is now either a string or an EXIT tuple.
- %% An EXIT tuple will fail in the following catch.
- drv_command(Port, [?FILE_CHDIR, pathname(Dir)]).
+set_cwd_int(Port, Dir) when is_binary(Dir) ->
+ case prim_file:is_translatable(Dir) of
+ false ->
+ {error, no_translation};
+ true ->
+ drv_command(Port, [?FILE_CHDIR, pathname(Dir)])
+ end;
+set_cwd_int(Port, Dir) when is_list(Dir) ->
+ drv_command(Port, [?FILE_CHDIR, pathname(Dir)]);
+set_cwd_int(_, _) ->
+ {error, badarg}.
@@ -775,7 +780,8 @@ altname(Port, File) when is_port(Port) ->
altname_int(Port, File).
altname_int(Port, File) ->
- drv_command(Port, [?FILE_ALTNAME, pathname(File)]).
+ drv_command(Port, [?FILE_ALTNAME, pathname(File)],
+ fun handle_fname_response/1).
%% write_file_info/{2,3,4}
@@ -868,7 +874,20 @@ read_link(Port, Link) when is_port(Port) ->
read_link_int(Port, Link).
read_link_int(Port, Link) ->
- drv_command(Port, [?FILE_READLINK, pathname(Link)]).
+ drv_command(Port, [?FILE_READLINK, pathname(Link)],
+ fun handle_fname_response/1).
+
+%% read_link_all/{2,3}
+
+read_link_all(Link) ->
+ read_link_all_int({?DRV, [binary]}, Link).
+
+read_link_all(Port, Link) when is_port(Port) ->
+ read_link_all_int(Port, Link).
+
+read_link_all_int(Port, Link) ->
+ drv_command(Port, [?FILE_READLINK, pathname(Link)],
+ fun handle_fname_response_all/1).
@@ -910,20 +929,112 @@ list_dir(Port, Dir) when is_port(Port) ->
list_dir_int(Port, Dir).
list_dir_int(Port, Dir) ->
- drv_command(Port, [?FILE_READDIR, pathname(Dir)], []).
-
+ drv_command(Port, [?FILE_READDIR, pathname(Dir)],
+ fun(P) ->
+ case list_dir_response(P, []) of
+ {ok, RawNames} ->
+ {ok, list_dir_convert(RawNames)};
+ Error ->
+ Error
+ end
+ end).
+
+list_dir_all(Dir) ->
+ list_dir_all_int({?DRV, [binary]}, Dir).
+
+list_dir_all(Port, Dir) when is_port(Port) ->
+ list_dir_all_int(Port, Dir).
+
+list_dir_all_int(Port, Dir) ->
+ drv_command(Port, [?FILE_READDIR, pathname(Dir)],
+ fun(P) ->
+ case list_dir_response(P, []) of
+ {ok, RawNames} ->
+ {ok, list_dir_convert_all(RawNames)};
+ Error ->
+ Error
+ end
+ end).
+
+list_dir_response(Port, Acc0) ->
+ case drv_get_response(Port) of
+ {lfname, []} ->
+ {ok, Acc0};
+ {lfname, Names} ->
+ Acc = [Name || <<L:16,Name:L/binary>> <= Names] ++ Acc0,
+ list_dir_response(Port, Acc);
+ Error ->
+ Error
+ end.
+list_dir_convert([Name|Names]) ->
+ %% If the filename cannot be converted, return error or ignore
+ %% with optional error logger warning, depending on +fn{u|a}{i|e|w}
+ %% emulator switches.
+ case prim_file:internal_native2name(Name) of
+ {error, warning} ->
+ error_logger:warning_msg("Non-unicode filename ~p ignored\n",
+ [Name]),
+ list_dir_convert(Names);
+ {error, ignore} ->
+ list_dir_convert(Names);
+ {error, error} ->
+ {error, {no_translation, Name}};
+ Converted when is_list(Converted) ->
+ [Converted|list_dir_convert(Names)]
+ end;
+list_dir_convert([]) -> [].
+
+list_dir_convert_all([Name|Names]) ->
+ %% If the filename cannot be converted, retain the filename as
+ %% a binary.
+ case prim_file:internal_native2name(Name) of
+ {error, _} ->
+ [Name|list_dir_convert(Names)];
+ Converted when is_list(Converted) ->
+ [Converted|list_dir_convert(Names)]
+ end;
+list_dir_convert_all([]) -> [].
%%%-----------------------------------------------------------------
%%% Functions to communicate with the driver
+handle_fname_response(Port) ->
+ case drv_get_response(Port) of
+ {fname, Name} ->
+ case prim_file:internal_native2name(Name) of
+ {error, warning} ->
+ error_logger:warning_msg("Non-unicode filename ~p "
+ "ignored when reading link\n",
+ [Name]),
+ {error, einval};
+ {error, _} ->
+ {error, einval};
+ Converted when is_list(Converted) ->
+ {ok, Converted}
+ end;
+ Error ->
+ Error
+ end.
+handle_fname_response_all(Port) ->
+ case drv_get_response(Port) of
+ {fname, Name} ->
+ case prim_file:internal_native2name(Name) of
+ {error, _} ->
+ {ok, Name};
+ Converted when is_list(Converted) ->
+ {ok, Converted}
+ end;
+ Error ->
+ Error
+ end.
%% Opens a driver port and converts any problems into {error, emfile}.
%% Returns {ok, Port} when successful.
drv_open(Driver, Portopts) ->
- try erlang:open_port({spawn, Driver}, Portopts) of
+ try erlang:open_port({spawn_driver, Driver}, Portopts) of
Port ->
{ok, Port}
catch
@@ -1028,19 +1139,10 @@ drv_command_nt(Port, Command, R) when is_port(Port) ->
%% Receives the response from a driver port.
%% Returns: {ok, ListOrBinary}|{error, Reason}
-drv_get_response(Port, R) when is_list(R) ->
- case drv_get_response(Port) of
- ok ->
- {ok, R};
- {ok, Name} ->
- drv_get_response(Port, [Name|R]);
- {append, Names} ->
- drv_get_response(Port, append(Names, R));
- Error ->
- Error
- end;
-drv_get_response(Port, _) ->
- drv_get_response(Port).
+drv_get_response(Port, undefined) ->
+ drv_get_response(Port);
+drv_get_response(Port, Fun) when is_function(Fun, 1) ->
+ Fun(Port).
drv_get_response(Port) ->
erlang:bump_reductions(100),
@@ -1060,10 +1162,6 @@ drv_get_response(Port) ->
%%%-----------------------------------------------------------------
%%% Utility functions.
-append([I | Is], R) when is_list(R) -> append(Is, [I | R]);
-append([], R) -> R.
-
-
%% Converts a list of mode atoms into a mode word for the driver.
%% Returns {Mode, Portopts, Setopts} where Portopts is a list of
%% options for erlang:open_port/2 and Setopts is a list of
@@ -1205,18 +1303,10 @@ translate_response(?FILE_RESP_N2DATA = X, L0) when is_list(L0) ->
end;
translate_response(?FILE_RESP_EOF, []) ->
eof;
-translate_response(?FILE_RESP_FNAME, []) ->
- ok;
-translate_response(?FILE_RESP_FNAME, Data) when is_binary(Data) ->
- {ok, prim_file:internal_native2name(Data)};
translate_response(?FILE_RESP_FNAME, Data) ->
- {ok, Data};
-translate_response(?FILE_RESP_LFNAME, []) ->
- ok;
-translate_response(?FILE_RESP_LFNAME, Data) when is_binary(Data) ->
- {append, transform_lfname(Data)};
+ {fname, Data};
translate_response(?FILE_RESP_LFNAME, Data) ->
- {append, transform_lfname(Data)};
+ {lfname, Data};
translate_response(?FILE_RESP_ALL_DATA, Data) ->
{ok, Data};
translate_response(X, Data) ->
@@ -1332,16 +1422,6 @@ transform_ldata(0, List, [Size | Sizes], R) ->
{Front, Rear} = lists_split(List, Size),
transform_ldata(0, Rear, Sizes, [Front | R]).
-transform_lfname(<<>>) -> [];
-transform_lfname(<<L:16, Name:L/binary, Names/binary>>) ->
- [ prim_file:internal_native2name(Name) | transform_lfname(Names)];
-transform_lfname([]) -> [];
-transform_lfname([L1,L2|Names]) ->
- L = (L1 bsl 8) bor L2,
- {Name, Rest} = lists_split(Names, L),
- [Name | transform_lfname(Rest)].
-
-
lists_split(List, 0) when is_list(List) ->
{[], List};
lists_split(List, N) when is_list(List), is_integer(N), N < 0 ->
diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl
index 51f07b5432..374255bbe6 100644
--- a/erts/test/otp_SUITE.erl
+++ b/erts/test/otp_SUITE.erl
@@ -273,7 +273,7 @@ call_to_size_1(Config) when is_list(Config) ->
Server = ?config(xref_server, Config),
%% Applications that do not call erlang:size/1:
- Apps = [compiler,debugger,kernel,observer,parsetools,
+ Apps = [asn1,compiler,debugger,kernel,observer,parsetools,
runtime_tools,stdlib,tools,webtool],
Fs = [{erlang,size,1}],