aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/.gitignore22
-rw-r--r--erts/aclocal.m4132
-rw-r--r--erts/configure.in200
-rw-r--r--erts/doc/src/erl_nif.xml196
-rw-r--r--erts/doc/src/erlang.xml15
-rw-r--r--erts/emulator/beam/beam_emu.c95
-rw-r--r--erts/emulator/beam/break.c2
-rw-r--r--erts/emulator/beam/erl_nif.c154
-rw-r--r--erts/emulator/beam/erl_nif.h16
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h24
-rw-r--r--erts/emulator/beam/erl_process.c2
-rw-r--r--erts/emulator/beam/erl_process.h7
-rw-r--r--erts/emulator/beam/global.h3
-rw-r--r--erts/emulator/beam/sys.h5
-rw-r--r--erts/emulator/test/nif_SUITE.erl63
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c189
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.c6
-rw-r--r--erts/emulator/test/trace_nif_SUITE_data/trace_nif.c6
-rwxr-xr-xerts/emulator/utils/beam_makeops4
-rw-r--r--erts/etc/unix/to_erl.c6
-rw-r--r--erts/preloaded/ebin/init.beambin44460 -> 44460 bytes
-rw-r--r--erts/preloaded/src/init.erl5
22 files changed, 820 insertions, 332 deletions
diff --git a/erts/.gitignore b/erts/.gitignore
new file mode 100644
index 0000000000..526d5da0b9
--- /dev/null
+++ b/erts/.gitignore
@@ -0,0 +1,22 @@
+/Makefile
+/configure
+/config.log
+/config.status
+/config.h.in
+
+/start_scripts/RELEASES.src
+/start_scripts/*.rel
+/start_scripts/*.boot
+/start_scripts/*.script
+
+/etc/common/Install
+/etc/common/erl.src
+
+/test/Emakefile
+/test/*.beam
+
+/emulator/test/Emakefile
+/emulator/test/*.beam
+/emulator/test/*_no_opt_SUITE.erl
+
+/emulator/pcre/pcre_exec_loop_break_cases.inc
diff --git a/erts/aclocal.m4 b/erts/aclocal.m4
index 0ad963db12..e9a0cc228f 100644
--- a/erts/aclocal.m4
+++ b/erts/aclocal.m4
@@ -1,4 +1,4 @@
-
+dnl
dnl %CopyrightBegin%
dnl
dnl Copyright Ericsson AB 1998-2009. All Rights Reserved.
@@ -15,6 +15,7 @@ dnl the License for the specific language governing rights and limitations
dnl under the License.
dnl
dnl %CopyrightEnd%
+dnl
dnl
dnl aclocal.m4
@@ -519,46 +520,79 @@ dnl On ofs1 the '-pthread' switch should be used
ETHR_DEFS="$ETHR_DEFS -D_POSIX_PTHREAD_SEMANTICS" ;;
linux*)
ETHR_DEFS="$ETHR_DEFS -D_POSIX_THREAD_SAFE_FUNCTIONS -D_GNU_SOURCE"
- if test "x$erl_xcomp_linux_kernel" != "x"; then
- linux_kernel_vsn_=$erl_xcomp_linux_kernel
- else
- linux_kernel_vsn_=`uname -r`
- fi
- usable_sigusrx=no
- usable_sigaltstack=no
- # FIXME: Test for actual problems instead of kernel versions.
- case $linux_kernel_vsn_ in
- [[0-1]].*|2.[[0-1]]|2.[[0-1]].*)
- ;;
- 2.[[2-3]]|2.[[2-3]].*)
- usable_sigusrx=yes
- ;;
- *)
+ if test X$cross_compiling = Xyes; then
+ if test "X$erl_xcomp_linux_usable_sigusrx" = "X"; then
usable_sigusrx=yes
+ usable_sigusrx_guessed=yes
+ else
+ usable_sigusrx=$erl_xcomp_linux_usable_sigusrx
+ usable_sigusrx_guessed=no
+ fi
+ if test "X$erl_xcomp_linux_usable_sigaltstack" = "X"; then
usable_sigaltstack=yes
- ;;
- esac
+ usable_sigaltstack_guessed=yes
+ else
+ usable_sigaltstack=$erl_xcomp_linux_usable_sigaltstack
+ usable_sigaltstack_guessed=no
+ fi
+ else
+ # FIXME: Test for actual problems instead of kernel versions
+ linux_kernel_vsn_=`uname -r`
+ case $linux_kernel_vsn_ in
+ [[0-1]].*|2.[[0-1]]|2.[[0-1]].*)
+ usable_sigusrx=no
+ usable_sigaltstack=no;;
+ 2.[[2-3]]|2.[[2-3]].*)
+ usable_sigusrx=yes
+ usable_sigaltstack=no;;
+ *)
+ usable_sigusrx=yes
+ usable_sigaltstack=yes;;
+ esac
+ usable_sigusrx_guessed=no
+ usable_sigaltstack_guessed=no
+ fi
AC_MSG_CHECKING(if SIGUSR1 and SIGUSR2 can be used)
AC_MSG_RESULT($usable_sigusrx)
+ if test $usable_sigusrx_guessed = yes; then
+ AC_MSG_WARN([result $usable_sigusrx guessed because of cross compilation])
+ fi
if test $usable_sigusrx = no; then
ETHR_DEFS="$ETHR_DEFS -DETHR_UNUSABLE_SIGUSRX"
fi
AC_MSG_CHECKING(if sigaltstack can be used)
AC_MSG_RESULT($usable_sigaltstack)
+ if test $usable_sigaltstack_guessed = yes; then
+ AC_MSG_WARN([result $usable_sigaltstack guessed because of cross compilation])
+ fi
if test $usable_sigaltstack = no; then
ETHR_DEFS="$ETHR_DEFS -DETHR_UNUSABLE_SIGALTSTACK"
fi
AC_MSG_CHECKING(for Native POSIX Thread Library)
- case `getconf GNU_LIBPTHREAD_VERSION 2>/dev/null` in
- nptl*) nptl=yes;;
- NPTL*) nptl=yes;;
- *) nptl=no;;
- esac
+ if test X$cross_compiling = Xyes; then
+ if test "X$erl_xcomp_linux_nptl" = "X"; then
+ nptl=yes
+ nptl_guessed=yes
+ else
+ nptl=$erl_xcomp_linux_nptl
+ nptl_guessed=no
+ fi
+ else
+ case `getconf GNU_LIBPTHREAD_VERSION 2>/dev/null` in
+ nptl*) nptl=yes;;
+ NPTL*) nptl=yes;;
+ *) nptl=no;;
+ esac
+ nptl_guessed=no
+ fi
AC_MSG_RESULT($nptl)
+ if test $nptl_guessed = yes; then
+ AC_MSG_WARN([result $nptl guessed because of cross compilation])
+ fi
if test $nptl = yes; then
ETHR_THR_LIB_BASE_NAME=nptl
fi
@@ -567,7 +601,10 @@ dnl On ofs1 the '-pthread' switch should be used
AC_CHECK_HEADER(nptl/pthread.h, need_nptl_incldir=yes)
if test $need_nptl_incldir = yes; then
# Ahh...
- nptl_path="$C_INCLUDE_PATH:$CPATH:/usr/local/include:/usr/include"
+ nptl_path="$C_INCLUDE_PATH:$CPATH"
+ if test X$cross_compiling != Xyes; then
+ nptl_path="$nptl_path:/usr/local/include:/usr/include"
+ fi
nptl_ws_path=
save_ifs="$IFS"; IFS=":"
for dir in $nptl_path; do
@@ -683,7 +720,7 @@ if test "x$ETHR_THR_LIB_BASE" != "x"; then
ETHR_LIB_NAME=$ethr_lib_name
fi
-AC_CHECK_SIZEOF(void *, 4)
+AC_CHECK_SIZEOF(void *)
AC_DEFINE_UNQUOTED(ETHR_SIZEOF_PTR, $ac_cv_sizeof_void_p, [Define to the size of pointers])
if test "X$disable_native_ethr_impls" = "Xyes"; then
@@ -751,13 +788,21 @@ case $clock_gettime_correction in
case $clock_gettime_correction in
unknown)
if test x$clock_gettime_compiles = xyes; then
- linux_kernel_vsn_=`uname -r`
- case $linux_kernel_vsn_ in
- [[0-1]].*|2.[[0-5]]|2.[[0-5]].*)
- erl_cv_time_correction=times ;;
- *)
- erl_cv_time_correction=clock_gettime;;
- esac
+ if test X$cross_compiling != Xyes; then
+ if test "X$erl_xcomp_linux_clock_gettime_correction" = "Xno"; then
+ erl_cv_time_correction=times
+ else
+ erl_cv_time_correction=clock_gettime
+ fi
+ else
+ linux_kernel_vsn_=`uname -r`
+ case $linux_kernel_vsn_ in
+ [[0-1]].*|2.[[0-5]]|2.[[0-5]].*)
+ erl_cv_time_correction=times ;;
+ *)
+ erl_cv_time_correction=clock_gettime;;
+ esac
+ fi
else
erl_cv_time_correction=times
fi
@@ -774,6 +819,7 @@ case $clock_gettime_correction in
;;
esac
])
+
xrtlib=""
case $erl_cv_time_correction in
times)
@@ -781,6 +827,9 @@ case $erl_cv_time_correction in
[Define if you do not have a high-res. timer & want to use times() instead])
;;
clock_gettime)
+ if test X$cross_compiling = Xyes -a X$erl_xcomp_linux_clock_gettime_correction = X; then
+ AC_MSG_WARN([result clock_gettime guessed because of cross compilation])
+ fi
xrtlib="-lrt"
AC_DEFINE(GETHRTIME_WITH_CLOCK_GETTIME,[1],
[Define if you want to use clock_gettime to simulate gethrtime])
@@ -840,7 +889,15 @@ int main() {
exit(5);
exit(0); return 0;
}
-], erl_gethrvtime=procfs_ioctl, erl_gethrvtime=false, erl_gethrvtime=false)
+],
+erl_gethrvtime=procfs_ioctl,
+erl_gethrvtime=false,
+if test "x$erl_xcomp_gethrvtime_procfs_ioctl" = "xyes"; then
+ erl_gethrvtime=procfs_ioctl
+else
+ erl_gethrvtime=false
+fi)
+
case $erl_gethrvtime in
procfs_ioctl)
AC_DEFINE(HAVE_GETHRVTIME_PROCFS_IOCTL,[1],
@@ -880,7 +937,14 @@ case $erl_gethrvtime in
exit(5);
exit(0); return 0;
}
- ], erl_clock_gettime=true, erl_clock_gettime=false, erl_clock_gettime=false)
+ ],
+ erl_clock_gettime=true,
+ erl_clock_gettime=false,
+ if test "x$erl_xcomp_clock_gettime" = "xyes"; then
+ erl_clock_gettime=true
+ else
+ erl_clock_gettime=false
+ fi)
LIBS=$save_libs
case $host_os in
linux*)
diff --git a/erts/configure.in b/erts/configure.in
index 895a357023..faccf5f102 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -94,13 +94,6 @@ enable_child_waiter_thread=no
ENABLE_ALLOC_TYPE_VARS=
AC_SUBST(ENABLE_ALLOC_TYPE_VARS)
-AC_ARG_WITH(xcomp-conf,
-[ --with-xcompconf=PATH path to cross compilation configuration])
-if test "x$with_xcompconf" != "xno" -a "x$with_xcompconf" != "x" ; then
- . $with_xcompconf
-fi
-
-
AC_ARG_ENABLE(threads,
[ --enable-threads enable async thread support
--disable-threads disable async thread support],
@@ -464,22 +457,18 @@ AC_SUBST(DEBUG_CFLAGS)
AC_SUBST(WFLAGS)
AC_SUBST(CFLAG_RUNTIME_LIBRARY_PATH)
-AC_CHECK_SIZEOF(void *, $erl_xcomp_void_p) # Needed for ARCH and smp checks below
+AC_CHECK_SIZEOF(void *) # Needed for ARCH and smp checks below
dnl
dnl Figure out operating system and cpu architecture
dnl
-if test "x$erl_xcomp_os" != "x"; then
- chk_opsys_=$erl_xcomp_os
+if test "x$host_alias" != "x"; then
+ chk_opsys_=$host_os
else
- if test "x$host_os" = "xwin32"; then
- chk_opsys_=win32
- else
- chk_opsys_=`uname -s`
- if test "x$chk_opsys_" = "xSunOS"; then
- chk_opsys_=$chk_opsys_`uname -r`
- fi
+ chk_opsys_=`uname -s`
+ if test "x$chk_opsys_" = "xSunOS"; then
+ chk_opsys_=$chk_opsys_`uname -r`
fi
fi
case $chk_opsys_ in
@@ -491,11 +480,12 @@ case $chk_opsys_ in
*) OPSYS=noopsys
esac
-if test "x$erl_xcomp_hw" != "x"; then
- chk_arch_=$erl_xcomp_hw
+if test "x$host_alias" != "x" -a "x$host_cpu" != "x"; then
+ chk_arch_=$host_cpu
else
chk_arch_=`uname -m`
fi
+
case $chk_arch_ in
sun4u) ARCH=ultrasparc;;
sparc64) ARCH=sparc64;;
@@ -1296,11 +1286,11 @@ dnl Interactive UX needs <net/errno.h> for socket related error codes.
dnl Some Linuxes needs <sys/socketio.h> instead of <sys/sockio.h>
dnl
AC_CHECK_HEADERS(fcntl.h limits.h unistd.h syslog.h dlfcn.h ieeefp.h \
- sys/stropts.h sys/sysctl.h \
+ sys/types.h sys/stropts.h sys/sysctl.h \
sys/ioctl.h sys/time.h sys/uio.h \
sys/socket.h sys/sockio.h sys/socketio.h \
net/errno.h malloc.h mach-o/dyld.h arpa/nameser.h \
- pty.h util.h utmp.h langinfo.h)
+ pty.h util.h utmp.h langinfo.h poll.h)
AC_CHECK_HEADER(sys/resource.h,
[AC_DEFINE(HAVE_SYS_RESOURCE_H, 1,
@@ -1389,11 +1379,13 @@ LM_STRUCT_SOCKADDR_SA_LEN
LM_STRUCT_EXCEPTION
AC_CHECK_SIZEOF(char, 1)
-AC_CHECK_SIZEOF(short, $erl_xcomp_short)
-AC_CHECK_SIZEOF(int, $erl_xcomp_int)
-AC_CHECK_SIZEOF(long, $erl_xcomp_long)
-AC_CHECK_SIZEOF(void *, $erl_xcomp_void_p)
-AC_CHECK_SIZEOF(long long, $erl_xcomp_long_long)
+AC_CHECK_SIZEOF(short)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(void *)
+AC_CHECK_SIZEOF(long long)
+AC_CHECK_SIZEOF(size_t)
+AC_CHECK_SIZEOF(off_t)
BITS64=
@@ -1457,71 +1449,26 @@ int main(void)
abort ();
return 0;
}
-],AC_MSG_RESULT(no)
-,AC_MSG_RESULT(yes)
-AC_MSG_ERROR([This gcc miscompiles the Erlang runtime system; please use a different version])
-,AC_MSG_RESULT(no))
-fi
-
-dnl AC_CHECK_SIZEOF(size_t, 4)dnl Assumes all cross compiling is to 32bit uP
-dnl
-dnl The disabled one above does not include stddef.h, alas!
-dnl
-AC_CACHE_CHECK([size of size_t], ac_cv_sizeof_size_t,
-AC_TRY_RUN([
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-int main(int argc, char **argv) {
- FILE *f = fopen("conftestval", "w");
- if (! f)
- exit(1); /* Failed */
- fprintf(f, "%d\n", (int) sizeof(size_t));
- exit(0); /* OK */
-}
-], ac_cv_sizeof_size_t=`cat conftestval`
-, ac_cv_sizeof_size_t=0
-, ac_cv_sizeof_size_t=$erl_xcomp_sizeof_size_t))
-AC_DEFINE_UNQUOTED(SIZEOF_SIZE_T, $ac_cv_sizeof_size_t, [The number of bytes in a size_t])
+], gcc_4_3_0_bug=no, gcc_4_3_0_bug=yes, gcc_4_3_0_bug=cross)
+
+case $gcc_4_3_0_bug in
+ yes|no)
+ gcc_4_3_0_bug_result=$gcc_4_3_0_bug;;
+ cross)
+ gcc_dumped_vsn=`$CC -dumpversion 2>/dev/null`
+ case gcc-$gcc_dumped_vsn in
+ gcc-4.3.0) gcc_4_3_0_bug=yes;;
+ *) gcc_4_3_0_bug=no;;
+ esac
+ gcc_4_3_0_bug_result="$gcc_4_3_0_bug; could not run test since cross compiling, checked version number ($gcc_dumped_vsn) instead";;
+esac
-dnl A standard size check does not include sys/types.h
-dnl
-AC_CACHE_CHECK([size of off_t], ac_cv_sizeof_off_t,
-AC_TRY_RUN([
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-int main(int argc, char **argv) {
- FILE *f = fopen("conftestval", "w");
- if (! f)
- exit(1); /* Failed */
- fprintf(f, "%d\n", (int) sizeof(off_t));
- exit(0); /* OK */
-}
-], ac_cv_sizeof_off_t=`cat conftestval`
-, ac_cv_sizeof_off_t=0
-, ac_cv_sizeof_off_t=$erl_xcomp_sizeof_off_t))
-AC_DEFINE_UNQUOTED(SIZEOF_OFF_T, $ac_cv_sizeof_off_t,
- [The number of bytes in an off_t])
+AC_MSG_RESULT([$gcc_4_3_0_bug_result])
+if test $gcc_4_3_0_bug = yes; then
+ AC_MSG_ERROR([This gcc miscompiles the Erlang runtime system; please use a different version])
+fi
-AC_MSG_CHECKING([int/long/void*/size_t sizes])
-AC_TRY_RUN([
-#include <stdlib.h>
-#include <stddef.h>
-int main(int argc, char **argv) {
- if (sizeof(void *) >= 4 &&
- sizeof(void *) == sizeof(size_t) &&
- (sizeof(void *) == sizeof(int) || sizeof(void *) == sizeof(long))) {
- exit(0); /* OK */
- }
- exit(1); /* Failed */
-}
-],AC_MSG_RESULT(ok)
-,AC_MSG_RESULT(failed)
-AC_MSG_ERROR([Cannot handle this combination of int/long/void*/size_t sizes])
-,AC_MSG_RESULT(ok))
+fi
if test "x$erl_xcomp_bigendian" != "x"; then
ac_cv_c_bigendian=$erl_xcomp_bigendian
@@ -1582,7 +1529,7 @@ AC_CHECK_FUNCS([ieee_handler fpsetmask finite isnan isinf res_gethostbyname dlop
pread pwrite writev memmove strerror strerror_r strncasecmp \
gethrtime localtime_r gmtime_r mremap memcpy mallopt \
sbrk _sbrk __sbrk brk _brk __brk \
- flockfile fstat strlcpy strlcat setsid posix2time setlocale nl_langinfo])
+ flockfile fstat strlcpy strlcat setsid posix2time setlocale nl_langinfo poll])
if test "X$host" = "Xwin32"; then
ac_cv_func_setvbuf_reversed=yes
fi
@@ -1858,9 +1805,11 @@ int main(void)
erts_cv___after_morecore_hook_can_track_malloc=no,
if test "x$erl_xcomp_after_morecore_hook" != "x"; then
erts_cv___after_morecore_hook_can_track_malloc=$erl_xcomp_after_morecore_hook
+ else
+ erts_cv___after_morecore_hook_can_track_malloc=no
fi)])
-if test "x$erts_cv___after_morecore_hook_can_track_malloc" = "xyes"; then
+if test $erts_cv___after_morecore_hook_can_track_malloc = yes; then
AC_DEFINE(ERTS___AFTER_MORECORE_HOOK_CAN_TRACK_MALLOC, 1, \
[Define if __after_morecore_hook can track malloc()s core memory use.])
fi
@@ -2116,7 +2065,11 @@ int main(void)
],
erts_cv_brk_wrappers_can_track_malloc=yes,
erts_cv_brk_wrappers_can_track_malloc=no,
- erts_cv_brk_wrappers_can_track_malloc=no)])
+ if test "x$erl_xcomp_dlsym_brk_wrappers" != "x"; then
+ erts_cv_brk_wrappers_can_track_malloc=$erl_xcomp_dlsym_brk_wrappers
+ else
+ erts_cv_brk_wrappers_can_track_malloc=no
+ fi)])
if test $erts_cv_brk_wrappers_can_track_malloc = yes; then
AC_DEFINE(ERTS_BRK_WRAPPERS_CAN_TRACK_MALLOC, 1, \
[Define if sbrk()/brk() wrappers can track malloc()s core memory use])
@@ -2643,7 +2596,14 @@ int main(int argc, const char **argv)
do_fmul();
return do_check();
}
-], erl_ok=reliable, erl_ok=unreliable, erl_ok=unreliable)
+],
+erl_ok=reliable,
+erl_ok=unreliable,
+if test "x$erl_xcomp_reliable_fpe" = "xyes"; then
+ erl_ok=reliable
+else
+ erl_ok=unreliable
+fi)
if test $erl_ok = unreliable; then
AC_DEFINE(NO_FPE_SIGNALS,[],
[Define if floating points exceptions are non-existing/not reliable])
@@ -2826,9 +2786,12 @@ fi
# Check for working poll().
#
AC_MSG_CHECKING([for working poll()])
-if test "x$erl_xcomp_poll" != "x"; then
- poll_works=$erl_xcomp_poll
+if test "x$ac_cv_header_poll_h" != "xyes" -o "x$ac_cv_func_poll" != "xyes"; then
+
+poll_works=no
+
else
+
AC_TRY_RUN([
#include <poll.h>
main()
@@ -2848,23 +2811,43 @@ main()
exit(0);
#endif
}
-], poll_works=true, poll_works=false, poll_works=false)
+],
+poll_works=yes,
+poll_works=no,
+poll_works=$erl_xcomp_poll)
+
+if test "X$poll_works" != "X"; then
+ guessed_poll_works=no
+else
+ guessed_poll_works=yes
+ case $host_os in
+ darwin*) poll_works=no;;
+ *) poll_works=yes;;
+ esac
+fi
+
fi
+
case $poll_works in
-true)
+yes)
AC_DEFINE(ERTS_USE_POLL, 1, [Define if poll() should be used instead of select()])
- AC_MSG_RESULT(ok)
+ AC_MSG_RESULT(yes)
;;
*)
#
# The USE_SELECT define is used by the ssl application (should not
# be used by erts).
#
+ poll_works=no
AC_DEFINE(USE_SELECT, 1, [Define if select() should be used instead of poll()])
- AC_MSG_RESULT(broken or based on select())
+ AC_MSG_RESULT([no; non-existing, broken, or based on select()])
;;
esac
+if test $guessed_poll_works = yes; then
+ AC_MSG_WARN([result $poll_works guessed based on OS ($host_os) because of cross compilation])
+fi
+
#
# If kqueue() found, check that it can be selected or polled on...
#
@@ -2900,7 +2883,14 @@ int main(void) {
}
return 0;
}
- ], ok_kqueue=true, ok_kqueue=false, ok_kqueue=false)
+ ],
+ ok_kqueue=true,
+ ok_kqueue=false,
+ if test "x$erl_xcomp_kqueue" = "xyes"; then
+ ok_kqueue=true
+ else
+ ok_kqueue=false
+ fi)
if test $ok_kqueue = true; then
AC_MSG_RESULT(yes);
else
@@ -2990,7 +2980,15 @@ int main(void) {
return 5;
return 0;
}
-], copying_putenv=yes, copying_putenv=no, copying_putenv=no)
+],
+copying_putenv=yes,
+copying_putenv=no,
+if test "x$erl_xcomp_putenv_copy" != "x"; then
+ copying_putenv=$erl_xcomp_putenv_copy
+else
+ copying_putenv=no
+fi)
+
if test $copying_putenv = yes; then
AC_DEFINE(HAVE_COPYING_PUTENV,[1],[Define if you have a putenv() that stores a copy of the key-value pair])
fi
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index c636d65ef3..2033ba8a66 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -34,12 +34,14 @@
<lib>erl_nif</lib>
<libsummary>API functions for an Erlang NIF library</libsummary>
<description>
- <warning><p>The NIF concept is introduced in R13B03 as an
+ <warning><p>The NIF concept was introduced in R13B03 as an
EXPERIMENTAL feature. The interfaces may be changed in any way
- in coming releases. The API introduced in this release is very
- sparse and contains only the most basic functions to read and
- write Erlang terms.
- </p></warning>
+ in coming releases. The API is still sparse and contains only
+ the most basic functions to read and write Erlang terms.
+ </p><p><em>R13B04</em>: The function prototypes of the NIFs
+ have changed to expect <c>argc</c> and <c>argv</c>
+ arguments. The arity of a NIF is by that no longer limited to
+ 3.</p></warning>
<p>A NIF library contains native implementation of some functions
of an erlang module. The native implemented functions (NIFs) are
@@ -56,7 +58,7 @@
/* niftest.c */
#include "erl_nif.h"
-static ERL_NIF_TERM hello(ErlNifEnv* env)
+static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_string(env, "Hello world!");
}
@@ -100,8 +102,9 @@ ok
</code>
<p>A better solution for a real module is to take advantage of
- the new attribute <c>on_load</c> to automatically load the NIF
- library when the module is loaded.</p>
+ the new directive <seealso
+ marker="doc/reference_manual:code_loading#on_load">on_load</seealso> to automatically
+ load the NIF library when the module is loaded.</p>
<p>A loaded NIF library is tied to the Erlang module code version
that loaded it. If the module is upgraded with a new version, the
new code will have to load its own NIF library (or maybe choose not
@@ -190,7 +193,7 @@ ok
<title>DATA TYPES</title>
<taglist>
- <tag><marker id="ErlDrvEnv"/>ErlDrvEnv</tag>
+ <tag><marker id="ErlNifEnv"/>ErlNifEnv</tag>
<item>
<p><c>ErlNifEnv</c> contains information about the context in
which a NIF call is made. This pointer should not be
@@ -205,31 +208,28 @@ ok
<p/>
<code type="none">
typedef struct {
- const char* name;
- unsigned arity;
- ERL_NIF_TERM (*fptr)(ErlNifEnv* env, ...);
+ const char* <em>name</em>;
+ unsigned <em>arity</em>;
+ ERL_NIF_TERM (*<em>fptr</em>)(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
} ErlNifFunc;
</code>
<p>Describes a NIF by its name, arity and implementation.
<c>fptr</c> is a pointer to the function that implements the
- NIF. The number of arguments must match the arity. A NIF of
- arity 2 will thus look like:</p>
- <p/>
- <code type="none">
-ERL_NIF_TERM my_nif(ErlNifEnv* env, ERL_NIF_TERM arg1, ERL_NIF_TERM arg2)
-{
- /* ... */
-}
-</code>
- <p>The maximum allowed arity for a NIF is 3 in current implementation.</p>
+ NIF. The argument <c>argv</c> of a NIF will contain the
+ function arguments passed to the NIF and <c>argc</c> is the
+ length of the array, i.e. the function arity. <c>argv[N-1]</c>
+ will thus denote the Nth argument to the NIF. Note that the
+ <c>argc</c> argument allows for the same C function to
+ implement several Erlang functions with different arity (but
+ same name probably).</p>
</item>
<tag><marker id="ErlNifBinary"/>ErlNifBinary</tag>
<item>
<p/>
<code type="none">
typedef struct {
- unsigned size;
- unsigned char* data;
+ unsigned <em>size</em>;
+ unsigned char* <em>data</em>;
} ErlNifBinary;
</code>
<p><c>ErlNifBinary</c> contains transient information about an
@@ -249,37 +249,36 @@ typedef struct {
</section>
<funcs>
- <func><name><ret>void*</ret><nametext>enif_get_data(ErlNifEnv* env)</nametext></name>
- <fsummary>Get the private data of a NIF library</fsummary>
- <desc><p>Returns the pointer to the private data that was set by <c>load</c>, <c>reload</c> or <c>upgrade</c>.</p></desc>
- </func>
<func><name><ret>void*</ret><nametext>enif_alloc(ErlNifEnv* env, size_t size)</nametext></name>
<fsummary>Allocate dynamic memory.</fsummary>
- <desc><p>Allocate memory of <c>size</c> bytes.</p></desc>
- </func>
- <func><name><ret>void</ret><nametext>enif_free(ErlNifEnv* env, void* ptr)</nametext></name>
- <fsummary>Free dynamic memory</fsummary>
- <desc><p>Free memory allocated by <c>enif_alloc</c>.</p></desc>
- </func>
- <func><name><ret>int</ret><nametext>enif_is_binary(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name>
- <fsummary>Determine if a term is a binary</fsummary>
- <desc><p>Return true if <c>term</c> is a binary</p></desc>
- </func>
- <func><name><ret>int</ret><nametext>enif_inspect_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term, ErlNifBinary* bin)</nametext></name>
- <fsummary>Inspect the content of a binary</fsummary>
- <desc><p>Initialize the structure pointed to by <c>bin</c> with
- transient information about the binary term
- <c>bin_term</c>. Return false if <c>bin_term</c> is not a binary.</p></desc>
+ <desc><p>Allocate memory of <c>size</c> bytes. Return NULL if allocation failed.</p></desc>
</func>
<func><name><ret>int</ret><nametext>enif_alloc_binary(ErlNifEnv* env, unsigned size, ErlNifBinary* bin)</nametext></name>
<fsummary>Create a new binary.</fsummary>
<desc><p>Allocate a new binary of size of <c>size</c>
bytes. Initialize the structure pointed to by <c>bin</c> to
- refer to the allocated binary.</p></desc>
+ refer to the allocated binary. Return false if allocation failed.</p></desc>
</func>
- <func><name><ret>void</ret><nametext>enif_release_binary(ErlNifEnv* env, ErlNifBinary* bin)</nametext></name>
- <fsummary>Release a binary.</fsummary>
- <desc><p>Release a binary obtained from <c>enif_alloc_binary</c> or <c>enif_inspect_binary</c>.</p></desc>
+ <func><name><ret>int</ret><nametext>enif_compare(ErlNifEnv* env, ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)</nametext></name>
+ <fsummary>Compare two terms</fsummary>
+ <desc><p>Return an integer less than, equal to, or greater than
+ zero if <c>lhs</c> is found, respectively, to be less than,
+ equal, or greater than <c>rhs</c>. Corresponds to the Erlang
+ operators <c>==</c>, <c>/=</c>, <c>=&lt;</c>, <c>&lt;</c>,
+ <c>&gt;=</c> and <c>&gt;</c> (but <em>not</em> <c>=:=</c> or <c>=/=</c>).</p></desc>
+ </func>
+ <func><name><ret>void</ret><nametext>enif_free(ErlNifEnv* env, void* ptr)</nametext></name>
+ <fsummary>Free dynamic memory</fsummary>
+ <desc><p>Free memory allocated by <c>enif_alloc</c>.</p></desc>
+ </func>
+ <func><name><ret>void*</ret><nametext>enif_get_data(ErlNifEnv* env)</nametext></name>
+ <fsummary>Get the private data of a NIF library</fsummary>
+ <desc><p>Return the pointer to the private data that was set by <c>load</c>, <c>reload</c> or <c>upgrade</c>.</p></desc>
+ </func>
+ <func><name><ret>int</ret><nametext>enif_get_double(ErlNifEnv* env, ERL_NIF_TERM term, double* dp)</nametext></name>
+ <fsummary>Read a floating-point number term.</fsummary>
+ <desc><p>Set <c>*dp</c> to the floating point value of
+ <c>term</c> or return false if <c>term</c> is not a float.</p></desc>
</func>
<func><name><ret>int</ret><nametext>enif_get_int(ErlNifEnv* env, ERL_NIF_TERM term, int* ip)</nametext></name>
<fsummary>Read an integer term.</fsummary>
@@ -287,45 +286,80 @@ typedef struct {
<c>term</c> or return false if <c>term</c> is not an integer or is
outside the bounds of type <c>int</c></p></desc>
</func>
- <func><name><ret>int</ret><nametext>enif_get_ulong(ErlNifEnv* env, ERL_NIF_TERM term, unsigned long* ip)</nametext></name>
- <fsummary>Read an unsigned long integer</fsummary>
- <desc><p>Set <c>*ip</c> to the unsigned long integer value of
- <c>term</c> or return false if <c>term</c> is not an unsigned
- integer or is outside the bounds of type <c>unsigned long</c></p></desc>
- </func>
<func><name><ret>int</ret><nametext>enif_get_list_cell(ErlNifEnv* env, ERL_NIF_TERM list, ERL_NIF_TERM* head, ERL_NIF_TERM* tail)</nametext></name>
<fsummary>Get head and tail from a list</fsummary>
<desc><p>Set <c>*head</c> and <c>*tail</c> from
<c>list</c> or return false if <c>list</c> is not a non-empty
list.</p></desc>
</func>
- <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)</nametext></name>
- <fsummary>Make a binary term.</fsummary>
- <desc><p>Make a binary term from <c>bin</c>. Will also release
- the binary.</p></desc>
+ <func><name><ret>int</ret><nametext>enif_get_tuple(ErlNifEnv* env, ERL_NIF_TERM term, int* arity, const ERL_NIF_TERM** array)</nametext></name>
+ <fsummary>Inspect the elements of a tuple.</fsummary>
+ <desc><p>If <c>term</c> is a tuple, set <c>*array</c> to point
+ to an array containing the elements of the tuple and set
+ <c>*arity</c> to the number of elements. Note that the array
+ is read-only an <c>(*array)[N-1]</c> will be the Nth element of
+ the tuple. <c>*array</c> is undefined if the arity of the tuple
+ is zero.</p><p>Return false if <c>term</c> is not a
+ tuple.</p></desc>
</func>
- <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_badarg(ErlNifEnv* env)</nametext></name>
- <fsummary>Make a badarg exception.</fsummary>
- <desc><p>Make a badarg exception to be returned from a NIF.</p></desc>
+ <func><name><ret>int</ret><nametext>enif_get_ulong(ErlNifEnv* env, ERL_NIF_TERM term, unsigned long* ip)</nametext></name>
+ <fsummary>Read an unsigned integer term.</fsummary>
+ <desc><p>Set <c>*ip</c> to the unsigned long integer value of
+ <c>term</c> or return false if <c>term</c> is not an unsigned integer or is
+ outside the bounds of type <c>unsigned long</c></p></desc>
</func>
- <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_int(ErlNifEnv* env, int i)</nametext></name>
- <fsummary>Create an integer term</fsummary>
- <desc><p>Create an integer term.</p></desc>
+ <func><name><ret>int</ret><nametext>enif_inspect_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term, ErlNifBinary* bin)</nametext></name>
+ <fsummary>Inspect the content of a binary</fsummary>
+ <desc><p>Initialize the structure pointed to by <c>bin</c> with
+ transient information about the binary term
+ <c>bin_term</c>. Return false if <c>bin_term</c> is not a binary.</p></desc>
</func>
- <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_ulong(ErlNifEnv* env, unsigned long i)</nametext></name>
- <fsummary>Create an integer term from an unsigned long int</fsummary>
- <desc><p>Create an integer term from an <c>unsigned long int</c>.</p></desc>
+ <func><name><ret>int</ret><nametext>enif_is_atom(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name>
+ <fsummary>Determine if a term is an atom</fsummary>
+ <desc><p>Return true if <c>term</c> is an atom.</p></desc>
+ </func>
+ <func><name><ret>int</ret><nametext>enif_is_binary(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name>
+ <fsummary>Determine if a term is a binary</fsummary>
+ <desc><p>Return true if <c>term</c> is a binary</p></desc>
+ </func>
+ <func><name><ret>int</ret><nametext>enif_is_identical(ErlNifEnv* env, ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)</nametext></name>
+ <fsummary>Erlang operator =:=</fsummary>
+ <desc><p>Return true if and only if the two terms are
+ identical. Corresponds to the Erlang operators <c>=:=</c> and
+ <c>=/=</c>.</p></desc>
+ </func>
+ <func><name><ret>int</ret><nametext>enif_is_ref(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name>
+ <fsummary>Determine if a term is a reference</fsummary>
+ <desc><p>Return true if <c>term</c> is a reference.</p></desc>
</func>
<func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_atom(ErlNifEnv* env, const char* name)</nametext></name>
<fsummary>Create an atom term</fsummary>
<desc><p>Create an atom term from the C-string <c>name</c>. Atom
terms may be saved and used between NIF calls.</p></desc>
</func>
- <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple(ErlNifEnv* env, unsigned cnt, ...)</nametext></name>
- <fsummary>Create a tuple term.</fsummary>
- <desc><p>Create a tuple term of arity <c>cnt</c>. Expects
- <c>cnt</c> number of arguments (after <c>cnt</c>) of type ERL_NIF_TERM as the
- elements of the tuple.</p></desc>
+ <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_badarg(ErlNifEnv* env)</nametext></name>
+ <fsummary>Make a badarg exception.</fsummary>
+ <desc><p>Make a badarg exception to be returned from a NIF.</p></desc>
+ </func>
+ <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)</nametext></name>
+ <fsummary>Make a binary term.</fsummary>
+ <desc><p>Make a binary term from <c>bin</c>. Will also release
+ the binary.</p></desc>
+ </func>
+ <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_double(ErlNifEnv* env, double d)</nametext></name>
+ <fsummary>Create an floating-point term</fsummary>
+ <desc><p>Create an floating-point term from a <c>double</c>.</p></desc>
+ </func>
+ <func><name><ret>int</ret><nametext>enif_make_existing_atom(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom)</nametext></name>
+ <fsummary>Create an existing atom term</fsummary>
+ <desc><p>Try to create the term of an already existing atom from
+ the C-string <c>name</c>. If the atom already exist store the
+ term in <c>*atom</c> and return true, otherwise return
+ false.</p></desc>
+ </func>
+ <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_int(ErlNifEnv* env, int i)</nametext></name>
+ <fsummary>Create an integer term</fsummary>
+ <desc><p>Create an integer term.</p></desc>
</func>
<func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_list(ErlNifEnv* env, unsigned cnt, ...)</nametext></name>
<fsummary>Create a list term.</fsummary>
@@ -337,11 +371,29 @@ typedef struct {
<fsummary>Create a list cell.</fsummary>
<desc><p>Create a list cell <c>[head | tail]</c>.</p></desc>
</func>
+ <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_ref(ErlNifEnv* env)</nametext></name>
+ <fsummary>Create a reference.</fsummary>
+ <desc><p>Create a reference like <seealso marker="erlang#make_ref-0">erlang:make_ref/0</seealso>.</p></desc>
+ </func>
<func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_string(ErlNifEnv* env, const char* string)</nametext></name>
<fsummary>Create a string.</fsummary>
- <desc><p>Creates a list containing the characters of the
+ <desc><p>Create a list containing the characters of the
C-string <c>string</c>.</p></desc>
</func>
+ <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_tuple(ErlNifEnv* env, unsigned cnt, ...)</nametext></name>
+ <fsummary>Create a tuple term.</fsummary>
+ <desc><p>Create a tuple term of arity <c>cnt</c>. Expects
+ <c>cnt</c> number of arguments (after <c>cnt</c>) of type ERL_NIF_TERM as the
+ elements of the tuple.</p></desc>
+ </func>
+ <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_ulong(ErlNifEnv* env, unsigned long i)</nametext></name>
+ <fsummary>Create an integer term from an unsigned long int</fsummary>
+ <desc><p>Create an integer term from an <c>unsigned long int</c>.</p></desc>
+ </func>
+ <func><name><ret>void</ret><nametext>enif_release_binary(ErlNifEnv* env, ErlNifBinary* bin)</nametext></name>
+ <fsummary>Release a binary.</fsummary>
+ <desc><p>Release a binary obtained from <c>enif_alloc_binary</c> or <c>enif_inspect_binary</c>.</p></desc>
+ </func>
</funcs>
<section>
<title>SEE ALSO</title>
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index fd4447009a..871fc0fd63 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -1929,7 +1929,7 @@ os_prompt%</pre>
</desc>
</func>
<func>
- <name>erlang:load_nif(Path, LoadInfo) -> ok | {error, Reason, Text}</name>
+ <name>erlang:load_nif(Path, LoadInfo) -> ok | {error, {Reason, Text}}</name>
<fsummary>Load NIF library</fsummary>
<type>
<v>Path = string()</v>
@@ -1940,9 +1940,10 @@ os_prompt%</pre>
</type>
<desc>
<warning>
- <p>This BIF is currently introduced as an experimental
- feature. The interface may be changed in any way in future
- releases.</p>
+ <p>This BIF is still an experimental feature. The interface
+ may be changed in any way in future releases.</p><p>In
+ R13B03 the return value on failure was
+ <c>{error,Reason,Text}</c>.</p>
</warning>
<p>Loads and links a dynamic library containing native
implemented functions (NIFs) for a module. <c>Path</c> is a
@@ -1957,10 +1958,10 @@ os_prompt%</pre>
<p>The call to <c>load_nif/2</c> must be made
<em>directly</em> from the Erlang code of the module that the
NIF library belongs to.</p>
- <p>It returns either <c>ok</c>, or <c>{error,Reason,Text}</c>
+ <p>It returns either <c>ok</c>, or <c>{error,{Reason,Text}}</c>
if loading fails. <c>Reason</c> is one of the atoms below,
while <c>Text</c> is a human readable string that may give
- some more information about the failure:</p>
+ some more information about the failure.</p>
<taglist>
<tag><c>load_failed</c></tag>
<item>
@@ -4641,7 +4642,7 @@ true</pre>
<fsummary>Split a binary into two</fsummary>
<type>
<v>Bin = Bin1 = Bin2 = binary()</v>
- <v>Pos = 1..byte_size(Bin)</v>
+ <v>Pos = 0..byte_size(Bin)</v>
</type>
<desc>
<p>Returns a tuple containing the binaries which are the result
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index dcaa43b51c..4ebb8853be 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -974,10 +974,6 @@ static int hibernate(Process* c_p, Eterm module, Eterm function,
static Eterm* call_fun(Process* p, int arity, Eterm* reg, Eterm args);
static Eterm* apply_fun(Process* p, Eterm fun, Eterm args, Eterm* reg);
static Eterm new_fun(Process* p, Eterm* reg, ErlFunEntry* fe, int num_free);
-static BIF_RETTYPE nif_dispatcher_0(Process* p, Uint* I);
-static BIF_RETTYPE nif_dispatcher_1(Process* p, Eterm arg1, Uint* I);
-static BIF_RETTYPE nif_dispatcher_2(Process* p, Eterm arg1, Eterm arg2, Uint* I);
-static BIF_RETTYPE nif_dispatcher_3(Process* p, Eterm arg1, Eterm arg2, Eterm arg3, Uint* I);
#if defined(_OSE_) || defined(VXWORKS)
static int init_done;
@@ -2949,11 +2945,38 @@ void process_main(void)
OpCase(call_nif):
{
- static void* const dispatchers[4] = {
- nif_dispatcher_0, nif_dispatcher_1, nif_dispatcher_2, nif_dispatcher_3
- };
- BifFunction vbf = dispatchers[I[-1]];
- goto apply_bif_or_nif;
+ /*
+ * call_nif is always first instruction in function:
+ *
+ * I[-3]: Module
+ * I[-2]: Function
+ * I[-1]: Arity
+ * I[0]: &&call_nif
+ * I[1]: Function pointer to NIF function
+ * I[2]: priv_data pointer
+ */
+ BifFunction vbf;
+
+ c_p->current = I-3; /* current and vbf set to please handle_error */
+ SWAPOUT;
+ c_p->fcalls = FCALLS - 1;
+ PROCESS_MAIN_CHK_LOCKS(c_p);
+ tmp_arg2 = I[-1];
+ ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
+
+ ASSERT(!ERTS_PROC_IS_EXITING(c_p));
+ {
+ typedef Eterm NifF(struct enif_environment_t*, int argc, Eterm argv[]);
+ NifF* fp = vbf = (NifF*) I[1];
+ struct enif_environment_t env;
+ erts_pre_nif(&env, c_p, (void*)I[2]);
+ reg[0] = r(0);
+ tmp_arg1 = (*fp)(&env, tmp_arg2, reg);
+ erts_post_nif(&env);
+ }
+ ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(tmp_arg1));
+ PROCESS_MAIN_CHK_LOCKS(c_p);
+ goto apply_bif_or_nif_epilogue;
OpCase(apply_bif):
/*
@@ -2966,17 +2989,15 @@ void process_main(void)
* code[3]: &&apply_bif
* code[4]: Function pointer to BIF function
*/
- vbf = (BifFunction) Arg(0);
- apply_bif_or_nif:
c_p->current = I-3; /* In case we apply process_info/1,2 or load_nif/1 */
c_p->i = I; /* In case we apply check_process_code/2. */
c_p->arity = 0; /* To allow garbage collection on ourselves
* (check_process_code/2).
*/
-
SWAPOUT;
c_p->fcalls = FCALLS - 1;
+ vbf = (BifFunction) Arg(0);
PROCESS_MAIN_CHK_LOCKS(c_p);
tmp_arg2 = I[-1];
ASSERT(tmp_arg2 <= 3);
@@ -3019,6 +3040,7 @@ void process_main(void)
break;
}
}
+apply_bif_or_nif_epilogue:
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
ERTS_HOLE_CHECK(c_p);
if (c_p->mbuf) {
@@ -5245,6 +5267,7 @@ save_stacktrace(Process* c_p, Eterm* pc, Eterm* reg, BifFunction bf,
* The Bif does not really exist (no BIF entry). It is a
* TRAP and traps are called through apply_bif, which also
* sets c_p->current (luckily).
+ * OR it is a NIF called by call_nif where current is also set.
*/
ASSERT(c_p->current);
s->current = c_p->current;
@@ -6148,51 +6171,3 @@ erts_current_reductions(Process *current, Process *p)
}
}
-static BIF_RETTYPE nif_dispatcher_0(Process* p, Uint* I)
-{
- typedef Eterm NifF(struct enif_environment_t*);
- NifF* fp = (NifF*) I[1];
- struct enif_environment_t env;
- Eterm ret;
- erts_pre_nif(&env, p, (void*)I[2]);
- ret = (*fp)(&env);
- erts_post_nif(&env);
- return ret;
-}
-
-static BIF_RETTYPE nif_dispatcher_1(Process* p, Eterm arg1, Uint* I)
-{
- typedef Eterm NifF(struct enif_environment_t*, Eterm);
- NifF* fp = (NifF*) I[1];
- struct enif_environment_t env;
- Eterm ret;
- erts_pre_nif(&env, p, (void*)I[2]);
- ret = (*fp)(&env, arg1);
- erts_post_nif(&env);
- return ret;
-}
-
-static BIF_RETTYPE nif_dispatcher_2(Process* p, Eterm arg1, Eterm arg2, Uint* I)
-{
- typedef Eterm NifF(struct enif_environment_t*, Eterm, Eterm);
- NifF* fp = (NifF*) I[1];
- struct enif_environment_t env;
- Eterm ret;
- erts_pre_nif(&env, p, (void*)I[2]);
- ret = (*fp)(&env, arg1, arg2);
- erts_post_nif(&env);
- return ret;
-}
-
-static BIF_RETTYPE nif_dispatcher_3(Process* p, Eterm arg1, Eterm arg2, Eterm arg3, Uint* I)
-{
- typedef Eterm NifF(struct enif_environment_t*, Eterm, Eterm, Eterm);
- NifF* fp = (NifF*) I[1];
- struct enif_environment_t env;
- Eterm ret;
- erts_pre_nif(&env, p, (void*)I[2]);
- ret = (*fp)(&env, arg1, arg2, arg3);
- erts_post_nif(&env);
- return ret;
-}
-
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 5ea47e16f5..cc69977b79 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -703,6 +703,8 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
erts_fdprintf(fd, "System version: ");
erts_print_system_version(fd, NULL, NULL);
erts_fdprintf(fd, "%s\n", "Compiled: " ERLANG_COMPILE_DATE);
+ erts_fdprintf(fd, "Taints: ");
+ erts_print_nif_taints(fd, NULL);
erts_fdprintf(fd, "Atoms: %d\n", atom_table_size());
info(fd, NULL); /* General system info */
if (process_tab != NULL) /* XXX true at init */
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index fa4454a3f3..2cb93112ae 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -35,13 +35,6 @@
#include <limits.h>
-/*
-static ERTS_INLINE Eterm* alloc_heap(ErlNifEnv* env, unsigned need)
-{
- return HAlloc(env->proc, need);
-}
-*/
-
#define MIN_HEAP_FRAG_SZ 200
static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need);
@@ -116,12 +109,21 @@ void enif_free(ErlNifEnv* env, void* ptr)
erts_free(ERTS_ALC_T_NIF, ptr);
}
+int enif_is_atom(ErlNifEnv* env, ERL_NIF_TERM term)
+{
+ return is_atom(term);
+}
int enif_is_binary(ErlNifEnv* env, ERL_NIF_TERM term)
{
return is_binary(term) && (binary_bitsize(term) % 8 == 0);
}
-
+
+int enif_is_ref(ErlNifEnv* env, ERL_NIF_TERM term)
+{
+ return is_ref(term);
+}
+
int enif_inspect_binary(ErlNifEnv* env, Eterm bin_term, ErlNifBinary* bin)
{
@@ -157,6 +159,25 @@ int enif_alloc_binary(ErlNifEnv* env, unsigned size, ErlNifBinary* bin)
return 1;
}
+int enif_realloc_binary(ErlNifEnv* env, ErlNifBinary* bin, unsigned size)
+{
+ Binary* oldbin;
+ Binary* newbin;
+ ASSERT(bin->ref_bin != NULL);
+
+ oldbin = (Binary*) bin->ref_bin;
+ newbin = (Binary *) erts_bin_realloc_fnf(oldbin, size);
+ if (!newbin) {
+ return 0;
+ }
+ newbin->orig_size = size;
+ bin->ref_bin = newbin;
+ bin->data = (unsigned char*) newbin->orig_bytes;
+ bin->size = size;
+ return 1;
+}
+
+
void enif_release_binary(ErlNifEnv* env, ErlNifBinary* bin)
{
if (bin->ref_bin == NULL) {
@@ -177,6 +198,28 @@ void enif_release_binary(ErlNifEnv* env, ErlNifBinary* bin)
#endif
}
+int enif_is_identical(ErlNifEnv* env, Eterm lhs, Eterm rhs)
+{
+ return EQ(lhs,rhs);
+}
+
+int enif_compare(ErlNifEnv* env, Eterm lhs, Eterm rhs)
+{
+ return cmp(lhs,rhs);
+}
+
+int enif_get_tuple(ErlNifEnv* env, Eterm tpl, int* arity, Eterm** array)
+{
+ Eterm* ptr;
+ if (is_not_tuple(tpl)) {
+ return 0;
+ }
+ ptr = tuple_val(tpl);
+ *arity = arityval(*ptr);
+ *array = ptr+1;
+ return 1;
+}
+
Eterm enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)
{
if (bin->ref_bin == NULL) {
@@ -203,7 +246,7 @@ Eterm enif_make_binary(ErlNifEnv* env, ErlNifBinary* bin)
}
}
-ERL_NIF_TERM enif_make_badarg(ErlNifEnv* env)
+Eterm enif_make_badarg(ErlNifEnv* env)
{
BIF_ERROR(env->proc, BADARG);
}
@@ -212,7 +255,7 @@ ERL_NIF_TERM enif_make_badarg(ErlNifEnv* env)
int enif_get_int(ErlNifEnv* env, Eterm term, int* ip)
{
#if SIZEOF_INT == SIZEOF_VOID_P
- return term_to_Sint(term, ip);
+ return term_to_Sint(term, (Sint*)ip);
#elif SIZEOF_LONG == SIZEOF_VOID_P
Sint i;
if (!term_to_Sint(term, &i) || i < INT_MIN || i > INT_MAX) {
@@ -234,6 +277,17 @@ int enif_get_ulong(ErlNifEnv* env, Eterm term, unsigned long* ip)
#endif
}
+int enif_get_double(ErlNifEnv* env, Eterm term, double* dp)
+{
+ FloatDef f;
+ if (is_not_float(term)) {
+ return 0;
+ }
+ GET_DOUBLE(term, f);
+ *dp = f.fd;
+ return 1;
+}
+
int enif_get_list_cell(ErlNifEnv* env, Eterm term, Eterm* head, Eterm* tail)
{
Eterm* val;
@@ -267,12 +321,24 @@ ERL_NIF_TERM enif_make_ulong(ErlNifEnv* env, unsigned long i)
}
+ERL_NIF_TERM enif_make_double(ErlNifEnv* env, double d)
+{
+ Eterm* hp = alloc_heap(env,FLOAT_SIZE_OBJECT);
+ FloatDef f;
+ f.fd = d;
+ PUT_DOUBLE(f, hp);
+ return make_float(hp);
+}
ERL_NIF_TERM enif_make_atom(ErlNifEnv* env, const char* name)
{
return am_atom_put(name, sys_strlen(name));
}
+int enif_make_existing_atom(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom)
+{
+ return erts_atom_get(name, sys_strlen(name), atom);
+}
ERL_NIF_TERM enif_make_tuple(ErlNifEnv* env, unsigned cnt, ...)
{
@@ -320,13 +386,43 @@ ERL_NIF_TERM enif_make_list(ErlNifEnv* env, unsigned cnt, ...)
ERL_NIF_TERM enif_make_string(ErlNifEnv* env, const char* string)
{
- Sint n = strlen(string);
+ Sint n = sys_strlen(string);
Eterm* hp = alloc_heap(env,n*2);
return erts_bld_string_n(&hp,NULL,string,n);
}
+ERL_NIF_TERM enif_make_ref(ErlNifEnv* env)
+{
+ Eterm* hp = alloc_heap(env, REF_THING_SIZE);
+ return erts_make_ref_in_buffer(hp);
+}
+
+#if 0 /* To be continued... */
+typedef struct enif_handle_type_t
+{
+ struct enif_handle_type_t* next;
+ struct enif_handle_type_t* prev;
+ const char* name;
+ void (*dtor)(void* obj);
+ erts_smp_atomic_t ref_cnt; /* num of handles of this type */
+}ErlNifHandleType;
+
+ErlNifHandleType*
+enif_create_handle_type(ErlNifEnv* env, const char* type_name,
+ void (*dtor)(void *))
+{
+
+}
+
+ERL_NIF_TERM enif_make_handle(ErlNifEnv* env, ErlNifHandleType* htype, void* obj)
+{
+}
+int enif_get_handle(ErlNifEnv* env, ERL_NIF_TERM term, void** objp)
+{
+}
+#endif
/***************************************************************************
** load_nif/2 **
@@ -361,7 +457,7 @@ static void refresh_cached_nif_data(Eterm* mod_code,
ErlNifFunc* func = &mod_nif->entry->funcs[i];
Uint* code_ptr;
- erts_atom_get(func->name, strlen(func->name), &f_atom);
+ erts_atom_get(func->name, sys_strlen(func->name), &f_atom);
code_ptr = *get_func_pp(mod_code, f_atom, func->arity);
code_ptr[5+2] = (Uint) mod_nif->data;
}
@@ -411,6 +507,18 @@ Eterm erts_nif_taints(Process* p)
return list;
}
+void erts_print_nif_taints(int to, void* to_arg)
+{
+ struct tainted_module_t* t;
+ const char* delim = "";
+ for (t=first_tainted_module ; t!=NULL; t=t->next) {
+ const Atom* atom = atom_tab(atom_val(t->module_atom));
+ erts_print(to,to_arg,"%s%.*s", delim, atom->len, atom->name);
+ delim = ",";
+ }
+ erts_print(to,to_arg,"\n");
+}
+
static Eterm load_nif_error(Process* p, const char* atom, const char* format, ...)
{
@@ -428,7 +536,8 @@ static Eterm load_nif_error(Process* p, const char* atom, const char* format, ..
for (;;) {
Eterm txt = erts_bld_string_n(hpp, &sz, dsbufp->str, dsbufp->str_len);
- ret = erts_bld_tuple(hpp, szp, 3, am_error, mkatom(atom), txt);
+ ret = erts_bld_tuple(hpp, szp, 2, am_error,
+ erts_bld_tuple(hpp, szp, 2, mkatom(atom), txt));
if (hpp != NULL) {
break;
}
@@ -489,8 +598,13 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
"module '%T' not allowed", mod_atom);
}
else if ((err=erts_sys_ddll_open2(lib_name, &handle, &errdesc)) != ERL_DE_NO_ERROR) {
- ret = load_nif_error(BIF_P, "load_failed", "Failed to load NIF library"
- " %s: '%s'", lib_name, errdesc.str);
+ const char slogan[] = "Failed to load NIF library";
+ if (strstr(errdesc.str, lib_name) != NULL) {
+ ret = load_nif_error(BIF_P, "load_failed", "%s: '%s'", slogan, errdesc.str);
+ }
+ else {
+ ret = load_nif_error(BIF_P, "load_failed", "%s %s: '%s'", slogan, lib_name, errdesc.str);
+ }
}
else if (erts_sys_ddll_load_nif_init(handle, &init_func, &errdesc) != ERL_DE_NO_ERROR) {
ret = load_nif_error(BIF_P, bad_lib, "Failed to find library init"
@@ -517,12 +631,8 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
for (i=0; i < entry->num_of_funcs && ret==am_ok; i++) {
Uint** code_pp;
ErlNifFunc* f = &entry->funcs[i];
- if (f->arity > 3) {
- ret = load_nif_error(BIF_P,bad_lib,"Function arity too high for NIF %s/%u",
- f->name, f->arity);
- }
- else if (!erts_atom_get(f->name, strlen(f->name), &f_atom)
- || (code_pp = get_func_pp(mod->code, f_atom, f->arity))==NULL) {
+ if (!erts_atom_get(f->name, sys_strlen(f->name), &f_atom)
+ || (code_pp = get_func_pp(mod->code, f_atom, f->arity))==NULL) {
ret = load_nif_error(BIF_P,bad_lib,"Function not found %T:%s/%u",
mod_atom, f->name, f->arity);
}
@@ -612,7 +722,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
for (i=0; i < entry->num_of_funcs; i++)
{
Uint* code_ptr;
- erts_atom_get(entry->funcs[i].name, strlen(entry->funcs[i].name), &f_atom);
+ erts_atom_get(entry->funcs[i].name, sys_strlen(entry->funcs[i].name), &f_atom);
code_ptr = *get_func_pp(mod->code, f_atom, entry->funcs[i].arity);
if (code_ptr[1] == 0) {
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index 8650b7ce47..e5e6d65c0e 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -20,23 +20,27 @@
/* Include file for writers of Native Implemented Functions.
*/
-#define ERL_NIF_MAJOR_VERSION 0
-#define ERL_NIF_MINOR_VERSION 1
+/* Version history:
+** 0.1: R13B03
+** 1.0: R13B04
+*/
+#define ERL_NIF_MAJOR_VERSION 1
+#define ERL_NIF_MINOR_VERSION 0
#include <stdlib.h>
typedef unsigned long ERL_NIF_TERM;
+struct enif_environment_t;
+typedef struct enif_environment_t ErlNifEnv;
+
typedef struct
{
const char* name;
unsigned arity;
- void* fptr; //ERL_NIF_TERM (*fptr)(void*, ...);
+ ERL_NIF_TERM (*fptr)(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
}ErlNifFunc;
-struct enif_environment_t;
-typedef struct enif_environment_t ErlNifEnv;
-
typedef struct enif_entry_t
{
int major;
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index 400c1822cc..7556806ce4 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -25,44 +25,68 @@
ERL_NIF_API_FUNC_DECL(void*,enif_get_data,(ErlNifEnv*));
ERL_NIF_API_FUNC_DECL(void*,enif_alloc,(ErlNifEnv*, size_t size));
ERL_NIF_API_FUNC_DECL(void,enif_free,(ErlNifEnv*, void* ptr));
+ERL_NIF_API_FUNC_DECL(int,enif_is_atom,(ErlNifEnv*, ERL_NIF_TERM term));
ERL_NIF_API_FUNC_DECL(int,enif_is_binary,(ErlNifEnv*, ERL_NIF_TERM term));
+ERL_NIF_API_FUNC_DECL(int,enif_is_ref,(ErlNifEnv*, ERL_NIF_TERM term));
ERL_NIF_API_FUNC_DECL(int,enif_inspect_binary,(ErlNifEnv*, ERL_NIF_TERM bin_term, ErlNifBinary* bin));
ERL_NIF_API_FUNC_DECL(int,enif_alloc_binary,(ErlNifEnv*, unsigned size, ErlNifBinary* bin));
+ERL_NIF_API_FUNC_DECL(int,enif_realloc_binary,(ErlNifEnv*, ErlNifBinary* bin, unsigned size));
ERL_NIF_API_FUNC_DECL(void,enif_release_binary,(ErlNifEnv*, ErlNifBinary* bin));
ERL_NIF_API_FUNC_DECL(int,enif_get_int,(ErlNifEnv*, ERL_NIF_TERM term, int* ip));
ERL_NIF_API_FUNC_DECL(int,enif_get_ulong,(ErlNifEnv*, ERL_NIF_TERM term, unsigned long* ip));
+ERL_NIF_API_FUNC_DECL(int,enif_get_double,(ErlNifEnv*, ERL_NIF_TERM term, double* dp));
ERL_NIF_API_FUNC_DECL(int,enif_get_list_cell,(ErlNifEnv* env, ERL_NIF_TERM term, ERL_NIF_TERM* head, ERL_NIF_TERM* tail));
+ERL_NIF_API_FUNC_DECL(int,enif_get_tuple,(ErlNifEnv* env, ERL_NIF_TERM tpl, int* arity, ERL_NIF_TERM** array));
+ERL_NIF_API_FUNC_DECL(int,enif_is_identical,(ErlNifEnv* env, ERL_NIF_TERM lhs, ERL_NIF_TERM rhs));
+ERL_NIF_API_FUNC_DECL(int,enif_compare,(ErlNifEnv* env, ERL_NIF_TERM lhs, ERL_NIF_TERM rhs));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_binary,(ErlNifEnv* env, ErlNifBinary* bin));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_badarg,(ErlNifEnv* env));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_int,(ErlNifEnv* env, int i));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ulong,(ErlNifEnv* env, unsigned long i));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_double,(ErlNifEnv* env, double d));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_atom,(ErlNifEnv* env, const char* name));
+ERL_NIF_API_FUNC_DECL(int,enif_make_existing_atom,(ErlNifEnv* env, const char* name, ERL_NIF_TERM* atom));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_tuple,(ErlNifEnv* env, unsigned cnt, ...));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list,(ErlNifEnv* env, unsigned cnt, ...));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_list_cell,(ErlNifEnv* env, ERL_NIF_TERM car, ERL_NIF_TERM cdr));
ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_string,(ErlNifEnv* env, const char* string));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_ref,(ErlNifEnv* env));
+/*
+** Add last to keep compatibility on Windows!!!
+*/
#endif
#ifdef ERL_NIF_API_FUNC_MACRO
# define enif_get_data ERL_NIF_API_FUNC_MACRO(enif_get_data)
# define enif_alloc ERL_NIF_API_FUNC_MACRO(enif_alloc)
# define enif_free ERL_NIF_API_FUNC_MACRO(enif_free)
+# define enif_is_atom ERL_NIF_API_FUNC_MACRO(enif_is_atom)
# define enif_is_binary ERL_NIF_API_FUNC_MACRO(enif_is_binary)
+# define enif_is_ref ERL_NIF_API_FUNC_MACRO(enif_is_ref)
# define enif_inspect_binary ERL_NIF_API_FUNC_MACRO(enif_inspect_binary)
# define enif_alloc_binary ERL_NIF_API_FUNC_MACRO(enif_alloc_binary)
+# define enif_realloc_binary ERL_NIF_API_FUNC_MACRO(enif_realloc_binary)
# define enif_release_binary ERL_NIF_API_FUNC_MACRO(enif_release_binary)
# define enif_get_int ERL_NIF_API_FUNC_MACRO(enif_get_int)
# define enif_get_ulong ERL_NIF_API_FUNC_MACRO(enif_get_ulong)
+# define enif_get_double ERL_NIF_API_FUNC_MACRO(enif_get_double)
+# define enif_get_tuple ERL_NIF_API_FUNC_MACRO(enif_get_tuple)
# define enif_get_list_cell ERL_NIF_API_FUNC_MACRO(enif_get_list_cell)
+# define enif_is_identical ERL_NIF_API_FUNC_MACRO(enif_is_identical)
+# define enif_compare ERL_NIF_API_FUNC_MACRO(enif_compare)
# define enif_make_binary ERL_NIF_API_FUNC_MACRO(enif_make_binary)
# define enif_make_badarg ERL_NIF_API_FUNC_MACRO(enif_make_badarg)
# define enif_make_int ERL_NIF_API_FUNC_MACRO(enif_make_int)
# define enif_make_ulong ERL_NIF_API_FUNC_MACRO(enif_make_ulong)
+# define enif_make_double ERL_NIF_API_FUNC_MACRO(enif_make_double)
# define enif_make_atom ERL_NIF_API_FUNC_MACRO(enif_make_atom)
+# define enif_make_existing_atom ERL_NIF_API_FUNC_MACRO(enif_make_existing_atom)
# define enif_make_tuple ERL_NIF_API_FUNC_MACRO(enif_make_tuple)
# define enif_make_list ERL_NIF_API_FUNC_MACRO(enif_make_list)
# define enif_make_list_cell ERL_NIF_API_FUNC_MACRO(enif_make_list_cell)
# define enif_make_string ERL_NIF_API_FUNC_MACRO(enif_make_string)
+# define enif_make_ref ERL_NIF_API_FUNC_MACRO(enif_make_ref)
+
#endif
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 9960172366..a4afe0574f 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -219,7 +219,7 @@ ErtsSchedulerData *erts_scheduler_data;
ErtsAlignedRunQueue *erts_aligned_run_queues;
Uint erts_no_run_queues;
-typedef struct {
+typedef union {
ErtsSchedulerData esd;
char align[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsSchedulerData))];
} ErtsAlignedSchedulerData;
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 7bae1e4efc..7597eb5e31 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -339,9 +339,14 @@ do { \
struct ErtsSchedulerData_ {
#ifdef ERTS_SMP
- ethr_tid tid; /* Thread id */
+ /*
+ * Keep X registers first (so we get as many low
+ * numbered registers as possible in the same cache
+ * line).
+ */
Eterm save_reg[ERTS_X_REGS_ALLOCATED]; /* X registers */
FloatDef freg[MAX_REG]; /* Floating point registers. */
+ ethr_tid tid; /* Thread id */
struct erl_bits_state erl_bits_state; /* erl_bits.c state */
void *match_pseudo_process; /* erl_db_util.c:db_prog_match() */
Process *free_process;
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 1b64e23174..62a788cbff 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -86,7 +86,8 @@ struct enif_environment_t /* ErlNifEnv */
};
extern void erts_pre_nif(struct enif_environment_t*, Process*, void* nif_data);
extern void erts_post_nif(struct enif_environment_t* env);
-extern Eterm erts_nif_taints(Process* p);
+extern Eterm erts_nif_taints(Process* p);
+extern void erts_print_nif_taints(int to, void* to_arg);
/*
* Port Specific Data.
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index 71cb6a36cc..4b949523fa 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -239,6 +239,11 @@ EXTERN_FUNCTION(int, real_printf, (const char *fmt, ...));
** Sint16: A signed integer of 16 bits exactly.
*/
+#if !((SIZEOF_VOID_P >= 4) && (SIZEOF_VOID_P == SIZEOF_SIZE_T) \
+ && ((SIZEOF_VOID_P == SIZEOF_INT) || (SIZEOF_VOID_P == SIZEOF_LONG)))
+#error Cannot handle this combination of int/long/void*/size_t sizes
+#endif
+
#if SIZEOF_VOID_P == 8
#undef ARCH_32
#define ARCH_64
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 213ff6637a..e47161fcbc 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -24,12 +24,13 @@
-include("test_server.hrl").
-export([all/1, fin_per_testcase/2, basic/1, reload/1, upgrade/1, heap_frag/1,
- neg/1]).
+ types/1, many_args/1, neg/1]).
+-export([many_args_100/100]).
-define(nif_stub,nif_stub_error(?LINE)).
all(suite) ->
- [basic, reload, upgrade, heap_frag, neg].
+ [basic, reload, upgrade, heap_frag, types, many_args, neg].
fin_per_testcase(_Func, _Config) ->
P1 = code:purge(nif_mod),
@@ -184,19 +185,68 @@ heap_frag_do(N, Max) ->
L = list_seq(N),
heap_frag_do(((N*5) div 4) + 1, Max).
+types(doc) -> ["Type tests"];
+types(suite) -> [];
+types(Config) when is_list(Config) ->
+ ensure_lib_loaded(Config),
+ ?line ok = type_test(),
+ lists:foreach(fun(Tpl) ->
+ Lst = erlang:tuple_to_list(Tpl),
+ Lst = tuple_2_list(Tpl)
+ end,
+ [{},{ok},{{}},{[],{}},{1,2,3,4,5}]),
+ Stuff = [[],{},0,0.0,(1 bsl 100),(fun()-> ok end),make_ref(),self()],
+ [eq_cmp(A,clone(B)) || A<-Stuff, B<-Stuff],
+ ok.
+
+clone(X) ->
+ binary_to_term(term_to_binary(X)).
+
+eq_cmp(A,B) ->
+ eq_cmp_do(A,B),
+ eq_cmp_do([A,B],[A,B]),
+ eq_cmp_do({A,B},{A,B}).
+
+eq_cmp_do(A,B) ->
+ %%?t:format("compare ~p and ~p\n",[A,B]),
+ Eq = (A =:= B),
+ ?line Eq = is_identical(A,B),
+ ?line Cmp = if
+ A < B -> -1;
+ A == B -> 0;
+ A > B -> 1
+ end,
+ ?line Cmp = case compare(A,B) of
+ C when is_integer(C), C < 0 -> -1;
+ 0 -> 0;
+ C when is_integer(C) -> 1
+ end,
+ ok.
+
+
+many_args(doc) -> ["Test NIF with many arguments"];
+many_args(suite) -> [];
+many_args(Config) when is_list(Config) ->
+ ?line ensure_lib_loaded(Config ,1),
+ ?line ok = apply(?MODULE,many_args_100,lists:seq(1,100)),
+ ?line ok = many_args_100(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100),
+ ok.
+
+
+
neg(doc) -> ["Negative testing of load_nif"];
neg(suite) -> [];
neg(Config) when is_list(Config) ->
?line {'EXIT',{badarg,_}} = (catch erlang:load_nif(badarg, 0)),
- ?line {error,load_failed,_} = erlang:load_nif("pink_unicorn", 0),
+ ?line {error,{load_failed,_}} = erlang:load_nif("pink_unicorn", 0),
?line Data = ?config(data_dir, Config),
?line File = filename:join(Data, "nif_mod"),
?line {ok,nif_mod,Bin} = compile:file(File, [binary,return_errors]),
?line {module,nif_mod} = erlang:load_module(nif_mod,Bin),
- ?line {error,bad_lib,_} = nif_mod:load_nif_lib(Config, no_init),
+ ?line {error,{bad_lib,_}} = nif_mod:load_nif_lib(Config, no_init),
?line ok.
@@ -230,6 +280,11 @@ call_history() -> ?nif_stub.
hold_nif_mod_priv_data(_Ptr) -> ?nif_stub.
nif_mod_call_history() -> ?nif_stub.
list_seq(_To) -> ?nif_stub.
+type_test() -> ?nif_stub.
+tuple_2_list(_) -> ?nif_stub.
+is_identical(_,_) -> ?nif_stub.
+compare(_,_) -> ?nif_stub.
+many_args_100(_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_) -> ?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 852495e234..4532062dce 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -1,6 +1,9 @@
#include "erl_nif.h"
+
+#include <stdio.h>
#include <string.h>
#include <assert.h>
+#include <limits.h>
#include "nif_mod.h"
@@ -65,7 +68,7 @@ static void unload(ErlNifEnv* env, void* priv_data)
}
}
-static ERL_NIF_TERM lib_version(ErlNifEnv* env)
+static ERL_NIF_TERM lib_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ADD_CALL("lib_version");
return enif_make_int(env, NIF_SUITE_LIB_VER);
@@ -89,19 +92,19 @@ static ERL_NIF_TERM make_call_history(ErlNifEnv* env, CallInfo** headp)
return list;
}
-static ERL_NIF_TERM call_history(ErlNifEnv* env)
+static ERL_NIF_TERM call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
PrivData* data = (PrivData*) enif_get_data(env);
return make_call_history(env,&data->call_history);
}
-static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, ERL_NIF_TERM a1)
+static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
PrivData* data = (PrivData*) enif_get_data(env);
unsigned long ptr_as_ulong;
- if (!enif_get_ulong(env,a1,&ptr_as_ulong)) {
+ if (!enif_get_ulong(env,argv[0],&ptr_as_ulong)) {
return enif_make_badarg(env);
}
if (data->nif_mod != NULL && --(data->nif_mod->ref_cnt) == 0) {
@@ -111,7 +114,7 @@ static ERL_NIF_TERM hold_nif_mod_priv_data(ErlNifEnv* env, ERL_NIF_TERM a1)
return enif_make_int(env,++(data->nif_mod->ref_cnt));
}
-static ERL_NIF_TERM nif_mod_call_history(ErlNifEnv* env)
+static ERL_NIF_TERM nif_mod_call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
PrivData* data = (PrivData*) enif_get_data(env);
@@ -121,11 +124,11 @@ static ERL_NIF_TERM nif_mod_call_history(ErlNifEnv* env)
return make_call_history(env,&data->nif_mod->call_history);
}
-static ERL_NIF_TERM list_seq(ErlNifEnv* env, ERL_NIF_TERM a1)
+static ERL_NIF_TERM list_seq(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ERL_NIF_TERM list;
int n;
- if (!enif_get_int(env, a1, &n)) {
+ if (!enif_get_int(env, argv[0], &n)) {
return enif_make_badarg(env);
}
list = enif_make_list(env, 0); /* NIL */
@@ -136,13 +139,183 @@ static ERL_NIF_TERM list_seq(ErlNifEnv* env, ERL_NIF_TERM a1)
return list;
}
+static int test_int(ErlNifEnv* env, int i1)
+{
+ int i2 = 0;
+ ERL_NIF_TERM int_term = enif_make_int(env, i1);
+ if (!enif_get_int(env,int_term, &i2) || i1 != i2) {
+ fprintf(stderr, "test_int(%d) ...FAILED i2=%d\r\n", i1, i2);
+ return 0;
+ }
+ return 1;
+}
+
+static int test_ulong(ErlNifEnv* env, unsigned long i1)
+{
+ unsigned long i2 = 0;
+ ERL_NIF_TERM int_term = enif_make_ulong(env, i1);
+ if (!enif_get_ulong(env,int_term, &i2) || i1 != i2) {
+ fprintf(stderr, "SVERK: test_ulong(%lu) ...FAILED i2=%lu\r\n", i1, i2);
+ return 0;
+ }
+ return 1;
+}
+
+static int test_double(ErlNifEnv* env, double d1)
+{
+ double d2 = 0;
+ ERL_NIF_TERM term = enif_make_double(env, d1);
+ if (!enif_get_double(env,term, &d2) || d1 != d2) {
+ fprintf(stderr, "SVERK: test_double(%e) ...FAILED i2=%e\r\n", d1, d2);
+ return 0;
+ }
+ return 1;
+}
+
+#define TAG_BITS 4
+#define SMALL_BITS (sizeof(void*)*8 - TAG_BITS)
+#define MAX_SMALL ((1L << (SMALL_BITS-1))-1)
+#define MIN_SMALL (-(1L << (SMALL_BITS-1)))
+
+static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int i;
+ unsigned long u;
+ double d;
+ ERL_NIF_TERM atom, ref1, ref2;
+
+ i = INT_MIN;
+ do {
+ if (!test_int(env,i)) {
+ goto error;
+ }
+ i += ~i / 3 + 1;
+ } while (i < 0);
+ i = INT_MAX;
+ do {
+ if (!test_int(env,i)) {
+ goto error;
+ }
+ i -= i / 3 + 1;
+ } while (i >= 0);
+
+ u = ULONG_MAX;
+ for (;;) {
+ if (!test_ulong(env,u)) {
+
+ }
+ if (u == 0) break;
+ u -= u / 3 + 1;
+ }
+
+ if (MAX_SMALL < INT_MAX) { /* 32-bit */
+ for (i=-10 ; i <= 10; i++) {
+ if (!test_int(env,MAX_SMALL+i)) {
+ goto error;
+ }
+ }
+ for (i=-10 ; i <= 10; i++) {
+ if (!test_int(env,MIN_SMALL+i)) {
+ goto error;
+ }
+ }
+ }
+ assert((MAX_SMALL < INT_MAX) == (MIN_SMALL > INT_MIN));
+
+ for (u=0 ; u < 10; u++) {
+ if (!test_ulong(env,MAX_SMALL+u) || !test_ulong(env,MAX_SMALL-u)) {
+ goto error;
+ }
+ }
+
+ for (d=3.141592e-100 ; d < 1e100 ; d *= 9.97) {
+ if (!test_double(env,d) || !test_double(env,-d)) {
+ goto error;
+ }
+ }
+
+ if (!enif_make_existing_atom(env,"nif_SUITE", &atom)
+ || !enif_is_identical(env,atom,enif_make_atom(env,"nif_SUITE"))) {
+ fprintf(stderr, "SVERK: nif_SUITE not an atom?\r\n");
+ goto error;
+ }
+ for (i=2; i; i--) {
+ if (enif_make_existing_atom(env,"nif_SUITE_pink_unicorn", &atom)) {
+ fprintf(stderr, "SVERK: pink unicorn exist?\r\n");
+ goto error;
+ }
+ }
+ ref1 = enif_make_ref(env);
+ ref2 = enif_make_ref(env);
+ if (!enif_is_ref(env,ref1) || !enif_is_ref(env,ref2)
+ || enif_is_identical(env,ref1,ref2) || enif_compare(env,ref1,ref2)==0) {
+ fprintf(stderr, "SVERK: strange refs?\r\n");
+ }
+ return enif_make_atom(env,"ok");
+
+error:
+ return enif_make_atom(env,"error");
+}
+
+static ERL_NIF_TERM tuple_2_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int arity = -1;
+ ERL_NIF_TERM* ptr;
+ ERL_NIF_TERM list = enif_make_list(env,0);
+
+ if (argc!=1 || !enif_get_tuple(env,argv[0],&arity,&ptr)) {
+ return enif_make_badarg(env);
+ }
+ while (--arity >= 0) {
+ list = enif_make_list_cell(env,ptr[arity],list);
+ }
+ return list;
+}
+
+static ERL_NIF_TERM is_identical(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ if (argc != 2) {
+ return enif_make_badarg(env);
+ }
+ return enif_make_atom(env, (enif_is_identical(env,argv[0],argv[1]) ?
+ "true" : "false"));
+}
+
+static ERL_NIF_TERM compare(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ if (argc != 2) {
+ return enif_make_badarg(env);
+ }
+ return enif_make_int(env, enif_compare(env,argv[0],argv[1]));
+}
+
+static ERL_NIF_TERM many_args_100(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int i, k;
+ if (argc == 100) {
+ for (i=1; i<=100; i++) {
+ if (!enif_get_int(env,argv[i-1],&k) || k!=i) {
+ goto badarg;
+ }
+ }
+ return enif_make_atom(env,"ok");
+ }
+badarg:
+ return enif_make_badarg(env);
+}
+
static ErlNifFunc nif_funcs[] =
{
{"lib_version", 0, lib_version},
{"call_history", 0, call_history},
{"hold_nif_mod_priv_data", 1, hold_nif_mod_priv_data},
{"nif_mod_call_history", 0, nif_mod_call_history},
- {"list_seq", 1, list_seq}
+ {"list_seq", 1, list_seq},
+ {"type_test", 0, type_test},
+ {"tuple_2_list", 1, tuple_2_list},
+ {"is_identical",2,is_identical},
+ {"compare",2,compare},
+ {"many_args_100", 100, many_args_100}
};
ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload)
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.c b/erts/emulator/test/nif_SUITE_data/nif_mod.c
index 18f676335a..2f2267cf78 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.c
@@ -58,13 +58,13 @@ static void unload(ErlNifEnv* env, void* priv_data)
}
}
-static ERL_NIF_TERM lib_version(ErlNifEnv* env)
+static ERL_NIF_TERM lib_version(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ADD_CALL("lib_version");
return enif_make_int(env, NIF_LIB_VER);
}
-static ERL_NIF_TERM call_history(ErlNifEnv* env)
+static ERL_NIF_TERM call_history(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
NifModPrivData* data = (NifModPrivData*) enif_get_data(env);
ERL_NIF_TERM list = enif_make_list(env, 0); /* NIL */
@@ -81,7 +81,7 @@ static ERL_NIF_TERM call_history(ErlNifEnv* env)
return list;
}
-static ERL_NIF_TERM get_priv_data_ptr(ErlNifEnv* env)
+static ERL_NIF_TERM get_priv_data_ptr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
ADD_CALL("get_priv_data_ptr");
return enif_make_ulong(env, (unsigned long)enif_get_data(env));
diff --git a/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c b/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c
index 732f1010ae..26f2420b8b 100644
--- a/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c
+++ b/erts/emulator/test/trace_nif_SUITE_data/trace_nif.c
@@ -20,18 +20,18 @@ static void unload(ErlNifEnv* env, void* priv_data)
{
}
-static ERL_NIF_TERM nif_0(ErlNifEnv* env)
+static ERL_NIF_TERM nif_0(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_tuple(env,2,
enif_make_atom(env,"ok"),
enif_make_list(env,0));
}
-static ERL_NIF_TERM nif_1(ErlNifEnv* env, ERL_NIF_TERM a1)
+static ERL_NIF_TERM nif_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_tuple(env,2,
enif_make_atom(env,"ok"),
- enif_make_list(env,1,a1));
+ enif_make_list(env,1,argv[0]));
}
diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops
index 2b7e8a6dde..4a859c3094 100755
--- a/erts/emulator/utils/beam_makeops
+++ b/erts/emulator/utils/beam_makeops
@@ -753,8 +753,8 @@ sub comment {
print "$prefix$line\n";
}
} else {
- print "$prefix Warning: Do not edit this file. It was automatically\n";
- print "$prefix generated by '$prog' on ", (scalar localtime), ".\n";
+ print "$prefix Warning: Do not edit this file.\n";
+ print "$prefix Auto-generated by '$prog'.\n";
}
if ($lang eq 'C') {
print " */\n";
diff --git a/erts/etc/unix/to_erl.c b/erts/etc/unix/to_erl.c
index 588d127445..886b301997 100644
--- a/erts/etc/unix/to_erl.c
+++ b/erts/etc/unix/to_erl.c
@@ -164,7 +164,7 @@ int main(int argc, char **argv)
dirp = opendir(pipename);
if(!dirp) {
- fprintf(stderr, "Can't access pipe directory %s.\n", pipename);
+ fprintf(stderr, "Can't access pipe directory %s: %s\n", pipename, strerror(errno));
exit(1);
}
@@ -205,7 +205,7 @@ int main(int argc, char **argv)
#ifdef DEBUG
fprintf(stderr, "Could not open FIFO %s for reading.\n", FIFO1);
#endif
- fprintf(stderr, "No running Erlang on pipe %s.\n", pipename);
+ fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno));
exit(1);
}
#ifdef DEBUG
@@ -216,7 +216,7 @@ int main(int argc, char **argv)
#ifdef DEBUG
fprintf(stderr, "Could not open FIFO %s for writing.\n", FIFO2);
#endif
- fprintf(stderr, "No running Erlang on pipe %s.\n", pipename);
+ fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno));
close(rfd);
exit(1);
}
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 7b6bafd1af..be1f71e6c5 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl
index c6f4c62f63..c0b3d286e8 100644
--- a/erts/preloaded/src/init.erl
+++ b/erts/preloaded/src/init.erl
@@ -1357,10 +1357,7 @@ run_on_load_handlers([M|Ms]) ->
{Pid,Ref} = spawn_monitor(Fun),
receive
{'DOWN',Ref,process,Pid,OnLoadRes} ->
- Keep = if
- is_boolean(OnLoadRes) -> OnLoadRes;
- true -> false
- end,
+ Keep = OnLoadRes =:= ok,
erlang:finish_after_on_load(M, Keep),
case Keep of
false ->