diff options
Diffstat (limited to 'erts')
-rw-r--r-- | erts/.gitignore | 22 | ||||
-rw-r--r-- | erts/aclocal.m4 | 132 | ||||
-rw-r--r-- | erts/configure.in | 200 | ||||
-rw-r--r-- | erts/doc/src/erl_nif.xml | 196 | ||||
-rw-r--r-- | erts/doc/src/erlang.xml | 15 | ||||
-rw-r--r-- | erts/emulator/Makefile.in | 2 | ||||
-rw-r--r-- | erts/emulator/beam/beam_emu.c | 95 | ||||
-rw-r--r-- | erts/emulator/beam/break.c | 2 | ||||
-rw-r--r-- | erts/emulator/beam/erl_nif.c | 154 | ||||
-rw-r--r-- | erts/emulator/beam/erl_nif.h | 16 | ||||
-rw-r--r-- | erts/emulator/beam/erl_nif_api_funcs.h | 24 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.c | 2 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.h | 7 | ||||
-rw-r--r-- | erts/emulator/beam/global.h | 3 | ||||
-rw-r--r-- | erts/emulator/beam/sys.h | 5 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE.erl | 63 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 189 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE_data/nif_mod.c | 6 | ||||
-rw-r--r-- | erts/emulator/test/trace_nif_SUITE_data/trace_nif.c | 6 | ||||
-rwxr-xr-x | erts/emulator/utils/beam_makeops | 4 | ||||
-rw-r--r-- | erts/etc/unix/to_erl.c | 6 | ||||
-rw-r--r-- | erts/preloaded/ebin/init.beam | bin | 44460 -> 44460 bytes | |||
-rw-r--r-- | erts/preloaded/src/init.erl | 5 |
23 files changed, 821 insertions, 333 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>=<</c>, <c><</c>, + <c>>=</c> and <c>></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/Makefile.in b/erts/emulator/Makefile.in index a2061134a5..903e1e96ba 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -402,7 +402,7 @@ endif $(RM) -f $(TARGET)/*/*/*.c $(TARGET)/*/*/*.h $(TARGET)/*/*/*.S $(RM) -f $(ERL_TOP)/erts/emulator/obj/$(TARGET)/*/*/*.o $(RM) -f $(BINDIR)/beam $(BINDIR)/beam.* - $(RM) -f $(BINDIR)/child_setup $(BINDIR)/child_setup.* + $(RM) -rf $(BINDIR)/child_setup $(BINDIR)/child_setup.* $(RM) -f $(BINDIR)/hipe_mkliterals $(BINDIR)/hipe_mkliterals.* @set -e ; cd zlib && $(MAKE) clean @set -e ; cd pcre && $(MAKE) clean 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 Binary files differindex 7b6bafd1af..be1f71e6c5 100644 --- a/erts/preloaded/ebin/init.beam +++ b/erts/preloaded/ebin/init.beam 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 -> |