diff options
Diffstat (limited to 'erts')
243 files changed, 9963 insertions, 3278 deletions
diff --git a/erts/Makefile.in b/erts/Makefile.in index 8b86fbadf2..1979c50781 100644 --- a/erts/Makefile.in +++ b/erts/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2006-2010. All Rights Reserved. +# Copyright Ericsson AB 2006-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ include vsn.mk # ---------------------------------------------------------------------- # Other erts dirs than the emulator dir... -ERTSDIRS = doc/src etc epmd lib_src +ERTSDIRS = etc epmd lib_src XINSTDIRS = preloaded ifeq ($(NO_START_SCRIPTS),) ERTSDIRS += start_scripts @@ -40,42 +40,36 @@ ifeq ($(BUILD_HYBRID_EMU),yes) EXTRA_FLAVORS += hybrid endif -# -# Some byggy 'make's get confused when a directory is created and used -# for storing files which other files depend on during the same "make -# session". As a workaround we do a 'make generate' (which creates -# all directories) before doing 'make opt', etc... -# - +.PHONY: all ifneq ($(BUILD_HYBRID_EMU),yes) all: smp opt else all: hybrid smp opt endif -debug opt docs clean: - @ case $@ in \ - docs|clean) ;; \ - *) ( cd emulator && $(MAKE) generate TYPE=$@ FLAVOR=$(FLAVOR)) ;; \ - esac - @ ( cd emulator && $(MAKE) $@ FLAVOR=$(FLAVOR)) - @for d in $(ERTSDIRS); do \ +.PHONY: docs +docs: + ( cd doc/src && $(MAKE) $@ ) + +.PHONY: debug opt clean +debug opt clean: + for d in emulator $(ERTSDIRS); do \ if test -d $$d; then \ - ( cd $$d && $(MAKE) $@ ) || exit $$? ; \ + ( cd $$d && $(MAKE) $@ FLAVOR=$(FLAVOR) ) || exit $$? ; \ fi ; \ - done + done # ---------------------------------------------------------------------- # These are "convenience targets", provided as shortcuts for developers # - don't use them in scripts or assume they will always stay like this! # +.PHONY: $(EXTRA_FLAVORS) $(EXTRA_FLAVORS): - @ ( cd emulator \ - && $(MAKE) generate TYPE=opt FLAVOR=$@ \ - && $(MAKE) opt FLAVOR=$@ ) + ( cd emulator && $(MAKE) opt FLAVOR=$@ ) ifneq ($(BUILD_HYBRID_EMU),yes) +.PHONY: hybrid hybrid: @echo '*** Omitted build of hybrid heap emulator' @echo '*** since target is $(TARGET)' @@ -88,6 +82,7 @@ endif # The copying of beam.dll should be removed when the beam dll need no longer be # in the same directory... +.PHONY: local_setup local_setup: @cd start_scripts && $(MAKE) @echo `ls $(ERL_TOP)/bin/` @@ -110,8 +105,7 @@ local_setup: cp $(ERL_TOP)/bin/$(TARGET)/escript.exe $(ERL_TOP)/bin/escript.exe; \ chmod 755 $(ERL_TOP)/bin/erl.exe $(ERL_TOP)/bin/erlc.exe \ $(ERL_TOP)/bin/werl.exe; \ - $(ERL_TOP)/erts/etc/win32/cygwin_tools/make_local_ini.sh \ - $(ERL_TOP); \ + make_local_ini.sh $(ERL_TOP); \ else \ sed -e "s;%FINAL_ROOTDIR%;$(ERL_TOP);" \ -e "s;erts-.*/bin;bin/$(TARGET);" \ @@ -135,11 +129,13 @@ local_setup: $(ERL_TOP)/bin/start_clean.script # Run the configure script +.PHONY: configure configure: @set -e ; cd autoconf && $(MAKE) # Remake the makefiles, if you already have configured but you have edited # a "Makefile.in". +.PHONY: makefiles makefiles: @set -e ; cd autoconf && $(MAKE) $@ @@ -147,21 +143,17 @@ makefiles: # Release targets # -release release_docs: -ifeq ($(BUILD_HYBRID_EMU),yes) - @if test $@ = release; then ( cd emulator && $(MAKE) $@ FLAVOR=hybrid) fi -else - @if test $@ = release; then ( $(MAKE) hybrid ) fi -endif - @if test $@ = release; then ( cd emulator && $(MAKE) $@ FLAVOR=smp) fi - @ (cd emulator && $(MAKE) $@ FLAVOR=plain) - @for d in $(ERTSDIRS) $(XINSTDIRS); do \ +.PHONY: release +release: + for f in plain $(EXTRA_FLAVORS) ; do \ + ( cd emulator && $(MAKE) release FLAVOR=$$f ) \ + done + for d in $(ERTSDIRS) $(XINSTDIRS); do \ if test -d $$d; then \ ( cd $$d && $(MAKE) $@ ) || exit $$? ; \ fi ; \ done -# ---------------------------------------------------------------------- - -.PHONY: debug opt docs clean local_setup configure release \ - release_docs run_test_cases hybrid smp +.PHONY: release_docs +release_docs: + ( cd doc/src && $(MAKE) $@ ) diff --git a/erts/aclocal.m4 b/erts/aclocal.m4 index bd228a2d1f..339a15a2bb 100644 --- a/erts/aclocal.m4 +++ b/erts/aclocal.m4 @@ -112,6 +112,94 @@ fi dnl ---------------------------------------------------------------------- dnl +dnl LM_WINDOWS_ENVIRONMENT +dnl +dnl +dnl Tries to determine thw windows build environment, i.e. +dnl MIXED_CYGWIN_VC or MIXED_MSYS_VC +dnl + +AC_DEFUN(LM_WINDOWS_ENVIRONMENT, +[ +MIXED_CYGWIN=no +MIXED_MSYS=no + +AC_MSG_CHECKING(for mixed cygwin or msys and native VC++ environment) +if test "X$host" = "Xwin32" -a "x$GCC" != "xyes"; then + if test -x /usr/bin/cygpath; then + CFLAGS="-O2" + MIXED_CYGWIN=yes + AC_MSG_RESULT([Cygwin and VC]) + MIXED_CYGWIN_VC=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_CYGWIN_VC" + elif test -x /usr/bin/msysinfo; then + CFLAGS="-O2" + MIXED_MSYS=yes + AC_MSG_RESULT([MSYS and VC]) + MIXED_MSYS_VC=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_MSYS_VC" + else + AC_MSG_RESULT([undeterminable]) + AC_MSG_ERROR(Seems to be mixed windows but not with cygwin, cannot handle this!) + fi +else + AC_MSG_RESULT([no]) + MIXED_CYGWIN_VC=no + MIXED_MSYS_VC=no +fi +AC_SUBST(MIXED_CYGWIN_VC) +AC_SUBST(MIXED_MSYS_VC) + +MIXED_VC=no +if test "x$MIXED_MSYS_VC" = "xyes" -o "x$MIXED_CYGWIN_VC" = "xyes" ; then + MIXED_VC=yes +fi + +AC_SUBST(MIXED_VC) + +if test "x$MIXED_MSYS" != "xyes"; then + AC_MSG_CHECKING(for mixed cygwin and native MinGW environment) + if test "X$host" = "Xwin32" -a "x$GCC" = x"yes"; then + if test -x /usr/bin/cygpath; then + CFLAGS="-O2" + MIXED_CYGWIN=yes + AC_MSG_RESULT([yes]) + MIXED_CYGWIN_MINGW=yes + CPPFLAGS="$CPPFLAGS -DERTS_MIXED_CYGWIN_MINGW" + else + AC_MSG_RESULT([undeterminable]) + AC_MSG_ERROR(Seems to be mixed windows but not with cygwin, cannot handle this!) + fi + else + AC_MSG_RESULT([no]) + MIXED_CYGWIN_MINGW=no + fi +else + MIXED_CYGWIN_MINGW=no +fi +AC_SUBST(MIXED_CYGWIN_MINGW) + +AC_MSG_CHECKING(if we mix cygwin with any native compiler) +if test "X$MIXED_CYGWIN" = "Xyes"; then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +AC_SUBST(MIXED_CYGWIN) + +AC_MSG_CHECKING(if we mix msys with another native compiler) +if test "X$MIXED_MSYS" = "Xyes" ; then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +AC_SUBST(MIXED_MSYS) +]) + +dnl ---------------------------------------------------------------------- +dnl dnl LM_FIND_EMU_CC dnl dnl @@ -125,8 +213,10 @@ AC_DEFUN(LM_FIND_EMU_CC, ac_cv_prog_emu_cc, [ AC_TRY_COMPILE([],[ -#ifdef __llvm__ -#error "llvm is currently unable to compile beam_emu.c" +#if defined(__clang_major__) && __clang_major__ >= 3 + /* clang 3.x or later is fine */ +#elif defined(__llvm__) +#error "this version of llvm is unable to correctly compile beam_emu.c" #endif __label__ lbl1; __label__ lbl2; @@ -168,6 +258,11 @@ if test $ac_cv_prog_emu_cc != no; then CFLAGS="" CPPFLAGS="" AC_TRY_COMPILE([],[ +#if defined(__clang_major__) && __clang_major__ >= 3 + /* clang 3.x or later is fine */ +#elif defined(__llvm__) +#error "this version of llvm is unable to correctly compile beam_emu.c" +#endif __label__ lbl1; __label__ lbl2; int x = magic(); diff --git a/erts/autoconf/win64.config.cache.static b/erts/autoconf/win64.config.cache.static new file mode 100755 index 0000000000..a8a2bfb59c --- /dev/null +++ b/erts/autoconf/win64.config.cache.static @@ -0,0 +1,271 @@ +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +ac_cv_c_bigendian=${ac_cv_c_bigendian=no} +ac_cv_c_compiler_gnu=${ac_cv_c_compiler_gnu=no} +ac_cv_c_const=${ac_cv_c_const=yes} +ac_cv_cxx_compiler_gnu=${ac_cv_cxx_compiler_gnu=no} +ac_cv_decl_h_errno=${ac_cv_decl_h_errno=no} +ac_cv_decl_inaddr_loopback=${ac_cv_decl_inaddr_loopback=no} +ac_cv_decl_inaddr_loopback_rpc=${ac_cv_decl_inaddr_loopback_rpc=no} +ac_cv_decl_inaddr_loopback_winsock2=${ac_cv_decl_inaddr_loopback_winsock2=yes} +ac_cv_decl_so_bsdcompat=${ac_cv_decl_so_bsdcompat=no} +ac_cv_decl_sys_errlist=${ac_cv_decl_sys_errlist=no} +ac_cv_env_AR_set=set +ac_cv_env_AR_value=ar.sh +ac_cv_env_CCC_set= +ac_cv_env_CCC_value= +ac_cv_env_CC_set=set +ac_cv_env_CC_value=cc.sh +ac_cv_env_CFLAGS_set= +ac_cv_env_CFLAGS_value= +ac_cv_env_CPPFLAGS_set= +ac_cv_env_CPPFLAGS_value= +ac_cv_env_CPP_set= +ac_cv_env_CPP_value= +ac_cv_env_CXXFLAGS_set= +ac_cv_env_CXXFLAGS_value= +ac_cv_env_CXX_set=set +ac_cv_env_CXX_value=cc.sh +ac_cv_env_LDFLAGS_set= +ac_cv_env_LDFLAGS_value= +ac_cv_env_build_alias_set=set +ac_cv_env_build_alias_value=win32 +ac_cv_env_host_alias_set=set +ac_cv_env_host_alias_value=win32 +ac_cv_env_target_alias_set=set +ac_cv_env_target_alias_value=win32 +ac_cv_exeext=${ac_cv_exeext=.exe} +ac_cv_func___brk=${ac_cv_func___brk=no} +ac_cv_func___sbrk=${ac_cv_func___sbrk=no} +ac_cv_func__brk=${ac_cv_func__brk=no} +ac_cv_func__doprnt=${ac_cv_func__doprnt=no} +ac_cv_func__sbrk=${ac_cv_func__sbrk=no} +ac_cv_func_accept=${ac_cv_func_accept=no} +ac_cv_func_alloca_works=${ac_cv_func_alloca_works=yes} +ac_cv_func_brk=${ac_cv_func_brk=no} +ac_cv_func_clock_gettime=${ac_cv_func_clock_gettime=no} +ac_cv_func_connect=${ac_cv_func_connect=no} +ac_cv_func_decl_fread=${ac_cv_func_decl_fread=yes} +ac_cv_func_dlopen=${ac_cv_func_dlopen=no} +ac_cv_func_dup2=${ac_cv_func_dup2=yes} +ac_cv_func_fdatasync=${ac_cv_func_fdatasync=no} +ac_cv_func_finite=${ac_cv_func_finite=no} +ac_cv_func_flockfile=${ac_cv_func_flockfile=no} +ac_cv_func_fork=${ac_cv_func_fork=no} +ac_cv_func_fork_works=${ac_cv_func_fork_works=no} +ac_cv_func_fpsetmask=${ac_cv_func_fpsetmask=no} +ac_cv_func_fstat=${ac_cv_func_fstat=yes} +ac_cv_func_gethostbyaddr=${ac_cv_func_gethostbyaddr=no} +ac_cv_func_gethostbyaddr_r=${ac_cv_func_gethostbyaddr_r=no} +ac_cv_func_gethostbyname=${ac_cv_func_gethostbyname=yes} +ac_cv_func_gethostbyname2=${ac_cv_func_gethostbyname2=no} +ac_cv_func_gethostbyname_r=${ac_cv_func_gethostbyname_r=no} +ac_cv_func_gethostname=${ac_cv_func_gethostname=no} +ac_cv_func_gethrtime=${ac_cv_func_gethrtime=no} +ac_cv_func_getifaddrs=${ac_cv_func_getifaddrs=no} +ac_cv_func_getipnodebyaddr=${ac_cv_func_getipnodebyaddr=no} +ac_cv_func_getipnodebyname=${ac_cv_func_getipnodebyname=no} +ac_cv_func_getpagesize=${ac_cv_func_getpagesize=no} +ac_cv_func_gettimeofday=${ac_cv_func_gettimeofday=no} +ac_cv_func_gmtime_r=${ac_cv_func_gmtime_r=no} +ac_cv_func_ieee_handler=${ac_cv_func_ieee_handler=no} +ac_cv_func_inet_ntoa=${ac_cv_func_inet_ntoa=no} +ac_cv_func_inet_pton=${ac_cv_func_inet_pton=yes} +ac_cv_func_isinf=${ac_cv_func_isinf=no} +ac_cv_func_isnan=${ac_cv_func_isnan=no} +ac_cv_func_localtime_r=${ac_cv_func_localtime_r=no} +ac_cv_func_mallopt=${ac_cv_func_mallopt=no} +ac_cv_func_memchr=${ac_cv_func_memchr=yes} +ac_cv_func_memcmp_working=${ac_cv_func_memcmp_working=yes} +ac_cv_func_memcpy=${ac_cv_func_memcpy=no} +ac_cv_func_memmove=${ac_cv_func_memmove=yes} +ac_cv_func_memset=${ac_cv_func_memset=yes} +ac_cv_func_mmap=${ac_cv_func_mmap=no} +ac_cv_func_mmap_fixed_mapped=${ac_cv_func_mmap_fixed_mapped=no} +ac_cv_func_mremap=${ac_cv_func_mremap=no} +ac_cv_func_nl_langinfo=${ac_cv_func_nl_langinfo=no} +ac_cv_func_openpty=${ac_cv_func_openpty=no} +ac_cv_func_poll=${ac_cv_func_poll=no} +ac_cv_func_posix2time=${ac_cv_func_posix2time=no} +ac_cv_func_posix_fadvise=${ac_cv_func_posix_fadvise=no} +ac_cv_func_pread=${ac_cv_func_pread=no} +ac_cv_func_pwrite=${ac_cv_func_pwrite=no} +ac_cv_func_res_gethostbyname=${ac_cv_func_res_gethostbyname=no} +ac_cv_func_sbrk=${ac_cv_func_sbrk=no} +ac_cv_func_sctp_bindx=${ac_cv_func_sctp_bindx=no} +ac_cv_func_sctp_peeloff=${ac_cv_func_sctp_peeloff=no} +ac_cv_func_select=${ac_cv_func_select=no} +ac_cv_func_setlocale=${ac_cv_func_setlocale=yes} +ac_cv_func_setsid=${ac_cv_func_setsid=no} +ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed=yes} +ac_cv_func_socket=${ac_cv_func_socket=no} +ac_cv_func_strchr=${ac_cv_func_strchr=yes} +ac_cv_func_strerror=${ac_cv_func_strerror=yes} +ac_cv_func_strerror_r=${ac_cv_func_strerror_r=no} +ac_cv_func_strlcat=${ac_cv_func_strlcat=no} +ac_cv_func_strlcpy=${ac_cv_func_strlcpy=no} +ac_cv_func_strncasecmp=${ac_cv_func_strncasecmp=no} +ac_cv_func_strrchr=${ac_cv_func_strrchr=yes} +ac_cv_func_strstr=${ac_cv_func_strstr=yes} +ac_cv_func_uname=${ac_cv_func_uname=no} +ac_cv_func_vfork=${ac_cv_func_vfork=no} +ac_cv_func_vfork_works=${ac_cv_func_vfork_works=no} +ac_cv_func_vprintf=${ac_cv_func_vprintf=yes} +ac_cv_func_writev=${ac_cv_func_writev=no} +ac_cv_have_decl_SCTPS_BOUND=${ac_cv_have_decl_SCTPS_BOUND=no} +ac_cv_have_decl_SCTPS_COOKIE_ECHOED=${ac_cv_have_decl_SCTPS_COOKIE_ECHOED=no} +ac_cv_have_decl_SCTPS_COOKIE_WAIT=${ac_cv_have_decl_SCTPS_COOKIE_WAIT=no} +ac_cv_have_decl_SCTPS_ESTABLISHED=${ac_cv_have_decl_SCTPS_ESTABLISHED=no} +ac_cv_have_decl_SCTPS_IDLE=${ac_cv_have_decl_SCTPS_IDLE=no} +ac_cv_have_decl_SCTPS_LISTEN=${ac_cv_have_decl_SCTPS_LISTEN=no} +ac_cv_have_decl_SCTPS_SHUTDOWN_ACK_SENT=${ac_cv_have_decl_SCTPS_SHUTDOWN_ACK_SENT=no} +ac_cv_have_decl_SCTPS_SHUTDOWN_PENDING=${ac_cv_have_decl_SCTPS_SHUTDOWN_PENDING=no} +ac_cv_have_decl_SCTPS_SHUTDOWN_RECEIVED=${ac_cv_have_decl_SCTPS_SHUTDOWN_RECEIVED=no} +ac_cv_have_decl_SCTPS_SHUTDOWN_SENT=${ac_cv_have_decl_SCTPS_SHUTDOWN_SENT=no} +ac_cv_have_decl_SCTP_ABORT=${ac_cv_have_decl_SCTP_ABORT=no} +ac_cv_have_decl_SCTP_ADDR_CONFIRMED=${ac_cv_have_decl_SCTP_ADDR_CONFIRMED=no} +ac_cv_have_decl_SCTP_ADDR_OVER=${ac_cv_have_decl_SCTP_ADDR_OVER=no} +ac_cv_have_decl_SCTP_BOUND=${ac_cv_have_decl_SCTP_BOUND=no} +ac_cv_have_decl_SCTP_CLOSED=${ac_cv_have_decl_SCTP_CLOSED=no} +ac_cv_have_decl_SCTP_COOKIE_ECHOED=${ac_cv_have_decl_SCTP_COOKIE_ECHOED=no} +ac_cv_have_decl_SCTP_COOKIE_WAIT=${ac_cv_have_decl_SCTP_COOKIE_WAIT=no} +ac_cv_have_decl_SCTP_DELAYED_ACK_TIME=${ac_cv_have_decl_SCTP_DELAYED_ACK_TIME=no} +ac_cv_have_decl_SCTP_EMPTY=${ac_cv_have_decl_SCTP_EMPTY=no} +ac_cv_have_decl_SCTP_EOF=${ac_cv_have_decl_SCTP_EOF=no} +ac_cv_have_decl_SCTP_ESTABLISHED=${ac_cv_have_decl_SCTP_ESTABLISHED=no} +ac_cv_have_decl_SCTP_LISTEN=${ac_cv_have_decl_SCTP_LISTEN=no} +ac_cv_have_decl_SCTP_SENDALL=${ac_cv_have_decl_SCTP_SENDALL=no} +ac_cv_have_decl_SCTP_SHUTDOWN_ACK_SENT=${ac_cv_have_decl_SCTP_SHUTDOWN_ACK_SENT=no} +ac_cv_have_decl_SCTP_SHUTDOWN_PENDING=${ac_cv_have_decl_SCTP_SHUTDOWN_PENDING=no} +ac_cv_have_decl_SCTP_SHUTDOWN_RECEIVED=${ac_cv_have_decl_SCTP_SHUTDOWN_RECEIVED=no} +ac_cv_have_decl_SCTP_SHUTDOWN_SENT=${ac_cv_have_decl_SCTP_SHUTDOWN_SENT=no} +ac_cv_have_decl_SCTP_UNORDERED=${ac_cv_have_decl_SCTP_UNORDERED=no} +ac_cv_have_decl_posix2time=${ac_cv_have_decl_posix2time=no} +ac_cv_header_arpa_inet_h=${ac_cv_header_arpa_inet_h=no} +ac_cv_header_arpa_nameser_h=${ac_cv_header_arpa_nameser_h=no} +ac_cv_header_dirent_dirent_h=${ac_cv_header_dirent_dirent_h=no} +ac_cv_header_dirent_ndir_h=${ac_cv_header_dirent_ndir_h=no} +ac_cv_header_dirent_sys_dir_h=${ac_cv_header_dirent_sys_dir_h=no} +ac_cv_header_dirent_sys_ndir_h=${ac_cv_header_dirent_sys_ndir_h=no} +ac_cv_header_dlfcn_h=${ac_cv_header_dlfcn_h=no} +ac_cv_header_fcntl_h=${ac_cv_header_fcntl_h=yes} +ac_cv_header_gl_gl_h=${ac_cv_header_gl_gl_h=yes} +ac_cv_header_ieeefp_h=${ac_cv_header_ieeefp_h=no} +ac_cv_header_ifaddrs_h=${ac_cv_header_ifaddrs_h=no} +ac_cv_header_inttypes_h=${ac_cv_header_inttypes_h=no} +ac_cv_header_langinfo_h=${ac_cv_header_langinfo_h=no} +ac_cv_header_limits_h=${ac_cv_header_limits_h=yes} +ac_cv_header_mach_o_dyld_h=${ac_cv_header_mach_o_dyld_h=no} +ac_cv_header_malloc_h=${ac_cv_header_malloc_h=yes} +ac_cv_header_memory_h=${ac_cv_header_memory_h=yes} +ac_cv_header_net_errno_h=${ac_cv_header_net_errno_h=no} +ac_cv_header_net_if_dl_h=${ac_cv_header_net_if_dl_h=no} +ac_cv_header_netdb_h=${ac_cv_header_netdb_h=no} +ac_cv_header_netinet_in_h=${ac_cv_header_netinet_in_h=no} +ac_cv_header_netpacket_packet_h=${ac_cv_header_netpacket_packet_h=no} +ac_cv_header_poll_h=${ac_cv_header_poll_h=no} +ac_cv_header_pty_h=${ac_cv_header_pty_h=no} +ac_cv_header_stdc=${ac_cv_header_stdc=yes} +ac_cv_header_stddef_h=${ac_cv_header_stddef_h=yes} +ac_cv_header_stdint_h=${ac_cv_header_stdint_h=yes} +ac_cv_header_stdlib_h=${ac_cv_header_stdlib_h=yes} +ac_cv_header_string_h=${ac_cv_header_string_h=yes} +ac_cv_header_strings_h=${ac_cv_header_strings_h=no} +ac_cv_header_sys_devpoll_h=${ac_cv_header_sys_devpoll_h=no} +ac_cv_header_sys_epoll_h=${ac_cv_header_sys_epoll_h=no} +ac_cv_header_sys_event_h=${ac_cv_header_sys_event_h=no} +ac_cv_header_sys_ioctl_h=${ac_cv_header_sys_ioctl_h=no} +ac_cv_header_sys_param_h=${ac_cv_header_sys_param_h=no} +ac_cv_header_sys_resource_h=${ac_cv_header_sys_resource_h=no} +ac_cv_header_sys_select_h=${ac_cv_header_sys_select_h=no} +ac_cv_header_sys_socket_h=${ac_cv_header_sys_socket_h=no} +ac_cv_header_sys_socketio_h=${ac_cv_header_sys_socketio_h=no} +ac_cv_header_sys_sockio_h=${ac_cv_header_sys_sockio_h=no} +ac_cv_header_sys_stat_h=${ac_cv_header_sys_stat_h=yes} +ac_cv_header_sys_stropts_h=${ac_cv_header_sys_stropts_h=no} +ac_cv_header_sys_sysctl_h=${ac_cv_header_sys_sysctl_h=no} +ac_cv_header_sys_time_h=${ac_cv_header_sys_time_h=no} +ac_cv_header_sys_types_h=${ac_cv_header_sys_types_h=yes} +ac_cv_header_sys_uio_h=${ac_cv_header_sys_uio_h=no} +ac_cv_header_sys_wait_h=${ac_cv_header_sys_wait_h=no} +ac_cv_header_syslog_h=${ac_cv_header_syslog_h=no} +ac_cv_header_time=${ac_cv_header_time=no} +ac_cv_header_unistd_h=${ac_cv_header_unistd_h=no} +ac_cv_header_util_h=${ac_cv_header_util_h=no} +ac_cv_header_utmp_h=${ac_cv_header_utmp_h=no} +ac_cv_header_valgrind_valgrind_h=${ac_cv_header_valgrind_valgrind_h=no} +ac_cv_header_vfork_h=${ac_cv_header_vfork_h=no} +ac_cv_header_windows_h=${ac_cv_header_windows_h=yes} +ac_cv_header_winsock2_h=${ac_cv_header_winsock2_h=yes} +ac_cv_header_ws2tcpip_h=${ac_cv_header_ws2tcpip_h=yes} +ac_cv_lib_dl_dlopen=${ac_cv_lib_dl_dlopen=no} +ac_cv_lib_inet_main=${ac_cv_lib_inet_main=no} +ac_cv_lib_kstat_kstat_open=${ac_cv_lib_kstat_kstat_open=no} +ac_cv_lib_m_sin=${ac_cv_lib_m_sin=no} +ac_cv_lib_nsl_gethostbyname=${ac_cv_lib_nsl_gethostbyname=no} +ac_cv_lib_nsl_main=${ac_cv_lib_nsl_main=no} +ac_cv_lib_resolv_res_gethostbyname=${ac_cv_lib_resolv_res_gethostbyname=no} +ac_cv_lib_rt_clock_gettime=${ac_cv_lib_rt_clock_gettime=no} +ac_cv_lib_socket_getpeername=${ac_cv_lib_socket_getpeername=no} +ac_cv_lib_socket_main=${ac_cv_lib_socket_main=yes} +ac_cv_lib_socket_socket=${ac_cv_lib_socket_socket=no} +ac_cv_lib_util_openpty=${ac_cv_lib_util_openpty=no} +ac_cv_lib_ws2_32_main=${ac_cv_lib_ws2_32_main=yes} +ac_cv_member_struct_ErlDrvEntry_stop_select=${ac_cv_member_struct_ErlDrvEntry_stop_select=no} +ac_cv_member_struct_sctp_paddrparams_spp_flags=${ac_cv_member_struct_sctp_paddrparams_spp_flags=no} +ac_cv_member_struct_sctp_paddrparams_spp_pathmtu=${ac_cv_member_struct_sctp_paddrparams_spp_pathmtu=no} +ac_cv_member_struct_sctp_paddrparams_spp_sackdelay=${ac_cv_member_struct_sctp_paddrparams_spp_sackdelay=no} +ac_cv_member_struct_sctp_remote_error_sre_data=${ac_cv_member_struct_sctp_remote_error_sre_data=no} +ac_cv_member_struct_sctp_send_failed_ssf_data=${ac_cv_member_struct_sctp_send_failed_ssf_data=no} +ac_cv_objext=${ac_cv_objext=o} +ac_cv_path_MKDIR=${ac_cv_path_MKDIR=/bin/mkdir} +ac_cv_path_RM=${ac_cv_path_RM=/bin/rm} +ac_cv_prog_AR=${ac_cv_prog_AR=ar.sh} +ac_cv_prog_CC=${ac_cv_prog_CC=cc.sh} +ac_cv_prog_CPP=${ac_cv_prog_CPP='cc.sh -E'} +ac_cv_prog_CXX=${ac_cv_prog_CXX=cc.sh} +ac_cv_prog_DED_LD=${ac_cv_prog_DED_LD=ld.sh} +ac_cv_prog_JAVAC=${ac_cv_prog_JAVAC=javac.sh} +ac_cv_prog_M4=${ac_cv_prog_M4=m4} +ac_cv_prog_RANLIB=${ac_cv_prog_RANLIB=true} +ac_cv_prog_cc_c89=${ac_cv_prog_cc_c89=} +ac_cv_prog_cc_g=${ac_cv_prog_cc_g=yes} +ac_cv_search_fdatasync=${ac_cv_search_fdatasync=no} +ac_cv_search_opendir=${ac_cv_search_opendir=no} +ac_cv_search_strerror=${ac_cv_search_strerror='none required'} +ac_cv_sizeof___int64=${ac_cv_sizeof___int64=8} +ac_cv_sizeof_char=${ac_cv_sizeof_char=1} +ac_cv_sizeof_int=${ac_cv_sizeof_int=4} +ac_cv_sizeof_long=${ac_cv_sizeof_long=4} +ac_cv_sizeof_long_long=${ac_cv_sizeof_long_long=8} +ac_cv_sizeof_off_t=${ac_cv_sizeof_off_t=4} +ac_cv_sizeof_short=${ac_cv_sizeof_short=2} +ac_cv_sizeof_size_t=${ac_cv_sizeof_size_t=8} +ac_cv_sizeof_void_p=${ac_cv_sizeof_void_p=8} +ac_cv_struct_exception=${ac_cv_struct_exception=no} +ac_cv_struct_sockaddr_sa_len=${ac_cv_struct_sockaddr_sa_len=no} +ac_cv_struct_tm=${ac_cv_struct_tm=time.h} +ac_cv_type_off_t=${ac_cv_type_off_t=yes} +ac_cv_type_pid_t=${ac_cv_type_pid_t=no} +ac_cv_type_signal=${ac_cv_type_signal=void} +ac_cv_type_size_t=${ac_cv_type_size_t=yes} +ac_cv_type_uid_t=${ac_cv_type_uid_t=no} +ac_cv_working_alloca_h=${ac_cv_working_alloca_h=no} +erl_cv_time_correction=${erl_cv_time_correction=none} +erts_cv___after_morecore_hook_can_track_malloc=${erts_cv___after_morecore_hook_can_track_malloc=no} +erts_cv_fwrite_unlocked=${erts_cv_fwrite_unlocked=no} +erts_cv_have__end_symbol=${erts_cv_have__end_symbol=no} +erts_cv_have_end_symbol=${erts_cv_have_end_symbol=no} +erts_cv_putc_unlocked=${erts_cv_putc_unlocked=no} +erts_cv_windows_h_includes_winsock2_h=${erts_cv_windows_h_includes_winsock2_h=no} diff --git a/erts/configure.in b/erts/configure.in index e3eb6034e6..b801994e14 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script. -*-m4-*- dnl %CopyrightBegin% dnl -dnl Copyright Ericsson AB 1997-2011. All Rights Reserved. +dnl Copyright Ericsson AB 1997-2012. All Rights Reserved. dnl dnl The contents of this file are subject to the Erlang Public License, dnl Version 1.1, (the "License"); you may not use this file except in @@ -383,12 +383,6 @@ case $host_os in # The ethread library requires _WIN32_WINNT of at least 0x0403. # -D_WIN32_WINNT=* from CPPFLAGS is saved in ETHR_DEFS. CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0500 -DWINVER=0x0500" - # _USE_32BIT_TIME_T is needed when using VC++ 2005 (ctime() will fail - # otherwise since we pass it a 32-bit value). - # - # FIXME: Use time_t all the way and remove _USE_32BIT_TIME_T. - AC_MSG_WARN([Reverting to 32-bit time_t]) - CPPFLAGS="$CPPFLAGS -D_USE_32BIT_TIME_T" ;; darwin*) CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE" @@ -398,53 +392,7 @@ case $host_os in esac - -MIXED_CYGWIN=no - -AC_MSG_CHECKING(for mixed cygwin and native VC++ environment) -if test "X$host" = "Xwin32" -a "x$GCC" != x"yes"; then - if test -x /usr/bin/cygpath; then - CFLAGS="-O2" - MIXED_CYGWIN=yes - AC_MSG_RESULT([yes]) - MIXED_CYGWIN_VC=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_CYGWIN_VC" - else - AC_MSG_RESULT([undeterminable]) - AC_MSG_ERROR(Seems to be mixed windows but not with cygwin, cannot handle this!) - fi -else - AC_MSG_RESULT([no]) - MIXED_CYGWIN_VC=no -fi -AC_SUBST(MIXED_CYGWIN_VC) - -AC_MSG_CHECKING(for mixed cygwin and native MinGW environment) -if test "X$host" = "Xwin32" -a "x$GCC" = x"yes"; then - if test -x /usr/bin/cygpath; then - CFLAGS="-O2" - MIXED_CYGWIN=yes - AC_MSG_RESULT([yes]) - MIXED_CYGWIN_MINGW=yes - CPPFLAGS="$CPPFLAGS -DERTS_MIXED_CYGWIN_MINGW" - else - AC_MSG_RESULT([undeterminable]) - AC_MSG_ERROR(Seems to be mixed windows but not with cygwin, cannot handle this!) - fi -else - AC_MSG_RESULT([no]) - MIXED_CYGWIN_MINGW=no -fi -AC_SUBST(MIXED_CYGWIN_MINGW) - -AC_MSG_CHECKING(if we mix cygwin with any native compiler) -if test "X$MIXED_CYGWIN" = "Xyes" ; then - AC_MSG_RESULT([yes]) -else - AC_MSG_RESULT([no]) -fi - -AC_SUBST(MIXED_CYGWIN) +LM_WINDOWS_ENVIRONMENT dnl dnl Flags to the C compiler @@ -490,19 +438,6 @@ CFLAG_RUNTIME_LIBRARY_PATH="-Wl,-R" case $host_os in darwin*) CFLAG_RUNTIME_LIBRARY_PATH= - AC_TRY_COMPILE([],[ - #if __GNUC__ >= 4 - ; - #else - #error old or no gcc - #endif - ], - gcc_need_no_cpp_precomp=no, - gcc_need_no_cpp_precomp=yes) - - if test x$gcc_need_no_cpp_precomp = xyes; then - CFLAGS="$CFLAGS -no-cpp-precomp" - fi ;; win32) CFLAG_RUNTIME_LIBRARY_PATH= @@ -1479,9 +1414,71 @@ AC_CHECK_HEADERS(fcntl.h limits.h unistd.h syslog.h dlfcn.h ieeefp.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 arpa/nameser.h \ + net/errno.h malloc.h arpa/nameser.h libdlpi.h \ pty.h util.h utmp.h langinfo.h poll.h sdkddkver.h) +AC_CHECK_MEMBERS([struct ifreq.ifr_hwaddr], [], [], + [#ifdef __WIN32__ + #else + #ifdef VXWORKS + #else + #include <net/if.h> + #endif + #endif + ]) + +AC_CHECK_MEMBERS([struct ifreq.ifr_enaddr], [], [], + [#ifdef __WIN32__ + #else + #ifdef VXWORKS + #else + #include <net/if.h> + #endif + #endif + ]) + +dnl ---------------------------------------------------------------------- +dnl Check the availability for libdlpi +dnl ---------------------------------------------------------------------- +AC_CHECK_LIB(dlpi, dlpi_open) +if test x"$ac_cv_lib_dlpi_dlpi_open" = x"no"; then + unset -v ac_cv_lib_dlpi_dlpi_open + dnl Try again now with -L/lib (or ditto 64) as argument to linker since + dnl gcc makes /usr/ccs/bin/ld ignore the crle configured linker default paths + dnl typically causing dlpi not being found on Solaris et.al + save_ldflags="$LDFLAGS" + try_dlpi_lib=/lib + if test x"$ac_cv_sizeof_void_p" = x"8"; then + if test -d /lib64; then + try_dlpi_lib=/lib64 + elif test -d /lib/64; then + try_dlpi_lib=/lib/64 + fi + fi + if test ! -f "$try_dlpi_lib/libdlpi.so" && \ + test -f "$try_dlpi_lib/libdlpi.so.1" + then + dnl It looks like there is a missing symlink + dnl - let's be helpful and notify the user + dnl NOTE this help is far from perfect e.g if there would be no + dnl *.so.1 but a *.so.1.123 or *.so.2 this will be no help + AC_MSG_ERROR( + [Your OS installation is missing a symbolic link. + Maybe it lacks some development package(s)... + It can anyhow be fixed with the following command: + # ln -s libdlpi.so.1 $try_dlpi_lib/libdlpi.so + ]) + fi + LDFLAGS="-L$try_dlpi_lib -R$try_dlpi_lib $LDFLAGS" + unset -v try_dlpi_lib + AC_MSG_NOTICE([Extending the search to include /lib]) + AC_CHECK_LIB(dlpi, dlpi_open) + if test x"$ac_cv_lib_dlpi_dlpi_open" = x"no"; then + LDFLAGS="$save_ldflags" + fi + unset -v save_ldflags +fi + AC_CHECK_HEADER(sys/resource.h, [AC_DEFINE(HAVE_SYS_RESOURCE_H, 1, [Define to 1 if you have the <sys/resource.h> header file]) @@ -1508,6 +1505,9 @@ if test "x$enable_sctp" != "xno" ; then #include <sys/socket.h> #endif ]) +fi + +if test x"$ac_cv_header_netinet_sctp_h" = x"yes"; then AC_CHECK_FUNCS([sctp_bindx sctp_peeloff]) AC_CHECK_DECLS([SCTP_UNORDERED, SCTP_ADDR_OVER, SCTP_ABORT, SCTP_EOF, SCTP_SENDALL, SCTP_ADDR_CONFIRMED, @@ -1589,6 +1589,7 @@ AC_CHECK_SIZEOF(void *) AC_CHECK_SIZEOF(long long) AC_CHECK_SIZEOF(size_t) AC_CHECK_SIZEOF(off_t) +AC_CHECK_SIZEOF(time_t) BITS64= @@ -1690,6 +1691,24 @@ dnl fdatasync requires linking against -lrt on SunOS <= 5.10. dnl OpenSolaris 2009.06 is SunOS 5.11 and does not require -lrt. AC_SEARCH_LIBS(fdatasync, [rt]) + +dnl sendfile syscall +case $host_os in + linux*|freebsd*|dragonfly*|darwin*) + AC_CHECK_FUNCS([sendfile]) + ;; + solaris*) + AC_SEARCH_LIBS(sendfilev, sendfile, + AC_DEFINE([HAVE_SENDFILEV],[1], + [Define to 1 if you have the `sendfilev' function.])) + ;; + win32) + LIBS="$LIBS -lmswsock" + ;; + *) + ;; +esac + dnl ---------------------------------------------------------------------- dnl Checks for library functions. dnl ---------------------------------------------------------------------- @@ -2458,6 +2477,17 @@ case $ARCH-$OPSYS in darwin_mcontext_leopard=no ;; esac + +if test X${enable_fp_exceptions} = Xauto ; then + case $host_os in + darwin*) + enable_fp_exceptions=no + AC_MSG_NOTICE([Floating point exceptions disabled by default on MacOS X]) ;; + *) + ;; + esac +fi + if test X${enable_fp_exceptions} = Xauto ; then if test X${enable_hipe} = Xyes; then enable_fp_exceptions=yes @@ -2505,7 +2535,7 @@ static void new_fp_exception(void) * Implement unmask_fpe() and check_fpe() based on CPU/OS combination */ -#if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) && !defined(__CYGWIN__) +#if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) static void unmask_x87(void) { @@ -3558,7 +3588,7 @@ elif test "x$with_ssl_zlib" = "xyes" || test "x$with_ssl_zlib" = "x"; then AC_MSG_WARN([Cannot search for zlib; missing cross system root (erl_xcomp_sysroot).]) SSL_LINK_WITH_ZLIB=no STATIC_ZLIB_LIBS= - elif test "x$MIXED_CYGWIN" = "xyes"; then + elif test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then SSL_LINK_WITH_ZLIB=no STATIC_ZLIB_LIBS= else @@ -3670,16 +3700,23 @@ case "$erl_xcomp_without_sysroot-$with_ssl" in AC_CHECK_PROG(REGTOOL, regtool, regtool, false) if test "$ac_cv_prog_REGTOOL" != false; then wrp="/machine/software/microsoft/windows/currentversion/" - urp="uninstall/openssl_is1/inno setup: app path" + if test "x$ARCH" = "xamd64"; then + urp="uninstall/openssl (64-bit)_is1/inno setup: app path" + regtool_subsystem=-w + else + urp="uninstall/openssl (32-bit)_is1/inno setup: app path" + regtool_subsystem=-W + fi rp="$wrp$urp" - if regtool -q get "$rp" > /dev/null; then + if regtool -q $regtool_subsystem get "$rp" > /dev/null; then true else - urp="uninstall/openssl (32-bit)_is1/inno setup: app path" + # Fallback to unspecified wordlength + urp="uninstall/openssl_is1/inno setup: app path" rp="$wrp$urp" fi - if regtool -q get "$rp" > /dev/null; then - ssl_install_dir=`regtool -q get "$rp"` + if regtool -q $regtool_subsystem get "$rp" > /dev/null; then + ssl_install_dir=`regtool -q $regtool_subsystem get "$rp"` # Try hard to get rid of spaces... if cygpath -d "$ssl_install_dir" > /dev/null 2>&1; then ssl_install_dir=`cygpath -d "$ssl_install_dir"` @@ -3687,6 +3724,20 @@ case "$erl_xcomp_without_sysroot-$with_ssl" in extra_dir=`cygpath $ssl_install_dir` fi fi + elif test "x$MIXED_MSYS" = "xyes"; then + AC_CHECK_PROG(REGTOOL, reg_query.sh, reg_query.sh, false) + if test "$ac_cv_prog_REGTOOL" != false; then + if test "x$ARCH" = "xamd64"; then + rp="HKLM/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall/OpenSSL (64-bit)_is1" + else + rp="HKLM/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall/OpenSSL_is1" + fi + key="Inno Setup: App Path" + if "$ac_cv_prog_REGTOOL" "$rp" "$key" > /dev/null; then + ssl_install_dir=`"$ac_cv_prog_REGTOOL" "$rp" "$key"` + extra_dir=`win2msys_path.sh "$ssl_install_dir"` + fi + fi fi # We search for OpenSSL in the common OS standard locations. SSL_APP=ssl @@ -3695,14 +3746,25 @@ case "$erl_xcomp_without_sysroot-$with_ssl" in SSL_CRYPTO_LIBNAME=crypto SSL_SSL_LIBNAME=ssl + + if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then + if test "x$ARCH" = "xamd64"; then + std_win_ssl_locations="/cygdrive/c/OpenSSL-Win64 /c/OpenSSL-Win64 /opt/local64/pgm/OpenSSL" + else + std_win_ssl_locations="/cygdrive/c/OpenSSL-Win32 /c/OpenSSL-Win32 /cygdrive/c/OpenSSL /c/OpenSSL /opt/local/pgm/OpenSSL" + fi + else + std_win_ssl_locations="" + fi + AC_MSG_CHECKING(for OpenSSL >= 0.9.7 in standard locations) - for rdir in $extra_dir /cygdrive/c/OpenSSL $std_ssl_locations; do + for rdir in $extra_dir $std_win_ssl_locations $std_ssl_locations; do dir="$erl_xcomp_sysroot$rdir" if test -f "$erl_xcomp_isysroot$rdir/include/openssl/opensslv.h"; then is_real_ssl=yes SSL_ROOT="$dir" - if test "x$MIXED_CYGWIN" = "xyes" ; then + if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then if test -f "$dir/lib/VC/libeay32.lib"; then SSL_RUNTIME_LIBDIR="$rdir/lib/VC" SSL_LIBDIR="$dir/lib/VC" @@ -3777,7 +3839,7 @@ case "$erl_xcomp_without_sysroot-$with_ssl" in ]) CPPFLAGS=$old_CPPFLAGS if test "x$ssl_found" = "xyes"; then - if test "x$MIXED_CYGWIN" = "xyes" ; then + if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then ssl_linkable=yes else saveCFLAGS="$CFLAGS" @@ -3889,7 +3951,7 @@ dnl so it is - be adoptable SSL_ROOT="$with_ssl" SSL_CRYPTO_LIBNAME=crypto SSL_SSL_LIBNAME=ssl - if test "x$MIXED_CYGWIN" = "xyes" && test -d "$with_ssl/lib/VC"; then + if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes" && test -d "$with_ssl/lib/VC"; then if test -f "$with_ssl/lib/VC/libeay32.lib"; then SSL_LIBDIR="$with_ssl/lib/VC" SSL_CRYPTO_LIBNAME=libeay32 @@ -4303,7 +4365,6 @@ AH_BOTTOM([ #endif ]) - dnl ---------------------------------------------------------------------- dnl Output the result. dnl ---------------------------------------------------------------------- @@ -4312,7 +4373,6 @@ dnl Note that the output files are relative to $srcdir AC_OUTPUT( emulator/$host/Makefile:emulator/Makefile.in - emulator/zlib/$host/Makefile:emulator/zlib/Makefile.in epmd/src/$host/Makefile:epmd/src/Makefile.in etc/common/$host/Makefile:etc/common/Makefile.in include/internal/$host/ethread.mk:include/internal/ethread.mk.in diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml index 88e8b284fb..4455d0ac92 100644 --- a/erts/doc/src/absform.xml +++ b/erts/doc/src/absform.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2001</year><year>2009</year> + <year>2001</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/erts/doc/src/driver.xml b/erts/doc/src/driver.xml index 9f246c4a6c..ac5729880d 100644 --- a/erts/doc/src/driver.xml +++ b/erts/doc/src/driver.xml @@ -30,11 +30,11 @@ </header> <note><p>This document was written a long time ago. A lot of it is still - valid, but some things have changed since it was first written. - Updates of this document are planned for the future. The reader - is encouraged to also read the - <seealso marker="erl_driver">erl_driver</seealso>, and the - <seealso marker="erl_driver">driver_entry</seealso> documentation. + interesting since it explains important concepts, but it was + written for an older driver interface so the examples does not + work anymore. The reader is encouraged to read + <seealso marker="erl_driver">erl_driver</seealso> and the + <seealso marker="driver_entry">driver_entry</seealso> documentation. </p></note> <section> diff --git a/erts/doc/src/driver_entry.xml b/erts/doc/src/driver_entry.xml index 8bdd154cb9..a2efdf3ebc 100644 --- a/erts/doc/src/driver_entry.xml +++ b/erts/doc/src/driver_entry.xml @@ -34,18 +34,22 @@ <lib>driver_entry</lib> <libsummary>The driver-entry structure used by erlang drivers.</libsummary> <description> - <p>As of erts version 5.5.3 the driver interface has been extended - (see <seealso marker="driver_entry#extended_marker">extended marker</seealso>). - The extended interface introduces - <seealso marker="erl_driver#version_management">version management</seealso>, - the possibility to pass capability flags - (see <seealso marker="driver_entry#driver_flags">driver flags</seealso>) - to the runtime system at driver initialization, and some new - driver API functions. </p> + <p> + As of erts version 5.9 (OTP release R15B) the driver interface + has been changed with larger types for the callbacks + <seealso marker="#output">output</seealso>, + <seealso marker="#control">control</seealso> and + <seealso marker="#call">call</seealso>. + See driver <seealso marker="erl_driver#version_management"> + version management</seealso> in + <seealso marker="erl_driver">erl_driver</seealso>. + </p> <note> <p>Old drivers (compiled with an <c>erl_driver.h</c> from an - earlier erts version than 5.5.3) have to be recompiled - (but do not have to use the extended interface).</p> + earlier erts version than 5.9) have to be updated and have + to use the extended interface (with + <seealso marker="erl_driver#version_management">version management + </seealso>).</p> </note> <p>The <c>driver_entry</c> structure is a C struct that all erlang drivers define. It contains entry points for the erlang driver @@ -53,7 +57,7 @@ the driver.</p> <p> <marker id="emulator"></marker> - The <seealso marker="driver_entry">erl_driver</seealso> driver + The <seealso marker="erl_driver">erl_driver</seealso> driver API functions need a port handle that identifies the driver instance (and the port in the emulator). This is only passed to the <c>start</c> function, but @@ -84,7 +88,7 @@ the emulator, the driver is <em>not</em> allowed to modify the <c>driver_entry</c>.</p> <note> - <p>Do <em>not</em> declare the <c>driver_entry</c><c>const</c>. This since the emulator needs to + <p>Do <em>not</em> declare the <c>driver_entry</c> <c>const</c>. This since the emulator needs to modify the <c>handle</c>, and the <c>handle2</c> fields. A statically allocated, and <c>const</c> declared <c>driver_entry</c> may be located in @@ -116,7 +120,7 @@ typedef struct erl_drv_entry { void (*stop)(ErlDrvData drv_data); /* called when port is closed, and when the emulator is halted. */ - void (*output)(ErlDrvData drv_data, char *buf, int len); + void (*output)(ErlDrvData drv_data, char *buf, ErlDrvSizeT len); /* called when we have output from erlang to the port */ void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event); @@ -130,8 +134,9 @@ typedef struct erl_drv_entry { void (*finish)(void); /* called before unloading the driver - DYNAMIC DRIVERS ONLY */ void *handle; /* Reserved -- Used by emulator internally */ - int (*control)(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen); + ErlDrvSSizeT (*control)(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen); /* "ioctl" for drivers - invoked by port_control/3 */ void (*timeout)(ErlDrvData drv_data); /* Handling of timeout in driver */ @@ -144,8 +149,9 @@ typedef struct erl_drv_entry { closed, and there is data in the driver queue that needs to be flushed before 'stop' can be called */ - int (*call)(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen, unsigned int *flags); + ErlDrvSSizeT (*call)(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, unsigned int *flags); /* Works mostly like 'control', a synchronous call into the driver. */ void (*event)(ErlDrvData drv_data, ErlDrvEvent event, @@ -192,7 +198,7 @@ typedef struct erl_drv_entry { <c>start</c>, then <c>stop</c> is the place to deallocate that memory.</p> </item> - <tag><marker id="output"/>void (*output)(ErlDrvData drv_data, char *buf, int len)</tag> + <tag><marker id="output"/>void (*output)(ErlDrvData drv_data, char *buf, ErlDrvSizeT len)</tag> <item> <p>This is called when an erlang process has sent data to the port. The data is pointed to by <c>buf</c>, and is @@ -243,7 +249,7 @@ typedef struct erl_drv_entry { emulator will modify this field; therefore, it is important that the <c>driver_entry</c> isn't declared <c>const</c>.</p> </item> - <tag><marker id="control"></marker>int (*control)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen)</tag> + <tag><marker id="control"></marker>ErlDrvSSizeT (*control)(ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen)</tag> <item> <p>This is a special routine invoked with the erlang function <c>port_control/3</c>. It works a little like an "ioctl" for @@ -316,7 +322,7 @@ typedef struct erl_drv_entry { opposed to the asynchronous function, which is called in some thread (if multithreading is enabled).</p> </item> - <tag><marker id="call"/>int (*call)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen, unsigned int *flags)</tag> + <tag><marker id="call"/>ErlDrvSSizeT (*call)(ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen, unsigned int *flags)</tag> <item> <p>This function is called from <c>erlang:port_call/3</c>. It works a lot like the <c>control</c> call-back, but uses the @@ -452,7 +458,7 @@ typedef struct erl_drv_entry { <title>SEE ALSO</title> <p><seealso marker="erl_driver">erl_driver(3)</seealso>, <seealso marker="kernel:erl_ddll">erl_ddll(3)</seealso>, - <seealso marker="erts:erlang">erlang(3)</seealso>, + <seealso marker="erlang">erlang(3)</seealso>, kernel(3)</p> </section> </cref> diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index d0a0ceaeba..cfbc38f176 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -41,25 +41,11 @@ to scroll back to text which has scrolled off the screen. The <c><![CDATA[erl]]></c> program must be used, however, in pipelines or if you want to redirect standard input or output.</p> - <note><p>As of ERTS version 5.8 (OTP-R14A) the runtime system will by - default bind schedulers to logical processors using the - <c>default_bind</c> bind type if the amount of schedulers are - at least equal to the amount of logical processors configured, - binding of schedulers is supported, and a CPU topology is - available at startup. - </p><p> - If the Erlang runtime system is the only operating system - process that binds threads to logical processors, this - improves the performance of the runtime system. However, - if other operating system processes (as for example - another Erlang runtime system) also bind threads to - logical processors, there might be a performance penalty - instead. If this is the case you, are are advised to - unbind the schedulers using the - <seealso marker="#+sbt">+sbtu</seealso> command line argument, - or by invoking - <seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, - unbound)</seealso>.</p> + <note><p>As of ERTS version 5.9 (OTP-R15B) the runtime system will by + default <em>not</em> bind schedulers to logical processors. + For more information see documentation of the + <seealso marker="#+sbt">+sbt</seealso> system flag. + </p> </note> </description> <funcs> @@ -679,41 +665,66 @@ </p> <taglist> <tag><c>u</c></tag> - <item><p>Same as - <seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, unbound)</seealso>. - </p></item> + <item> + <p><c>unbound</c> - Schedulers will not be bound to logical + processors, i.e., the operating system decides where the + scheduler threads execute, and when to migrate them. This is + the default.</p> + </item> <tag><c>ns</c></tag> - <item><p>Same as - <seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, no_spread)</seealso>. - </p></item> + <item> + <p><c>no_spread</c> - Schedulers with close scheduler + identifiers will be bound as close as possible in hardware.</p> + </item> <tag><c>ts</c></tag> - <item><p>Same as - <seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, thread_spread)</seealso>. - </p></item> + <item> + <p><c>thread_spread</c> - Thread refers to hardware threads + (e.g. Intel's hyper-threads). Schedulers with low scheduler + identifiers, will be bound to the first hardware thread of + each core, then schedulers with higher scheduler identifiers + will be bound to the second hardware thread of each core, + etc.</p> + </item> <tag><c>ps</c></tag> - <item><p>Same as - <seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, processor_spread)</seealso>. - </p></item> + <item> + <p><c>processor_spread</c> - Schedulers will be spread like + <c>thread_spread</c>, but also over physical processor chips.</p> + </item> <tag><c>s</c></tag> - <item><p>Same as - <seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, spread)</seealso>. - </p></item> + <item> + <p><c>spread</c> - Schedulers will be spread as much as + possible.</p> + </item> <tag><c>nnts</c></tag> - <item><p>Same as - <seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, no_node_thread_spread)</seealso>. - </p></item> + <item> + <p><c>no_node_thread_spread</c> - Like <c>thread_spread</c>, + but if multiple NUMA (Non-Uniform Memory Access) nodes exists, + schedulers will be spread over one NUMA node at a time, + i.e., all logical processors of one NUMA node will be bound + to schedulers in sequence.</p> + </item> <tag><c>nnps</c></tag> - <item><p>Same as - <seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, no_node_processor_spread)</seealso>. - </p></item> + <item> + <p><c>no_node_processor_spread</c> - Like + <c>processor_spread</c>, but if multiple NUMA nodes exists, + schedulers will be spread over one NUMA node at a time, i.e., + all logical processors of one NUMA node will be bound to + schedulers in sequence.</p> + </item> <tag><c>tnnps</c></tag> - <item><p>Same as - <seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, thread_no_node_processor_spread)</seealso>. - </p></item> + <item> + <p><c>thread_no_node_processor_spread</c> - A combination of + <c>thread_spread</c>, and <c>no_node_processor_spread</c>. + Schedulers will be spread over hardware threads across NUMA + nodes, but schedulers will only be spread over processors + internally in one NUMA node at a time.</p> + </item> <tag><c>db</c></tag> - <item><p>Same as - <seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, default_bind)</seealso>. - </p></item> + <item> + <p><c>default_bind</c> - Binds schedulers the default way. + Currently the default is <c>thread_no_node_processor_spread</c> + (which might change in the future).</p> + </item> </taglist> <p>Binding of schedulers is currently only supported on newer Linux, Solaris, FreeBSD, and Windows systems.</p> @@ -725,24 +736,34 @@ that the <c>+sct</c> flag may have to be passed before the <c>+sbt</c> flag on the command line (in case no CPU topology has been automatically detected).</p> - <p>The runtime system will by default bind schedulers to logical - processors using the <c>default_bind</c> bind type if the amount - of schedulers are at least equal to the amount of logical - processors configured, binding of schedulers is supported, - and a CPU topology is available at startup. + <p>The runtime system will by default <em>not</em> bind schedulers + to logical processors. </p> - <p><em>NOTE:</em> If the Erlang runtime system is the only operating - system process that binds threads to logical processors, this - improves the performance of the runtime system. However, if other - operating system processes (as for example another Erlang runtime - system) also bind threads to logical processors, there might be a - performance penalty instead. If this is the case you, are advised - to unbind the schedulers using the <c>+sbtu</c> command line - argument, or by invoking - <seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, - unbound)</seealso>.</p> - <p>For more information, see - <seealso marker="erlang#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, SchedulerBindType)</seealso>. + <p><em>NOTE:</em> If the Erlang runtime system is the only operating system + process that binds threads to logical processors, this + improves the performance of the runtime system. However, + if other operating system processes (as for example + another Erlang runtime system) also bind threads to + logical processors, there might be a performance penalty + instead. In some cases this performance penalty might be + severe. If this is the case, you are advised to not + bind the schedulers.</p> + <p>How schedulers are bound matters. For example, in + situations when there are fewer running processes than + schedulers online, the runtime system tries to migrate + processes to schedulers with low scheduler identifiers. + The more the schedulers are spread over the hardware, + the more resources will be available to the runtime + system in such situations. + </p> + <p> + <em>NOTE:</em> If a scheduler fails to bind, this + will often be silently ignored. This since it isn't always + possible to verify valid logical processor identifiers. If + an error is reported, it will be reported to the + <c>error_logger</c>. If you want to verify that the + schedulers actually have bound as requested, call + <seealso marker="erlang#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. </p> </item> <tag><marker id="+scl"><c>+scl true|false</c></marker></tag> @@ -773,6 +794,12 @@ <item><c><![CDATA[<IdDefs> = <LogicalIds><ThreadIds><CoreIds><ProcessorIds><NodeIds> | <LogicalIds><ThreadIds><CoreIds><NodeIds><ProcessorIds>]]></c></item> <item><c><![CDATA[CpuTopology = <IdDefs>:<IdDefs> | <IdDefs>]]></c></item> </list> + <p>Set a user defined CPU topology. The user defined + CPU topology will override any automatically detected + CPU topology. The CPU topology is used when + <seealso marker="#+sbt">binding schedulers to logical + processors</seealso>. + </p> <p>Upper-case letters signify real identifiers and lower-case letters signify fake identifiers only used for description of the topology. Identifiers passed as real identifiers may @@ -872,7 +899,7 @@ how the real CPU topology looks like is likely to decrease the performance of the runtime system.</p> <p>For more information, see - <seealso marker="erlang#system_flag_cpu_topology">erlang:system_flag(cpu_topology, CpuTopology)</seealso>.</p> + <seealso marker="erlang#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso>.</p> </item> <tag><marker id="+swt"><c>+swt very_low|low|medium|high|very_high</c></marker></tag> <item> diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml index 8e18dd6657..b5df4ca0c8 100644 --- a/erts/doc/src/erl_driver.xml +++ b/erts/doc/src/erl_driver.xml @@ -37,15 +37,18 @@ <p>As of erts version 5.5.3 the driver interface has been extended (see <seealso marker="driver_entry#extended_marker">extended marker</seealso>). The extended interface introduce - <seealso marker="erl_driver#version_management">version management</seealso>, + <seealso marker="#version_management">version management</seealso>, the possibility to pass capability flags (see <seealso marker="driver_entry#driver_flags">driver flags</seealso>) to the runtime system at driver initialization, and some new driver API functions. </p> <note> - <p>Old drivers (compiled with an <c>erl_driver.h</c> from an - earlier erts version than 5.5.3) have to be recompiled - (but does not have to use the extended interface).</p> + <p>As of erts version 5.9 old drivers has to be recompiled + and has to use the extended interface. They also has to be + adjusted to the + <seealso marker="#rewrites_for_64_bits">64-bit capable driver interface. + </seealso> + </p> </note> <p>The driver calls back to the emulator, using the API functions declared in <c>erl_driver.h</c>. They are used for @@ -242,9 +245,9 @@ </p> </item> <tag>Adding / removing drivers</tag> - <item>A driver can add and later remove drivers.</item> + <item><p>A driver can add and later remove drivers.</p></item> <tag>Monitoring processes</tag> - <item>A driver can monitor a process that does not own a port.</item> + <item><p>A driver can monitor a process that does not own a port.</p></item> <tag><marker id="version_management">Version management</marker></tag> <item> <p>Version management is enabled for drivers that have set the @@ -268,15 +271,203 @@ versions differ, or if the major versions are equal and the minor version used by the driver is greater than the one used by the runtime system.</p> - <p>The emulator tries to check that a driver that doesn't use the - extended driver interface isn't incompatible when loading it. - It can, however, not make sure that it isn't incompatible. Therefore, - when loading a driver that doesn't use the extended driver - interface, there is a risk that it will be loaded also when - the driver is incompatible. When the driver uses the extended driver - interface, the emulator can verify that it isn't of an incompatible - driver version. You are therefore advised to use the extended driver - interface.</p> + <p>The emulator will refuse to load a driver that does not use + the extended driver interface since, + to allow for 64-bit capable drivers, + incompatible type changes for the callbacks + <seealso marker="driver_entry#output">output</seealso>, + <seealso marker="driver_entry#control">control</seealso> and + <seealso marker="driver_entry#call">call</seealso> + were introduced in release R15B. A driver written + with the old types would compile with warnings and when + called return garbage sizes to the emulator causing it + to read random memory and create huge incorrect result blobs.</p> + <p>Therefore it is not enough to just recompile drivers written with + version management for pre-R15B types; the types has to be changed + in the driver suggesting other rewrites especially regarding + size variables. Investigate all warnings when recompiling!</p> + <p>Also, the API driver functions <c>driver_output*</c>, + <c>driver_vec_to_buf</c>, <c>driver_alloc/realloc*</c> + and the <c>driver_*</c> queue functions were changed to have + larger length arguments and return values. This is a + lesser problem since code that passes smaller types + will get them auto converted in the calls and as long as + the driver does not handle sizes that overflow an <c>int</c> + all will work as before.</p> + </item> + </taglist> + </section> + + <section> + <marker id="rewrites_for_64_bits"/> + <title> + REWRITES FOR 64-BIT DRIVER INTERFACE + </title> + <p> + For erts-5.9 two new integer types + <seealso marker="#ErlDrvSizeT">ErlDrvSizeT</seealso> and + <seealso marker="#ErlDrvSSizeT">ErlDrvSSizeT</seealso> + were introduced that can hold 64-bit sizes if necessary. + </p> + <p> + To not update a driver and just recompile it probably works + when building for a 32-bit machine creating a false sense of security. + Hopefully that will generate many important warnings. + But when recompiling the same driver later on for a 64-bit machine + there <em>will</em> be warnings and almost certainly crashes. + So it is a BAD idea to postpone updating the driver and + not fixing the warnings! + </p> + <p> + When recompiling with <c>gcc</c> use the <c>-Wstrict-prototypes</c> + flag to get better warnings. Try to find a similar flag if you + are using some other compiler. + </p> + <p> + Here follows a checklist for rewriting a pre erts-5.9 driver, + most important first. + </p> + <taglist> + <tag>Return types for driver callbacks</tag> + <item> + <p> + Rewrite driver callback + <c><seealso marker="driver_entry#control">control</seealso></c> + to use return type <c>ErlDrvSSizeT</c> instead of <c>int</c>. + </p> + <p> + Rewrite driver callback + <c><seealso marker="driver_entry#call">call</seealso></c> + to use return type <c>ErlDrvSSizeT</c> instead of <c>int</c>. + </p> + <note> + <p> + These changes are essential to not crash the emulator + or worse cause malfunction. + Without them a driver may return garbage in the high 32 bits + to the emulator causing it to build a huge result from random + bytes either crashing on memory allocation or succeeding with + a random result from the driver call. + </p> + </note> + </item> + <tag>Arguments to driver callbacks</tag> + <item> + <p> + Driver callback + <c><seealso marker="driver_entry#output">output</seealso></c> + now gets <c>ErlDrvSizeT</c> as 3:rd argument instead + of previously <c>int</c>. + </p> + <p> + Driver callback + <c><seealso marker="driver_entry#control">control</seealso></c> + now gets <c>ErlDrvSizeT</c> as 4:th and 6:th arguments instead + of previously <c>int</c>. + </p> + <p> + Driver callback + <c><seealso marker="driver_entry#call">call</seealso></c> + now gets <c>ErlDrvSizeT</c> as 4:th and 6:th arguments instead + of previously <c>int</c>. + </p> + <p> + Sane compiler's calling conventions probably make these changes + necessary only for a driver to handle data chunks that require + 64-bit size fields (mostly larger than 2 GB since that is what + an <c>int</c> of 32 bits can hold). But it is possible to think + of non-sane calling conventions that would make the driver + callbacks mix up the arguments causing malfunction. + </p> + <note> + <p> + The argument type change is from signed to unsigned which + may cause problems for e.g. loop termination conditions or + error conditions if you just change the types all over the place. + </p> + </note> + </item> + <tag>Larger <c>size</c> field in <c>ErlIOVec</c></tag> + <item> + <p> + The <c>size</c> field in + <seealso marker="#ErlIOVec"><c>ErlIOVec</c></seealso> + has been changed to <c>ErlDrvSizeT</c> from <c>int</c>. + Check all code that use that field. + </p> + <p> + Automatic type casting probably makes these changes necessary only + for a driver that encounters sizes larger than 32 bits. + </p> + <note> + <p> + The <c>size</c> field changed from signed to unsigned which + may cause problems for e.g. loop termination conditions or + error conditions if you just change the types all over the place. + </p> + </note> + </item> + <tag>Arguments and return values in the driver API</tag> + <item> + <p> + Many driver API functions has changed argument type + and/or return value to <c>ErlDrvSizeT</c> from mostly <c>int</c>. + Automatic type casting probably makes these changes necessary only + for a driver that encounters sizes larger than 32 bits. + </p> + <taglist> + <tag><seealso marker="#driver_output">driver_output</seealso></tag> + <item>3:rd argument</item> + <tag><seealso marker="#driver_output2">driver_output2</seealso></tag> + <item>3:rd and 5:th arguments</item> + <tag> + <seealso marker="#driver_output_binary">driver_output_binary</seealso> + </tag> + <item>3:rd 5:th and 6:th arguments</item> + <tag><seealso marker="#driver_outputv">driver_outputv</seealso></tag> + <item>3:rd and 5:th arguments</item> + <tag> + <seealso marker="#driver_vec_to_buf">driver_vec_to_buf</seealso> + </tag> + <item>3:rd argument and return value</item> + <tag><seealso marker="#driver_alloc">driver_alloc</seealso></tag> + <item>1:st argument</item> + <tag><seealso marker="#driver_realloc">driver_realloc</seealso></tag> + <item>2:nd argument</item> + <tag> + <seealso marker="#driver_alloc_binary">driver_alloc_binary</seealso> + </tag> + <item>1:st argument</item> + <tag> + <seealso marker="#driver_realloc_binary">driver_realloc_binary</seealso> + </tag> + <item>2:nd argument</item> + <tag><seealso marker="#driver_enq">driver_enq</seealso></tag> + <item>3:rd argument</item> + <tag><seealso marker="#driver_pushq">driver_pushq</seealso></tag> + <item>3:rd argument</item> + <tag><seealso marker="#driver_deq">driver_deq</seealso></tag> + <item>2:nd argument and return value</item> + <tag><seealso marker="#driver_sizeq">driver_sizeq</seealso></tag> + <item>return value</item> + <tag><seealso marker="#driver_enq_bin">driver_enq_bin</seealso></tag> + <item>3:rd and 4:th argument</item> + <tag><seealso marker="#driver_pushq_bin">driver_pushq_bin</seealso></tag> + <item>3:rd and 4:th argument</item> + <tag><seealso marker="#driver_enqv">driver_enqv</seealso></tag> + <item>3:rd argument</item> + <tag><seealso marker="#driver_pushqv">driver_pushqv</seealso></tag> + <item>3:rd argument</item> + <tag><seealso marker="#driver_peekqv">driver_peekqv</seealso></tag> + <item>return value</item> + </taglist> + <note> + <p> + This is a change from signed to unsigned which + may cause problems for e.g. loop termination conditions and + error conditions if you just change the types all over the place. + </p> + </note> </item> </taglist> </section> @@ -285,7 +476,11 @@ <title>DATA TYPES</title> <taglist> - <tag><marker id="ErlDrvSysInfo"/>ErlDrvSysInfo</tag> + <tag><marker id="ErlDrvSizeT"/>ErlDrvSizeT</tag> + <item><p>An unsigned integer type to be used as <c>size_t</c></p></item> + <tag><marker id="ErlDrvSSizeT"/>ErlDrvSSizeT</tag> + <item><p>A signed integer type the size of <c>ErlDrvSizeT</c></p></item> + <tag><marker id="ErlDrvSysInfo"/>ErlDrvSysInfo</tag> <item> <p/> <code type="none"> @@ -332,12 +527,12 @@ typedef struct ErlDrvSysInfo { <tag><c>erts_version</c></tag> <item>A string containing the version number of the runtime system (the same as returned by - <seealso marker="erts:erlang#system_info_version">erlang:system_info(version)</seealso>). + <seealso marker="erlang#system_info_version">erlang:system_info(version)</seealso>). </item> <tag><c>otp_release</c></tag> <item>A string containing the OTP release number (the same as returned by - <seealso marker="erts:erlang#system_info_otp_release">erlang:system_info(otp_release)</seealso>). + <seealso marker="erlang#system_info_otp_release">erlang:system_info(otp_release)</seealso>). </item> <tag><c>thread_support</c></tag> <item>A value <c>!= 0</c> if the runtime system has thread support; @@ -351,12 +546,12 @@ typedef struct ErlDrvSysInfo { <item>The number of async threads in the async thread pool used by <seealso marker="#driver_async">driver_async()</seealso> (the same as returned by - <seealso marker="erts:erlang#system_info_thread_pool_size">erlang:system_info(thread_pool_size)</seealso>). + <seealso marker="erlang#system_info_thread_pool_size">erlang:system_info(thread_pool_size)</seealso>). </item> <tag><c>scheduler_threads</c></tag> <item>The number of scheduler threads used by the runtime system (the same as returned by - <seealso marker="erts:erlang#system_info_schedulers">erlang:system_info(schedulers)</seealso>). + <seealso marker="erlang#system_info_schedulers">erlang:system_info(schedulers)</seealso>). </item> <tag><c>nif_major_version</c></tag> <item>The value of <c>ERL_NIF_MAJOR_VERSION</c> when the runtime system was compiled. @@ -371,7 +566,7 @@ typedef struct ErlDrvSysInfo { <p/> <code type="none"> typedef struct ErlDrvBinary { - int orig_size; + ErlDrvSint orig_size; char orig_bytes[]; } ErlDrvBinary; </code> @@ -423,7 +618,7 @@ typedef struct ErlDrvBinary { <item> <p>The <c>ErlDrvData</c> is a handle to driver-specific data, passed to the driver call-backs. It is a pointer, and is - most often casted to a specific pointer in the driver.</p> + most often type casted to a specific pointer in the driver.</p> </item> <tag>SysIOVec</tag> <item> @@ -437,7 +632,7 @@ typedef struct ErlDrvBinary { <code type="none"> typedef struct ErlIOVec { int vsize; - int size; + ErlDrvSizeT size; SysIOVec* iov; ErlDrvBinary** binv; } ErlIOVec; @@ -630,7 +825,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_output(ErlDrvPort port, char *buf, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_output(ErlDrvPort port, char *buf, ErlDrvSizeT len)</nametext></name> <fsummary>Send data from driver to port owner</fsummary> <desc> <marker id="driver_output"></marker> @@ -650,7 +845,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_output2(ErlDrvPort port, char *hbuf, int hlen, char *buf, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_output2(ErlDrvPort port, char *hbuf, ErlDrvSizeT hlen, char *buf, ErlDrvSizeT len)</nametext></name> <fsummary>Send data and binary data to port owner</fsummary> <desc> <marker id="driver_output2"></marker> @@ -665,7 +860,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_output_binary(ErlDrvPort port, char *hbuf, int hlen, ErlDrvBinary* bin, int offset, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_output_binary(ErlDrvPort port, char *hbuf, ErlDrvSizeT hlen, ErlDrvBinary* bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext></name> <fsummary>Send data from a driver binary to port owner</fsummary> <desc> <marker id="driver_output_binary"></marker> @@ -688,7 +883,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_outputv(ErlDrvPort port, char* hbuf, int hlen, ErlIOVec *ev, int skip)</nametext></name> + <name><ret>int</ret><nametext>driver_outputv(ErlDrvPort port, char* hbuf, ErlDrvSizeT hlen, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> <fsummary>Send vectorized data to port owner</fsummary> <desc> <marker id="driver_outputv"></marker> @@ -711,7 +906,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_vec_to_buf(ErlIOVec *ev, char *buf, int len)</nametext></name> + <name><ret>ErlDrvSizeT</ret><nametext>driver_vec_to_buf(ErlIOVec *ev, char *buf, ErlDrvSizeT len)</nametext></name> <fsummary>Collect data segments into a buffer</fsummary> <desc> <marker id="driver_vec_to_buf"></marker> @@ -738,7 +933,7 @@ typedef struct ErlIOVec { <c>time</c> parameter is the time in milliseconds before the timer expires.</p> <p>When the timer reaches 0 and expires, the driver entry - function <seealso marker="driver_entry#emulator">timeout</seealso> is called.</p> + function <seealso marker="driver_entry#timeout">timeout</seealso> is called.</p> <p>Note that there is only one timer on each driver instance; setting a new timer will replace an older one.</p> <p>Return value is 0 (-1 only when the <c>timeout</c> driver @@ -832,7 +1027,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>void *</ret><nametext>driver_alloc(size_t size)</nametext></name> + <name><ret>void *</ret><nametext>driver_alloc(ErlDrvSizeT size)</nametext></name> <fsummary>Allocate memory</fsummary> <desc> <marker id="driver_alloc"></marker> @@ -846,7 +1041,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>void *</ret><nametext>driver_realloc(void *ptr, size_t size)</nametext></name> + <name><ret>void *</ret><nametext>driver_realloc(void *ptr, ErlDrvSizeT size)</nametext></name> <fsummary>Resize an allocated memory block</fsummary> <desc> <marker id="driver_realloc"></marker> @@ -872,7 +1067,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>ErlDrvBinary*</ret><nametext>driver_alloc_binary(int size)</nametext></name> + <name><ret>ErlDrvBinary*</ret><nametext>driver_alloc_binary(ErlDrvSizeT size)</nametext></name> <fsummary>Allocate a driver binary</fsummary> <desc> <marker id="driver_alloc_binary"></marker> @@ -892,7 +1087,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>ErlDrvBinary*</ret><nametext>driver_realloc_binary(ErlDrvBinary *bin, int size)</nametext></name> + <name><ret>ErlDrvBinary*</ret><nametext>driver_realloc_binary(ErlDrvBinary *bin, ErlDrvSizeT size)</nametext></name> <fsummary>Resize a driver binary</fsummary> <desc> <marker id="driver_realloc_binary"></marker> @@ -958,7 +1153,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_enq(ErlDrvPort port, char* buf, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_enq(ErlDrvPort port, char* buf, ErlDrvSizeT len)</nametext></name> <fsummary>Enqueue data in the driver queue</fsummary> <desc> <marker id="driver_enq"></marker> @@ -982,7 +1177,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_pushq(ErlDrvPort port, char* buf, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_pushq(ErlDrvPort port, char* buf, ErlDrvSizeT len)</nametext></name> <fsummary>Push data at the head of the driver queue</fsummary> <desc> <marker id="driver_pushq"></marker> @@ -997,7 +1192,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_deq(ErlDrvPort port, int size)</nametext></name> + <name><ret>ErlDrvSizeT</ret><nametext>driver_deq(ErlDrvPort port, ErlDrvSizeT size)</nametext></name> <fsummary>Dequeue data from the head of the driver queue</fsummary> <desc> <marker id="driver_deq"></marker> @@ -1013,7 +1208,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_sizeq(ErlDrvPort port)</nametext></name> + <name><ret>ErlDrvSizeT</ret><nametext>driver_sizeq(ErlDrvPort port)</nametext></name> <fsummary>Return the size of the driver queue</fsummary> <desc> <marker id="driver_sizeq"></marker> @@ -1026,7 +1221,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_enq_bin(ErlDrvPort port, ErlDrvBinary *bin, int offset, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_enq_bin(ErlDrvPort port, ErlDrvBinary *bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext></name> <fsummary>Enqueue binary in the driver queue</fsummary> <desc> <marker id="driver_enq_bin"></marker> @@ -1043,7 +1238,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_pushq_bin(ErlDrvPort port, ErlDrvBinary *bin, int offset, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_pushq_bin(ErlDrvPort port, ErlDrvBinary *bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext></name> <fsummary>Push binary at the head of the driver queue</fsummary> <desc> <marker id="driver_pushq_bin"></marker> @@ -1060,13 +1255,35 @@ typedef struct ErlIOVec { </desc> </func> <func> + <name><ret>ErlDrvSizeT</ret><nametext>driver_peekqv(ErlDrvPort port, ErlIOVec *ev)</nametext></name> + <fsummary>Get the driver queue as an IO vector</fsummary> + <desc> + <marker id="driver_peekqv"></marker> + <p> + This function retrieves the driver queue into a supplied + <c>ErlIOVec</c> <c>ev</c>. It also returns the queue size. + This is one of two ways to get data out of the queue. + </p> + <p> + If <c>ev</c> is <c>NULL</c> all ones i.e. <c>-1</c> type cast to + <c>ErlDrvSizeT</c> is returned. + </p> + <p>Nothing is removed from the queue by this function, that must be done + with <c>driver_deq</c>.</p> + <p>This function can be called from an arbitrary thread if a + <seealso marker="#ErlDrvPDL">port data lock</seealso> + associated with the <c>port</c> is locked by the calling + thread during the call.</p> + </desc> + </func> + <func> <name><ret>SysIOVec*</ret><nametext>driver_peekq(ErlDrvPort port, int *vlen)</nametext></name> <fsummary>Get the driver queue as a vector</fsummary> <desc> <marker id="driver_peekq"></marker> <p>This function retrieves the driver queue as a pointer to an array of <c>SysIOVec</c>s. It also returns the number of - elements in <c>vlen</c>. This is the only way to get data + elements in <c>vlen</c>. This is one of two ways to get data out of the queue.</p> <p>Nothing is removed from the queue by this function, that must be done with <c>driver_deq</c>.</p> @@ -1079,7 +1296,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_enqv(ErlDrvPort port, ErlIOVec *ev, int skip)</nametext></name> + <name><ret>int</ret><nametext>driver_enqv(ErlDrvPort port, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> <fsummary>Enqueue vector in the driver queue</fsummary> <desc> <marker id="driver_enqv"></marker> @@ -1095,7 +1312,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_pushqv(ErlDrvPort port, ErlIOVec *ev, int skip)</nametext></name> + <name><ret>int</ret><nametext>driver_pushqv(ErlDrvPort port, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> <fsummary>Push vector at the head of the driver queue</fsummary> <desc> <marker id="driver_pushqv"></marker> @@ -1494,7 +1711,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len term encoded with the <seealso marker="erl_ext_dist">external format</seealso>, i.e., a term that has been encoded by - <seealso marker="erts:erlang#term_to_binary/2">erlang:term_to_binary</seealso>, + <seealso marker="erlang#term_to_binary/2">erlang:term_to_binary</seealso>, <seealso marker="erl_interface:ei">erl_interface</seealso>, etc. For example, if <c>binp</c> is a pointer to an <c>ErlDrvBinary</c> that contains the term <c>{17, 4711}</c> encoded with the @@ -1694,7 +1911,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len The driver defined handle is normally created in the <seealso marker="driver_entry#start">driver start call-back</seealso> when a port is created via - <seealso marker="erts:erlang#open_port/2">erlang:open_port/2</seealso>. </item> + <seealso marker="erlang#open_port/2">erlang:open_port/2</seealso>. </item> </taglist> <p>The caller of <c>driver_create_port()</c> is allowed to manipulate the newly created port when <c>driver_create_port()</c> @@ -2462,7 +2679,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len <title>SEE ALSO</title> <p><seealso marker="driver_entry">driver_entry(3)</seealso>, <seealso marker="kernel:erl_ddll">erl_ddll(3)</seealso>, - <seealso marker="erts:erlang">erlang(3)</seealso></p> + <seealso marker="erlang">erlang(3)</seealso></p> <p>An Alternative Distribution Driver (ERTS User's Guide Ch. 3)</p> </section> diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 8daa67aa87..5fc6508aad 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -136,9 +136,7 @@ ok then retrieved by calling <seealso marker="#enif_priv_data">enif_priv_data</seealso>.</p> <p>There is no way to explicitly unload a NIF library. A library will be automatically unloaded when the module code that it belongs to is purged - by the code server. A NIF library will also be unloaded if it is replaced - by another version of the library by a second call to - <c>erlang:load_nif/2</c> from the same module code.</p> + by the code server.</p> </description> <section> <title>FUNCTIONALITY</title> @@ -308,21 +306,9 @@ ok initialization is needed.</p> </item> - <tag><marker id="reload"/>int (*reload)(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)</tag> - <item><p><c>reload</c> is called when the NIF library is loaded - and there is already a previously loaded library for this - module code.</p> - <p>Works the same as <c>load</c>. The only difference is that - <c>*priv_data</c> already contains the value set by the - previous call to <c>load</c> or <c>reload</c>.</p> - <p>The library will fail to load if <c>reload</c> returns - anything other than 0 or if <c>reload</c> is NULL.</p> - </item> - <tag><marker id="upgrade"/>int (*upgrade)(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)</tag> <item><p><c>upgrade</c> is called when the NIF library is loaded - and there is no previously loaded library for this module - code, BUT there is old code of this module with a loaded NIF library.</p> + and there is old code of this module with a loaded NIF library.</p> <p>Works the same as <c>load</c>. The only difference is that <c>*old_priv_data</c> already contains the value set by the last call to <c>load</c> or <c>reload</c> for the old module @@ -339,6 +325,23 @@ ok called for a replaced library as a consequence of <c>reload</c>.</p> </item> + <tag><marker id="reload"/>int (*reload)(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)</tag> + <note><p>The reload mechanism is <em>deprecated</em>. It was only intended + as a development feature. Do not use it as an upgrade method for + live production systems. It might be removed in future releases. Be sure + to pass <c>reload</c> as <c>NULL</c> to <seealso marker="#ERL_NIF_INIT">ERL_NIF_INIT</seealso> + to disable it when not used.</p> + </note> + <item><p><c>reload</c> is called when the NIF library is loaded + and there is already a previously loaded library for this + module code.</p> + <p>Works the same as <c>load</c>. The only difference is that + <c>*priv_data</c> already contains the value set by the + previous call to <c>load</c> or <c>reload</c>.</p> + <p>The library will fail to load if <c>reload</c> returns + anything other than 0 or if <c>reload</c> is NULL.</p> + </item> + </taglist> </section> diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 2ea144eb3f..8c438b0bd7 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -215,9 +215,9 @@ representation of <c>Atom</c>. If <c>Encoding</c> is <c>latin1</c>, there will be one byte for each character in the text representation. If <c>Encoding</c> is <c>utf8</c> or - <c>unicode</c>, the characters will encoded using UTF-8 + <c>unicode</c>, the characters will be encoded using UTF-8 (meaning that characters from 16#80 up to 0xFF will be - encode in two bytes).</p> + encoded in two bytes).</p> <note><p>Currently, <c>atom_to_binary(Atom, latin1)</c> can never fail because the text representation of an atom can only contain @@ -268,7 +268,7 @@ <p>If <c>PosLen</c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> - <p><c>Start</c> is zero-based, i.e:</p> + <p><c>Start</c> is zero-based, i.e.:</p> <code> 1> Bin = <<1,2,3>> 2> binary_part(Bin,{0,2}). @@ -724,9 +724,12 @@ false</pre> size limit.</p> </item> <tag><c>{line_length, integer()}</c></tag> - <item><p>Applies only to line oriented protocols - (<c>line</c>, <c>http</c>). Lines longer than this - will be truncated.</p> + <item><p>For packet type <c>line</c>, truncate lines longer + than the indicated length.</p> + <p>Option <c>line_length</c> also applies to <c>http*</c> + packet types as an alias for option <c>packet_size</c> in the + case when <c>packet_size</c> itself is not set. This usage is + only intended for backward compatibility.</p> </item> </taglist> <pre> @@ -770,9 +773,9 @@ false</pre> turned off, nothing happens.</p> <p>Once <c>demonitor(MonitorRef)</c> has returned it is guaranteed that no <c>{'DOWN', MonitorRef, _, _, _}</c> message - due to the monitor will be placed in the callers message queue + due to the monitor will be placed in the caller's message queue in the future. A <c>{'DOWN', MonitorRef, _, _, _}</c> message - might have been placed in the callers message queue prior to + might have been placed in the caller's message queue prior to the call, though. Therefore, in most cases, it is advisable to remove such a <c>'DOWN'</c> message from the message queue after monitoring has been stopped. @@ -815,7 +818,7 @@ false</pre> <tag><c>flush</c></tag> <item> <p>Remove (one) <c>{_, MonitorRef, _, _, _}</c> message, - if there is one, from the callers message queue after + if there is one, from the caller's message queue after monitoring has been stopped.</p> <p>Calling <c>demonitor(MonitorRef, [flush])</c> is equivalent to the following, but more efficient:</p> @@ -844,7 +847,7 @@ false</pre> <item><p>The monitor was not found and could not be removed. This probably because someone already has placed a <c>'DOWN'</c> message corresponding to this monitor - in the callers message queue. + in the caller's message queue. </p> </item> </taglist> @@ -2866,7 +2869,7 @@ os_prompt%</pre> <p>For external programs, the <c>PATH</c> is searched (or an equivalent method is used to find programs, depending on operating system). This is done by invoking - the shell och certain platforms. The first space + the shell on certain platforms. The first space separated token of the command will be considered as the name of the executable (or driver). This (among other things) makes this option unsuitable for running @@ -3906,7 +3909,7 @@ os_prompt%</pre> <item> <p>Return the current call stack back-trace (<em>stacktrace</em>) of the process. The stack has the same format as returned by - <seealso marker="#get_stacktrace/1">erlang:get_stacktrace/0</seealso>. + <seealso marker="#get_stacktrace/0">erlang:get_stacktrace/0</seealso>. </p> </item> <tag><c>{dictionary, Dictionary}</c></tag> @@ -4878,6 +4881,7 @@ true</pre> <v>Type, Res -- see below</v> </type> <desc> + <p>All times are in milliseconds unless otherwise specified.</p> <p>Returns information about the system as specified by <c>Type</c>:</p> <taglist> @@ -4891,15 +4895,20 @@ true</pre> <item> <p>Returns <c>{Total_Exact_Reductions, Exact_Reductions_Since_Last_Call}</c>.</p> - <p><em>NOTE:</em><c>statistics(exact_reductions)</c> is - a more expensive operation than - <seealso marker="#statistics_reductions">statistics(reductions)</seealso> - especially on an Erlang machine with SMP support.</p> + <note><p><c>statistics(exact_reductions)</c> is + a more expensive operation than + <seealso marker="#statistics_reductions">statistics(reductions)</seealso> + especially on an Erlang machine with SMP support.</p> + </note> </item> <tag><c>garbage_collection</c></tag> <item> <p>Returns <c>{Number_of_GCs, Words_Reclaimed, 0}</c>. This information may not be valid for all implementations.</p> + <pre> +> <input>statistics(garbage_collection).</input> +{85,23961,0} +</pre> </item> <tag><c>io</c></tag> <item> @@ -4911,12 +4920,18 @@ true</pre> <tag><marker id="statistics_reductions"><c>reductions</c></marker></tag> <item> <p>Returns - <c>{Total_Reductions, Reductions_Since_Last_Call}</c>.</p> - <p><em>NOTE:</em> From erts version 5.5 (OTP release R11B) - this value does not include reductions performed in current - time slices of currently scheduled processes. If an - exact value is wanted, use - <seealso marker="#statistics_exact_reductions">statistics(exact_reductions)</seealso>.</p> + <c>{Total_Reductions, Reductions_Since_Last_Call}</c>.</p> + <note> + <p>From erts version 5.5 (OTP release R11B) + this value does not include reductions performed in current + time slices of currently scheduled processes. If an + exact value is wanted, use + <seealso marker="#statistics_exact_reductions">statistics(exact_reductions)</seealso>.</p> + </note> + <pre> +> <input>statistics(reductions).</input> +{2046,11} +</pre> </item> <tag><c>run_queue</c></tag> <item> @@ -4929,7 +4944,74 @@ true</pre> Note that the run-time is the sum of the run-time for all threads in the Erlang run-time system and may therefore be greater than the wall-clock time.</p> + <pre> +> <input>statistics(runtime).</input> +{1690,1620} +</pre> + </item> + <tag><marker id="statistics_scheduler_wall_time"><c>scheduler_wall_time</c></marker></tag> + <item> + <p>Returns a list of tuples with + <c>{SchedulerId, ActiveTime, TotalTime}</c>, where <c>SchedulerId</c> is an integer id of the scheduler, <c>ActiveTime</c> is + the duration the scheduler has been busy, <c>TotalTime</c> is the total time duration since + <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> + activation. The time unit is not defined and may be subject to change + between releases, operating systems and system restarts. + <c>scheduler_wall_time</c> should only be used to calculate relative + values for scheduler-utilization. <c>ActiveTime</c> can never exceed <c>TotalTime</c>. + </p> + + <p>The definition of a busy scheduler is when it is not idle or not + scheduling (selecting) a process or port, meaning; executing process + code, executing linked-in-driver or NIF code, executing + built-in-functions or any other runtime handling, garbage collecting + or handling any other memory management. Note, a scheduler may also be + busy even if the operating system has scheduled out the scheduler + thread. + </p> + + <p> + Returns <c>undefined</c> if the system flag <seealso marker="#system_flag_scheduler_wall_time"> + scheduler_wall_time</seealso> is turned off. + </p> + + <p>The list of scheduler information is unsorted and may appear in different order + between calls. + </p> + <p>Using <c>scheduler_wall_time</c> to calculate scheduler utilization.</p> +<pre> +> <input>erlang:system_flag(scheduler_wall_time, true).</input> +false +> <input>Ts0 = lists:sort(erlang:statistics(scheduler_wall_time)), ok.</input> +ok +</pre> + <p>Some time later we will take another snapshot and calculate scheduler-utilization per scheduler.</p> +<pre> +> <input>Ts1 = lists:sort(erlang:statistics(scheduler_wall_time)), ok.</input> +ok +> <input>lists:map(fun({{I, A0, T0}, {I, A1, T1}}) -> + {I, (A1 - A0)/(T1 - T0)} end, lists:zip(Ts0,Ts1)).</input> +[{1,0.9743474730177548}, + {2,0.9744843782751444}, + {3,0.9995902361669045}, + {4,0.9738012596572161}, + {5,0.9717956667018103}, + {6,0.9739235846420741}, + {7,0.973237033077876}, + {8,0.9741297293248656}] +</pre> + <p>Using the same snapshots to calculate a total scheduler-utilization.</p> +<pre> +> <input>{A, T} = lists:foldl(fun({{_, A0, T0}, {_, A1, T1}}, {Ai,Ti}) -> + {Ai + (A1 - A0), Ti + (T1 - T0)} end, {0, 0}, lists:zip(Ts0,Ts1)), A/T.</input> +0.9769136803764825 +</pre> + + <note> + <p><c>scheduler_wall_time</c> is by default disabled. Use <c>erlang:system_flag(scheduler_wall_time, true)</c> to enable it. </p> + </note> </item> + <tag><c>wall_clock</c></tag> <item> <p>Returns @@ -4939,14 +5021,6 @@ true</pre> opposed to runtime or CPU time.</p> </item> </taglist> - <p>All times are in milliseconds.</p> - <pre> -> <input>statistics(runtime).</input> -{1690,1620} -> <input>statistics(reductions).</input> -{2046,11} -> <input>statistics(garbage_collection).</input> -{85,23961,0}</pre> </desc> </func> <func> @@ -5069,6 +5143,14 @@ true</pre> <v>Flag, Value, OldValue -- see below</v> </type> <desc> + <warning> + <p>The + <seealso marker="#system_flag_cpu_topology">cpu_topology</seealso>, + and + <seealso marker="#system_flag_scheduler_bind_type">scheduler_bind_type</seealso> + <c>Flag</c>s are <em>deprecated</em> and have been scheduled for + removal in erts-5.10/OTP-R16.</p> + </warning> <p>Sets various system properties of the Erlang node. Returns the old value of the flag.</p> <taglist> @@ -5079,6 +5161,12 @@ true</pre> </item> <tag><marker id="system_flag_cpu_topology"><c>erlang:system_flag(cpu_topology, CpuTopology)</c></marker></tag> <item> + <p><em>NOTE:</em> This argument is <em>deprecated</em> and + scheduled for removal in erts-5.10/OTP-R16. Instead of using + this argument you are advised to use the <c>erl</c> command + line argument <seealso marker="erts:erl#+sct">+sct</seealso>. + When this argument has been removed a final CPU topology to use + will be determined at emulator boot time.</p> <p>Sets the user defined <c>CpuTopology</c>. The user defined CPU topology will override any automatically detected CPU topology. By passing <c>undefined</c> as <c>CpuTopology</c> @@ -5093,15 +5181,15 @@ true</pre> to rebind according to the new CPU topology. </p> <p>The user defined CPU topology can also be set by passing - the <seealso marker="erl#+sct">+sct</seealso> command + the <seealso marker="erts:erl#+sct">+sct</seealso> command line argument to <c>erl</c>. </p> <p>For information on the <c>CpuTopology</c> type and more, see the documentation of <seealso marker="#system_info_cpu_topology">erlang:system_info(cpu_topology)</seealso>, - the <c>erl</c> <seealso marker="erl#+sct">+sct</seealso> - emulator flag, and - <seealso marker="#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, How)</seealso>. + and the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> + and <seealso marker="erts:erl#+sbt">+sbt</seealso> + command line flags. </p> </item> <tag><c>erlang:system_flag(fullsweep_after, Number)</c></tag> @@ -5177,6 +5265,12 @@ true</pre> </item> <tag><marker id="system_flag_scheduler_bind_type"><c>erlang:system_flag(scheduler_bind_type, How)</c></marker></tag> <item> + <p><em>NOTE:</em> This argument is <em>deprecated</em> and + scheduled for removal in erts-5.10/OTP-R16. Instead of using + this argument you are advised to use the <c>erl</c> command + line argument <seealso marker="erts:erl#+sbt">+sbt</seealso>. + When this argument has been removed a final scheduler bind type + to use will be determined at emulator boot time.</p> <p>Controls if and how schedulers are bound to logical processors.</p> <p>When <c>erlang:system_flag(scheduler_bind_type, How)</c> is @@ -5198,93 +5292,61 @@ true</pre> the CPU topology needs to be known. If the runtime system fails to automatically detect the CPU topology, it can be defined. For more information on how to define the CPU topology, see - <seealso marker="#system_flag_cpu_topology">erlang:system_flag(cpu_topology, CpuTopology)</seealso>. + the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> command + line flag. </p> - <p>The runtime system will by default bind schedulers to logical - processors using the <c>default_bind</c> bind type if the amount - of schedulers are at least equal to the amount of logical - processors configured, binding of schedulers is supported, - and a CPU topology is available at startup. + <p>The runtime system will by default <em>not</em> bind schedulers + to logical processors. </p> <p><em>NOTE:</em> If the Erlang runtime system is the only operating system process that binds threads to logical processors, this improves the performance of the runtime system. However, if other operating system processes (as for example another Erlang runtime system) also bind threads to logical processors, there - might be a performance penalty instead. If this is the case you, - are are advised to unbind the schedulers using the - <seealso marker="erl#+sbt">+sbtu</seealso> command line argument, - or <c>erlang:system_flag(scheduler_bind_type, unbound)</c>.</p> + might be a performance penalty instead. In some cases this + performance penalty might be severe. If this is the case, you + are advised to not bind the schedulers.</p> <p>Schedulers can be bound in different ways. The <c>How</c> argument determines how schedulers are bound. <c>How</c> can currently be one of:</p> <taglist> <tag><c>unbound</c></tag> - <item> - <p>Schedulers will not be bound to logical processors, i.e., - the operating system decides where the scheduler threads - execute, and when to migrate them. This is the default.</p> - </item> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt u</seealso>. + </p></item> <tag><c>no_spread</c></tag> - <item> - <p>Schedulers with close scheduler identifiers will be bound - as close as possible in hardware.</p> - </item> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt ns</seealso>. + </p></item> <tag><c>thread_spread</c></tag> - <item> - <p>Thread refers to hardware threads (e.g. Intels - hyper-threads). Schedulers with low scheduler identifiers, - will be bound to the first hardware thread of each core, - then schedulers with higher scheduler identifiers will be - bound to the second hardware thread of each core, etc.</p> - </item> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt ts</seealso>. + </p></item> <tag><c>processor_spread</c></tag> - <item> - <p>Schedulers will be spread like <c>thread_spread</c>, but - also over physical processor chips.</p> - </item> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt ps</seealso>. + </p></item> <tag><c>spread</c></tag> - <item> - <p>Schedulers will be spread as much as possible.</p> - </item> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt s</seealso>. + </p></item> <tag><c>no_node_thread_spread</c></tag> - <item> - <p>Like <c>thread_spread</c>, but if multiple NUMA - (Non-Uniform Memory Access) nodes exists, - schedulers will be spread over one NUMA node at a time, - i.e., all logical processors of one NUMA node will - be bound to schedulers in sequence.</p> - </item> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt nnts</seealso>. + </p></item> <tag><c>no_node_processor_spread</c></tag> - <item> - <p>Like <c>processor_spread</c>, but if multiple NUMA - nodes exists, schedulers will be spread over one - NUMA node at a time, i.e., all logical processors of - one NUMA node will be bound to schedulers in sequence.</p> - </item> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt nnps</seealso>. + </p></item> <tag><c>thread_no_node_processor_spread</c></tag> - <item> - <p>A combination of <c>thread_spread</c>, and - <c>no_node_processor_spread</c>. Schedulers will be - spread over hardware threads across NUMA nodes, but - schedulers will only be spread over processors internally - in one NUMA node at a time.</p> - </item> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt tnnps</seealso>. + </p></item> <tag><c>default_bind</c></tag> - <item> - <p>Binds schedulers the default way. Currently the default - is <c>thread_no_node_processor_spread</c> (which might change - in the future).</p> - </item> + <item><p>Same as the <c>erl</c> command line argument + <seealso marker="erts:erl#+sbt">+sbt db</seealso>. + </p></item> </taglist> - <p>How schedulers are bound matters. For example, in - situations when there are fewer running processes than - schedulers online, the runtime system tries to migrate - processes to schedulers with low scheduler identifiers. - The more the schedulers are spread over the hardware, - the more resources will be available to the runtime - system in such situations. - </p> <p>The value returned equals <c>How</c> before the <c>scheduler_bind_type</c> flag was changed.</p> <p>Failure:</p> @@ -5303,17 +5365,25 @@ true</pre> </item> </taglist> <p>The scheduler bind type can also be set by passing - the <seealso marker="erl#+sbt">+sbt</seealso> command + the <seealso marker="erts:erl#+sbt">+sbt</seealso> command line argument to <c>erl</c>. </p> <p>For more information, see <seealso marker="#system_info_scheduler_bind_type">erlang:system_info(scheduler_bind_type)</seealso>, <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>, - the <c>erl</c> <seealso marker="erl#+sbt">+sbt</seealso> - emulator flag, and - <seealso marker="#system_flag_cpu_topology">erlang:system_flag(cpu_topology, CpuTopology)</seealso>. + the <c>erl</c> <seealso marker="erts:erl#+sbt">+sbt</seealso> + and <seealso marker="erts:erl#+sct">+sct</seealso> command line + flags. </p> </item> + <tag><marker id="system_flag_scheduler_wall_time"><c>erlang:system_flag(scheduler_wall_time, Boolean)</c></marker></tag> + <item> + <p>Turns on/off scheduler wall time measurements. </p> + <p>For more information see, + <seealso marker="#statistics_scheduler_wall_time">erlang:statistics(scheduler_wall_time)</seealso>. + </p> + </item> + <tag><marker id="system_flag_schedulers_online"><c>erlang:system_flag(schedulers_online, SchedulersOnline)</c></marker></tag> <item> <p>Sets the amount of schedulers online. Valid range is @@ -5325,6 +5395,7 @@ true</pre> <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>. </p> </item> + <tag><c>erlang:system_flag(trace_control_word, TCW)</c></tag> <item> <p>Sets the value of the node's trace control word to @@ -5512,10 +5583,12 @@ true</pre> <item> <p>Returns the <c>CpuTopology</c> which currently is used by the emulator. The CPU topology is used when binding schedulers - to logical processors. The CPU topology used is the user defined - CPU topology if such exist; otherwise, the automatically - detected CPU topology if such exist. If no CPU topology - exist <c>undefined</c> is returned.</p> + to logical processors. The CPU topology used is the + <seealso marker="erlang#system_info_cpu_topology_defined">user + defined CPU topology</seealso> if such exists; otherwise, the + <seealso marker="erlang#system_info_cpu_topology_detected">automatically + detected CPU topology</seealso> if such exists. If no CPU topology + exists, <c>undefined</c> is returned.</p> <p>Types:</p> <list type="bulleted"> <item><c>CpuTopology = LevelEntryList | undefined</c></item> @@ -5562,8 +5635,8 @@ true</pre> <item> <p>Returns the user defined <c>CpuTopology</c>. For more information see the documentation of - <seealso marker="#system_flag_cpu_topology">erlang:system_flag(cpu_topology, CpuTopology)</seealso> - and the documentation of the + the <c>erl</c> <seealso marker="erts:erl#+sct">+sct</seealso> command + line flag, and the documentation of the <seealso marker="#system_info_cpu_topology">cpu_topology</seealso> argument. </p> @@ -5641,7 +5714,7 @@ true</pre> <item> <p>Returns the value of the distribution buffer busy limit in bytes. This limit can be set on startup by passing the - <seealso marker="erl#+zdbbl">+zdbbl</seealso> command line + <seealso marker="erts:erl#+zdbbl">+zdbbl</seealso> command line flag to <c>erl</c>.</p> </item> <tag><c>fullsweep_after</c></tag> @@ -5843,14 +5916,13 @@ true</pre> <p>Returns information on how user has requested schedulers to be bound or not bound.</p> <p><em>NOTE:</em> Even though user has requested - schedulers to be bound via - <seealso marker="#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, How)</seealso>, - they might have silently failed to bind. In order to - inspect actual scheduler bindings call + schedulers to be bound, they might have silently failed + to bind. In order to inspect actual scheduler bindings call <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. </p> <p>For more information, see - <seealso marker="#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, How)</seealso>, and + the <c>erl</c> <seealso marker="erts:erl#+sbt">+sbt</seealso> + command line argument, and <seealso marker="#system_info_scheduler_bindings">erlang:system_info(scheduler_bindings)</seealso>. </p> </item> @@ -5873,7 +5945,8 @@ true</pre> <p>Note that only schedulers online can be bound to logical processors.</p> <p>For more information, see - <seealso marker="#system_flag_scheduler_bind_type">erlang:system_flag(scheduler_bind_type, How)</seealso>, + the <c>erl</c> <seealso marker="erts:erl#+sbt">+sbt</seealso> + command line argument, <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>. </p> </item> @@ -7097,7 +7170,7 @@ true</pre> <c>Id</c> has no effect on the caller in the future (unless the link is setup again). If caller is trapping exits, an <c>{'EXIT', Id, _}</c> message due to the link might have - been placed in the callers message queue prior to the call, + been placed in the caller's message queue prior to the call, though. Note, the <c>{'EXIT', Id, _}</c> message can be the result of the link, but can also be the result of <c>Id</c> calling <c>exit/2</c>. Therefore, it <em>may</em> be diff --git a/erts/doc/src/erts_alloc.xml b/erts/doc/src/erts_alloc.xml index 3b5ee5391c..ec5e7d9b74 100644 --- a/erts/doc/src/erts_alloc.xml +++ b/erts/doc/src/erts_alloc.xml @@ -212,8 +212,8 @@ <p>Apart from the ordinary allocators described above a number of pre-allocators are used for some specific data types. These pre-allocators pre-allocate a fixed amount of memory for certain data - types when the run-time system starts. As long as there are available - pre-allocated memory, it will be used. When no pre-allocated memory is + types when the run-time system starts. As long as pre-allocated memory + is available, it will be used. When no pre-allocated memory is available, memory will be allocated in ordinary allocators. These pre-allocators are typically much faster than the ordinary allocators, but can only satisfy a limited amount of requests.</p> @@ -436,10 +436,10 @@ in "the <c>alloc_util</c> framework" section.</item> <tag><marker id="M_t"><c><![CDATA[+M<S>t true|false]]></c></marker></tag> <item> - Multiple, thread specific instances of the allocator. + <p>Multiple, thread specific instances of the allocator. This option will only have any effect on the runtime system with SMP support. Default behaviour on the runtime system with - SMP support: + SMP support:</p> <taglist> <tag><c>ll_alloc</c></tag> <item><c>1</c> instance.</item> @@ -448,9 +448,9 @@ a lock-free instance of its own and other threads will use a common instance.</item> </taglist> - It was previously (before ERTS version 5.9) possible to configure + <p>It was previously (before ERTS version 5.9) possible to configure a smaller amount of thread specific instances than schedulers. - This is, however, not possible any more. + This is, however, not possible any more.</p> </item> </taglist> <p>Currently the following flags are available for configuration of diff --git a/erts/doc/src/match_spec.xml b/erts/doc/src/match_spec.xml index f0390c9db8..cd2b3abc1e 100644 --- a/erts/doc/src/match_spec.xml +++ b/erts/doc/src/match_spec.xml @@ -75,7 +75,7 @@ <item>MatchCondition ::= { GuardFunction } | { GuardFunction, ConditionExpression, ... } </item> - <item>BoolFunction ::= <c><![CDATA[is_atom]]></c> | <c><![CDATA[is_constant]]></c> | + <item>BoolFunction ::= <c><![CDATA[is_atom]]></c> | <c><![CDATA[is_float]]></c> | <c><![CDATA[is_integer]]></c> | <c><![CDATA[is_list]]></c> | <c><![CDATA[is_number]]></c> | <c><![CDATA[is_pid]]></c> | <c><![CDATA[is_port]]></c> | <c><![CDATA[is_reference]]></c> | <c><![CDATA[is_tuple]]></c> | <c><![CDATA[is_binary]]></c> | @@ -133,7 +133,7 @@ <item>MatchCondition ::= { GuardFunction } | { GuardFunction, ConditionExpression, ... } </item> - <item>BoolFunction ::= <c><![CDATA[is_atom]]></c> | <c><![CDATA[is_constant]]></c> | + <item>BoolFunction ::= <c><![CDATA[is_atom]]></c> | <c><![CDATA[is_float]]></c> | <c><![CDATA[is_integer]]></c> | <c><![CDATA[is_list]]></c> | <c><![CDATA[is_number]]></c> | <c><![CDATA[is_pid]]></c> | <c><![CDATA[is_port]]></c> | <c><![CDATA[is_reference]]></c> | <c><![CDATA[is_tuple]]></c> | <c><![CDATA[is_binary]]></c> | @@ -172,7 +172,7 @@ <title>Functions allowed in all types of match specifications</title> <p>The different functions allowed in <c><![CDATA[match_spec]]></c> work like this: </p> - <p><em>is_atom, is_constant, is_float, is_integer, is_list, is_number, is_pid, is_port, is_reference, is_tuple, is_binary, is_function: </em> Like the corresponding guard tests in + <p><em>is_atom, is_float, is_integer, is_list, is_number, is_pid, is_port, is_reference, is_tuple, is_binary, is_function: </em> Like the corresponding guard tests in Erlang, return <c><![CDATA[true]]></c> or <c><![CDATA[false]]></c>. </p> <p><em>is_record: </em>Takes an additional parameter, which SHALL diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index 4cef9669dd..d7967212b1 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -30,6 +30,507 @@ </header> <p>This document describes the changes made to the ERTS application.</p> +<section><title>Erts 5.9.0.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + A feature test for the <c>lwsync</c> instruction + performed on PowerPC hardware at runtime system startup + got into an eternal loop if the instruction was not + supported. This bug was introduced in erts-5.9/OTP-R15B.</p> + <p> + Own Id: OTP-9843</p> + </item> + <item> + <p> + I/O events could potentially be delayed for ever when + enabling kernel-poll on a non-SMP runtime system + executing on Solaris. When also combined with + async-threads the runtime system hung before completing + the boot phase. This bug was introduced in + erts-5.9/OTP-R15B.</p> + <p> + Own Id: OTP-9844</p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 5.9</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Honor option <c>packet_size</c> for http packet parsing + by both TCP socket and <c>erlang:decode_packet</c>. This + gives the ability to accept HTTP headers larger than the + default setting, but also avoid DoS attacks by accepting + lines only up to whatever length you wish to allow. For + consistency, packet type <c>line</c> also honor option + <c>packet_size</c>. (Thanks to Steve Vinoski)</p> + <p> + Own Id: OTP-9389</p> + </item> + <item> + <p> A few contracts in the <c>lists</c> module have been + corrected. </p> + <p> + Own Id: OTP-9616</p> + </item> + <item> + <p> + The Unicode noncharacter code points 16#FFFE and 16#FFFE + were not allowed to be encoded or decoded using the + <c>unicode</c> module or bit syntax. That was + inconsistent with the other noncharacters 16#FDD0 to + 16#FDEF that could be encoded/decoded. To resolve the + inconsistency, 16#FFFE and 16#FFFE can now be encoded and + decoded. (Thanks to Alisdair Sullivan.)</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9624</p> + </item> + <item> + <p> + Make epp search directory of current file first when + including another file This completes a partial fix in + R11 that only worked for include_lib(). (Thanks to + Richard Carlsson)</p> + <p> + Own Id: OTP-9645</p> + </item> + <item> + <p> + Fixed memory leak in + <c>enif_inspect_io_list_as_binary</c> when applied on a + process independent environment.</p> + <p> + Own Id: OTP-9668</p> + </item> + <item> + <p>The number of beam catches allowed in code are no + longer statically defined and will grow according to its + need.</p> + <p> + Own Id: OTP-9692</p> + </item> + <item> + <p> + Add missing parenthesis in heart doc.</p> + <p> + Add missing spaces in the Reference Manual distributed + section.</p> + <p> + In the HTML version of the doc those spaces are necessary + to separate those words.</p> + <p> + Own Id: OTP-9693</p> + </item> + <item> + <p> + Fixes module erlang doc style: option description (Thanks + to Ricardo Catalinas Jim�nez)</p> + <p> + Own Id: OTP-9697</p> + </item> + <item> + <p> + Specifying a scope to binary:match/3 when using multiple + searchstrings resulted in faulty return values. This is + now corrected.</p> + <p> + Own Id: OTP-9701</p> + </item> + <item> + <p> + The runtime system crashed if more than one thread tried + to exit the runtime system at the same time.</p> + <p> + Own Id: OTP-9705</p> + </item> + <item> + <p> + Fix documentation for erlang:process_flag/2</p> + <p> + For the subsection about process_flag(save_calls, N) + there's an unrelated paragraph about process priorities + which was copied from the preceeding subsection regarding + process_flag(priority, Level). (Thanks to Filipe David + Manana)</p> + <p> + Own Id: OTP-9714</p> + </item> + <item> + <p> + Calls to <c>erlang:system_flag(schedulers_online, N)</c> + and/or <c>erlang:system_flag(multi_scheduling, + block|unblock)</c> could cause internal data used by this + functionality to get into an inconsistent state. When + this happened various problems occurred. This bug was + quite hard to trigger, so hopefully no-one has been + effected by it.</p> + <p> + A spinlock used by the run-queue management sometimes got + heavily contended. This code has now been rewritten, and + the spinlock has been removed.</p> + <p> + Own Id: OTP-9727</p> + </item> + <item> + <p> + Use libdlpi to get physical address (Thanks to Trond + Norbye)</p> + <p> + Own Id: OTP-9818</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> An option list argument can now be passed to + <c>file:read_file_info/2, file:read_link_info/2</c> and + <c>file:write_file_info/3</c> and set time type + information in the call. Valid options are <c>{time, + local}, {time, universal}</c> and <c>{time, posix}</c>. + In the case of <c>posix</c> time no conversions are made + which makes the operation a bit faster. </p> + <p> + Own Id: OTP-7687</p> + </item> + <item> + <p>A number of memory allocation optimizations have been + implemented. Most optimizations reduce contention caused + by synchronization between threads during allocation and + deallocation of memory. Most notably:</p> <list> <item> + Synchronization of memory management in scheduler + specific allocator instances has been rewritten to use + lock-free synchronization. </item> <item> Synchronization + of memory management in scheduler specific pre-allocators + has been rewritten to use lock-free synchronization. + </item> <item> The 'mseg_alloc' memory segment allocator + now use scheduler specific instances instead of one + instance. Apart from reducing contention this also + ensures that memory allocators always create memory + segments on the local NUMA node on a NUMA system. </item> + </list> + <p> + Own Id: OTP-7775</p> + </item> + <item> + <p> + The ethread atomic memory operations API used by the + runtime system has been extended and improved.</p> + <p> + The ethread library now also performs runtime tests for + presence of hardware features, such as for example SSE2 + instructions, instead of requiring this to be determined + at compile time.</p> + <p> + All uses of the old deprecated atomic API in the runtime + system have been replaced with the use of the new atomic + API. In a lot of places this change imply a relaxation of + memory barriers used.</p> + <p> + Own Id: OTP-9014</p> + </item> + <item> + <p>gen_sctp:open/0-2 may now return + {error,eprotonosupport} if SCTP is not supported</p> + <p>gen_sctp:peeloff/1 has been implemented and creates a + one-to-one socket which also are supported now</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9239</p> + </item> + <item> + <p> + Sendfile has been added to the file module's API. + sendfile/2 is used to read data from a file and send it + to a tcp socket using a zero copying mechanism if + available on that OS.</p> + <p> + Thanks to Tuncer Ayaz and Steve Vinovski for original + implementation</p> + <p> + Own Id: OTP-9240</p> + </item> + <item> + <p> + enif_get_reverse_list function added to nif API. This + function should be used to reverse small lists which are + deep within other structures making it impractical to do + the reverse in Erlang.</p> + <p> + Own Id: OTP-9392</p> + </item> + <item> + <p> + The deprecated concat_binary/1 BIF has been removed. Use + <c>list_to_binary</c> or <c>iolist_to_binary/1</c> + instead.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9421</p> + </item> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + <item> + <p>Line number and filename information are now included + in exception backtraces as a fourth element in the MFA + tuple. The information will be pretty-printed by the + shell and used by <c>common_test</c> to provide better + indication of where a test case.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9468</p> + </item> + <item> + <p>All binary constants used to be handled as heap + binaries (i.e. the entire binary would be copied when + sent to another process). Binary constants larger than 64 + bytes are now refc binaries (i.e. the actual data in the + binary will not be copied when sent to another + process).</p> + <p> + Own Id: OTP-9486</p> + </item> + <item> + <p> + If a float and an integer is compared, the integer is + only converted to a float if the float datatype can + contain it. Otherwise the float is converted to an + integer.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9497</p> + </item> + <item> + <p> + Add NIF function enif_is_number</p> + <p> + This function allows for easily determining if a term + represents or not a number (integer, float, small or + big).(Thanks to Filipe David Manana)</p> + <p> + Own Id: OTP-9629</p> + </item> + <item> + <p> + The ERTS internal system block functionality has been + replaced by new functionality for blocking the system. + The old system block functionality had contention issues + and complexity issues. The new functionality piggy-backs + on thread progress tracking functionality needed by newly + introduced lock-free synchronization in the runtime + system. When the functionality for blocking the system + isn't used, there is more or less no overhead at all. + This since the functionality for tracking thread progress + is there and needed anyway.</p> + <p> + Own Id: OTP-9631</p> + </item> + <item> + <p> + An ERTS internal, generic, many to one, lock-free queue + for communication between threads has been introduced. + The many to one scenario is very common in ERTS, so it + can be used in a lot of places in the future. Currently + it is used by scheduling of certain jobs, and the async + thread pool, but more uses are planned for the future.</p> + <p> + Drivers using the driver_async functionality are not + automatically locked to the system anymore, and can be + unloaded as any dynamically linked in driver.</p> + <p> + Scheduling of ready async jobs is now also interleaved in + between other jobs. Previously all ready async jobs were + performed at once.</p> + <p> + Own Id: OTP-9632</p> + </item> + <item> + <p> + Tuple funs (a two-element tuple with a module name and a + function) are now officially deprecated and will be + removed in R16. Use '<c>fun M:F/A</c>' instead. To make + you aware that your system uses tuple funs, the very + first time a tuple fun is applied, a warning will be sent + to the error logger.</p> + <p> + Own Id: OTP-9649</p> + </item> + <item> + <p> + Changed the internal BIF calling convention. Will make + simpler faster code and allow BIFs with an arbitrary + arity.</p> + <p> + Own Id: OTP-9662</p> + </item> + <item> + <p> + Windows native critical sections are now used internally + in the runtime system on Windows as mutex implementation. + This since they perform better under extreme contention + than our own implementation.</p> + <p> + Own Id: OTP-9671</p> + </item> + <item> + <p> + Convert some erl_nif macros into inline functions. Allow + for better compile time type checking. (Thanks to Tuncer + Ayaz)</p> + <p> + Own Id: OTP-9675</p> + </item> + <item> + <p> + The <c>+scl</c> command line flag has been added. It can + be used for disabling compaction of scheduler load. For + more information see the <c>erl(1)</c> documentation.</p> + <p> + Own Id: OTP-9695</p> + </item> + <item> + <p>The build system has been updated so that Erlang/OTP + can be built on Mac OS X Lion systems without a GCC + compiler. The INSTALL guide has been updated with + instructions on how to install a GCC compiler and build + Erlang/OTP with it, in order to get a run-time system + with better performance.</p> + <p> + Own Id: OTP-9712</p> + </item> + <item> + <p> + When loading a module, the system use to run on a single + scheduler during the entire loading process. This has + been changed to only take down the system just before + inserting the loaded code into the system tables, + resulting in a much shorter disruption if a module is + loaded in a busy system. (Suggested by Bob Ippolito.)</p> + <p> + Own Id: OTP-9720</p> + </item> + <item> + <p> + Possible to run HiPE without floating point exceptions + (FPE). Useful on platforms that lack reliable FPE. Slower + float operations compared to HiPE with FPE.</p> + <p> + Own Id: OTP-9724</p> + </item> + <item> + <p> + As of ERTS version 5.9 (OTP-R15B) the runtime system will + by default <em>not</em> bind schedulers to logical + processors.</p> + <p> + If the Erlang runtime system is the only operating system + process that binds threads to logical processors, this + improves the performance of the runtime system. However, + if other operating system processes (as for example + another Erlang runtime system) also bind threads to + logical processors, there might be a performance penalty + instead. In some cases this performance penalty might be + severe. Due to this, we change the default so that the + user must make an active decision in order to bind + schedulers.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9726</p> + </item> + <item> + <p> + The use of <c>erlang:system_flag(scheduler_bind_type, + _)</c> and <c>erlang:system_flag(cpu_topology, _)</c> + have been deprecated and scheduled for removal in + erts-5.10/OTP-R16. For more information see the + documentation of <c>erlang:system_flag/2</c>.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9749</p> + </item> + <item> + <p> + An ancient workaround for a Windows bug was removed from + the open_port code, open_port({spawn,...}...) is now + faster. Thanks to Daniel Goertzen.</p> + <p> + Own Id: OTP-9766</p> + </item> + <item> + <p> + The use of deprecated 32bit time_t on 32bit Windows is + removed.</p> + <p> + Own Id: OTP-9767</p> + </item> + <item> + <p> + The NIF <c>reload</c> mechanism is deprecated. Do not use + it as an upgrade method for live production systems. It + might be removed in future releases. It can still serve + as a development feature but a warning message will be + logged each time it is used.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9771</p> + </item> + <item> + <p>The driver interface has been changed to enable 64-bit + aware drivers. Most importantly the return types for + ErlDrvEntry callbacks 'call' and 'control' has ben + enlarged which require drivers to be changed or they will + cause emulator crashes. See <seealso + marker="erl_driver#rewrites_for_64_bits"> Rewrites for + 64-bit driver interface </seealso> in the driver manual. + </p> + <p>Due to this driver <seealso + marker="erl_driver#version_management">version + management</seealso> is now mandatory. A driver that is + not written with version management or a driver that was + compiled with the wrong major version will be not be + loaded by the emulator.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9795</p> + </item> + <item> + <p> + Eliminate use of deprecated regexp module</p> + <p> + Own Id: OTP-9810</p> + </item> + </list> + </section> + +</section> + <section><title>Erts 5.8.5</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index 708d4ca0a3..279844adb2 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2011. All Rights Reserved. +# Copyright Ericsson AB 1996-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -28,21 +28,26 @@ Z_LIB=@Z_LIB@ NO_INLINE_FUNCTIONS=false OPCODE_TABLES = $(ERL_TOP)/lib/compiler/src/genop.tab beam/ops.tab +DEBUG_CFLAGS = @DEBUG_CFLAGS@ +CONFIGURE_CFLAGS = @CFLAGS@ + # # Run this make file with TYPE set to the type of emulator you want. # Different versions of the emulator for different uses. The default # is "debug". For a normal version use "opt". # +DEFS=@DEFS@ THR_DEFS=@EMU_THR_DEFS@ M4FLAGS= CREATE_DIRS= LDFLAGS=@LDFLAGS@ +ARFLAGS=rc ifeq ($(TYPE),debug) PURIFY = TYPEMARKER = .debug -TYPE_FLAGS = @DEBUG_CFLAGS@ -DDEBUG +TYPE_FLAGS = $(DEBUG_CFLAGS) -DDEBUG ENABLE_ALLOC_TYPE_VARS += debug ifeq ($(TARGET),win32) TYPE_FLAGS += -DNO_JUMP_TABLE @@ -53,7 +58,7 @@ else ifeq ($(TYPE),purify) PURIFY = purify $(PURIFY_BUILD_OPTIONS) TYPEMARKER = .purify -TYPE_FLAGS = @DEBUG_CFLAGS@ -DPURIFY -DNO_JUMP_TABLE -DERTS_MSEG_FAKE_SEGMENTS +TYPE_FLAGS = $(DEBUG_CFLAGS) -DPURIFY -DNO_JUMP_TABLE -DERTS_MSEG_FAKE_SEGMENTS ENABLE_ALLOC_TYPE_VARS += purify else @@ -67,14 +72,14 @@ else ifeq ($(TYPE),purecov) PURIFY = purecov --follow-child-processes=yes $(PURECOV_BUILD_OPTIONS) TYPEMARKER = .purecov -TYPE_FLAGS = @DEBUG_CFLAGS@ -DPURECOV -DNO_JUMP_TABLE +TYPE_FLAGS = $(DEBUG_CFLAGS) -DPURECOV -DNO_JUMP_TABLE ENABLE_ALLOC_TYPE_VARS += purecov else ifeq ($(TYPE),gcov) PURIFY = TYPEMARKER = .gcov -TYPE_FLAGS = @DEBUG_CFLAGS@ -DERTS_GCOV -DNO_JUMP_TABLE -fprofile-arcs -ftest-coverage -O0 -DERTS_CAN_INLINE=0 -DERTS_INLINE= +TYPE_FLAGS = $(DEBUG_CFLAGS) -DERTS_GCOV -DNO_JUMP_TABLE -fprofile-arcs -ftest-coverage -O0 -DERTS_CAN_INLINE=0 -DERTS_INLINE= ifneq ($(findstring solaris,$(TARGET)),solaris) LIBS += -lgcov endif @@ -84,7 +89,7 @@ else ifeq ($(TYPE),valgrind) PURIFY = TYPEMARKER = .valgrind -TYPE_FLAGS = @DEBUG_CFLAGS@ -DVALGRIND -DNO_JUMP_TABLE -DERTS_MSEG_FAKE_SEGMENTS +TYPE_FLAGS = $(DEBUG_CFLAGS) -DVALGRIND -DNO_JUMP_TABLE -DERTS_MSEG_FAKE_SEGMENTS ENABLE_ALLOC_TYPE_VARS += valgrind else @@ -147,6 +152,15 @@ endif TF_MARKER=$(TYPEMARKER)$(FLAVOR_MARKER) +ifeq ($(FLAVOR)-@ERTS_BUILD_SMP_EMU@,smp-no) +VOID_EMULATOR = '*** SMP emulator disabled by configure' +else +ifeq ($(TYPE)-@HAVE_VALGRIND@,valgrind-no) +VOID_EMULATOR = '*** valgrind emulator disabled by configure' +else +VOID_EMULATOR = +endif +endif OPSYS=@OPSYS@ sol2CFLAGS= @@ -187,7 +201,7 @@ else EMU_CC = @EMU_CC@ endif WFLAGS = @WFLAGS@ -CFLAGS = @STATIC_CFLAGS@ $(TYPE_FLAGS) $(FLAVOR_FLAGS) @DEFS@ $(WFLAGS) $(THR_DEFS) $(ARCHCFLAGS) +CFLAGS = @STATIC_CFLAGS@ $(TYPE_FLAGS) $(FLAVOR_FLAGS) $(DEFS) $(WFLAGS) $(THR_DEFS) $(ARCHCFLAGS) HCC = @HCC@ LD = @LD@ DEXPORT = @DEXPORT@ @@ -198,6 +212,7 @@ RM = @RM@ MKDIR = @MKDIR@ USING_MINGW=@MIXED_CYGWIN_MINGW@ +MIXED_MSYS=@MIXED_MSYS@ ifeq ($(TARGET),win32) LIB_PREFIX= @@ -237,9 +252,12 @@ ifeq ($(TARGET), win32) GEN_OPT_FLGS = $(OPT_LEVEL) UNROLL_FLG = RC=rc.sh +ifeq ($(MIXED_MSYS), yes) +MAKE_PRELOAD_EXTRA = -msys +endif ifeq ($(USING_MINGW), yes) -RES_EXT=@OBJEXT@ -MAKE_PRELOAD_EXTRA=-windres +RES_EXT = @OBJEXT@ +MAKE_PRELOAD_EXTRA += " -windres" else RES_EXT=res endif @@ -259,30 +277,29 @@ CS_PURIFY = CS_TYPE_FLAGS = $(subst QUANTIFY,FAKE_QUANTIFY, \ $(subst PURIFY,FAKE_PURIFY, $(TYPE_FLAGS))) endif -CS_CFLAGS_ = $(CS_TYPE_FLAGS) @DEFS@ $(WFLAGS) +CS_CFLAGS_ = $(CS_TYPE_FLAGS) $(DEFS) $(WFLAGS) ifeq ($(GCC),yes) CS_CFLAGS = $(subst -O2, $(GEN_OPT_FLGS) $(UNROLL_FLG), $(CS_CFLAGS_)) else CS_CFLAGS = $(CS_CFLAGS_) endif CS_LDFLAGS = $(LDFLAGS) -CS_LIBS = -L../lib/internal/$(TARGET) -lerts_internal @ERTS_INTERNAL_X_LIBS@ +CS_LIBS = -L../lib/internal/$(TARGET) -lerts_internal$(TYPEMARKER) @ERTS_INTERNAL_X_LIBS@ LIBS += @TERMCAP_LIB@ -L../lib/internal/$(TARGET) @ERTS_INTERNAL_X_LIBS@ ifdef Z_LIB # Use shared zlib library LIBS += $(Z_LIB) +DEPLIBS = else +DEPLIBS=$(ZLIB_LIBRARY) ifeq ($(TARGET),win32) -LIBS += -L$(ERL_TOP)/erts/emulator/zlib/obj/$(TARGET)/$(TYPE) -lz -DEPLIBS = $(ERL_TOP)/erts/emulator/zlib/obj/$(TARGET)/$(TYPE)/z.lib +LIBS += -L$(ZLIB_OBJDIR) -lz else # Build on darwin fails if -lz is used -LIBS += $(ERL_TOP)/erts/emulator/zlib/obj/$(TARGET)/$(TYPE)/libz.a -DEPLIBS = $(ERL_TOP)/erts/emulator/zlib/obj/$(TARGET)/$(TYPE)/libz.a +LIBS += $(ZLIB_LIBRARY) endif - endif ifeq ($(TARGET),win32) @@ -309,12 +326,9 @@ LIBSCTP = @LIBSCTP@ ORG_THR_LIBS=@EMU_THR_LIBS@ THR_LIB_NAME=@EMU_THR_LIB_NAME@ -ifneq ($(strip $(THR_LIB_NAME)),) -DEPLIBS += $(ERL_TOP)/erts/lib/internal/$(TARGET)/$(LIB_PREFIX)erts_internal_r$(TYPEMARKER)$(LIB_SUFFIX) \ - $(ERL_TOP)/erts/lib/internal/$(TARGET)/$(LIB_PREFIX)ethread$(TYPEMARKER)$(LIB_SUFFIX) -else -DEPLIBS += $(ERL_TOP)/erts/lib/internal/$(TARGET)/$(LIB_PREFIX)erts_internal$(TYPEMARKER)$(LIB_SUFFIX) -endif +ERTS_LIB_DIR = $(ERL_TOP)/erts/lib_src +ERTS_LIB = $(ERTS_LIB_DIR)/obj/$(TARGET)/$(TYPE)/MADE +DEPLIBS += $(ERTS_LIB) THR_LIBS=$(subst -l$(THR_LIB_NAME),-l$(THR_LIB_NAME)$(TYPEMARKER), \ $(subst -lerts_internal_r,-lerts_internal_r$(TYPEMARKER),$(ORG_THR_LIBS))) @@ -350,8 +364,7 @@ OBJDIR = obj/$(TTF_DIR) CREATE_DIRS += $(OBJDIR) \ pcre/obj/$(TARGET)/$(TYPE) \ - zlib/obj/$(TARGET)/$(TYPE) - + $(ZLIB_OBJDIR) BINDIR = $(ERL_TOP)/bin/$(TARGET) @@ -359,7 +372,6 @@ ERLANG_OSTYPE = @ERLANG_OSTYPE@ ENABLE_ALLOC_TYPE_VARS += @ERLANG_OSTYPE@ -EMULATOR_EXECUTABLE_ELIB = beam.elib$(TF_MARKER) ifeq ($(TARGET), win32) EMULATOR_EXECUTABLE = beam$(TF_MARKER).dll else @@ -375,15 +387,12 @@ else UNIX_ONLY_BUILDS = endif -ifeq ($(TYPE)-@HAVE_VALGRIND@,valgrind-no) -all: - @echo '*** valgrind not found by configure' -else -ifeq ($(FLAVOR)-@ERTS_BUILD_SMP_EMU@,smp-no) +.PHONY: all +ifdef VOID_EMULATOR all: - @echo '*** Omitted build of emulator with smp support' + @echo $(VOID_EMULATOR)' - omitted target all' else -all: generate erts_lib zlib $(BINDIR)/$(EMULATOR_EXECUTABLE) $(UNIX_ONLY_BUILDS) +all: $(BINDIR)/$(EMULATOR_EXECUTABLE) $(UNIX_ONLY_BUILDS) ifeq ($(OMIT_OMIT_FP),yes) @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' @@ -394,37 +403,25 @@ ifeq ($(OMIT_OMIT_FP),yes) @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' endif endif -endif - -ifdef Z_LIB -zlib: - @echo 'Skip zlib directory, use shared library' -else -zlib: - @set -e ; cd zlib && $(MAKE) TYPE=$(TYPE) $(TYPE) -endif - +include zlib/zlib.mk include pcre/pcre.mk -erts_lib: - cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE) +$(ERTS_LIB): + cd $(ERTS_LIB_DIR) && $(MAKE) $(TYPE) +.PHONY: clean clean: -ifeq ($(TARGET),win32) - $(RM) -f $(TARGET)/beams.rc -endif - $(RM) -f $(TARGET)/*.c $(TARGET)/*.h $(TARGET)/depend.mk - $(RM) -f $(TARGET)/*/*/*.c $(TARGET)/*/*/*.h $(TARGET)/*/*/*.S - $(RM) -f $(ERL_TOP)/erts/emulator/obj/$(TARGET)/*/*/*.o - $(RM) -f $(BINDIR)/beam $(BINDIR)/beam.* - $(RM) -rf $(BINDIR)/child_setup $(BINDIR)/child_setup.* - $(RM) -f $(BINDIR)/hipe_mkliterals $(BINDIR)/hipe_mkliterals.* - @set -e ; cd zlib && $(MAKE) clean - rm -f $(OBJS) $(OBJDIR)/libepcre.a - -.PHONY: all zlib clean - + $(RM) -f $(GENERATE) + $(RM) -rf $(TARGET)/*.c $(TARGET)/*.h $(TARGET)/*-GENERATED + $(RM) -rf $(TARGET)/*/* + $(RM) -rf obj/$(TARGET) + $(RM) -rf pcre/obj/$(TARGET) $(PCRE_GENINC) + $(RM) -rf zlib/obj/$(TARGET) + $(RM) -rf bin/$(TARGET) + cd $(ERTS_LIB_DIR) && $(MAKE) clean + +.PHONY: docs docs: # ---------------------------------------------------------------------- @@ -437,13 +434,11 @@ ifeq ($(TARGET),win32) RELEASE_INCLUDES += sys/$(ERLANG_OSTYPE)/erl_win_dyn_driver.h endif -ifeq ($(TYPE)-@HAVE_VALGRIND@,valgrind-no) -release_spec: - @echo '*** valgrind not found by configure' -else -ifeq ($(FLAVOR)-@ERTS_BUILD_SMP_EMU@,smp-no) + +.PHONY: release_spec +ifdef VOID_EMULATOR release_spec: - @echo '*** No emulator with smp support to install' + @echo $(VOID_EMULATOR)' - omitted target release_spec (install)' else release_spec: all $(INSTALL_DIR) $(RELSYSDIR) @@ -460,8 +455,8 @@ ifeq ($(ERLANG_OSTYPE), unix) $(INSTALL_PROGRAM) $(BINDIR)/$(CS_EXECUTABLE) $(RELSYSDIR)/bin endif endif -endif +.PHONY: release_docs_spec release_docs_spec: # ---------------------------------------------------------------------- @@ -470,48 +465,41 @@ release_docs_spec: _create_dirs := $(shell mkdir -p $(CREATE_DIRS)) -.PHONY : generate - -GENERATE= $(TTF_DIR)/beam_opcodes.h \ - $(TARGET)/erl_bif_table.c \ - $(TARGET)/erl_version.h \ - $(TTF_DIR)/driver_tab.c \ - $(TTF_DIR)/erl_alloc_types.h - -ifeq ($(TARGET),win32) -GENERATE += $(TARGET)/beams.rc -else -GENERATE += $(TARGET)/preload.c -endif +GENERATE = +HIPE_ASM = ifeq ($(findstring vxworks,$(TARGET)),vxworks) else ifdef HIPE_ENABLED -GENERATE += $(TTF_DIR)/hipe_x86_asm.h \ +HIPE_ASM += $(TTF_DIR)/hipe_x86_asm.h \ $(TTF_DIR)/hipe_amd64_asm.h \ $(TTF_DIR)/hipe_sparc_asm.h \ $(TTF_DIR)/hipe_ppc_asm.h \ - $(TTF_DIR)/hipe_arm_asm.h \ + $(TTF_DIR)/hipe_arm_asm.h + +GENERATE += $(HIPE_ASM) \ $(TTF_DIR)/hipe_literals.h \ $(BINDIR)/hipe_mkliterals$(TF_MARKER) endif endif -ifeq ($(FLAVOR)-@ERTS_BUILD_SMP_EMU@,smp-no) -GENERATE= -endif - -generate: $(GENERATE) - ifdef HIPE_ENABLED OPCODE_TABLES += hipe/hipe_ops.tab endif -$(TTF_DIR)/beam_opcodes.h $(TTF_DIR)/beam_opcodes.c: $(OPCODE_TABLES) utils/beam_makeops +$(TTF_DIR)/beam_cold.h \ +$(TTF_DIR)/beam_hot.h \ +$(TTF_DIR)/beam_opcodes.c \ +$(TTF_DIR)/beam_opcodes.h \ +$(TTF_DIR)/beam_pred_funcs.h \ +$(TTF_DIR)/beam_tr_funcs.h \ + : $(TTF_DIR)/OPCODES-GENERATED +$(TTF_DIR)/OPCODES-GENERATED: $(OPCODE_TABLES) utils/beam_makeops LANG=C $(PERL) utils/beam_makeops \ -wordsize @EXTERNAL_WORD_SIZE@ \ -outdir $(TTF_DIR) \ - -emulator $(OPCODE_TABLES) + -emulator $(OPCODE_TABLES) && echo $? >$(TTF_DIR)/OPCODES-GENERATED +GENERATE += $(TTF_DIR)/OPCODES-GENERATED # bif and atom table ATOMS= beam/atom.names @@ -531,32 +519,44 @@ BIFS += hipe/hipe_perfctr.tab endif endif -TABLES= $(TARGET)/erl_bif_table.c $(TARGET)/erl_bif_table.h \ - $(TARGET)/erl_bif_wrap.c $(TARGET)/erl_bif_list.h \ - $(TARGET)/erl_atom_table.c $(TARGET)/erl_atom_table.h \ - $(TARGET)/erl_pbifs.c - -$(TABLES): $(ATOMS) $(BIFS) utils/make_tables +$(TARGET)/erl_bif_table.c \ +$(TARGET)/erl_bif_table.h \ +$(TARGET)/erl_bif_wrap.c \ +$(TARGET)/erl_bif_list.h \ +$(TARGET)/erl_atom_table.c \ +$(TARGET)/erl_atom_table.h \ +$(TARGET)/erl_pbifs.c \ + : $(TARGET)/TABLES-GENERATED +$(TARGET)/TABLES-GENERATED: $(ATOMS) $(BIFS) utils/make_tables LANG=C $(PERL) utils/make_tables -src $(TARGET) -include $(TARGET)\ - $(ATOMS) $(BIFS) + $(ATOMS) $(BIFS) && echo $? >$(TARGET)/TABLES-GENERATED +GENERATE += $(TARGET)/TABLES-GENERATED $(TTF_DIR)/erl_alloc_types.h: beam/erl_alloc.types utils/make_alloc_types LANG=C $(PERL) utils/make_alloc_types -src $< -dst $@ $(ENABLE_ALLOC_TYPE_VARS) +GENERATE += $(TTF_DIR)/erl_alloc_types.h # version include file $(TARGET)/erl_version.h: ../vsn.mk LANG=C $(PERL) utils/make_version -o $@ $(SYSTEM_VSN) $(VSN)$(SERIALNO) $(TARGET) +GENERATE += $(TARGET)/erl_version.h # driver table $(TTF_DIR)/driver_tab.c: Makefile.in LANG=C $(PERL) utils/make_driver_tab -o $@ $(DRV_OBJS) +GENERATE += $(TTF_DIR)/driver_tab.c + + # Preloaded code. # # This list must be consistent with PRE_LOADED_MODULES in # lib/kernel/src/Makefile. ifeq ($(TARGET),win32) -$(TARGET)/beams.rc: $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \ +# On windows the preloaded objects are in a resource object. +PRELOAD_OBJ = $(OBJDIR)/beams.$(RES_EXT) +PRELOAD_SRC = $(TARGET)/beams.rc +$(PRELOAD_SRC): $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \ $(ERL_TOP)/erts/preloaded/ebin/init.beam \ $(ERL_TOP)/erts/preloaded/ebin/prim_inet.beam \ $(ERL_TOP)/erts/preloaded/ebin/prim_file.beam \ @@ -566,7 +566,9 @@ $(TARGET)/beams.rc: $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \ $(ERL_TOP)/erts/preloaded/ebin/erlang.beam LANG=C $(PERL) utils/make_preload $(MAKE_PRELOAD_EXTRA) -rc $^ > $@ else -$(TARGET)/preload.c: $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \ +PRELOAD_OBJ = $(OBJDIR)/preload.o +PRELOAD_SRC = $(TARGET)/preload.c +$(PRELOAD_SRC): $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \ $(ERL_TOP)/erts/preloaded/ebin/init.beam \ $(ERL_TOP)/erts/preloaded/ebin/prim_inet.beam \ $(ERL_TOP)/erts/preloaded/ebin/prim_file.beam \ @@ -577,6 +579,17 @@ $(TARGET)/preload.c: $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \ LANG=C $(PERL) utils/make_preload -old $^ > $@ endif +.PHONY : generate +ifdef VOID_EMULATOR +generate: + @echo $(VOID_EMULATOR)' - omitted target generate' +else +generate: $(TTF_DIR)/GENERATED $(PRELOAD_SRC) + +$(TTF_DIR)/GENERATED: $(GENERATE) + echo $? >$(TTF_DIR)/GENERATED +endif + # ---------------------------------------------------------------------- # Pattern rules # @@ -653,7 +666,7 @@ endif # CS_SRC = sys/$(ERLANG_OSTYPE)/erl_child_setup.c -$(BINDIR)/$(CS_EXECUTABLE): $(CS_SRC) +$(BINDIR)/$(CS_EXECUTABLE): $(TTF_DIR)/GENERATED $(PRELOAD_SRC) $(CS_SRC) $(ERTS_LIB) $(CS_PURIFY) $(CC) $(CS_LDFLAGS) -o $(BINDIR)/$(CS_EXECUTABLE) \ $(CS_CFLAGS) $(COMMON_INCLUDES) $(CS_SRC) $(CS_LIBS) @@ -682,16 +695,7 @@ $(ERL_TOP)/lib/%.beam: # Object files # -# On windows the preloaded objects are in a resource object. - -ifeq ($(TARGET),win32) -PRELOAD = $(OBJDIR)/beams.$(RES_EXT) -else -PRELOAD = $(OBJDIR)/preload.o -endif - - -INIT_OBJS = $(OBJDIR)/erl_main.o $(PRELOAD) +INIT_OBJS = $(OBJDIR)/erl_main.o $(PRELOAD_OBJ) EMU_OBJS = \ $(OBJDIR)/beam_emu.o $(OBJDIR)/beam_opcodes.o \ @@ -831,6 +835,9 @@ BASE_OBJS = $(RUN_OBJS) $(EMU_OBJS) $(OS_OBJS) $(EXTRA_BASE_OBJS) OBJS = $(BASE_OBJS) $(DRV_OBJS) +$(INIT_OBJS): $(TTF_DIR)/GENERATED +$(OBJS): $(TTF_DIR)/GENERATED + ######################################## # HiPE section @@ -854,30 +861,49 @@ $(OBJDIR)/%.o: hipe/%.c $(BINDIR)/hipe_mkliterals$(TF_MARKER): $(OBJDIR)/hipe_mkliterals.o $(CC) $(CFLAGS) $(INCLUDES) -o $@ $< -$(OBJDIR)/hipe_mkliterals.o: $(TTF_DIR)/hipe_x86_asm.h $(TTF_DIR)/hipe_ppc_asm.h $(TTF_DIR)/beam_opcodes.h +$(OBJDIR)/hipe_mkliterals.o: $(HIPE_ASM) $(TTF_DIR)/erl_alloc_types.h \ + $(TTF_DIR)/OPCODES-GENERATED $(TARGET)/TABLES-GENERATED $(TTF_DIR)/hipe_literals.h: $(BINDIR)/hipe_mkliterals$(TF_MARKER) $(BINDIR)/hipe_mkliterals$(TF_MARKER) -c > $@ -$(OBJDIR)/hipe_x86_glue.o: hipe/hipe_x86_glue.S $(TTF_DIR)/hipe_x86_asm.h $(TTF_DIR)/hipe_literals.h hipe/hipe_mode_switch.h -$(TTF_DIR)/hipe_x86_bifs.S: hipe/hipe_x86_bifs.m4 hipe/hipe_x86_asm.m4 hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h -$(OBJDIR)/hipe_x86_bifs.o: $(TTF_DIR)/hipe_x86_bifs.S $(TTF_DIR)/hipe_literals.h - -$(OBJDIR)/hipe_amd64_glue.o: hipe/hipe_amd64_glue.S $(TTF_DIR)/hipe_amd64_asm.h $(TTF_DIR)/hipe_literals.h hipe/hipe_mode_switch.h -$(TTF_DIR)/hipe_amd64_bifs.S: hipe/hipe_amd64_bifs.m4 hipe/hipe_amd64_asm.m4 hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h -$(OBJDIR)/hipe_amd64_bifs.o: $(TTF_DIR)/hipe_amd64_bifs.S $(TTF_DIR)/hipe_literals.h - -$(OBJDIR)/hipe_sparc_glue.o: hipe/hipe_sparc_glue.S $(TTF_DIR)/hipe_sparc_asm.h hipe/hipe_mode_switch.h $(TTF_DIR)/hipe_literals.h -$(TTF_DIR)/hipe_sparc_bifs.S: hipe/hipe_sparc_bifs.m4 hipe/hipe_sparc_asm.m4 hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h -$(OBJDIR)/hipe_sparc_bifs.o: $(TTF_DIR)/hipe_sparc_bifs.S $(TTF_DIR)/hipe_literals.h - -$(OBJDIR)/hipe_ppc_glue.o: hipe/hipe_ppc_glue.S $(TTF_DIR)/hipe_ppc_asm.h hipe/hipe_mode_switch.h $(TTF_DIR)/hipe_literals.h -$(TTF_DIR)/hipe_ppc_bifs.S: hipe/hipe_ppc_bifs.m4 hipe/hipe_ppc_asm.m4 hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h -$(OBJDIR)/hipe_ppc_bifs.o: $(TTF_DIR)/hipe_ppc_bifs.S $(TTF_DIR)/hipe_literals.h - -$(OBJDIR)/hipe_arm_glue.o: hipe/hipe_arm_glue.S $(TTF_DIR)/hipe_arm_asm.h hipe/hipe_mode_switch.h $(TTF_DIR)/hipe_literals.h -$(TTF_DIR)/hipe_arm_bifs.S: hipe/hipe_arm_bifs.m4 hipe/hipe_arm_asm.m4 hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h -$(OBJDIR)/hipe_arm_bifs.o: $(TTF_DIR)/hipe_arm_bifs.S $(TTF_DIR)/hipe_literals.h +$(OBJDIR)/hipe_x86_glue.o: hipe/hipe_x86_glue.S \ + $(TTF_DIR)/hipe_x86_asm.h $(TTF_DIR)/hipe_literals.h \ + hipe/hipe_mode_switch.h +$(TTF_DIR)/hipe_x86_bifs.S: hipe/hipe_x86_bifs.m4 hipe/hipe_x86_asm.m4 \ + hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h +$(OBJDIR)/hipe_x86_bifs.o: $(TTF_DIR)/hipe_x86_bifs.S \ + $(TTF_DIR)/hipe_literals.h + +$(OBJDIR)/hipe_amd64_glue.o: hipe/hipe_amd64_glue.S \ + $(TTF_DIR)/hipe_amd64_asm.h $(TTF_DIR)/hipe_literals.h \ + hipe/hipe_mode_switch.h +$(TTF_DIR)/hipe_amd64_bifs.S: hipe/hipe_amd64_bifs.m4 hipe/hipe_amd64_asm.m4 \ + hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h +$(OBJDIR)/hipe_amd64_bifs.o: $(TTF_DIR)/hipe_amd64_bifs.S \ + $(TTF_DIR)/hipe_literals.h + +$(OBJDIR)/hipe_sparc_glue.o: hipe/hipe_sparc_glue.S \ + $(TTF_DIR)/hipe_sparc_asm.h hipe/hipe_mode_switch.h \ + $(TTF_DIR)/hipe_literals.h +$(TTF_DIR)/hipe_sparc_bifs.S: hipe/hipe_sparc_bifs.m4 hipe/hipe_sparc_asm.m4 \ + hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h +$(OBJDIR)/hipe_sparc_bifs.o: $(TTF_DIR)/hipe_sparc_bifs.S \ + $(TTF_DIR)/hipe_literals.h + +$(OBJDIR)/hipe_ppc_glue.o: hipe/hipe_ppc_glue.S $(TTF_DIR)/hipe_ppc_asm.h \ + hipe/hipe_mode_switch.h $(TTF_DIR)/hipe_literals.h +$(TTF_DIR)/hipe_ppc_bifs.S: hipe/hipe_ppc_bifs.m4 hipe/hipe_ppc_asm.m4 \ + hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h +$(OBJDIR)/hipe_ppc_bifs.o: $(TTF_DIR)/hipe_ppc_bifs.S \ + $(TTF_DIR)/hipe_literals.h + +$(OBJDIR)/hipe_arm_glue.o: hipe/hipe_arm_glue.S $(TTF_DIR)/hipe_arm_asm.h \ + hipe/hipe_mode_switch.h $(TTF_DIR)/hipe_literals.h +$(TTF_DIR)/hipe_arm_bifs.S: hipe/hipe_arm_bifs.m4 hipe/hipe_arm_asm.m4 \ + hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h +$(OBJDIR)/hipe_arm_bifs.o: $(TTF_DIR)/hipe_arm_bifs.S \ + $(TTF_DIR)/hipe_literals.h # end of HiPE section ######################################## @@ -924,13 +950,6 @@ $(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS) endif -# -# Create directories -# - -$(CREATE_DIRS): - $(MKDIR) -p $@ - # ---------------------------------------------------------------------- # Dependencies # @@ -942,7 +961,7 @@ $(TARGET)/Makefile: Makefile.in #SED_REPL_WIN_DRIVE=s|\([ ]\)\([A-Za-z]\):|\1/cygdrive/\2|g;s|^\([A-Za-z]\):|/cygdrive/\1|g SED_REPL_O=s|^\([^:]*:\)|$$(OBJDIR)/\1|g -SED_REPL_ELIB_O=s|^\([^:]*\).o[ ]*:|$$(OBJDIR)/\1.elib.o:|g +SED_REPL_O_ZLIB=s|^\([^:]*:\)|$$(ZLIB_OBJDIR)/\1|g SED_REPL_TTF_DIR=s|$(TTF_DIR)/|$$(TTF_DIR)/|g SED_REPL_ERL_TOP=s|\([ ]\)$(ERL_TOP)/|\1$$(ERL_TOP)/|g;s|^$(ERL_TOP)/|$$(ERL_TOP)/|g SED_REPL_POLL=s|$$(OBJDIR)/erl_poll.o|$$(OBJDIR)/erl_poll.kp.o $$(OBJDIR)/erl_poll.nkp.o|g @@ -962,7 +981,7 @@ SED_SUFFIX= endif SED_DEPEND=sed '$(SED_PREFIX)$(SED_REPL_O);$(SED_REPL_TTF_DIR);$(SED_REPL_ERL_TOP)$(SED_SUFFIX)' -SED_ELIB_DEPEND=sed '$(SED_PREFIX)$(SED_REPL_ELIB_O);$(SED_REPL_TTF_DIR);$(SED_REPL_ERL_TOP)$(SED_SUFFIX)' +SED_DEPEND_ZLIB=sed '$(SED_PREFIX)$(SED_REPL_O_ZLIB)' ifdef HIPE_ENABLED HIPE_SRC=$(wildcard hipe/*.c) @@ -971,7 +990,8 @@ HIPE_SRC= endif BEAM_SRC=$(wildcard beam/*.c) -DRV_SRC=$(wildcard drivers/common/*.c) $(wildcard drivers/$(ERLANG_OSTYPE)/*.c) +DRV_COMMON_SRC=$(wildcard drivers/common/*.c) +DRV_OSTYPE_SRC=$(wildcard drivers/$(ERLANG_OSTYPE)/*.c) ALL_SYS_SRC=$(wildcard sys/$(ERLANG_OSTYPE)/*.c) $(wildcard sys/common/*.c) TARGET_SRC=$(wildcard $(TARGET)/*.c) $(wildcard $(TTF_DIR)/*.c) @@ -982,7 +1002,7 @@ ifeq ($(TARGET),win32) #DEP_CC=$(EMU_CC) DEP_CC=$(CC) -DEP_FLAGS=-MM $(subst -O2,,$(CFLAGS)) $(INCLUDES) -I../etc/win32 -Idrivers/common +DEP_FLAGS=-MM $(subst -O2,,$(CFLAGS)) $(INCLUDES) -I../etc/win32 -Idrivers/common -Idrivers/$(ERLANG_OSTYPE) # ifeq (@MIXED_CYGWIN_VC@,yes) # VC++ used for compiling. If __GNUC__ is defined we will include # other headers then when compiling which will result in faulty @@ -1002,28 +1022,40 @@ MG_FLAG=-MG endif DEP_CC=$(CC) -DEP_FLAGS=-MM $(MG_FLAG) $(CFLAGS) $(INCLUDES) -Idrivers/common +DEP_FLAGS=-MM $(MG_FLAG) $(CFLAGS) $(INCLUDES) -Idrivers/common -Idrivers/$(ERLANG_OSTYPE) SYS_SRC=$(ALL_SYS_SRC) endif +.PHONY: depend +ifdef VOID_EMULATOR depend: + @echo $(VOID_EMULATOR)' - omitted target depend' +else +depend: $(TTF_DIR)/depend.mk +$(TTF_DIR)/depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC) $(DEP_CC) $(DEP_FLAGS) $(BEAM_SRC) \ - | $(SED_DEPEND) > $(TARGET)/depend.mk - $(DEP_CC) $(DEP_FLAGS) $(DRV_SRC) \ - | $(SED_DEPEND) >> $(TARGET)/depend.mk + | $(SED_DEPEND) > $(TTF_DIR)/depend.mk + $(DEP_CC) $(DEP_FLAGS) -DLIBSCTP=$(LIBSCTP) $(DRV_COMMON_SRC) \ + | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk + $(DEP_CC) $(DEP_FLAGS) -I../etc/$(ERLANG_OSTYPE) $(DRV_OSTYPE_SRC) \ + | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk $(DEP_CC) $(DEP_FLAGS) $(SYS_SRC) \ - | $(SED_DEPEND) >> $(TARGET)/depend.mk + | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk $(DEP_CC) $(DEP_FLAGS) $(TARGET_SRC) \ - | $(SED_DEPEND) >> $(TARGET)/depend.mk -ifneq ($(TARGET),win32) - $(DEP_CC) $(DEP_FLAGS) $(ELIB_C_FILES) \ - | $(SED_ELIB_DEPEND) >> $(TARGET)/depend.mk -endif + | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk + $(DEP_CC) $(DEP_FLAGS) $(ZLIB_SRC) \ + | $(SED_DEPEND_ZLIB) >> $(TTF_DIR)/depend.mk ifdef HIPE_ENABLED $(DEP_CC) $(DEP_FLAGS) $(HIPE_SRC) \ - | $(SED_DEPEND) >> $(TARGET)/depend.mk + | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk +endif + cd $(ERTS_LIB_DIR) && $(MAKE) depend endif --include $(TARGET)/depend.mk - - +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(MAKECMDGOALS),generate) +ifndef VOID_EMULATOR +-include $(TTF_DIR)/depend.mk +endif +endif +endif diff --git a/erts/emulator/beam/atom.h b/erts/emulator/beam/atom.h index cb245a87b1..fd9c04d3d0 100644 --- a/erts/emulator/beam/atom.h +++ b/erts/emulator/beam/atom.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2010. All Rights Reserved. + * Copyright Ericsson AB 1996-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -34,7 +34,7 @@ /* Internal atom cache needs MAX_ATOM_TABLE_SIZE to be less than an unsigned 32 bit integer. See external.c(erts_encode_ext_dist_header_setup) for more details. */ -#define MAX_ATOM_TABLE_SIZE ((MAX_ATOM_INDEX + 1 < (1UL << 32)) ? MAX_ATOM_INDEX + 1 : (1UL << 32)) +#define MAX_ATOM_TABLE_SIZE ((MAX_ATOM_INDEX + 1 < (UWORD_CONSTANT(1) << 32)) ? MAX_ATOM_INDEX + 1 : (UWORD_CONSTANT(1) << 32)) #else #define MAX_ATOM_TABLE_SIZE (MAX_ATOM_INDEX + 1) #endif diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 71454b3e57..7be40976f6 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -95,6 +95,7 @@ atom atom atom atom_used atom attributes atom await_proc_exit +atom await_sched_wall_time_modifications atom awaiting_load atom awaiting_unload atom backtrace backtrace_depth @@ -239,6 +240,7 @@ atom generational atom get_seq_token atom get_tcw atom getenv +atom gather_sched_wall_time_result atom getting_linked atom getting_unlinked atom global @@ -554,6 +556,7 @@ atom waiting atom wall_clock atom warning atom warning_msg +atom scheduler_wall_time atom wordsize atom write_concurrency atom xor diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index bc8c001454..78a9d76a20 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -578,7 +578,7 @@ check_process_code(Process* rp, Module* modp) } #define in_area(ptr,start,nbytes) \ - ((unsigned long)((char*)(ptr) - (char*)(start)) < (nbytes)) + ((UWord)((char*)(ptr) - (char*)(start)) < (nbytes)) static int any_heap_ref_ptrs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size) diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index dd31376a2d..dd13cd179a 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -495,16 +495,6 @@ erts_find_local_func(Eterm mfa[3]) { return NULL; } -/* bp_hash */ -ERTS_INLINE Uint bp_sched2ix() { -#ifdef ERTS_SMP - ErtsSchedulerData *esdp; - esdp = erts_get_scheduler_data(); - return esdp->no - 1; -#else - return 0; -#endif -} static void bp_hash_init(bp_time_hash_t *hash, Uint n) { Uint size = sizeof(bp_data_time_item_t)*n; Uint i; @@ -1339,15 +1329,19 @@ static BpData *get_break(Process *p, BeamInstr *pc, BeamInstr break_op) { } static BpData *is_break(BeamInstr *pc, BeamInstr break_op) { - BpData **rs = (BpData **) pc[-4]; + BpData **rs; BpData *bd = NULL, *ebd = NULL; ASSERT(pc[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); + if (erts_is_native_break(pc)) { + return NULL; + } + rs = (BpData **) pc[-4]; if (! rs) { return NULL; } - bd = ebd = rs[bp_sched2ix()]; + bd = ebd = rs[erts_bp_sched2ix()]; ASSERT(bd); if ( (break_op == 0) || (bd->this_instr == break_op)) { return bd; diff --git a/erts/emulator/beam/beam_bp.h b/erts/emulator/beam/beam_bp.h index 2ec5818688..167069552f 100644 --- a/erts/emulator/beam/beam_bp.h +++ b/erts/emulator/beam/beam_bp.h @@ -144,8 +144,6 @@ extern erts_smp_spinlock_t erts_bp_lock; #define ErtsSmpBPUnlock(BDC) #endif -ERTS_INLINE Uint bp_sched2ix(void); - #ifdef ERTS_SMP #define bp_sched2ix_proc(p) ((p)->scheduler_data->no - 1) #else @@ -247,4 +245,19 @@ BpData *erts_get_time_break(Process *p, BeamInstr *pc); BeamInstr *erts_find_local_func(Eterm mfa[3]); +ERTS_GLB_INLINE Uint erts_bp_sched2ix(void); + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF +ERTS_GLB_INLINE Uint erts_bp_sched2ix(void) +{ +#ifdef ERTS_SMP + ErtsSchedulerData *esdp; + esdp = erts_get_scheduler_data(); + return esdp->no - 1; +#else + return 0; +#endif +} +#endif + #endif /* _BEAM_BP_H */ diff --git a/erts/emulator/beam/beam_catches.c b/erts/emulator/beam/beam_catches.c index a550ec5ad0..406ef1db5f 100644 --- a/erts/emulator/beam/beam_catches.c +++ b/erts/emulator/beam/beam_catches.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2000-2010. All Rights Reserved. + * Copyright Ericsson AB 2000-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 68e6383f7f..c65b2be106 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -45,7 +45,7 @@ /* #define HARDDEBUG 1 */ #if defined(NO_JUMP_TABLE) -# define OpCase(OpCode) case op_##OpCode: lb_##OpCode +# define OpCase(OpCode) case op_##OpCode # define CountCase(OpCode) case op_count_##OpCode # define OpCode(OpCode) ((Uint*)op_##OpCode) # define Goto(Rel) {Go = (int)(Rel); goto emulator_loop;} @@ -53,7 +53,7 @@ #else # define OpCase(OpCode) lb_##OpCode # define CountCase(OpCode) lb_count_##OpCode -# define Goto(Rel) goto *(Rel) +# define Goto(Rel) goto *((void *)Rel) # define LabelAddr(Label) &&Label # define OpCode(OpCode) (&&lb_##OpCode) #endif @@ -199,7 +199,7 @@ do { \ } \ } while (0) -#define ClauseFail() goto lb_jump_f +#define ClauseFail() goto jump_f #define SAVE_CP(X) \ do { \ @@ -234,6 +234,12 @@ BeamInstr beam_return_trace[1]; /* OpCode(i_return_trace) */ BeamInstr beam_exception_trace[1]; /* UGLY also OpCode(i_return_trace) */ BeamInstr beam_return_time_trace[1]; /* OpCode(i_return_time_trace) */ + +/* + * We should warn only once for tuple funs. + */ +static erts_smp_atomic_t warned_for_tuple_funs; + /* * All Beam instructions in numerical order. */ @@ -1015,6 +1021,7 @@ init_emulator(void) #if defined(VXWORKS) init_done = 0; #endif + erts_smp_atomic_init_nob(&warned_for_tuple_funs, (erts_aint_t) 0); process_main(); } @@ -2540,6 +2547,7 @@ void process_main(void) lb_Cl_error: { if (Arg(0) != 0) { OpCase(jump_f): { + jump_f: SET_I((BeamInstr *) Arg(0)); Goto(*I); } @@ -3113,7 +3121,7 @@ void process_main(void) /* Fall through */ OpCase(error_action_code): { - no_error_handler: + handle_error: reg[0] = r(0); SWAPOUT; I = handle_error(c_p, NULL, reg, NULL); @@ -3274,7 +3282,7 @@ void process_main(void) OpCase(i_func_info_IaaI): { c_p->freason = EXC_FUNCTION_CLAUSE; c_p->current = I + 2; - goto lb_error_action_code; + goto handle_error; } OpCase(try_case_end_s): @@ -4960,7 +4968,7 @@ void process_main(void) if (I) { Goto(*I); } - goto no_error_handler; + goto handle_error; } @@ -6187,6 +6195,26 @@ call_fun(Process* p, /* Current process. */ if (!is_atom(module) || !is_atom(function)) { goto badfun; } + + /* + * If this is the first time a tuple fun is used, + * send a warning to the logger. + */ + if (erts_smp_atomic_xchg_nob(&warned_for_tuple_funs, + (erts_aint_t) 1) == 0) { + erts_dsprintf_buf_t* dsbufp; + + dsbufp = erts_create_logger_dsbuf(); + erts_dsprintf(dsbufp, "Call to tuple fun {%T,%T}.\n\n" + "Tuple funs are deprecated and will be removed " + "in R16. Use \"fun M:F/A\" instead, for example " + "\"fun %T:%T/%d\".\n\n" + "(This warning will only be shown the first time " + "a tuple fun is called.)\n", + module, function, module, function, arity); + erts_send_warning_to_logger(p->group_leader, dsbufp); + } + if ((ep = erts_find_export_entry(module, function, arity)) == NULL) { ep = erts_find_export_entry(erts_proc_get_error_handler(p), am_undefined_function, 3); diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 4427defe0c..dd788df6e4 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -254,6 +254,7 @@ typedef struct LoaderState { char* file_name; /* Name of file we are reading (usually chunk name). */ byte* file_p; /* Current pointer within file. */ unsigned file_left; /* Number of bytes left in file. */ + ErlDrvBinary* bin; /* Binary holding BEAM file (or NULL) */ /* * The following are used mainly for diagnostics. @@ -499,8 +500,10 @@ static void free_state(LoaderState* stp); static Eterm insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, Eterm group_leader, Eterm module, BeamInstr* code, Uint size); +static int init_iff_file(LoaderState* stp, byte* code, Uint size); static int scan_iff_file(LoaderState* stp, Uint* chunk_types, Uint num_types, Uint num_mandatory); +static int verify_chunks(LoaderState* stp); static int load_atom_table(LoaderState* stp); static int load_import_table(LoaderState* stp); static int read_export_table(LoaderState* stp); @@ -630,40 +633,23 @@ erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, Eterm* modp, byte* code, Uint unloaded_size) { Eterm retval = am_badfile; - ErlDrvBinary* bin = NULL; stp->module = *modp; stp->group_leader = group_leader; - /* - * Check if the module is compressed (or possibly invalid/corrupted). - */ - if ( !(unloaded_size >= 4 && - code[0] == 'F' && code[1] == 'O' && - code[2] == 'R' && code[3] == '1') ) { - bin = (ErlDrvBinary *) - erts_gzinflate_buffer((char*)code, unloaded_size); - if (bin == NULL) { - goto load_error; - } - code = (byte*)bin->orig_bytes; - unloaded_size = bin->orig_size; - } +#if defined(LOAD_MEMORY_HARD_DEBUG) && defined(DEBUG) + erts_fprintf(stderr,"Loading a module\n"); +#endif /* * Scan the IFF file. */ -#if defined(LOAD_MEMORY_HARD_DEBUG) && defined(DEBUG) - erts_fprintf(stderr,"Loading a module\n"); -#endif - CHKALLOC(); CHKBLK(ERTS_ALC_T_CODE,stp->code); - stp->file_name = "IFF header for Beam file"; - stp->file_p = code; - stp->file_left = unloaded_size; - if (!scan_iff_file(stp, chunk_types, NUM_CHUNK_TYPES, NUM_MANDATORY)) { + if (!init_iff_file(stp, code, unloaded_size) || + !scan_iff_file(stp, chunk_types, NUM_CHUNK_TYPES, NUM_MANDATORY) || + !verify_chunks(stp)) { goto load_error; } @@ -787,9 +773,6 @@ erts_prepare_loading(LoaderState* stp, Process *c_p, Eterm group_leader, retval = NIL; load_error: - if (bin) { - driver_free_binary(bin); - } if (retval != NIL) { free_state(stp); } @@ -864,6 +847,7 @@ erts_alloc_loader_state(void) LoaderState* stp; stp = erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(LoaderState)); + stp->bin = NULL; stp->function = THE_NON_VALUE; /* Function not known yet */ stp->arity = 0; stp->specific_op = -1; @@ -897,6 +881,9 @@ erts_alloc_loader_state(void) static void free_state(LoaderState* stp) { + if (stp->bin != 0) { + driver_free_binary(stp->bin); + } if (stp->code != 0) { erts_free(ERTS_ALC_T_CODE, stp->code); } @@ -956,6 +943,7 @@ free_state(LoaderState* stp) if (stp->fname != 0) { erts_free(ERTS_ALC_T_LOADER_TMP, stp->fname); } + erts_free(ERTS_ALC_T_LOADER_TMP, stp); } @@ -968,7 +956,7 @@ insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, Eterm retval; int i; - if ((retval = beam_make_current_old(c_p, c_p_locks, module)) < 0) { + if ((retval = beam_make_current_old(c_p, c_p_locks, module)) != NIL) { erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); erts_dsprintf(dsbufp, "Module %T must be purged before loading\n", @@ -1011,23 +999,47 @@ insert_new_code(Process *c_p, ErtsProcLocks c_p_locks, } static int -scan_iff_file(LoaderState* stp, Uint* chunk_types, Uint num_types, Uint num_mandatory) +init_iff_file(LoaderState* stp, byte* code, Uint size) { - MD5_CTX context; + Uint form_id = MakeIffId('F', 'O', 'R', '1'); Uint id; Uint count; - int i; + + if (size < 4) { + goto load_error; + } /* - * The binary must start with an IFF 'FOR1' chunk. + * Check if the module is compressed (or possibly invalid/corrupted). */ + if (MakeIffId(code[0], code[1], code[2], code[3]) != form_id) { + stp->bin = (ErlDrvBinary *) erts_gzinflate_buffer((char*)code, size); + if (stp->bin == NULL) { + goto load_error; + } + code = (byte*)stp->bin->orig_bytes; + size = stp->bin->orig_size; + if (size < 4) { + goto load_error; + } + } - GetInt(stp, 4, id); - if (id != MakeIffId('F', 'O', 'R', '1')) { + /* + * The binary must start with an IFF 'FOR1' chunk. + */ + if (MakeIffId(code[0], code[1], code[2], code[3]) != form_id) { LoadError0(stp, "not a BEAM file: no IFF 'FOR1' chunk"); } /* + * Initialize our "virtual file system". + */ + + stp->file_name = "IFF header for Beam file"; + stp->file_p = code + 4; + stp->file_left = size - 4; + + /* * Retrieve the chunk size and verify it. If the size is equal to * or less than the size of the binary, it is ok and we will use it * as the limit for the logical file size. @@ -1048,6 +1060,21 @@ scan_iff_file(LoaderState* stp, Uint* chunk_types, Uint num_types, Uint num_mand if (id != MakeIffId('B', 'E', 'A', 'M')) { LoadError0(stp, "not a BEAM file: IFF form type is not 'BEAM'"); } + return 1; + + load_error: + return 0; +} + +/* + * Scan the IFF file. The header should have been verified by init_iff_file(). + */ +static int +scan_iff_file(LoaderState* stp, Uint* chunk_types, Uint num_types, Uint num_mandatory) +{ + Uint count; + Uint id; + int i; /* * Initialize the chunks[] array in the state. @@ -1104,17 +1131,25 @@ scan_iff_file(LoaderState* stp, Uint* chunk_types, Uint num_types, Uint num_mand stp->file_p += count; stp->file_left -= count; } + return 1; - /* - * At this point, we have read the entire IFF file, and we - * know that it is syntactically correct. - * - * Now check that it contains all mandatory chunks. At the - * same time calculate the MD5 for the module. - */ + load_error: + return 0; +} + +/* + * Verify that all mandatory chunks are present and calculate + * MD5 for the module. + */ + +static int +verify_chunks(LoaderState* stp) +{ + int i; + MD5_CTX context; MD5Init(&context); - for (i = 0; i < num_mandatory; i++) { + for (i = 0; i < NUM_MANDATORY; i++) { if (stp->chunks[i].start != NULL) { MD5Update(&context, stp->chunks[i].start, stp->chunks[i].size); } else { @@ -1124,41 +1159,49 @@ scan_iff_file(LoaderState* stp, Uint* chunk_types, Uint num_types, Uint num_mand LoadError1(stp, "mandatory chunk of type '%s' not found\n", sbuf); } } - if (LITERAL_CHUNK < num_types) { - if (stp->chunks[LAMBDA_CHUNK].start != 0) { - byte* start = stp->chunks[LAMBDA_CHUNK].start; - Uint left = stp->chunks[LAMBDA_CHUNK].size; - /* - * The idea here is to ignore the OldUniq field for the fun; it is - * based on the old broken hash function, which can be different - * on little endian and big endian machines. - */ - if (left >= 4) { - static byte zero[4]; - MD5Update(&context, start, 4); - start += 4; - left -= 4; + /* + * If there is a lambda chunk, include parts of it in the MD5. + */ + if (stp->chunks[LAMBDA_CHUNK].start != 0) { + byte* start = stp->chunks[LAMBDA_CHUNK].start; + Uint left = stp->chunks[LAMBDA_CHUNK].size; + + /* + * The idea here is to ignore the OldUniq field for the fun; it is + * based on the old broken hash function, which can be different + * on little endian and big endian machines. + */ + if (left >= 4) { + static byte zero[4]; + MD5Update(&context, start, 4); + start += 4; + left -= 4; - while (left >= 24) { - /* Include: Function Arity Index NumFree */ - MD5Update(&context, start, 20); - /* Set to zero: OldUniq */ - MD5Update(&context, zero, 4); - start += 24; - left -= 24; - } - } - /* Can't happen for a correct 'FunT' chunk */ - if (left > 0) { - MD5Update(&context, start, left); + while (left >= 24) { + /* Include: Function Arity Index NumFree */ + MD5Update(&context, start, 20); + /* Set to zero: OldUniq */ + MD5Update(&context, zero, 4); + start += 24; + left -= 24; } } - if (stp->chunks[LITERAL_CHUNK].start != 0) { - MD5Update(&context, stp->chunks[LITERAL_CHUNK].start, - stp->chunks[LITERAL_CHUNK].size); + /* Can't happen for a correct 'FunT' chunk */ + if (left > 0) { + MD5Update(&context, start, left); } } + + + /* + * If there is a literal chunk, include it in the MD5. + */ + if (stp->chunks[LITERAL_CHUNK].start != 0) { + MD5Update(&context, stp->chunks[LITERAL_CHUNK].start, + stp->chunks[LITERAL_CHUNK].size); + } + MD5Final(stp->mod_md5, &context); return 1; @@ -1391,7 +1434,7 @@ static int read_literal_table(LoaderState* stp) { int i; - BeamInstr uncompressed_sz; + uLongf uncompressed_sz; byte* uncompressed = 0; GetInt(stp, 4, uncompressed_sz); @@ -1401,7 +1444,7 @@ read_literal_table(LoaderState* stp) LoadError0(stp, "failed to uncompress literal table (constant pool)"); } stp->file_p = uncompressed; - stp->file_left = uncompressed_sz; + stp->file_left = (unsigned) uncompressed_sz; GetInt(stp, 4, stp->num_literals); stp->literals = (Literal *) erts_alloc(ERTS_ALC_T_LOADER_TMP, stp->num_literals * sizeof(Literal)); @@ -3457,7 +3500,6 @@ gen_jump_tab(LoaderState* stp, GenOpArg S, GenOpArg Fail, GenOpArg Size, GenOpAr } size = max - min + 1; - /* * Allocate structure and fill in the fixed fields. */ @@ -3489,7 +3531,7 @@ gen_jump_tab(LoaderState* stp, GenOpArg S, GenOpArg Fail, GenOpArg Size, GenOpAr op->a[i] = Fail; } for (i = 0; i < Size.val; i += 2) { - int index; + Sint index; index = fixed_args+Rest[i].val-min; ASSERT(fixed_args <= index && index < arity); op->a[index] = Rest[i+1]; @@ -5407,7 +5449,7 @@ code_get_chunk_2(BIF_ALIST_2) Process* p = BIF_P; Eterm Bin = BIF_ARG_1; Eterm Chunk = BIF_ARG_2; - LoaderState state; + LoaderState* stp; Uint chunk = 0; ErlSubBin* sb; Uint offset; @@ -5419,15 +5461,16 @@ code_get_chunk_2(BIF_ALIST_2) Eterm real_bin; byte* temp_alloc = NULL; + stp = erts_alloc_loader_state(); if ((start = erts_get_aligned_binary_bytes(Bin, &temp_alloc)) == NULL) { error: erts_free_aligned_binary_bytes(temp_alloc); + if (stp) { + free_state(stp); + } BIF_ERROR(p, BADARG); } - state.module = THE_NON_VALUE; /* Suppress diagnostiscs */ - state.file_name = "IFF header for Beam file"; - state.file_p = start; - state.file_left = binary_size(Bin); + stp->module = THE_NON_VALUE; /* Suppress diagnostics */ for (i = 0; i < 4; i++) { Eterm* chunkp; Eterm num; @@ -5445,25 +5488,30 @@ code_get_chunk_2(BIF_ALIST_2) if (is_not_nil(Chunk)) { goto error; } - if (!scan_iff_file(&state, &chunk, 1, 1)) { - erts_free_aligned_binary_bytes(temp_alloc); - return am_undefined; + if (!init_iff_file(stp, start, binary_size(Bin)) || + !scan_iff_file(stp, &chunk, 1, 1) || + stp->chunks[0].start == NULL) { + res = am_undefined; + goto done; } ERTS_GET_REAL_BIN(Bin, real_bin, offset, bitoffs, bitsize); if (bitoffs) { - res = new_binary(p, state.chunks[0].start, state.chunks[0].size); + res = new_binary(p, stp->chunks[0].start, stp->chunks[0].size); } else { sb = (ErlSubBin *) HAlloc(p, ERL_SUB_BIN_SIZE); sb->thing_word = HEADER_SUB_BIN; sb->orig = real_bin; - sb->size = state.chunks[0].size; + sb->size = stp->chunks[0].size; sb->bitsize = 0; sb->bitoffs = 0; - sb->offs = offset + (state.chunks[0].start - start); + sb->offs = offset + (stp->chunks[0].start - start); sb->is_writable = 0; res = make_binary(sb); } + + done: erts_free_aligned_binary_bytes(temp_alloc); + free_state(stp); return res; } @@ -5476,21 +5524,29 @@ code_module_md5_1(BIF_ALIST_1) { Process* p = BIF_P; Eterm Bin = BIF_ARG_1; - LoaderState state; + LoaderState* stp; + byte* bytes; byte* temp_alloc = NULL; + Eterm res; - if ((state.file_p = erts_get_aligned_binary_bytes(Bin, &temp_alloc)) == NULL) { + stp = erts_alloc_loader_state(); + if ((bytes = erts_get_aligned_binary_bytes(Bin, &temp_alloc)) == NULL) { + free_state(stp); BIF_ERROR(p, BADARG); } - state.module = THE_NON_VALUE; /* Suppress diagnostiscs */ - state.file_name = "IFF header for Beam file"; - state.file_left = binary_size(Bin); - - if (!scan_iff_file(&state, chunk_types, NUM_CHUNK_TYPES, NUM_MANDATORY)) { - return am_undefined; + stp->module = THE_NON_VALUE; /* Suppress diagnostiscs */ + if (!init_iff_file(stp, bytes, binary_size(Bin)) || + !scan_iff_file(stp, chunk_types, NUM_CHUNK_TYPES, NUM_MANDATORY) || + !verify_chunks(stp)) { + res = am_undefined; + goto done; } + res = new_binary(p, stp->mod_md5, sizeof(stp->mod_md5)); + + done: erts_free_aligned_binary_bytes(temp_alloc); - return new_binary(p, state.mod_md5, sizeof(state.mod_md5)); + free_state(stp); + return res; } #define WORDS_PER_FUNCTION 6 @@ -5776,7 +5832,6 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) int code_size; int rval; int i; - ErlDrvBinary* bin = NULL; byte* temp_alloc = NULL; byte* bytes; Uint size; @@ -5809,29 +5864,17 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) size = binary_size(Beam); /* - * Uncompressed if needed. - */ - if (!(size >= 4 && bytes[0] == 'F' && bytes[1] == 'O' && - bytes[2] == 'R' && bytes[3] == '1')) { - bin = (ErlDrvBinary *) erts_gzinflate_buffer((char*)bytes, size); - if (bin == NULL) { - goto error; - } - bytes = (byte*)bin->orig_bytes; - size = bin->orig_size; - } - - /* * Scan the Beam binary and read the interesting sections. */ - stp->file_name = "IFF header for Beam file"; - stp->file_p = bytes; - stp->file_left = size; stp->module = Mod; stp->group_leader = p->group_leader; stp->num_functions = n; - if (!scan_iff_file(stp, chunk_types, NUM_CHUNK_TYPES, NUM_MANDATORY)) { + if (!init_iff_file(stp, bytes, size)) { + goto error; + } + if (!scan_iff_file(stp, chunk_types, NUM_CHUNK_TYPES, NUM_MANDATORY) || + !verify_chunks(stp)) { goto error; } define_file(stp, "code chunk header", CODE_CHUNK); @@ -5986,13 +6029,11 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) if (patch_funentries(Patchlist)) { erts_free_aligned_binary_bytes(temp_alloc); free_state(stp); - if (bin != NULL) { - driver_free_binary(bin); - } return Mod; } error: + erts_free_aligned_binary_bytes(temp_alloc); free_state(stp); BIF_ERROR(p, BADARG); } diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h index 4e22ee4d79..997ba197db 100644 --- a/erts/emulator/beam/beam_load.h +++ b/erts/emulator/beam/beam_load.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2010. All Rights Reserved. + * Copyright Ericsson AB 1999-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 8ab363a1ec..f8305944a4 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -43,6 +43,9 @@ static Export* set_cpu_topology_trap = NULL; static Export* await_proc_exit_trap = NULL; Export* erts_format_cpu_topology_trap = NULL; +static Export *await_sched_wall_time_mod_trap; +static erts_smp_atomic32_t sched_wall_time; + #define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1) /* @@ -870,8 +873,6 @@ BIF_RETTYPE spawn_opt_1(BIF_ALIST_1) } } else if (arg == am_scheduler && is_small(val)) { Sint scheduler = signed_val(val); - if (erts_common_run_queue && erts_no_schedulers > 1) - goto error; if (scheduler < 0 || erts_no_schedulers < scheduler) goto error; so.scheduler = (int) scheduler; @@ -1535,8 +1536,6 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2) ErtsRunQueue *old; ErtsRunQueue *new; Sint sched; - if (erts_common_run_queue && erts_no_schedulers > 1) - goto error; if (!is_small(BIF_ARG_2)) goto error; sched = signed_val(BIF_ARG_2); @@ -3389,6 +3388,61 @@ BIF_RETTYPE universaltime_to_localtime_1(BIF_ALIST_1) BIF_RET(TUPLE2(hp, res1, res2)); } +/* convert calendar:universaltime_to_seconds/1 */ + +BIF_RETTYPE universaltime_to_posixtime_1(BIF_ALIST_1) +{ + Sint year, month, day; + Sint hour, minute, second; + + Sint64 seconds = 0; + Eterm *hp; + Uint hsz = 0; + + if (!time_to_parts(BIF_ARG_1, &year, &month, &day, + &hour, &minute, &second)) + BIF_ERROR(BIF_P, BADARG); + + if (!univ_to_seconds(year, month, day, hour, minute, second, &seconds)) { + BIF_ERROR(BIF_P, BADARG); + } + + erts_bld_sint64(NULL, &hsz, seconds); + hp = HAlloc(BIF_P, hsz); + BIF_RET(erts_bld_sint64(&hp, NULL, seconds)); +} + +/* convert calendar:seconds_to_universaltime/1 */ + +BIF_RETTYPE posixtime_to_universaltime_1(BIF_ALIST_1) +{ + Sint year, month, day; + Sint hour, minute, second; + Eterm res1, res2; + Eterm* hp; + + Sint64 time = 0; + + if (!term_to_Sint64(BIF_ARG_1, &time)) { + BIF_ERROR(BIF_P, BADARG); + } + + if (!seconds_to_univ(time, &year, &month, &day, + &hour, &minute, &second)) { + BIF_ERROR(BIF_P, BADARG); + } + + hp = HAlloc(BIF_P, 4+4+3); + res1 = TUPLE3(hp,make_small(year),make_small(month), + make_small(day)); + hp += 4; + res2 = TUPLE3(hp,make_small(hour),make_small(minute), + make_small(second)); + hp += 4; + BIF_RET(TUPLE2(hp, res1, res2)); +} + + /**********************************************************************/ @@ -4109,6 +4163,18 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); BIF_RET(am_true); + } else if (BIF_ARG_1 == am_scheduler_wall_time) { + if (BIF_ARG_2 == am_true || BIF_ARG_2 == am_false) { + erts_aint32_t new = BIF_ARG_2 == am_true ? 1 : 0; + erts_aint32_t old = erts_smp_atomic32_xchg_nob(&sched_wall_time, + new); + Eterm ref = erts_sched_wall_time_request(BIF_P, 1, new); + ASSERT(is_value(ref)); + BIF_TRAP2(await_sched_wall_time_mod_trap, + BIF_P, + ref, + old ? am_true : am_false); + } } else if (ERTS_IS_ATOM_STR("scheduling_statistics", BIF_ARG_1)) { int what; if (ERTS_IS_ATOM_STR("disable", BIF_ARG_2)) @@ -4128,8 +4194,20 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) if (is_value(res)) BIF_RET(res); } else if (ERTS_IS_ATOM_STR("cpu_topology", BIF_ARG_1)) { + erts_send_warning_to_logger_str( + BIF_P->group_leader, + "A call to erlang:system_flag(cpu_topology, _) was made.\n" + "The cpu_topology argument is deprecated and scheduled\n" + "for removal in erts-5.10/OTP-R16. For more information\n" + "see the erlang:system_flag/2 documentation.\n"); BIF_TRAP1(set_cpu_topology_trap, BIF_P, BIF_ARG_2); } else if (ERTS_IS_ATOM_STR("scheduler_bind_type", BIF_ARG_1)) { + erts_send_warning_to_logger_str( + BIF_P->group_leader, + "A call to erlang:system_flag(scheduler_bind_type, _) was\n" + "made. The scheduler_bind_type argument is deprecated and\n" + "scheduled for removal in erts-5.10/OTP-R16. For more\n" + "information see the erlang:system_flag/2 documentation.\n"); return erts_bind_schedulers(BIF_P, BIF_ARG_2); } error: @@ -4394,6 +4472,9 @@ void erts_init_bif(void) am_format_cpu_topology, 1); await_proc_exit_trap = erts_export_put(am_erlang,am_await_proc_exit,3); + await_sched_wall_time_mod_trap + = erts_export_put(am_erlang, am_await_sched_wall_time_modifications, 2); + erts_smp_atomic32_init_nob(&sched_wall_time, 0); } #ifdef HARDDEBUG diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 987008c937..8cc568b16c 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -806,6 +806,12 @@ bif file:native_name_encoding/0 # bif erlang:check_old_code/1 + +# +# New in R15B +# +bif erlang:universaltime_to_posixtime/1 +bif erlang:posixtime_to_universaltime/1 # # Obsolete # diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c index 46db9ca99c..25ac790d81 100644 --- a/erts/emulator/beam/big.c +++ b/erts/emulator/beam/big.c @@ -1325,7 +1325,7 @@ static dsize_t I_lshift(ErtsDigit* x, dsize_t xl, Sint y, return 1; } else { - long ay = (y < 0) ? -y : y; + SWord ay = (y < 0) ? -y : y; int bw = ay / D_EXP; int sw = ay % D_EXP; dsize_t rl; @@ -1450,6 +1450,20 @@ erts_make_integer(Uint x, Process *p) return uint_to_big(x,hp); } } +/* + * As erts_make_integer, but from a whole UWord. + */ +Eterm +erts_make_integer_from_uword(UWord x, Process *p) +{ + Eterm* hp; + if (IS_USMALL(0,x)) + return make_small(x); + else { + hp = HAlloc(p, BIG_UWORD_HEAP_SIZE(x)); + return uword_to_big(x,hp); + } +} /* ** convert Uint to bigint @@ -1830,6 +1844,7 @@ dsize_t big_bytes(Eterm x) /* ** Load a bignum from bytes ** xsz is the number of bytes in xp +** *r is untouched if number fits in small */ Eterm bytes_to_big(byte *xp, dsize_t xsz, int xsgn, Eterm *r) { @@ -1838,7 +1853,7 @@ Eterm bytes_to_big(byte *xp, dsize_t xsz, int xsgn, Eterm *r) ErtsDigit d; int i; - while(xsz >= sizeof(ErtsDigit)) { + while(xsz > sizeof(ErtsDigit)) { d = 0; for(i = sizeof(ErtsDigit); --i >= 0;) d = (d << 8) | xp[i]; @@ -1853,11 +1868,20 @@ Eterm bytes_to_big(byte *xp, dsize_t xsz, int xsgn, Eterm *r) d = 0; for(i = xsz; --i >= 0;) d = (d << 8) | xp[i]; + if (++rsz == 1 && IS_USMALL(xsgn,d)) { + if (xsgn) d = -d; + return make_small(d); + } *rwp = d; rwp++; - rsz++; } - return big_norm(r, rsz, (short) xsgn); + if (xsgn) { + *r = make_neg_bignum_header(rsz); + } + else { + *r = make_pos_bignum_header(rsz); + } + return make_big(r); } /* diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h index 256f1c2b45..7eb1e5afe2 100644 --- a/erts/emulator/beam/big.h +++ b/erts/emulator/beam/big.h @@ -145,6 +145,7 @@ Eterm small_to_big(Sint, Eterm*); Eterm uint_to_big(Uint, Eterm*); Eterm uword_to_big(UWord, Eterm*); Eterm erts_make_integer(Uint, Process *); +Eterm erts_make_integer_from_uword(UWord x, Process *p); dsize_t big_bytes(Eterm); Eterm bytes_to_big(byte*, dsize_t, int, Eterm*); diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c index 29461877c5..3d2725e239 100644 --- a/erts/emulator/beam/binary.c +++ b/erts/emulator/beam/binary.c @@ -47,7 +47,7 @@ erts_init_binary(void) away. If not, this test is not very expensive... */ erl_exit(ERTS_ABORT_EXIT, "Internal error: Address of orig_bytes[0] of a Binary" - "is *not* 8-byte aligned\n"); + " is *not* 8-byte aligned\n"); } } diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 784e55ecd2..6f5020dc14 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2011. All Rights Reserved. + * Copyright Ericsson AB 1996-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -182,6 +182,7 @@ print_process_info(int to, void *to_arg, Process *p) { int garbing = 0; int running = 0; + time_t tmp_t; struct saved_calls *scb; /* display the PID */ @@ -244,8 +245,8 @@ print_process_info(int to, void *to_arg, Process *p) } erts_print(to, to_arg, "Spawned by: %T\n", p->parent); - - erts_print(to, to_arg, "Started: %s", ctime((time_t*)&p->started.tv_sec)); + tmp_t = p->started.tv_sec; + erts_print(to, to_arg, "Started: %s", ctime(&tmp_t)); ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p); erts_print(to, to_arg, "Message queue length: %d\n", p->msg.len); @@ -645,6 +646,9 @@ bin_check(void) void erl_crash_dump_v(char *file, int line, char* fmt, va_list args) { +#ifdef ERTS_SMP + ErtsThrPrgrData tpd_buf; /* in case we aren't a managed thread... */ +#endif int fd; time_t now; size_t dumpnamebufsize = MAXPATHLEN; @@ -662,7 +666,7 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) * We do not release system again. We expect an exit() or abort() after * dump has been written. */ - erts_thr_progress_fatal_error_block(60000); + erts_thr_progress_fatal_error_block(60000, &tpd_buf); /* Either worked or not... */ /* Allow us to pass certain places without locking... */ diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 44c5ba1e26..bee61e7273 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -54,9 +54,9 @@ #endif #if defined(ERTS_DIST_MSG_DBG) || defined(ERTS_RAW_DIST_MSG_DBG) -static void bw(byte *buf, int sz) +static void bw(byte *buf, ErlDrvSizeT sz) { - bin_write(ERTS_PRINT_STDERR,NULL,buf,sz); + bin_write(ERTS_PRINT_STDERR, NULL, buf, sz); } #endif @@ -536,7 +536,7 @@ alloc_dist_obuf(Uint size) Binary *bin = erts_bin_drv_alloc(obuf_size); bin->flags = BIN_FLAG_DRV; erts_refc_init(&bin->refc, 1); - bin->orig_size = (long) obuf_size; + bin->orig_size = (SWord) obuf_size; obuf = (ErtsDistOutputBuf *) &bin->orig_bytes[0]; #ifdef DEBUG obuf->dbg_pattern = ERTS_DIST_OUTPUT_BUF_DBG_PATTERN; @@ -897,9 +897,9 @@ erts_dsig_send_group_leader(ErtsDSigData *dsdp, Eterm leader, Eterm remote) int erts_net_message(Port *prt, DistEntry *dep, byte *hbuf, - int hlen, + ErlDrvSizeT hlen, byte *buf, - int len) + ErlDrvSizeT len) { #define DIST_CTL_DEFAULT_SIZE 64 ErtsDistExternal ede; @@ -924,7 +924,7 @@ int erts_net_message(Port *prt, Uint tuple_arity; int res; #ifdef ERTS_DIST_MSG_DBG - int orig_len = len; + ErlDrvSizeT orig_len = len; #endif UseTmpHeapNoproc(DIST_CTL_DEFAULT_SIZE); @@ -940,7 +940,7 @@ int erts_net_message(Port *prt, UnUseTmpHeapNoproc(DIST_CTL_DEFAULT_SIZE); return 0; } - if (hlen > 0) + if (hlen != 0) goto data_error; if (len == 0) { /* HANDLE TICK !!! */ UnUseTmpHeapNoproc(DIST_CTL_DEFAULT_SIZE); diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index 140a84d5fc..df27186680 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2002-2011. All Rights Reserved. + * Copyright Ericsson AB 2002-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -1095,7 +1095,7 @@ get_kb_value(char *param_end, char** argv, int* ip) char *param = argv[*ip]+1; char *value = get_value(param_end, argv, ip); errno = 0; - tmp = (Sint) strtol(value, &rest, 10); + tmp = (Sint) ErtsStrToSint(value, &rest, 10); if (errno != 0 || rest == value || tmp < 0 || max < ((Uint) tmp)) bad_value(param, param_end, value); if (max == (Uint) tmp) @@ -1112,7 +1112,7 @@ get_byte_value(char *param_end, char** argv, int* ip) char *param = argv[*ip]+1; char *value = get_value(param_end, argv, ip); errno = 0; - tmp = (Sint) strtol(value, &rest, 10); + tmp = (Sint) ErtsStrToSint(value, &rest, 10); if (errno != 0 || rest == value || tmp < 0) bad_value(param, param_end, value); return (Uint) tmp; @@ -1126,7 +1126,7 @@ get_amount_value(char *param_end, char** argv, int* ip) char *param = argv[*ip]+1; char *value = get_value(param_end, argv, ip); errno = 0; - tmp = (Sint) strtol(value, &rest, 10); + tmp = (Sint) ErtsStrToSint(value, &rest, 10); if (errno != 0 || rest == value || tmp < 0) bad_value(param, param_end, value); return (Uint) tmp; @@ -1577,9 +1577,11 @@ erts_alloc_register_scheduler(void *vesdp) } } +#ifdef ERTS_SMP void erts_alloc_scheduler_handle_delayed_dealloc(void *vesdp, int *need_thr_progress, + ErtsThrPrgrVal *thr_prgr_p, int *more_work) { ErtsSchedulerData *esdp = (ErtsSchedulerData *) vesdp; @@ -1599,10 +1601,12 @@ erts_alloc_scheduler_handle_delayed_dealloc(void *vesdp, erts_alcu_check_delayed_dealloc(allctr, 1, need_thr_progress, + thr_prgr_p, more_work); } } } +#endif erts_aint32_t erts_alloc_fix_alloc_shrink(int ix, erts_aint32_t flgs) @@ -2877,8 +2881,9 @@ reply_alloc_info(void *vair) ainfo); ainfo = erts_bld_tuple(hpp, szp, 2, erts_bld_atom(hpp, szp, - "otps"), + "options"), ainfo); + ainfo = erts_bld_cons(hpp, szp,ainfo,NIL); } ainfo = erts_bld_tuple(hpp, szp, 3, alloc_atom, @@ -3117,10 +3122,10 @@ void *safe_realloc(void *ptr, Uint sz) \* */ #define ERTS_ALC_TEST_ABORT erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n") -unsigned long erts_alc_test(unsigned long op, - unsigned long a1, - unsigned long a2, - unsigned long a3) +UWord erts_alc_test(UWord op, + UWord a1, + UWord a2, + UWord a3) { switch (op >> 8) { case 0x0: return erts_alcu_test(op, a1, a2); @@ -3134,24 +3139,24 @@ unsigned long erts_alc_test(unsigned long op, case 0xf00: #ifdef USE_THREADS if (((Allctr_t *) a1)->thread_safe) - return (unsigned long) erts_alcu_alloc_ts(ERTS_ALC_T_UNDEF, + return (UWord) erts_alcu_alloc_ts(ERTS_ALC_T_UNDEF, (void *) a1, (Uint) a2); else #endif - return (unsigned long) erts_alcu_alloc(ERTS_ALC_T_UNDEF, + return (UWord) erts_alcu_alloc(ERTS_ALC_T_UNDEF, (void *) a1, (Uint) a2); case 0xf01: #ifdef USE_THREADS if (((Allctr_t *) a1)->thread_safe) - return (unsigned long) erts_alcu_realloc_ts(ERTS_ALC_T_UNDEF, + return (UWord) erts_alcu_realloc_ts(ERTS_ALC_T_UNDEF, (void *) a1, (void *) a2, (Uint) a3); else #endif - return (unsigned long) erts_alcu_realloc(ERTS_ALC_T_UNDEF, + return (UWord) erts_alcu_realloc(ERTS_ALC_T_UNDEF, (void *) a1, (void *) a2, (Uint) a3); @@ -3181,7 +3186,7 @@ unsigned long erts_alc_test(unsigned long op, if (argv[i][0] == '-' && argv[i][1] == 't') handle_au_arg(&init, &argv[i][2], argv, &i); else - return (unsigned long) NULL; + return (UWord) NULL; i++; } } @@ -3222,25 +3227,25 @@ unsigned long erts_alc_test(unsigned long op, break; } - return (unsigned long) allctr; + return (UWord) allctr; } case 0xf04: erts_alcu_stop((Allctr_t *) a1); erts_free(ERTS_ALC_T_UNDEF, (void *) a1); break; #ifdef USE_THREADS - case 0xf05: return (unsigned long) 1; - case 0xf06: return (unsigned long) ((Allctr_t *) a1)->thread_safe; + case 0xf05: return (UWord) 1; + case 0xf06: return (UWord) ((Allctr_t *) a1)->thread_safe; #ifdef ETHR_NO_FORKSAFETY - case 0xf07: return (unsigned long) 0; + case 0xf07: return (UWord) 0; #else - case 0xf07: return (unsigned long) ((Allctr_t *) a1)->thread_safe; + case 0xf07: return (UWord) ((Allctr_t *) a1)->thread_safe; #endif case 0xf08: { ethr_mutex *mtx = erts_alloc(ERTS_ALC_T_UNDEF, sizeof(ethr_mutex)); if (ethr_mutex_init(mtx) != 0) ERTS_ALC_TEST_ABORT; - return (unsigned long) mtx; + return (UWord) mtx; } case 0xf09: { ethr_mutex *mtx = (ethr_mutex *) a1; @@ -3259,7 +3264,7 @@ unsigned long erts_alc_test(unsigned long op, ethr_cond *cnd = erts_alloc(ERTS_ALC_T_UNDEF, sizeof(ethr_cond)); if (ethr_cond_init(cnd) != 0) ERTS_ALC_TEST_ABORT; - return (unsigned long) cnd; + return (UWord) cnd; } case 0xf0d: { ethr_cond *cnd = (ethr_cond *) a1; @@ -3285,7 +3290,7 @@ unsigned long erts_alc_test(unsigned long op, (void *) a2, NULL) != 0) ERTS_ALC_TEST_ABORT; - return (unsigned long) tid; + return (UWord) tid; } case 0xf11: { ethr_tid *tid = (ethr_tid *) a1; @@ -3302,13 +3307,13 @@ unsigned long erts_alc_test(unsigned long op, default: break; } - return (unsigned long) 0; + return (UWord) 0; default: break; } ASSERT(0); - return ~((unsigned long) 0); + return ~((UWord) 0); } #ifdef DEBUG @@ -3544,7 +3549,7 @@ check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func) erl_exit(ERTS_ABORT_EXIT, "ERROR: Fence at beginning of memory block (p=0x%u) " "clobbered.\n", - (unsigned long) ptr); + (UWord) ptr); } memcpy((void *) &post_pattern, (void *) (((char *)ptr)+sz), sizeof(UWord)); @@ -3561,12 +3566,12 @@ check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func) erl_exit(ERTS_ABORT_EXIT, "ERROR: Fence at end of memory block (p=0x%u, sz=%u) " "clobbered.\n", - (unsigned long) ptr, (unsigned long) sz); + (UWord) ptr, (UWord) sz); if (found_type != GET_TYPE_OF_PATTERN(post_pattern)) erl_exit(ERTS_ABORT_EXIT, "ERROR: Fence around memory block (p=0x%u, sz=%u) " "clobbered.\n", - (unsigned long) ptr, (unsigned long) sz); + (UWord) ptr, (UWord) sz); ftype = type_no_str(found_type); if (!ftype) { @@ -3589,7 +3594,7 @@ check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func) erl_exit(ERTS_ABORT_EXIT, "ERROR: Memory block (p=0x%u, sz=%u) allocated as type \"%s\"," " but %s as type \"%s\".\n", - (unsigned long) ptr, (unsigned long) sz, ftype, op_str, otype); + (UWord) ptr, (UWord) sz, ftype, op_str, otype); } #ifdef HARD_DEBUG diff --git a/erts/emulator/beam/erl_alloc.h b/erts/emulator/beam/erl_alloc.h index f4133cdb1a..e475f9d8a2 100644 --- a/erts/emulator/beam/erl_alloc.h +++ b/erts/emulator/beam/erl_alloc.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2002-2011. All Rights Reserved. + * Copyright Ericsson AB 2002-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -21,6 +21,10 @@ #define ERL_ALLOC_H__ #include "erl_alloc_types.h" +#undef ERL_THR_PROGRESS_TSD_TYPE_ONLY +#define ERL_THR_PROGRESS_TSD_TYPE_ONLY +#include "erl_thr_progress.h" +#undef ERL_THR_PROGRESS_TSD_TYPE_ONLY #include "erl_alloc_util.h" #ifdef USE_THREADS #include "erl_threads.h" @@ -80,10 +84,10 @@ void erts_alloc_late_init(void); #if defined(GET_ERTS_ALC_TEST) || defined(ERTS_ALC_INTERNAL__) /* Only for testing */ -unsigned long erts_alc_test(unsigned long, - unsigned long, - unsigned long, - unsigned long); +UWord erts_alc_test(UWord, + UWord, + UWord, + UWord); #endif #define ERTS_ALC_O_ALLOC 0 @@ -132,9 +136,12 @@ typedef struct { extern ErtsAllocatorThrSpec_t erts_allctr_thr_spec[ERTS_ALC_A_MAX+1]; void erts_alloc_register_scheduler(void *vesdp); +#ifdef ERTS_SMP void erts_alloc_scheduler_handle_delayed_dealloc(void *vesdp, int *need_thr_progress, + ErtsThrPrgrVal *thr_prgr_p, int *more_work); +#endif erts_aint32_t erts_alloc_fix_alloc_shrink(int ix, erts_aint32_t flgs); __decl_noreturn void erts_alloc_enomem(ErtsAlcType_t,Uint) diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index 962db8b831..90a6c0cbee 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -367,6 +367,7 @@ type EXPORT LONG_LIVED_LOW CODE export_entry type MONITOR_SH STANDARD_LOW PROCESSES monitor_sh type NLINK_SH STANDARD_LOW PROCESSES nlink_sh type AINFO_REQ STANDARD_LOW SYSTEM alloc_info_request +type SCHED_WTIME_REQ STANDARD_LOW SYSTEM sched_wall_time_request +else # "fullword" @@ -383,6 +384,7 @@ type EXPORT LONG_LIVED CODE export_entry type MONITOR_SH FIXED_SIZE PROCESSES monitor_sh type NLINK_SH FIXED_SIZE PROCESSES nlink_sh type AINFO_REQ SHORT_LIVED SYSTEM alloc_info_request +type SCHED_WTIME_REQ SHORT_LIVED SYSTEM sched_wall_time_request +endif diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c index af386c9197..e0d525bdde 100644 --- a/erts/emulator/beam/erl_alloc_util.c +++ b/erts/emulator/beam/erl_alloc_util.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2002-2011. All Rights Reserved. + * Copyright Ericsson AB 2002-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -949,7 +949,6 @@ ddq_check_incoming(ErtsAllctrDDQueue_t *ddq) ERTS_THR_MEMORY_BARRIER; else { ddq->head.next.unref_end = (ErtsAllctrDDBlock_t *) ilast; - ERTS_THR_MEMORY_BARRIER; ddq->head.next.thr_progress = erts_thr_progress_later(); erts_atomic32_set_relb(&ddq->tail.data.um_refc_ix, um_refc_ix); @@ -961,12 +960,24 @@ ddq_check_incoming(ErtsAllctrDDQueue_t *ddq) return 1; } +static ERTS_INLINE void +store_earliest_thr_prgr(ErtsThrPrgrVal *prev_val, ErtsAllctrDDQueue_t *ddq) +{ + if (!ddq->head.next.thr_progress_reached + && (*prev_val == ERTS_THR_PRGR_INVALID + || erts_thr_progress_cmp(ddq->head.next.thr_progress, + *prev_val) < 0)) { + *prev_val = ddq->head.next.thr_progress; + } +} + static ERTS_INLINE int handle_delayed_dealloc(Allctr_t *allctr, int allctr_locked, int use_limit, int ops_limit, int *need_thr_progress, + ErtsThrPrgrVal *thr_prgr_p, int *need_more_work) { int need_thr_prgr = 0; @@ -1008,8 +1019,12 @@ handle_delayed_dealloc(Allctr_t *allctr, if (have_checked_incoming) break; need_thr_prgr = ddq_check_incoming(ddq); - if (need_thr_progress) + if (need_thr_progress) { *need_thr_progress |= need_thr_prgr; + if (need_thr_prgr) + store_earliest_thr_prgr(thr_prgr_p, ddq); + + } have_checked_incoming = 1; goto dequeue; } @@ -1067,6 +1082,8 @@ handle_delayed_dealloc(Allctr_t *allctr, if (need_thr_progress && !(need_thr_prgr | need_mr_wrk)) { need_thr_prgr = ddq_check_incoming(ddq); *need_thr_progress |= need_thr_prgr; + if (need_thr_prgr) + store_earliest_thr_prgr(thr_prgr_p, ddq); } if (allctr->thread_safe && !allctr_locked) @@ -1086,25 +1103,27 @@ enqueue_dealloc_other_instance(ErtsAlcType_t type, Allctr_t *allctr, void *ptr) #endif +#ifdef ERTS_SMP void erts_alcu_check_delayed_dealloc(Allctr_t *allctr, int limit, int *need_thr_progress, + ErtsThrPrgrVal *thr_prgr_p, int *more_work) { -#ifdef ERTS_SMP handle_delayed_dealloc(allctr, 0, limit, ERTS_ALCU_DD_OPS_LIM_HIGH, need_thr_progress, + thr_prgr_p, more_work); -#endif } +#endif #define ERTS_ALCU_HANDLE_DD_IN_OP(Allctr, Locked) \ handle_delayed_dealloc((Allctr), (Locked), 1, \ - ERTS_ALCU_DD_OPS_LIM_LOW, NULL, NULL) + ERTS_ALCU_DD_OPS_LIM_LOW, NULL, NULL, NULL) /* Multi block carrier alloc/realloc/free ... */ @@ -3014,9 +3033,7 @@ info_options(Allctr_t *allctr, add_2tup(hpp, szp, &res, am.low, allctr->mseg_opt.low_mem ? am_true : am_false); #endif add_2tup(hpp, szp, &res, am.ramv, allctr->ramv ? am_true : am_false); - add_2tup(hpp, szp, &res, am.t, (allctr->t - ? bld_uint(hpp, szp, (Uint) allctr->t) - : am_false)); + add_2tup(hpp, szp, &res, am.t, (allctr->t ? am_true : am_false)); add_2tup(hpp, szp, &res, am.e, am_true); } @@ -3958,7 +3975,8 @@ realloc_thr_pref(ErtsAlcType_t type, void *extra, void *p, Uint size, if (used_allctr->thread_safe && (!force_move || used_allctr != pref_allctr)) erts_mtx_lock(&used_allctr->mutex); - ERTS_SMP_LC_ASSERT(erts_lc_mtx_is_locked(&used_allctr->mutex)); + ERTS_SMP_LC_ASSERT(!used_allctr->thread_safe || + erts_lc_mtx_is_locked(&used_allctr->mutex)); cpy_size = BLK_SZ(blk); if (used_allctr->thread_safe && (!force_move || used_allctr != pref_allctr)) diff --git a/erts/emulator/beam/erl_alloc_util.h b/erts/emulator/beam/erl_alloc_util.h index df560a0de2..cedf4ccf85 100644 --- a/erts/emulator/beam/erl_alloc_util.h +++ b/erts/emulator/beam/erl_alloc_util.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2002-2011. All Rights Reserved. + * Copyright Ericsson AB 2002-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -170,7 +170,9 @@ Eterm erts_alcu_info(Allctr_t *, int, int *, void *, Uint **, Uint *); void erts_alcu_init(AlcUInit_t *); void erts_alcu_current_size(Allctr_t *, AllctrSize_t *, ErtsAlcUFixInfo_t *, int); -void erts_alcu_check_delayed_dealloc(Allctr_t *, int, int *, int *); +#ifdef ERTS_SMP +void erts_alcu_check_delayed_dealloc(Allctr_t *, int, int *, ErtsThrPrgrVal *, int *); +#endif erts_aint32_t erts_alcu_fix_alloc_shrink(Allctr_t *, erts_aint32_t); #endif @@ -227,7 +229,7 @@ erts_aint32_t erts_alcu_fix_alloc_shrink(Allctr_t *, erts_aint32_t); extern int erts_have_sbmbc_alloc; -typedef union {char c[8]; long l; double d;} Unit_t; +typedef union {char c[ERTS_ALLOC_ALIGN_BYTES]; long l; double d;} Unit_t; typedef struct Carrier_t_ Carrier_t; struct Carrier_t_ { diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c index 2dc7237f7c..8bca9ae582 100644 --- a/erts/emulator/beam/erl_async.c +++ b/erts/emulator/beam/erl_async.c @@ -304,8 +304,9 @@ static ERTS_INLINE ErtsAsync *async_get(ErtsThrQ_t *q, switch (erts_thr_q_inspect(q, 1)) { case ERTS_THR_Q_DIRTY: break; + case ERTS_THR_Q_NEED_THR_PRGR: #ifdef ERTS_SMP - case ERTS_THR_Q_NEED_THR_PRGR: { + { ErtsThrPrgrVal prgr = erts_thr_q_need_thr_progress(q); erts_thr_progress_wakeup(NULL, prgr); /* @@ -522,8 +523,8 @@ int erts_async_ready_clean(void *varq, void *val) switch (cstate) { case ERTS_THR_Q_DIRTY: return ERTS_ASYNC_READY_DIRTY; -#ifdef ERTS_SMP case ERTS_THR_Q_NEED_THR_PRGR: +#ifdef ERTS_SMP *((ErtsThrPrgrVal *) val) = erts_thr_q_need_thr_progress(&arq->thr_q); return ERTS_ASYNC_READY_NEED_THR_PRGR; diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c index 7e7bec9b87..cc4f2be8eb 100644 --- a/erts/emulator/beam/erl_bif_binary.c +++ b/erts/emulator/beam/erl_bif_binary.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010. All Rights Reserved. + * Copyright Ericsson AB 2010-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c index b2d5722e9b..37d540b41b 100644 --- a/erts/emulator/beam/erl_bif_ddll.c +++ b/erts/emulator/beam/erl_bif_ddll.c @@ -1580,24 +1580,6 @@ static int do_load_driver_entry(DE_Handle *dh, char *path, char *name) } switch (dp->extended_marker) { - case 0: - /* - * This may be an old driver that has been recompiled. If so, - * at least the fields that existed in extended driver version - * 1.0 should be zero. If not, a it is a bad driver. We cannot - * be completely certain that this is a valid driver but this is - * the best we can do with old drivers... - */ - if (dp->major_version != 0 - || dp->minor_version != 0 - || dp->driver_flags != 0 - || dp->handle2 != NULL - || dp->process_exit != NULL) { - /* Old driver; needs to be recompiled... */ - res = ERL_DE_LOAD_ERROR_INCORRECT_VERSION; - goto error; - } - break; case ERL_DRV_EXTENDED_MARKER: if (ERL_DRV_EXTENDED_MAJOR_VERSION != dp->major_version || ERL_DRV_EXTENDED_MINOR_VERSION < dp->minor_version) { diff --git a/erts/emulator/beam/erl_bif_guard.c b/erts/emulator/beam/erl_bif_guard.c index 01e6977a2c..a715756c15 100644 --- a/erts/emulator/beam/erl_bif_guard.c +++ b/erts/emulator/beam/erl_bif_guard.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2006-2010. All Rights Reserved. + * Copyright Ericsson AB 2006-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -52,7 +52,7 @@ BIF_RETTYPE abs_1(BIF_ALIST_1) /* integer arguments */ if (is_small(BIF_ARG_1)) { i0 = signed_val(BIF_ARG_1); - i = labs(i0); + i = ERTS_SMALL_ABS(i0); if (i0 == MIN_SMALL) { hp = HAlloc(BIF_P, BIG_UINT_HEAP_SIZE); BIF_RET(uint_to_big(i, hp)); @@ -467,7 +467,7 @@ Eterm erts_gc_abs_1(Process* p, Eterm* reg, Uint live) /* integer arguments */ if (is_small(arg)) { i0 = signed_val(arg); - i = labs(i0); + i = ERTS_SMALL_ABS(i0); if (i0 == MIN_SMALL) { if (ERTS_NEED_GC(p, BIG_UINT_HEAP_SIZE)) { erts_garbage_collect(p, BIG_UINT_HEAP_SIZE, reg, live+1); diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index a79feaebdb..ebd475f73a 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -57,6 +57,8 @@ static Export* alloc_info_trap = NULL; static Export* alloc_sizes_trap = NULL; +static Export *gather_sched_wall_time_res_trap; + #define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1) /* Keep erts_system_version as a global variable for easy access from a core */ @@ -78,7 +80,6 @@ static char erts_system_version[] = ("Erlang " ERLANG_OTP_RELEASE #ifdef ERTS_SMP " [smp:%beu:%beu]" #endif - " [rq:%beu]" #ifdef USE_THREADS " [async-threads:%d]" #endif @@ -301,9 +302,7 @@ erts_print_system_version(int to, void *arg, Process *c_p) #endif return erts_print(to, arg, erts_system_version #ifdef ERTS_SMP - , total, online, erts_no_run_queues -#else - , 1 + , total, online #endif #ifdef USE_THREADS , erts_async_max_threads @@ -3183,7 +3182,12 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1) Eterm res; Eterm* hp; - if (BIF_ARG_1 == am_context_switches) { + if (BIF_ARG_1 == am_scheduler_wall_time) { + res = erts_sched_wall_time_request(BIF_P, 0, 0); + if (is_non_value(res)) + BIF_RET(am_undefined); + BIF_TRAP1(gather_sched_wall_time_res_trap, BIF_P, res); + } else if (BIF_ARG_1 == am_context_switches) { Eterm cs = erts_make_integer(erts_get_total_context_switches(), BIF_P); hp = HAlloc(BIF_P, 3); res = TUPLE2(hp, cs, SMALL_ZERO); @@ -3230,7 +3234,7 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1) res = TUPLE2(hp, b1, b2); BIF_RET(res); } else if (BIF_ARG_1 == am_runtime) { - unsigned long u1, u2, dummy; + UWord u1, u2, dummy; Eterm b1, b2; elapsed_time_both(&u1,&dummy,&u2,&dummy); b1 = erts_make_integer(u1,BIF_P); @@ -4163,6 +4167,8 @@ erts_bif_info_init(void) alloc_info_trap = erts_export_put(am_erlang, am_alloc_info, 1); alloc_sizes_trap = erts_export_put(am_erlang, am_alloc_sizes, 1); + gather_sched_wall_time_res_trap + = erts_export_put(am_erlang, am_gather_sched_wall_time_result, 1); process_info_init(); os_info_init(); } diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c index 6b8f1b21fd..cd423eb200 100644 --- a/erts/emulator/beam/erl_bif_port.c +++ b/erts/emulator/beam/erl_bif_port.c @@ -254,13 +254,13 @@ port_call(Process* c_p, Eterm arg1, Eterm arg2, Eterm arg3) Uint size; byte *bytes; byte *endp; - size_t real_size; + ErlDrvSizeT real_size; erts_driver_t *drv; byte port_input[256]; /* Default input buffer to encode in */ byte port_result[256]; /* Buffer for result from port. */ byte* port_resp; /* Pointer to result buffer. */ char *prc; - int ret; + ErlDrvSSizeT ret; Eterm res; Sint result_size; Eterm *hp; @@ -366,9 +366,9 @@ port_call(Process* c_p, Eterm arg1, Eterm arg2, Eterm arg3) erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); #ifdef HARDDEBUG { - int z; - printf("real_size = %ld,%d, ret = %d\r\n",real_size, - (int) real_size, ret); + ErlDrvSizeT z; + printf("real_size = %ld,%d, ret = %ld,%d\r\n", (unsigned long) real_size, + (int) real_size, (unsigned long)ret, (int) ret); printf("["); for(z = 0; z < real_size; ++z) { printf("%d, ",(int) bytes[z]); @@ -1077,7 +1077,7 @@ struct packet_callback_args }; #define in_area(ptr,start,nbytes) \ - ((unsigned long)((char*)(ptr) - (char*)(start)) < (nbytes)) + ((UWord)((char*)(ptr) - (char*)(start)) < (nbytes)) static Eterm http_bld_string(struct packet_callback_args* pca, Uint **hpp, Uint *szp, diff --git a/erts/emulator/beam/erl_cpu_topology.c b/erts/emulator/beam/erl_cpu_topology.c index 03c0ef904a..fe3693d0ca 100644 --- a/erts/emulator/beam/erl_cpu_topology.c +++ b/erts/emulator/beam/erl_cpu_topology.c @@ -486,10 +486,7 @@ erts_sched_check_cpu_bind_post_suspend(ErtsSchedulerData *esdp) erts_thr_set_main_status(1, (int) esdp->no); /* Make sure we check if we should bind to a cpu or not... */ - if (esdp->run_queue->flags & ERTS_RUNQ_FLG_SHARED_RUNQ) - erts_smp_atomic32_set_nob(&esdp->chk_cpu_bind, 1); - else - esdp->run_queue->flags |= ERTS_RUNQ_FLG_CHK_CPU_BIND; + esdp->run_queue->flags |= ERTS_RUNQ_FLG_CHK_CPU_BIND; } #endif @@ -502,11 +499,7 @@ erts_sched_check_cpu_bind(ErtsSchedulerData *esdp) erts_cpu_groups_callback_list_t *cgcl; erts_cpu_groups_callback_call_t *cgcc; #ifdef ERTS_SMP - if (erts_common_run_queue) - erts_smp_atomic32_set_nob(&esdp->chk_cpu_bind, 0); - else { - esdp->run_queue->flags &= ~ERTS_RUNQ_FLG_CHK_CPU_BIND; - } + esdp->run_queue->flags &= ~ERTS_RUNQ_FLG_CHK_CPU_BIND; #endif erts_smp_runq_unlock(esdp->run_queue); erts_smp_rwmtx_rwlock(&cpuinfo_rwmtx); @@ -1729,16 +1722,8 @@ erts_init_cpu_topology(void) scheduler2cpu_map[ix].bound_id = -1; } - if (cpu_bind_order == ERTS_CPU_BIND_UNDEFINED) { - int ncpus = erts_get_cpu_configured(cpuinfo); - if (ncpus < 1 || erts_no_schedulers < ncpus) - cpu_bind_order = ERTS_CPU_BIND_NONE; - else - cpu_bind_order = ((system_cpudata || user_cpudata) - && (erts_bind_to_cpu(cpuinfo, -1) != -ENOTSUP) - ? ERTS_CPU_BIND_DEFAULT_BIND - : ERTS_CPU_BIND_NONE); - } + if (cpu_bind_order == ERTS_CPU_BIND_UNDEFINED) + cpu_bind_order = ERTS_CPU_BIND_NONE; reader_groups_map = add_cpu_groups(reader_groups, reader_groups_callback, diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 38b4a2d460..51bdf53823 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2011. All Rights Reserved. + * Copyright Ericsson AB 1996-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -251,7 +251,7 @@ free_dbtable(DbTable* tb) ASSERT(is_immed(tb->common.heir_data)); erts_db_free(ERTS_ALC_T_DB_TABLE, tb, (void *) tb, sizeof(DbTable)); ERTS_ETS_MISC_MEM_ADD(-sizeof(DbTable)); - ERTS_THR_MEMORY_BARRIER; + ERTS_SMP_MEMORY_BARRIER; } #ifdef ERTS_SMP @@ -2853,10 +2853,10 @@ void init_db(void) bits = erts_fit_in_bits(db_max_tabs-1); if (bits > SMALL_BITS) { erl_exit(1,"Max limit for ets tabled too high %u (max %u).", - db_max_tabs, 1L<<SMALL_BITS); + db_max_tabs, ((Uint)1)<<SMALL_BITS); } - meta_main_tab_slot_mask = (1L<<bits) - 1; - meta_main_tab_seq_incr = (1L<<bits); + meta_main_tab_slot_mask = (((Uint)1)<<bits) - 1; + meta_main_tab_seq_incr = (((Uint)1)<<bits); size = sizeof(*meta_main_tab)*db_max_tabs; meta_main_tab = erts_db_alloc_nt(ERTS_ALC_T_DB_TABLES, size); @@ -2869,7 +2869,7 @@ void init_db(void) SET_NEXT_FREE_SLOT(db_max_tabs-1, (Uint)-1); meta_main_tab_first_free = 0; - meta_name_tab_mask = (1L<<(bits-1)) - 1; /* At least half the size of main tab */ + meta_name_tab_mask = (((Uint) 1)<<(bits-1)) - 1; /* At least half the size of main tab */ size = sizeof(struct meta_name_tab_entry)*(meta_name_tab_mask+1); meta_name_tab = erts_db_alloc_nt(ERTS_ALC_T_DB_TABLES, size); ERTS_ETS_MISC_MEM_ADD(size); @@ -3816,7 +3816,7 @@ void db_info(int to, void *to_arg, int show) /* Called by break handler */ Uint erts_get_ets_misc_mem_size(void) { - ERTS_THR_MEMORY_BARRIER; + ERTS_SMP_MEMORY_BARRIER; /* Memory not allocated in ets_alloc */ return (Uint) erts_smp_atomic_read_nob(&erts_ets_misc_mem_size); } diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c index 038a667b06..c726be5fb4 100644 --- a/erts/emulator/beam/erl_db_hash.c +++ b/erts/emulator/beam/erl_db_hash.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2011. All Rights Reserved. + * Copyright Ericsson AB 1998-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -105,11 +105,7 @@ #define NSEG_2 256 /* Size of second segment table */ #define NSEG_INC 128 /* Number of segments to grow after that */ -#ifdef ETHR_ORDERED_READ_DEPEND -#define SEGTAB(tb) ((struct segment**)erts_smp_atomic_read_nob(&(tb)->segtab)) -#else -#define SEGTAB(tb) ((struct segment**)erts_smp_atomic_read_rb(&(tb)->segtab)) -#endif +#define SEGTAB(tb) ((struct segment**)erts_smp_atomic_read_ddrb(&(tb)->segtab)) #define NACTIVE(tb) ((int)erts_smp_atomic_read_nob(&(tb)->nactive)) #define NITEMS(tb) ((int)erts_smp_atomic_read_nob(&(tb)->common.nitems)) diff --git a/erts/emulator/beam/erl_db_hash.h b/erts/emulator/beam/erl_db_hash.h index 23ac493118..cddd8dfadd 100644 --- a/erts/emulator/beam/erl_db_hash.h +++ b/erts/emulator/beam/erl_db_hash.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2009. All Rights Reserved. + * Copyright Ericsson AB 1998-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in diff --git a/erts/emulator/beam/erl_debug.h b/erts/emulator/beam/erl_debug.h index bdfbaddbbf..c49354a2b3 100644 --- a/erts/emulator/beam/erl_debug.h +++ b/erts/emulator/beam/erl_debug.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * Copyright Ericsson AB 2004-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -51,7 +51,7 @@ extern Uint32 verbose; -void upp(byte*, int); +void upp(byte*, size_t); void pat(Eterm); void pinfo(void); void pp(Process*); diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h index ae0c9def90..7510f6b724 100644 --- a/erts/emulator/beam/erl_driver.h +++ b/erts/emulator/beam/erl_driver.h @@ -85,6 +85,7 @@ #include "erl_drv_nif.h" #include <stdlib.h> +#include <string.h> /* ssize_t on Mac OS X */ #if defined(VXWORKS) # include <ioLib.h> @@ -134,8 +135,8 @@ typedef struct { #define DO_WRITE ERL_DRV_WRITE #define ERL_DRV_EXTENDED_MARKER (0xfeeeeeed) -#define ERL_DRV_EXTENDED_MAJOR_VERSION 1 -#define ERL_DRV_EXTENDED_MINOR_VERSION 5 +#define ERL_DRV_EXTENDED_MAJOR_VERSION 2 +#define ERL_DRV_EXTENDED_MINOR_VERSION 0 /* * The emulator will refuse to load a driver with different major @@ -160,10 +161,15 @@ typedef struct { /* * Integer types */ - +#if defined(__WIN32__) && (SIZEOF_VOID_P == 8) +typedef unsigned __int64 ErlDrvTermData; +typedef unsigned __int64 ErlDrvUInt; +typedef signed __int64 ErlDrvSInt; +#else typedef unsigned long ErlDrvTermData; typedef unsigned long ErlDrvUInt; typedef signed long ErlDrvSInt; +#endif #if defined(__WIN32__) typedef unsigned __int64 ErlDrvUInt64; @@ -178,13 +184,21 @@ typedef long long ErlDrvSInt64; #error No 64-bit integer type #endif +#if defined(__WIN32__) +typedef ErlDrvUInt ErlDrvSizeT; +typedef ErlDrvSInt ErlDrvSSizeT; +#else +typedef size_t ErlDrvSizeT; +typedef ssize_t ErlDrvSSizeT; +#endif + /* * A binary as seen in a driver. Note that a binary should never be * altered by the driver when it has been sent to Erlang. */ typedef struct erl_drv_binary { - long orig_size; /* total length of binary */ + ErlDrvSInt orig_size; /* total length of binary */ char orig_bytes[1]; /* the data (char instead of byte!) */ } ErlDrvBinary; @@ -244,7 +258,7 @@ typedef struct { typedef struct erl_io_vec { int vsize; /* length of vectors */ - int size; /* total size in bytes */ + ErlDrvSizeT size; /* total size in bytes */ SysIOVec* iov; ErlDrvBinary** binv; } ErlIOVec; @@ -285,8 +299,8 @@ typedef struct erl_drv_entry { void (*stop)(ErlDrvData drv_data); /* called when port is closed, and when the emulator is halted. */ - void (*output)(ErlDrvData drv_data, char *buf, int len); - /* called when we have output from erlang to + void (*output)(ErlDrvData drv_data, char *buf, ErlDrvSizeT len); + /* called when we have output from erlang to the port */ void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event); /* called when we have input from one of @@ -299,10 +313,10 @@ typedef struct erl_drv_entry { void (*finish)(void); /* called before unloading the driver - DYNAMIC DRIVERS ONLY */ void *handle; /* Reserved -- Used by emulator internally */ - int (*control)(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen); - /* "ioctl" for drivers - invoked by - port_control/3 */ + ErlDrvSSizeT (*control)(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, char **rbuf, + ErlDrvSizeT rlen); /* "ioctl" for drivers - invoked by + port_control/3 */ void (*timeout)(ErlDrvData drv_data); /* Handling of timeout in driver */ void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev); /* called when we have output from erlang @@ -313,10 +327,12 @@ typedef struct erl_drv_entry { closed, and there is data in the driver queue that needs to be flushed before 'stop' can be called */ - int (*call)(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen, unsigned int *flags); - /* Works mostly like 'control', a synchronous - call into the driver. */ + ErlDrvSSizeT (*call)(ErlDrvData drv_data, + unsigned int command, char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, + unsigned int *flags); /* Works mostly like 'control', + a synchronous + call into the driver. */ void (*event)(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_data); /* Called when an event selected by @@ -355,11 +371,17 @@ typedef struct erl_drv_entry { #ifndef ERL_DRIVER_TYPES_ONLY #if defined(VXWORKS) -# define DRIVER_INIT(DRIVER_NAME) ErlDrvEntry* DRIVER_NAME ## _init(void) +# define DRIVER_INIT(DRIVER_NAME) \ + ErlDrvEntry* DRIVER_NAME ## _init(void); \ + ErlDrvEntry* DRIVER_NAME ## _init(void) #elif defined(__WIN32__) -# define DRIVER_INIT(DRIVER_NAME) __declspec(dllexport) ErlDrvEntry* driver_init(void) +# define DRIVER_INIT(DRIVER_NAME) \ + __declspec(dllexport) ErlDrvEntry* driver_init(void); \ + __declspec(dllexport) ErlDrvEntry* driver_init(void) #else -# define DRIVER_INIT(DRIVER_NAME) ErlDrvEntry* driver_init(void) +# define DRIVER_INIT(DRIVER_NAME) \ + ErlDrvEntry* driver_init(void); \ + ErlDrvEntry* driver_init(void) #endif /* @@ -368,14 +390,16 @@ typedef struct erl_drv_entry { EXTERN int driver_select(ErlDrvPort port, ErlDrvEvent event, int mode, int on); EXTERN int driver_event(ErlDrvPort port, ErlDrvEvent event, ErlDrvEventData event_data); -EXTERN int driver_output(ErlDrvPort port, char *buf, int len); -EXTERN int driver_output2(ErlDrvPort port, char *hbuf, int hlen, - char *buf, int len); -EXTERN int driver_output_binary(ErlDrvPort port, char *hbuf, int hlen, - ErlDrvBinary* bin, int offset, int len); -EXTERN int driver_outputv(ErlDrvPort port, char* hbuf, int hlen, ErlIOVec *ev, - int skip); -EXTERN int driver_vec_to_buf(ErlIOVec *ev, char *buf, int len); + +EXTERN int driver_output(ErlDrvPort port, char *buf, ErlDrvSizeT len); +EXTERN int driver_output2(ErlDrvPort port, char *hbuf, ErlDrvSizeT hlen, + char *buf, ErlDrvSizeT len); +EXTERN int driver_output_binary(ErlDrvPort port, char *hbuf, ErlDrvSizeT hlen, + ErlDrvBinary* bin, + ErlDrvSizeT offset, ErlDrvSizeT len); +EXTERN int driver_outputv(ErlDrvPort port, char* hbuf, ErlDrvSizeT hlen, + ErlIOVec *ev, ErlDrvSizeT skip); +EXTERN ErlDrvSizeT driver_vec_to_buf(ErlIOVec *ev, char *buf, ErlDrvSizeT len); EXTERN int driver_set_timer(ErlDrvPort port, unsigned long time); EXTERN int driver_cancel_timer(ErlDrvPort port); EXTERN int driver_read_timer(ErlDrvPort port, unsigned long *time_left); @@ -436,8 +460,8 @@ EXTERN int get_port_flags(ErlDrvPort port); * since the binary is a shared object it MUST be written once. */ -EXTERN ErlDrvBinary* driver_alloc_binary(int size); -EXTERN ErlDrvBinary* driver_realloc_binary(ErlDrvBinary *bin, int size); +EXTERN ErlDrvBinary* driver_alloc_binary(ErlDrvSizeT size); +EXTERN ErlDrvBinary* driver_realloc_binary(ErlDrvBinary *bin, ErlDrvSizeT size); EXTERN void driver_free_binary(ErlDrvBinary *bin); /* Referenc count on driver binaries */ @@ -446,24 +470,24 @@ EXTERN ErlDrvSInt driver_binary_inc_refc(ErlDrvBinary *dbp); EXTERN ErlDrvSInt driver_binary_dec_refc(ErlDrvBinary *dbp); /* Allocation interface */ -EXTERN void *driver_alloc(size_t size); -EXTERN void *driver_realloc(void *ptr, size_t size); +EXTERN void *driver_alloc(ErlDrvSizeT size); +EXTERN void *driver_realloc(void *ptr, ErlDrvSizeT size); EXTERN void driver_free(void *ptr); /* Queue interface */ -EXTERN int driver_enq(ErlDrvPort port, char* buf, int len); -EXTERN int driver_pushq(ErlDrvPort port, char* buf, int len); -EXTERN int driver_deq(ErlDrvPort port, int size); -EXTERN int driver_sizeq(ErlDrvPort port); -EXTERN int driver_enq_bin(ErlDrvPort port, ErlDrvBinary *bin, int offset, - int len); -EXTERN int driver_pushq_bin(ErlDrvPort port, ErlDrvBinary *bin, int offset, - int len); - -EXTERN int driver_peekqv(ErlDrvPort port, ErlIOVec *ev); +EXTERN int driver_enq(ErlDrvPort port, char* buf, ErlDrvSizeT len); +EXTERN int driver_pushq(ErlDrvPort port, char* buf, ErlDrvSizeT len); +EXTERN ErlDrvSizeT driver_deq(ErlDrvPort port, ErlDrvSizeT size); +EXTERN ErlDrvSizeT driver_sizeq(ErlDrvPort port); +EXTERN int driver_enq_bin(ErlDrvPort port, ErlDrvBinary *bin, ErlDrvSizeT offset, + ErlDrvSizeT len); +EXTERN int driver_pushq_bin(ErlDrvPort port, ErlDrvBinary *bin, ErlDrvSizeT offset, + ErlDrvSizeT len); + +EXTERN ErlDrvSizeT driver_peekqv(ErlDrvPort port, ErlIOVec *ev); EXTERN SysIOVec* driver_peekq(ErlDrvPort port, int *vlen); -EXTERN int driver_enqv(ErlDrvPort port, ErlIOVec *ev, int skip); -EXTERN int driver_pushqv(ErlDrvPort port, ErlIOVec *ev, int skip); +EXTERN int driver_enqv(ErlDrvPort port, ErlIOVec *ev, ErlDrvSizeT skip); +EXTERN int driver_pushqv(ErlDrvPort port, ErlIOVec *ev, ErlDrvSizeT skip); /* * Add and remove driver entries. diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index eb2b945877..bde87b8346 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -357,10 +357,11 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj) erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); p->gcstatus = p->status; p->status = P_GARBING; + erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + if (erts_system_monitor_long_gc != 0) { get_now(&ms1, &s1, &us1); } - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); ERTS_CHK_OFFHEAP(p); @@ -910,7 +911,18 @@ minor_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl) * XXX: WARNING: If HiPE starts storing other non-Erlang values on the * nstack, such as floats, then this will have to be changed. */ -#define offset_nstack(p,offs,area,area_size) offset_heap_ptr(hipe_nstack_start((p)),hipe_nstack_used((p)),(offs),(area),(area_size)) +static ERTS_INLINE void offset_nstack(Process* p, Sint offs, + char* area, Uint area_size) +{ + if (p->hipe.nstack) { + ASSERT(p->hipe.nsp && p->hipe.nstend); + offset_heap_ptr(hipe_nstack_start(p), hipe_nstack_used(p), + offs, area, area_size); + } + else { + ASSERT(!p->hipe.nsp && !p->hipe.nstend); + } +} #else /* !HIPE */ diff --git a/erts/emulator/beam/erl_gc.h b/erts/emulator/beam/erl_gc.h index 807ef8ae8d..1801df359a 100644 --- a/erts/emulator/beam/erl_gc.h +++ b/erts/emulator/beam/erl_gc.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2007-2010. All Rights Reserved. + * Copyright Ericsson AB 2007-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -62,7 +62,7 @@ do { \ } while(0) #define in_area(ptr,start,nbytes) \ - ((unsigned long)((char*)(ptr) - (char*)(start)) < (nbytes)) + ((UWord)((char*)(ptr) - (char*)(start)) < (nbytes)) extern Uint erts_test_long_gc_sleep; diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index 6c4ba2af68..717315d8bd 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -111,7 +111,6 @@ Eterm erts_error_logger_warnings; /* What to map warning logs to, am_error, int erts_compat_rel; -static int use_multi_run_queue; static int no_schedulers; static int no_schedulers_online; @@ -254,8 +253,7 @@ erl_init(int ncpu) erts_init_time(); erts_init_sys_common_misc(); erts_init_process(ncpu); - erts_init_scheduling(use_multi_run_queue, - no_schedulers, + erts_init_scheduling(no_schedulers, no_schedulers_online); erts_init_cpu_topology(); /* Must be after init_scheduling */ erts_alloc_late_init(); @@ -613,7 +611,6 @@ early_init(int *argc, char **argv) /* size_t envbufsz; erts_sched_compact_load = 1; - use_multi_run_queue = 1; erts_printf_eterm_func = erts_printf_term; erts_disable_tolerant_timeofday = 0; display_items = 200; @@ -1257,12 +1254,8 @@ erl_start(int argc, char **argv) erts_usage(); } } - else if (sys_strcmp("mrq", sub_param) == 0) - use_multi_run_queue = 1; else if (sys_strcmp("nsp", sub_param) == 0) erts_use_sender_punish = 0; - else if (sys_strcmp("srq", sub_param) == 0) - use_multi_run_queue = 0; else if (sys_strcmp("wt", sub_param) == 0) { arg = get_arg(sub_param+2, argv[i+1], &i); if (erts_sched_set_wakeup_limit(arg) != 0) { diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c index 44da6b6c51..09e85893c3 100644 --- a/erts/emulator/beam/erl_lock_check.c +++ b/erts/emulator/beam/erl_lock_check.c @@ -173,7 +173,6 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "pix_lock", "address" }, { "run_queues_lists", NULL }, { "sched_stat", NULL }, - { "run_queue_sleep_list", "address" }, #endif { "async_init_mtx", NULL }, #ifdef ERTS_SMP @@ -1253,7 +1252,7 @@ erts_lc_init_lock(erts_lc_lock_t *lck, char *name, Uint16 flags) { lck->id = erts_lc_get_lock_order_id(name); - lck->extra = &lck->extra; + lck->extra = (UWord) &lck->extra; ASSERT(is_not_immed(lck->extra)); lck->flags = flags; lck->inited = ERTS_LC_INITITALIZED; diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index 16be47d540..ab1ab7b1ea 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2010. All Rights Reserved. + * Copyright Ericsson AB 1997-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 62798bb2c1..58a09986d2 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -531,7 +531,7 @@ int enif_alloc_binary(size_t size, ErlNifBinary* bin) } refbin->flags = BIN_FLAG_DRV; /* BUGBUG: Flag? */ erts_refc_init(&refbin->refc, 1); - refbin->orig_size = (long) size; + refbin->orig_size = (SWord) size; bin->size = size; bin->data = (unsigned char*) refbin->orig_bytes; @@ -744,7 +744,8 @@ int enif_get_int(ErlNifEnv* env, Eterm term, int* ip) { #if SIZEOF_INT == ERTS_SIZEOF_ETERM return term_to_Sint(term, (Sint*)ip); -#elif SIZEOF_LONG == ERTS_SIZEOF_ETERM +#elif (SIZEOF_LONG == ERTS_SIZEOF_ETERM) || \ + (SIZEOF_LONG_LONG == ERTS_SIZEOF_ETERM) Sint i; if (!term_to_Sint(term, &i) || i < INT_MIN || i > INT_MAX) { return 0; @@ -760,7 +761,8 @@ int enif_get_uint(ErlNifEnv* env, Eterm term, unsigned* ip) { #if SIZEOF_INT == ERTS_SIZEOF_ETERM return term_to_Uint(term, (Uint*)ip); -#elif SIZEOF_LONG == ERTS_SIZEOF_ETERM +#elif (SIZEOF_LONG == ERTS_SIZEOF_ETERM) || \ + (SIZEOF_LONG_LONG == ERTS_SIZEOF_ETERM) Uint i; if (!term_to_Uint(term, &i) || i > UINT_MAX) { return 0; @@ -776,6 +778,13 @@ int enif_get_long(ErlNifEnv* env, Eterm term, long* ip) return term_to_Sint(term, ip); #elif SIZEOF_LONG == 8 return term_to_Sint64(term, ip); +#elif SIZEOF_LONG == SIZEOF_INT + int tmp,ret; + ret = enif_get_int(env,term,&tmp); + if (ret) { + *ip = (long) tmp; + } + return ret; #else # error Unknown long word size #endif @@ -787,6 +796,14 @@ int enif_get_ulong(ErlNifEnv* env, Eterm term, unsigned long* ip) return term_to_Uint(term, ip); #elif SIZEOF_LONG == 8 return term_to_Uint64(term, ip); +#elif SIZEOF_LONG == SIZEOF_INT + int ret; + unsigned int tmp; + ret = enif_get_uint(env,term,&tmp); + if (ret) { + *ip = (unsigned long) tmp; + } + return ret; #else # error Unknown long word size #endif @@ -847,7 +864,8 @@ ERL_NIF_TERM enif_make_int(ErlNifEnv* env, int i) { #if SIZEOF_INT == ERTS_SIZEOF_ETERM return IS_SSMALL(i) ? make_small(i) : small_to_big(i,alloc_heap(env,2)); -#elif SIZEOF_LONG == ERTS_SIZEOF_ETERM +#elif (SIZEOF_LONG == ERTS_SIZEOF_ETERM) || \ + (SIZEOF_LONG_LONG == ERTS_SIZEOF_ETERM) return make_small(i); #endif } @@ -856,7 +874,8 @@ ERL_NIF_TERM enif_make_uint(ErlNifEnv* env, unsigned i) { #if SIZEOF_INT == ERTS_SIZEOF_ETERM return IS_USMALL(0,i) ? make_small(i) : uint_to_big(i,alloc_heap(env,2)); -#elif SIZEOF_LONG == ERTS_SIZEOF_ETERM +#elif (SIZEOF_LONG == ERTS_SIZEOF_ETERM) || \ + (SIZEOF_LONG_LONG == ERTS_SIZEOF_ETERM) return make_small(i); #endif } @@ -868,6 +887,8 @@ ERL_NIF_TERM enif_make_long(ErlNifEnv* env, long i) } #if SIZEOF_LONG == ERTS_SIZEOF_ETERM return small_to_big(i, alloc_heap(env,2)); +#elif SIZEOF_LONG_LONG == ERTS_SIZEOF_ETERM + return make_small(i); #elif SIZEOF_LONG == 8 ensure_heap(env,3); return erts_sint64_to_big(i, &env->hp); @@ -881,6 +902,8 @@ ERL_NIF_TERM enif_make_ulong(ErlNifEnv* env, unsigned long i) } #if SIZEOF_LONG == ERTS_SIZEOF_ETERM return uint_to_big(i,alloc_heap(env,2)); +#elif SIZEOF_LONG_LONG == ERTS_SIZEOF_ETERM + return make_small(i); #elif SIZEOF_LONG == 8 ensure_heap(env,3); return erts_uint64_to_big(i, &env->hp); @@ -1157,7 +1180,7 @@ static ErlNifResourceType* find_resource_type(Eterm module, Eterm name) } #define in_area(ptr,start,nbytes) \ - ((unsigned long)((char*)(ptr) - (char*)(start)) < (nbytes)) + ((UWord)((char*)(ptr) - (char*)(start)) < (nbytes)) static void close_lib(struct erl_module_nif* lib) @@ -1484,6 +1507,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) Eterm ret = am_ok; int veto; struct erl_module_nif* lib = NULL; + int reload_warning = 0; len = list_length(BIF_ARG_1); if (len < 0) { @@ -1623,6 +1647,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) else { mod->nif->entry = NULL; /* to prevent 'unload' callback */ erts_unload_nif(mod->nif); + reload_warning = 1; } } else { @@ -1669,7 +1694,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) } else { /* Function traced, patch the original instruction word */ BpData** bps = (BpData**) code_ptr[1]; - BpData* bp = (BpData*) bps[bp_sched2ix()]; + BpData* bp = (BpData*) bps[erts_bp_sched2ix()]; bp->orig_instr = (BeamInstr) BeamOp(op_call_nif); } code_ptr[5+1] = (BeamInstr) entry->funcs[i].fptr; @@ -1691,6 +1716,15 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2) erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_free(ERTS_ALC_T_TMP, lib_name); + + if (reload_warning) { + erts_dsprintf_buf_t* dsbufp = erts_create_logger_dsbuf(); + erts_dsprintf(dsbufp, + "Repeated calls to erlang:load_nif from module '%T'.\n\n" + "The NIF reload mechanism is deprecated and must not " + "be used in production systems.\n", mod_atom); + erts_send_warning_to_logger(BIF_P->group_leader, dsbufp); + } BIF_RET(ret); } diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index fea527f954..e5d99dc4f1 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -87,7 +87,11 @@ typedef long long ErlNifSInt64; typedef unsigned int ERL_NIF_TERM; #else # define ERL_NIF_VM_VARIANT "beam.vanilla" +# if SIZEOF_LONG == SIZEOF_VOID_P typedef unsigned long ERL_NIF_TERM; +# elif SIZEOF_LONG_LONG == SIZEOF_VOID_P +typedef unsigned long long ERL_NIF_TERM; +# endif #endif struct enif_environment_t; diff --git a/erts/emulator/beam/erl_nmgc.c b/erts/emulator/beam/erl_nmgc.c index d7bfb2ab12..2a8c819360 100644 --- a/erts/emulator/beam/erl_nmgc.c +++ b/erts/emulator/beam/erl_nmgc.c @@ -1391,7 +1391,7 @@ Eterm *erts_inc_alloc(int need) if (ma_gc_flags & GC_MAJOR) { if (need > 254) { blackmap[(Eterm*)this - global_old_heap] = 255; - *(int*)((long)(&blackmap[(Eterm*)this - global_old_heap]+4) & ~3) = + *(int*)((UWord)(&blackmap[(Eterm*)this - global_old_heap]+4) & ~3) = need; } else blackmap[(Eterm*)this - global_old_heap] = need; diff --git a/erts/emulator/beam/erl_node_container_utils.h b/erts/emulator/beam/erl_node_container_utils.h index 2c67e781e0..329a2204cc 100644 --- a/erts/emulator/beam/erl_node_container_utils.h +++ b/erts/emulator/beam/erl_node_container_utils.h @@ -176,7 +176,7 @@ extern int erts_use_r9_pids_ports; * 32-bit CPU. */ -#define ERTS_MAX_PROCESSES ((1L << 27)-1) +#define ERTS_MAX_PROCESSES ((SWORD_CONSTANT(1) << 27)-1) #if (ERTS_MAX_PROCESSES > MAX_SMALL) # error "The maximum number of processes must fit in a SMALL." #endif diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index 87b8e5131b..a2b08fcf56 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -731,7 +731,6 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) int reds = ERTS_PORT_REDS_EXECUTE; erts_aint_t io_tasks_executed = 0; int fpe_was_unmasked; - ErtsPortTaskExeBlockData blk_data = {runq, NULL}; ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); @@ -965,8 +964,6 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) #endif done: - blk_data.resp = &res; - ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); ERTS_PORT_REDUCTIONS_EXECUTED(runq, reds); @@ -1048,8 +1045,6 @@ erts_port_migrate(Port *prt, int *prt_locked, ERTS_SMP_LC_CHK_RUNQ_LOCK(from_rq, *from_locked); ERTS_SMP_LC_CHK_RUNQ_LOCK(to_rq, *to_locked); - ASSERT(!erts_common_run_queue); - if (!*from_locked || !*to_locked) { if (from_rq < to_rq) { if (!*to_locked) { diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 84c0ded016..138acfeb2c 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2011. All Rights Reserved. + * Copyright Ericsson AB 1996-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -196,8 +196,6 @@ do { \ erts_sched_stat_t erts_sched_stat; -ErtsRunQueue *erts_common_run_queue; - #ifdef USE_THREADS static erts_tsd_key_t sched_data_key; #endif @@ -225,16 +223,11 @@ typedef union { static ErtsAlignedSchedulerSleepInfo *aligned_sched_sleep_info; -#ifndef BM_COUNTERS -static int processes_busy; -#endif - Process** process_tab; static Uint last_reductions; static Uint last_exact_reductions; Uint erts_default_process_flags; Eterm erts_system_monitor; -Eterm erts_system_monitor_msg_queue_len; Eterm erts_system_monitor_long_gc; Eterm erts_system_monitor_large_heap; struct erts_system_monitor_flags_t erts_system_monitor_flags; @@ -354,40 +347,25 @@ dbg_chk_aux_work_val(erts_aint32_t value) { erts_aint32_t valid = 0; -#ifdef ERTS_SSI_AUX_WORK_SET_TMO valid |= ERTS_SSI_AUX_WORK_SET_TMO; -#endif -#ifdef ERTS_SSI_AUX_WORK_CHECK_CHILDREN - valid |= ERTS_SSI_AUX_WORK_CHECK_CHILDREN; -#endif -#ifdef ERTS_SSI_AUX_WORK_MISC valid |= ERTS_SSI_AUX_WORK_MISC; -#endif -#ifdef ERTS_SSI_AUX_WORK_MISC_THR_PRGR - valid |= ERTS_SSI_AUX_WORK_MISC_THR_PRGR; -#endif -#ifdef ERTS_SSI_AUX_WORK_ASYNC_READY - valid |= ERTS_SSI_AUX_WORK_ASYNC_READY; -#endif -#ifdef ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN - valid |= ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN; -#endif - -#ifdef ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM valid |= ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM; -#endif -#ifdef ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC valid |= ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC; +#if ERTS_USE_ASYNC_READY_Q + valid |= ERTS_SSI_AUX_WORK_ASYNC_READY; + valid |= ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN; #endif -#ifdef ERTS_SSI_AUX_WORK_DD +#ifdef ERTS_SMP + valid |= ERTS_SSI_AUX_WORK_MISC_THR_PRGR; valid |= ERTS_SSI_AUX_WORK_DD; -#endif -#ifdef ERTS_SSI_AUX_WORK_DD valid |= ERTS_SSI_AUX_WORK_DD_THR_PRGR; #endif -#ifdef ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK +#if HAVE_ERTS_MSEG valid |= ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK; #endif +#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN + valid |= ERTS_SSI_AUX_WORK_CHECK_CHILDREN; +#endif if (~valid & value) erl_exit(ERTS_ABORT_EXIT, @@ -497,9 +475,6 @@ erts_init_process(int ncpu) p_serial_shift = erts_fit_in_bits(erts_max_processes - 1); p_serial_mask = ((~(~((Uint) 0) << proc_bits)) >> p_serial_shift); erts_process_tab_index_mask = ~(~((Uint) 0) << p_serial_shift); -#ifndef BM_COUNTERS - processes_busy = 0; -#endif last_reductions = 0; last_exact_reductions = 0; erts_default_process_flags = 0; @@ -546,6 +521,209 @@ erts_late_init_process(void) } +static void +init_sched_wall_time(ErtsSchedWallTime *swtp) +{ + swtp->enabled = 0; + swtp->start = 0; + swtp->working.total = 0; + swtp->working.start = 0; + swtp->working.currently = 0; +} + +static ERTS_INLINE Uint64 +sched_wall_time_ts(void) +{ +#ifdef HAVE_GETHRTIME + return (Uint64) sys_gethrtime(); +#else + Uint64 res; + SysTimeval tv; + sys_gettimeofday(&tv); + res = (Uint64) tv.tv_sec*1000000; + res += (Uint64) tv.tv_usec; + return res; +#endif +} + +static ERTS_INLINE void +sched_wall_time_change(ErtsSchedulerData *esdp, int working) +{ + if (esdp->sched_wall_time.enabled) { + Uint64 ts = sched_wall_time_ts(); + if (working) { +#ifdef DEBUG + ASSERT(!esdp->sched_wall_time.working.currently); + esdp->sched_wall_time.working.currently = 1; +#endif + ts -= esdp->sched_wall_time.start; + esdp->sched_wall_time.working.start = ts; + } + else { +#ifdef DEBUG + ASSERT(esdp->sched_wall_time.working.currently); + esdp->sched_wall_time.working.currently = 0; +#endif + ts -= esdp->sched_wall_time.start; + ts -= esdp->sched_wall_time.working.start; + esdp->sched_wall_time.working.total += ts; + } + } +} + +typedef struct { + int set; + int enable; + Process *proc; + Eterm ref; + Eterm ref_heap[REF_THING_SIZE]; + Uint req_sched; + erts_smp_atomic32_t refc; +} ErtsSchedWallTimeReq; + +#if !HALFWORD_HEAP +ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(swtreq, + ErtsSchedWallTimeReq, + 5, + ERTS_ALC_T_SCHED_WTIME_REQ) +#else +static ERTS_INLINE ErtsSchedWallTimeReq * +swtreq_alloc(void) +{ + return erts_alloc(ERTS_ALC_T_SCHED_WTIME_REQ, + sizeof(ErtsSchedWallTimeReq)); +} + +static ERTS_INLINE void +swtreq_free(ErtsSchedWallTimeReq *ptr) +{ + erts_free(ERTS_ALC_T_SCHED_WTIME_REQ, ptr); +} +#endif + +static void +reply_sched_wall_time(void *vswtrp) +{ + Uint64 working = 0, total = 0; + ErtsSchedulerData *esdp = erts_get_scheduler_data(); + ErtsSchedWallTimeReq *swtrp = (ErtsSchedWallTimeReq *) vswtrp; + ErtsProcLocks rp_locks = (swtrp->req_sched == esdp->no + ? ERTS_PROC_LOCK_MAIN + : 0); + Process *rp = swtrp->proc; + Eterm ref_copy = NIL, msg; + Eterm *hp = NULL; + Eterm **hpp; + Uint sz, *szp; + ErlOffHeap *ohp = NULL; + ErlHeapFragment *bp = NULL; + + ASSERT(esdp); + + if (swtrp->set) { + if (!swtrp->enable && esdp->sched_wall_time.enabled) + esdp->sched_wall_time.enabled = 0; + else if (swtrp->enable && !esdp->sched_wall_time.enabled) { + Uint64 ts = sched_wall_time_ts(); + esdp->sched_wall_time.enabled = 1; + esdp->sched_wall_time.start = ts; + esdp->sched_wall_time.working.total = 0; + esdp->sched_wall_time.working.start = 0; + esdp->sched_wall_time.working.currently = 1; + } + } + + if (esdp->sched_wall_time.enabled) { + Uint64 ts = sched_wall_time_ts(); + ASSERT(esdp->sched_wall_time.working.currently); + ts -= esdp->sched_wall_time.start; + total = ts; + ts -= esdp->sched_wall_time.working.start; + working = esdp->sched_wall_time.working.total + ts; + } + + sz = 0; + hpp = NULL; + szp = &sz; + + while (1) { + if (hpp) + ref_copy = STORE_NC(hpp, ohp, swtrp->ref); + else + *szp += REF_THING_SIZE; + + if (swtrp->set) + msg = ref_copy; + else { + msg = (!esdp->sched_wall_time.enabled + ? am_notsup + : erts_bld_tuple(hpp, szp, 3, + make_small(esdp->no), + erts_bld_uint64(hpp, szp, working), + erts_bld_uint64(hpp, szp, total))); + + msg = erts_bld_tuple(hpp, szp, 2, ref_copy, msg); + } + if (hpp) + break; + + hp = erts_alloc_message_heap(sz, &bp, &ohp, rp, &rp_locks); + szp = NULL; + hpp = &hp; + } + + erts_queue_message(rp, &rp_locks, bp, msg, NIL); + + if (swtrp->req_sched == esdp->no) + rp_locks &= ~ERTS_PROC_LOCK_MAIN; + + if (rp_locks) + erts_smp_proc_unlock(rp, rp_locks); + + erts_smp_proc_dec_refc(rp); + + if (erts_smp_atomic32_dec_read_nob(&swtrp->refc) == 0) + swtreq_free(vswtrp); +} + +Eterm +erts_sched_wall_time_request(Process *c_p, int set, int enable) +{ + ErtsSchedulerData *esdp = ERTS_PROC_GET_SCHDATA(c_p); + Eterm ref; + ErtsSchedWallTimeReq *swtrp; + Eterm *hp; + + if (!set && !esdp->sched_wall_time.enabled) + return THE_NON_VALUE; + + swtrp = swtreq_alloc(); + ref = erts_make_ref(c_p); + hp = &swtrp->ref_heap[0]; + + swtrp->set = set; + swtrp->enable = enable; + swtrp->proc = c_p; + swtrp->ref = STORE_NC(&hp, NULL, ref); + swtrp->req_sched = esdp->no; + erts_smp_atomic32_init_nob(&swtrp->refc, + (erts_aint32_t) erts_no_schedulers); + + erts_smp_proc_add_refc(c_p, (Sint32) erts_no_schedulers); + +#ifdef ERTS_SMP + if (erts_no_schedulers > 1) + erts_schedule_multi_misc_aux_work(1, + erts_no_schedulers, + reply_sched_wall_time, + (void *) swtrp); +#endif + + reply_sched_wall_time((void *) swtrp); + + return ref; +} + static ERTS_INLINE ErtsProcList * proclist_create(Process *p) { @@ -718,6 +896,27 @@ unset_aux_work_flags(ErtsSchedulerSleepInfo *ssi, erts_aint32_t flgs) return erts_atomic32_read_band_nob(&ssi->aux_work, ~flgs); } +#ifdef ERTS_SMP + +static ERTS_INLINE void +thr_prgr_current_reset(ErtsAuxWorkData *awdp) +{ + awdp->current_thr_prgr = ERTS_THR_PRGR_INVALID; +} + +static ERTS_INLINE ErtsThrPrgrVal +thr_prgr_current(ErtsAuxWorkData *awdp) +{ + ErtsThrPrgrVal current = awdp->current_thr_prgr; + if (current == ERTS_THR_PRGR_INVALID) { + current = erts_thr_progress_current(); + awdp->current_thr_prgr = current; + } + return current; +} + +#endif + typedef struct erts_misc_aux_work_t_ erts_misc_aux_work_t; struct erts_misc_aux_work_t_ { void (*func)(void *); @@ -778,8 +977,8 @@ misc_aux_work_clean(ErtsThrQ_t *q, case ERTS_THR_Q_DIRTY: set_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_MISC); return aux_work | ERTS_SSI_AUX_WORK_MISC; -#ifdef ERTS_SMP case ERTS_THR_Q_NEED_THR_PRGR: +#ifdef ERTS_SMP set_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_MISC_THR_PRGR); erts_thr_progress_wakeup(awdp->esdp, erts_thr_q_need_thr_progress(q)); @@ -790,7 +989,7 @@ misc_aux_work_clean(ErtsThrQ_t *q, return aux_work; } -static erts_aint32_t +static ERTS_INLINE erts_aint32_t handle_misc_aux_work(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) { @@ -810,12 +1009,13 @@ handle_misc_aux_work(ErtsAuxWorkData *awdp, #ifdef ERTS_SMP -static erts_aint32_t +static ERTS_INLINE erts_aint32_t handle_misc_aux_work_thr_prgr(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) { - if (!erts_thr_progress_has_reached(awdp->misc.thr_prgr)) - return aux_work; + if (!erts_thr_progress_has_reached_this(thr_prgr_current(awdp), + awdp->misc.thr_prgr)) + return aux_work & ~ERTS_SSI_AUX_WORK_MISC_THR_PRGR; unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_MISC_THR_PRGR); @@ -888,7 +1088,7 @@ erts_notify_check_async_ready_queue(void *vno) ERTS_SSI_AUX_WORK_ASYNC_READY); } -static erts_aint32_t +static ERTS_INLINE erts_aint32_t handle_async_ready(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) { @@ -910,7 +1110,7 @@ handle_async_ready(ErtsAuxWorkData *awdp, | ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN); } -static erts_aint32_t +static ERTS_INLINE erts_aint32_t handle_async_ready_clean(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) { @@ -918,7 +1118,8 @@ handle_async_ready_clean(ErtsAuxWorkData *awdp, #ifdef ERTS_SMP if (awdp->async_ready.need_thr_prgr - && !erts_thr_progress_has_reached(awdp->misc.thr_prgr)) { + && !erts_thr_progress_has_reached_this(thr_prgr_current(awdp), + awdp->async_ready.thr_prgr)) { return aux_work & ~ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN; } @@ -937,6 +1138,7 @@ handle_async_ready_clean(ErtsAuxWorkData *awdp, erts_thr_progress_wakeup(awdp->esdp, awdp->async_ready.thr_prgr); awdp->async_ready.need_thr_prgr = 1; + return aux_work & ~ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN; #endif default: return aux_work; @@ -945,7 +1147,7 @@ handle_async_ready_clean(ErtsAuxWorkData *awdp, #endif -static erts_aint32_t +static ERTS_INLINE erts_aint32_t handle_fix_alloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) { ErtsSchedulerSleepInfo *ssi = awdp->ssi; @@ -973,16 +1175,18 @@ erts_alloc_notify_delayed_dealloc(int ix) ERTS_SSI_AUX_WORK_DD); } -static erts_aint32_t +static ERTS_INLINE erts_aint32_t handle_delayed_dealloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) { ErtsSchedulerSleepInfo *ssi = awdp->ssi; int need_thr_progress = 0; + ErtsThrPrgrVal wakeup = ERTS_THR_PRGR_INVALID; int more_work = 0; unset_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_DD); erts_alloc_scheduler_handle_delayed_dealloc((void *) awdp->esdp, &need_thr_progress, + &wakeup, &more_work); if (more_work) { if (set_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_DD) @@ -994,9 +1198,12 @@ handle_delayed_dealloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) } if (need_thr_progress) { + if (wakeup == ERTS_THR_PRGR_INVALID) + wakeup = erts_thr_progress_later_than(thr_prgr_current(awdp)); + awdp->dd.thr_prgr = wakeup; set_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_DD_THR_PRGR); - awdp->dd.thr_prgr = erts_thr_progress_later(); - erts_thr_progress_wakeup(awdp->esdp, awdp->dd.thr_prgr); + awdp->dd.thr_prgr = wakeup; + erts_thr_progress_wakeup(awdp->esdp, wakeup); } else if (awdp->dd.completed_callback) { awdp->dd.completed_callback(awdp->dd.completed_arg); @@ -1006,14 +1213,16 @@ handle_delayed_dealloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) return aux_work & ~ERTS_SSI_AUX_WORK_DD; } -static erts_aint32_t +static ERTS_INLINE erts_aint32_t handle_delayed_dealloc_thr_prgr(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) { ErtsSchedulerSleepInfo *ssi; int need_thr_progress; int more_work; + ErtsThrPrgrVal wakeup = ERTS_THR_PRGR_INVALID; + ErtsThrPrgrVal current = thr_prgr_current(awdp); - if (!erts_thr_progress_has_reached(awdp->dd.thr_prgr)) + if (!erts_thr_progress_has_reached_this(current, awdp->dd.thr_prgr)) return aux_work & ~ERTS_SSI_AUX_WORK_DD_THR_PRGR; ssi = awdp->ssi; @@ -1022,6 +1231,7 @@ handle_delayed_dealloc_thr_prgr(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) erts_alloc_scheduler_handle_delayed_dealloc((void *) awdp->esdp, &need_thr_progress, + &wakeup, &more_work); if (more_work) { set_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_DD); @@ -1031,8 +1241,10 @@ handle_delayed_dealloc_thr_prgr(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) } if (need_thr_progress) { - awdp->dd.thr_prgr = erts_thr_progress_later(); - erts_thr_progress_wakeup(awdp->esdp, awdp->dd.thr_prgr); + if (wakeup == ERTS_THR_PRGR_INVALID) + wakeup = erts_thr_progress_later_than(current); + awdp->dd.thr_prgr = wakeup; + erts_thr_progress_wakeup(awdp->esdp, wakeup); } else { unset_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_DD_THR_PRGR); @@ -1129,7 +1341,7 @@ erts_smp_notify_check_children_needed(void) ERTS_SSI_AUX_WORK_CHECK_CHILDREN); } -static erts_aint32_t +static ERTS_INLINE erts_aint32_t handle_check_children(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) { unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_CHECK_CHILDREN); @@ -1139,9 +1351,9 @@ handle_check_children(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) #endif -#ifdef ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK +#if HAVE_ERTS_MSEG -static erts_aint32_t +static ERTS_INLINE erts_aint32_t handle_mseg_cache_check(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) { unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK); @@ -1151,7 +1363,7 @@ handle_mseg_cache_check(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) #endif -static erts_aint32_t +static ERTS_INLINE erts_aint32_t handle_setup_aux_work_timer(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) { unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_SET_TMO); @@ -1159,69 +1371,92 @@ handle_setup_aux_work_timer(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) return aux_work & ~ERTS_SSI_AUX_WORK_SET_TMO; } -static ERTS_INLINE erts_aint32_t -handle_aux_work(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) +static erts_aint32_t +handle_aux_work(ErtsAuxWorkData *awdp, erts_aint32_t orig_aux_work) { +#undef HANDLE_AUX_WORK +#define HANDLE_AUX_WORK(FLG, HNDLR) \ + ignore |= FLG; \ + if (aux_work & FLG) { \ + aux_work = HNDLR(awdp, aux_work); \ + ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); \ + if (!(aux_work & ~ignore)) { \ + ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); \ + return aux_work; \ + } \ + } + + erts_aint32_t aux_work = orig_aux_work; + erts_aint32_t ignore = 0; + +#ifdef ERTS_SMP + thr_prgr_current_reset(awdp); +#endif + + ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); + ASSERT(aux_work); + /* * Handlers are *only* allowed to modify flags in return value * and ssi flags that are explicity handled by the handler. * Handlers are, e.g., not allowed to read the ssi flag field and * then unconditionally return that value. + * + * Flag field returned should only contain flags for work that + * can continue immediately. + */ + + /* + * Keep ERTS_SSI_AUX_WORK flags in expected frequency order relative + * eachother. Most frequent first. */ - ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); - if (aux_work & ERTS_SSI_AUX_WORK_SET_TMO) { - aux_work = handle_setup_aux_work_timer(awdp, aux_work); - ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); - } #ifdef ERTS_SMP - if (aux_work & ERTS_SSI_AUX_WORK_MISC_THR_PRGR) { - aux_work = handle_misc_aux_work_thr_prgr(awdp, aux_work); - ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); - } + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_DD, + handle_delayed_dealloc); + /* DD must be before DD_THR_PRGR */ + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_DD_THR_PRGR, + handle_delayed_dealloc_thr_prgr); #endif - if (aux_work & ERTS_SSI_AUX_WORK_MISC) { - aux_work = handle_misc_aux_work(awdp, aux_work); - ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); - } + + HANDLE_AUX_WORK((ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM + | ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC), + handle_fix_alloc); + #if ERTS_USE_ASYNC_READY_Q - if (aux_work & ERTS_SSI_AUX_WORK_ASYNC_READY) { - aux_work = handle_async_ready(awdp, aux_work); - ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); - } - if (aux_work & ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN) { - aux_work = handle_async_ready_clean(awdp, aux_work); - ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); - } + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_ASYNC_READY, + handle_async_ready); + /* ASYNC_READY must be before ASYNC_READY_CLEAN */ + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN, + handle_async_ready_clean); #endif -#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN - if (aux_work & ERTS_SSI_AUX_WORK_CHECK_CHILDREN) { - aux_work = handle_check_children(awdp, aux_work); - ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); - } -#endif - if (aux_work & (ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM - | ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC)) { - aux_work = handle_fix_alloc(awdp, aux_work); - ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); - } + #ifdef ERTS_SMP - if (aux_work & ERTS_SSI_AUX_WORK_DD) { - aux_work = handle_delayed_dealloc(awdp, aux_work); - ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); - } - if (aux_work & ERTS_SSI_AUX_WORK_DD_THR_PRGR) { - aux_work = handle_delayed_dealloc_thr_prgr(awdp, aux_work); - ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); - } + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_MISC_THR_PRGR, + handle_misc_aux_work_thr_prgr); #endif -#ifdef ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK - if (aux_work & ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK) { - aux_work = handle_mseg_cache_check(awdp, aux_work); - ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); - } + /* MISC_THR_PRGR must be before MISC */ + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_MISC, + handle_misc_aux_work); + +#ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_CHECK_CHILDREN, + handle_check_children); +#endif + + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_SET_TMO, + handle_setup_aux_work_timer); + +#if HAVE_ERTS_MSEG + HANDLE_AUX_WORK(ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK, + handle_mseg_cache_check); #endif + ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); + return aux_work; + +#undef HANDLE_AUX_WORK + } typedef struct { @@ -1715,6 +1950,7 @@ aux_thread(void *unused) static void scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) { + int working = 1; ErtsSchedulerSleepInfo *ssi = esdp->ssi; int spincount; erts_aint32_t aux_work = 0; @@ -1724,21 +1960,12 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); - erts_smp_spin_lock(&rq->sleepers.lock); flgs = sched_prep_spin_wait(ssi); if (flgs & ERTS_SSI_FLG_SUSPENDED) { /* Go suspend instead... */ - erts_smp_spin_unlock(&rq->sleepers.lock); return; } - ssi->prev = NULL; - ssi->next = rq->sleepers.list; - if (rq->sleepers.list) - rq->sleepers.list->prev = ssi; - rq->sleepers.list = ssi; - erts_smp_spin_unlock(&rq->sleepers.lock); - /* * If all schedulers are waiting, one of them *should* * be waiting in erl_sys_schedule() @@ -1754,12 +1981,17 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) tse_wait: + if (thr_prgr_active != working) + sched_wall_time_change(esdp, thr_prgr_active); + while (1) { aux_work = erts_atomic32_read_acqb(&ssi->aux_work); if (aux_work) { - if (!thr_prgr_active) + if (!thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 1); + sched_wall_time_change(esdp, 1); + } aux_work = handle_aux_work(&esdp->aux_work_data, aux_work); if (aux_work && erts_thr_progress_update(esdp)) erts_thr_progress_leader_update(esdp); @@ -1768,8 +2000,10 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) if (aux_work) flgs = erts_smp_atomic32_read_acqb(&ssi->flags); else { - if (thr_prgr_active) + if (thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 0); + sched_wall_time_change(esdp, 0); + } erts_thr_progress_prepare_wait(esdp); flgs = sched_spin_wait(ssi, spincount); @@ -1806,8 +2040,10 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) if (flgs & ~ERTS_SSI_FLG_SUSPENDED) erts_smp_atomic32_read_band_nob(&ssi->flags, ERTS_SSI_FLG_SUSPENDED); - if (!thr_prgr_active) + if (!thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 1); + sched_wall_time_change(esdp, 1); + } erts_smp_runq_lock(rq); sched_active(esdp->no, rq); @@ -1823,14 +2059,21 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) sched_waiting_sys(esdp->no, rq); + erts_smp_runq_unlock(rq); + ASSERT(working); + sched_wall_time_change(esdp, working = 0); + spincount = ERTS_SCHED_SYS_SLEEP_SPINCOUNT; while (spincount-- > 0) { sys_poll_aux_work: + if (working) + sched_wall_time_change(esdp, working = 0); + ASSERT(!erts_port_task_have_outstanding_io_tasks()); erl_sys_schedule(1); /* Might give us something to do */ @@ -1845,6 +2088,8 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) aux_work = erts_atomic32_read_acqb(&ssi->aux_work); if (aux_work) { + if (!working) + sched_wall_time_change(esdp, working = 1); #ifdef ERTS_SMP if (!thr_prgr_active) erts_thr_progress_active(esdp, thr_prgr_active = 1); @@ -1937,6 +2182,9 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) erts_smp_runq_unlock(rq); + if (working) + sched_wall_time_change(esdp, working = 0); + #ifdef ERTS_SMP if (thr_prgr_active) erts_thr_progress_active(esdp, thr_prgr_active = 0); @@ -1972,6 +2220,8 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) if (flgs & ~ERTS_SSI_FLG_SUSPENDED) erts_smp_atomic32_read_band_nob(&ssi->flags, ERTS_SSI_FLG_SUSPENDED); #endif + if (!working) + sched_wall_time_change(esdp, working = 1); sched_active_sys(esdp->no, rq); } @@ -1997,10 +2247,10 @@ ssi_flags_set_wake(ErtsSchedulerSleepInfo *ssi) } static void -wake_scheduler(ErtsRunQueue *rq, int incq, int one) +wake_scheduler(ErtsRunQueue *rq, int incq) { ErtsSchedulerSleepInfo *ssi; - ErtsSchedulerSleepList *sl; + erts_aint32_t flgs; /* * The unlocked run queue is not strictly necessary @@ -2012,56 +2262,13 @@ wake_scheduler(ErtsRunQueue *rq, int incq, int one) */ ERTS_SMP_LC_ASSERT(!erts_smp_lc_runq_is_locked(rq)); - sl = &rq->sleepers; - - erts_smp_spin_lock(&sl->lock); - ssi = sl->list; - if (!ssi) - erts_smp_spin_unlock(&sl->lock); - else if (one) { - erts_aint32_t flgs; - if (ssi->prev) - ssi->prev->next = ssi->next; - else { - ASSERT(sl->list == ssi); - sl->list = ssi->next; - } - if (ssi->next) - ssi->next->prev = ssi->prev; - - erts_smp_spin_unlock(&sl->lock); - - flgs = ssi_flags_set_wake(ssi); - erts_sched_finish_poke(ssi, flgs); - - if (incq && !erts_common_run_queue && (flgs & ERTS_SSI_FLG_WAITING)) - non_empty_runq(rq); - } - else { - sl->list = NULL; - erts_smp_spin_unlock(&sl->lock); + ssi = rq->scheduler->ssi; - ERTS_THR_MEMORY_BARRIER; - do { - ErtsSchedulerSleepInfo *wake_ssi = ssi; - ssi = ssi->next; - erts_sched_finish_poke(wake_ssi, ssi_flags_set_wake(wake_ssi)); - } while (ssi); - } -} + flgs = ssi_flags_set_wake(ssi); + erts_sched_finish_poke(ssi, flgs); -static void -wake_all_schedulers(void) -{ - if (erts_common_run_queue) - wake_scheduler(erts_common_run_queue, 0, 0); - else { - int ix; - for (ix = 0; ix < erts_no_run_queues; ix++) { - ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); - wake_scheduler(rq, 0, 1); - } - } + if (incq && (flgs & ERTS_SSI_FLG_WAITING)) + non_empty_runq(rq); } #define ERTS_NO_USED_RUNQS_SHIFT 16 @@ -2154,7 +2361,7 @@ chk_wake_sched(ErtsRunQueue *crq, int ix, int activate) erts_smp_xrunq_unlock(crq, wrq); } } - wake_scheduler(wrq, 0, 1); + wake_scheduler(wrq, 0); return 1; } return 0; @@ -2202,7 +2409,7 @@ smp_notify_inc_runq(ErtsRunQueue *runq) { #ifdef ERTS_SMP if (runq) - wake_scheduler(runq, 1, 1); + wake_scheduler(runq, 1); #endif } @@ -2217,19 +2424,12 @@ erts_sched_notify_check_cpu_bind(void) { #ifdef ERTS_SMP int ix; - if (erts_common_run_queue) { - for (ix = 0; ix < erts_no_schedulers; ix++) - erts_smp_atomic32_set_relb(&ERTS_SCHEDULER_IX(ix)->chk_cpu_bind, 1); - wake_all_schedulers(); - } - else { - for (ix = 0; ix < erts_no_run_queues; ix++) { - ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); - erts_smp_runq_lock(rq); - rq->flags |= ERTS_RUNQ_FLG_CHK_CPU_BIND; - erts_smp_runq_unlock(rq); - wake_scheduler(rq, 0, 1); - }; + for (ix = 0; ix < erts_no_run_queues; ix++) { + ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); + erts_smp_runq_lock(rq); + rq->flags |= ERTS_RUNQ_FLG_CHK_CPU_BIND; + erts_smp_runq_unlock(rq); + wake_scheduler(rq, 0); } #else erts_sched_check_cpu_bind(erts_get_scheduler_data()); @@ -2498,7 +2698,7 @@ evacuate_run_queue(ErtsRunQueue *evac_rq, ErtsRunQueue *rq) if (notify_to_rq) smp_notify_inc_runq(rq); - wake_scheduler(evac_rq, 0, 1); + wake_scheduler(evac_rq, 0); } static int @@ -2656,9 +2856,6 @@ static int try_steal_task(ErtsRunQueue *rq) { int res, rq_locked, vix, active_rqs, blnc_rqs; - - if (erts_common_run_queue) - return 0; /* * We are not allowed to steal jobs to this run queue @@ -3335,14 +3532,10 @@ init_aux_work_data(ErtsAuxWorkData *awdp, ErtsSchedulerData *esdp) } void -erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online) +erts_init_scheduling(int no_schedulers, int no_schedulers_online) { int ix, n, no_ssi; -#ifndef ERTS_SMP - mrq = 0; -#endif - init_misc_op_list_alloc(); ASSERT(no_schedulers_online <= no_schedulers); @@ -3351,7 +3544,7 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online) /* Create and initialize run queues */ - n = (int) (mrq ? no_schedulers : 1); + n = no_schedulers; erts_aligned_run_queues = erts_alloc_permanent_cache_aligned(ERTS_ALC_T_RUNQS, @@ -3376,14 +3569,9 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online) erts_smp_mtx_init_x(&rq->mtx, "run_queue", make_small(ix + 1)); erts_smp_cnd_init(&rq->cnd); -#ifdef ERTS_SMP - erts_smp_spinlock_init(&rq->sleepers.lock, "run_queue_sleep_list"); - rq->sleepers.list = NULL; -#endif - rq->waiting = 0; rq->woken = 0; - rq->flags = !mrq ? ERTS_RUNQ_FLG_SHARED_RUNQ : 0; + rq->flags = 0; rq->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS; rq->full_reds_history_sum = 0; for (rix = 0; rix < ERTS_FULL_REDS_HISTORY_SIZE; rix++) { @@ -3429,8 +3617,6 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online) rq->ports.end = NULL; } - erts_common_run_queue = !mrq ? ERTS_RUNQ_IX(0) : NULL; - #ifdef ERTS_SMP if (erts_no_run_queues != 1) { @@ -3507,22 +3693,18 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online) erts_init_atom_cache_map(&esdp->atom_cache_map); - if (erts_common_run_queue) { - esdp->run_queue = erts_common_run_queue; - esdp->run_queue->scheduler = NULL; - } - else { - esdp->run_queue = ERTS_RUNQ_IX(ix); - esdp->run_queue->scheduler = esdp; - } + esdp->run_queue = ERTS_RUNQ_IX(ix); + esdp->run_queue->scheduler = esdp; -#ifdef ERTS_SMP - erts_smp_atomic32_init_nob(&esdp->chk_cpu_bind, 0); -#endif init_aux_work_data(&esdp->aux_work_data, esdp); + init_sched_wall_time(&esdp->sched_wall_time); } init_misc_aux_work(); +#if !HALFWORD_HEAP + init_swtreq_alloc(); +#endif + #ifdef ERTS_SMP @@ -3541,8 +3723,7 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online) schdlr_sspnd.msb.ongoing = 0; erts_smp_atomic32_init_nob(&schdlr_sspnd.active, no_schedulers); schdlr_sspnd.msb.procs = NULL; - init_no_runqs(no_schedulers, - erts_common_run_queue ? 1 : no_schedulers_online); + init_no_runqs(no_schedulers, no_schedulers_online); balance_info.last_active_runqs = no_schedulers; erts_smp_mtx_init(&balance_info.update_mtx, "migration_info_update"); balance_info.forced_check_balance = 0; @@ -3555,16 +3736,9 @@ erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online) balance_info.n = 0; if (no_schedulers_online < no_schedulers) { - if (erts_common_run_queue) { - for (ix = no_schedulers_online; ix < no_schedulers; ix++) - erts_smp_atomic32_read_bor_nob(&ERTS_SCHED_SLEEP_INFO_IX(ix)->flags, - ERTS_SSI_FLG_SUSPENDED); - } - else { - for (ix = no_schedulers_online; ix < erts_no_run_queues; ix++) - evacuate_run_queue(ERTS_RUNQ_IX(ix), - ERTS_RUNQ_IX(ix % no_schedulers_online)); - } + for (ix = no_schedulers_online; ix < erts_no_run_queues; ix++) + evacuate_run_queue(ERTS_RUNQ_IX(ix), + ERTS_RUNQ_IX(ix % no_schedulers_online)); } schdlr_sspnd.wait_curr_online = no_schedulers_online; @@ -3609,8 +3783,6 @@ ErtsRunQueue * erts_schedid2runq(Uint id) { int ix; - if (erts_common_run_queue) - return erts_common_run_queue; ix = (int) id - 1; ASSERT(0 <= ix && ix < erts_no_run_queues); return ERTS_RUNQ_IX(ix); @@ -3855,6 +4027,8 @@ suspend_scheduler(ErtsSchedulerData *esdp) if (erts_system_profile_flags.scheduler) profile_scheduler(make_small(esdp->no), am_inactive); + sched_wall_time_change(esdp, 0); + erts_smp_mtx_lock(&schdlr_sspnd.mtx); flgs = sched_prep_spin_suspended(ssi, ERTS_SSI_FLG_SUSPENDED); @@ -3901,9 +4075,11 @@ suspend_scheduler(ErtsSchedulerData *esdp) wake = 0; } - flgs = erts_smp_atomic32_read_acqb(&ssi->flags); - if (!(flgs & ERTS_SSI_FLG_SUSPENDED)) - break; + if (curr_online && !ongoing_multi_scheduling_block()) { + flgs = erts_smp_atomic32_read_acqb(&ssi->flags); + if (!(flgs & ERTS_SSI_FLG_SUSPENDED)) + break; + } erts_smp_mtx_unlock(&schdlr_sspnd.mtx); while (1) { @@ -3911,16 +4087,20 @@ suspend_scheduler(ErtsSchedulerData *esdp) aux_work = erts_atomic32_read_acqb(&ssi->aux_work); if (aux_work) { - if (!thr_prgr_active) + if (!thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 1); + sched_wall_time_change(esdp, 1); + } aux_work = handle_aux_work(&esdp->aux_work_data, aux_work); if (aux_work && erts_thr_progress_update(esdp)) erts_thr_progress_leader_update(esdp); } if (!aux_work) { - if (thr_prgr_active) + if (thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 0); + sched_wall_time_change(esdp, 0); + } erts_thr_progress_prepare_wait(esdp); flgs = sched_spin_suspended(ssi, ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT); @@ -3975,8 +4155,10 @@ suspend_scheduler(ErtsSchedulerData *esdp) if (erts_system_profile_flags.scheduler) profile_scheduler(make_small(esdp->no), am_active); - if (!thr_prgr_active) + if (!thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 1); + sched_wall_time_change(esdp, 1); + } erts_smp_runq_lock(esdp->run_queue); non_empty_runq(esdp->run_queue); @@ -4095,10 +4277,6 @@ erts_set_schedulers_online(Process *p, for (ix = online; ix < no; ix++) erts_sched_poke(ERTS_SCHED_SLEEP_INFO_IX(ix)); } - else if (erts_common_run_queue) { - for (ix = online; ix < no; ix++) - scheduler_ix_resume_wake(ix); - } else { if (plocks) { have_unlocked_plocks = 1; @@ -4146,15 +4324,6 @@ erts_set_schedulers_online(Process *p, for (ix = no; ix < online; ix++) erts_sched_poke(ERTS_SCHED_SLEEP_INFO_IX(ix)); } - else if (erts_common_run_queue) { - for (ix = no; ix < online; ix++) { - ErtsSchedulerSleepInfo *ssi; - ssi = ERTS_SCHED_SLEEP_INFO_IX(ix); - erts_smp_atomic32_read_bor_nob(&ssi->flags, - ERTS_SSI_FLG_SUSPENDED); - } - wake_all_schedulers(); - } else { if (plocks) { have_unlocked_plocks = 1; @@ -4181,7 +4350,7 @@ erts_set_schedulers_online(Process *p, erts_smp_mtx_lock(&schdlr_sspnd.mtx); for (ix = no; ix < online; ix++) { ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); - wake_scheduler(rq, 0, 1); + wake_scheduler(rq, 0); } } } @@ -4274,33 +4443,26 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all) res = ERTS_SCHDLR_SSPND_YIELD_DONE_MSCHED_BLOCKED; schdlr_sspnd.msb.wait_active = 2; } - if (erts_common_run_queue) { - for (ix = 1; ix < online; ix++) - erts_smp_atomic32_read_bor_nob(&ERTS_SCHED_SLEEP_INFO_IX(ix)->flags, - ERTS_SSI_FLG_SUSPENDED); - wake_all_schedulers(); - } - else { - erts_smp_mtx_unlock(&schdlr_sspnd.mtx); - erts_smp_mtx_lock(&balance_info.update_mtx); - set_no_used_runqs(1); - for (ix = 0; ix < online; ix++) { - ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); - erts_smp_runq_lock(rq); - ASSERT(!(rq->flags & ERTS_RUNQ_FLG_SUSPENDED)); - ERTS_RUNQ_RESET_MIGRATION_PATHS(rq, 0x7); - erts_smp_runq_unlock(rq); - } - /* - * Evacuate all activities in all other run queues - * into the first run queue. Note order is important, - * online run queues has to be evacuated last. - */ - for (ix = erts_no_run_queues-1; ix >= 1; ix--) - evacuate_run_queue(ERTS_RUNQ_IX(ix), ERTS_RUNQ_IX(0)); - erts_smp_mtx_unlock(&balance_info.update_mtx); - erts_smp_mtx_lock(&schdlr_sspnd.mtx); + + erts_smp_mtx_unlock(&schdlr_sspnd.mtx); + erts_smp_mtx_lock(&balance_info.update_mtx); + set_no_used_runqs(1); + for (ix = 0; ix < online; ix++) { + ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); + erts_smp_runq_lock(rq); + ASSERT(!(rq->flags & ERTS_RUNQ_FLG_SUSPENDED)); + ERTS_RUNQ_RESET_MIGRATION_PATHS(rq, 0x7); + erts_smp_runq_unlock(rq); } + /* + * Evacuate all activities in all other run queues + * into the first run queue. Note order is important, + * online run queues has to be evacuated last. + */ + for (ix = erts_no_run_queues-1; ix >= 1; ix--) + evacuate_run_queue(ERTS_RUNQ_IX(ix), ERTS_RUNQ_IX(0)); + erts_smp_mtx_unlock(&balance_info.update_mtx); + erts_smp_mtx_lock(&schdlr_sspnd.mtx); if (erts_smp_atomic32_read_nob(&schdlr_sspnd.active) != schdlr_sspnd.msb.wait_active) { @@ -4412,12 +4574,6 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all) ASSERT(erts_smp_atomic32_read_nob(&schdlr_sspnd.active) == 1); ERTS_SCHDLR_SSPND_CHNG_SET(0, ERTS_SCHDLR_SSPND_CHNG_MSB); } - else if (erts_common_run_queue) { - for (ix = 1; ix < schdlr_sspnd.online; ix++) - erts_smp_atomic32_read_band_nob(&ERTS_SCHED_SLEEP_INFO_IX(ix)->flags, - ~ERTS_SSI_FLG_SUSPENDED); - wake_all_schedulers(); - } else { int online = schdlr_sspnd.online; erts_smp_mtx_unlock(&schdlr_sspnd.mtx); @@ -5096,7 +5252,7 @@ suspend_process_2(BIF_ALIST_2) /* This is really a piece of cake without SMP support... */ if (!smon->active) { - suspend_process(erts_common_run_queue, suspendee); + suspend_process(ERTS_RUNQ_IX(0), suspendee); smon->active++; res = am_true; } @@ -5666,8 +5822,6 @@ erts_proc_migrate(Process *p, ErtsProcLocks *plcks, || from_locked); ERTS_SMP_LC_CHK_RUNQ_LOCK(from_rq, *from_locked); ERTS_SMP_LC_CHK_RUNQ_LOCK(to_rq, *to_locked); - - ASSERT(!erts_common_run_queue); /* * If we have the lock on the run queue to migrate to, @@ -5818,25 +5972,17 @@ erts_process_status(Process *c_p, ErtsProcLocks c_p_locks, int i; ErtsSchedulerData *esdp; - if (erts_common_run_queue) - erts_smp_runq_lock(erts_common_run_queue); - for (i = 0; i < erts_no_schedulers; i++) { esdp = ERTS_SCHEDULER_IX(i); - if (!erts_common_run_queue) - erts_smp_runq_lock(esdp->run_queue); + erts_smp_runq_lock(esdp->run_queue); if (esdp->free_process && esdp->free_process->id == rpid) { res = am_free; - if (!erts_common_run_queue) - erts_smp_runq_unlock(esdp->run_queue); + erts_smp_runq_unlock(esdp->run_queue); break; } - if (!erts_common_run_queue) - erts_smp_runq_unlock(esdp->run_queue); + erts_smp_runq_unlock(esdp->run_queue); } - if (erts_common_run_queue) - erts_smp_runq_unlock(erts_common_run_queue); #endif } @@ -6147,10 +6293,8 @@ Process *schedule(Process *p, int calls) #ifdef ERTS_SMP - if (!(rq->flags & ERTS_RUNQ_FLG_SHARED_RUNQ) - && rq->check_balance_reds <= 0) { + if (rq->check_balance_reds <= 0) check_balance(rq); - } ERTS_SMP_LC_ASSERT(!erts_thr_progress_is_blocking()); ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq)); @@ -6160,20 +6304,15 @@ Process *schedule(Process *p, int calls) continue_check_activities_to_run: - if (rq->flags & (ERTS_RUNQ_FLG_SHARED_RUNQ - | ERTS_RUNQ_FLG_CHK_CPU_BIND + if (rq->flags & (ERTS_RUNQ_FLG_CHK_CPU_BIND | ERTS_RUNQ_FLG_SUSPENDED)) { - if ((rq->flags & ERTS_RUNQ_FLG_SUSPENDED) - || (erts_smp_atomic32_read_acqb(&esdp->ssi->flags) - & ERTS_SSI_FLG_SUSPENDED)) { + if (rq->flags & ERTS_RUNQ_FLG_SUSPENDED) { ASSERT(erts_smp_atomic32_read_nob(&esdp->ssi->flags) & ERTS_SSI_FLG_SUSPENDED); suspend_scheduler(esdp); } - if ((rq->flags & ERTS_RUNQ_FLG_CHK_CPU_BIND) - || erts_smp_atomic32_read_acqb(&esdp->chk_cpu_bind)) { + if (rq->flags & ERTS_RUNQ_FLG_CHK_CPU_BIND) erts_sched_check_cpu_bind(esdp); - } } { @@ -6215,16 +6354,11 @@ Process *schedule(Process *p, int calls) empty_runq(rq); - if (rq->flags & (ERTS_RUNQ_FLG_SHARED_RUNQ - | ERTS_RUNQ_FLG_SUSPENDED)) { - if ((rq->flags & ERTS_RUNQ_FLG_SUSPENDED) - || (erts_smp_atomic32_read_acqb(&esdp->ssi->flags) - & ERTS_SSI_FLG_SUSPENDED)) { - ASSERT(erts_smp_atomic32_read_nob(&esdp->ssi->flags) - & ERTS_SSI_FLG_SUSPENDED); - non_empty_runq(rq); - goto continue_check_activities_to_run; - } + if (rq->flags & ERTS_RUNQ_FLG_SUSPENDED) { + ASSERT(erts_smp_atomic32_read_nob(&esdp->ssi->flags) + & ERTS_SSI_FLG_SUSPENDED); + non_empty_runq(rq); + goto continue_check_activities_to_run; } else if (!(rq->flags & ERTS_RUNQ_FLG_INACTIVE)) { /* @@ -6289,11 +6423,7 @@ Process *schedule(Process *p, int calls) else if (rq->wakeup_other < wakeup_other_limit) rq->wakeup_other += rq->len*wo_reds + ERTS_WAKEUP_OTHER_FIXED_INC; else { - if (erts_common_run_queue) { - if (erts_common_run_queue->waiting) - wake_scheduler(erts_common_run_queue, 0, 1); - } - else if (erts_smp_atomic32_read_acqb(&no_empty_run_queues) != 0) { + if (erts_smp_atomic32_read_acqb(&no_empty_run_queues) != 0) { wake_scheduler_on_empty_runq(rq); rq->wakeup_other = 0; } @@ -6892,7 +7022,9 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). goto error; } +#ifdef BM_COUNTERS processes_busy++; +#endif BM_COUNT(processes_spawned); #ifndef HYBRID @@ -8128,15 +8260,6 @@ static void doit_exit_link(ErtsLink *lnk, void *vpcontext) if (rlnk) erts_destroy_link(rlnk); erts_deref_dist_entry(dep); - } else { -#ifndef ERTS_SMP - /* XXX Is this possible? Shouldn't this link - previously have been removed if the node - had previously been disconnected. */ - ASSERT(0); -#endif - /* This is possible when smp support has been enabled, - and dist port and process exits simultaneously. */ } break; @@ -8415,7 +8538,9 @@ continue_exit_process(Process *p pbt = ERTS_PROC_SET_CALL_TIME(p, ERTS_PROC_LOCKS_ALL, NULL); erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL); +#ifdef BM_COUNTERS processes_busy--; +#endif if (dep) { erts_do_net_exits(dep, reason); diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 69ff423133..c23810f15a 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2011. All Rights Reserved. + * Copyright Ericsson AB 1996-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -144,12 +144,10 @@ extern int erts_sched_thread_suggested_stack_size; (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 1)) #define ERTS_RUNQ_FLG_SUSPENDED \ (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 2)) -#define ERTS_RUNQ_FLG_SHARED_RUNQ \ - (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 3)) #define ERTS_RUNQ_FLG_CHK_CPU_BIND \ - (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 4)) + (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 3)) #define ERTS_RUNQ_FLG_INACTIVE \ - (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 5)) + (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 4)) #define ERTS_RUNQ_FLGS_MIGRATION_QMASKS \ (ERTS_RUNQ_FLGS_EMIGRATE_QMASK \ @@ -250,33 +248,25 @@ typedef enum { | ERTS_SSI_FLG_WAITING \ | ERTS_SSI_FLG_SUSPENDED) -#define ERTS_SSI_AUX_WORK_SET_TMO (((erts_aint32_t) 1) << 0) -#define ERTS_SSI_AUX_WORK_CHECK_CHILDREN (((erts_aint32_t) 1) << 1) -#define ERTS_SSI_AUX_WORK_MISC (((erts_aint32_t) 1) << 2) -#ifdef ERTS_SMP -#define ERTS_SSI_AUX_WORK_MISC_THR_PRGR (((erts_aint32_t) 1) << 3) -#endif -#define ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM (((erts_aint32_t) 1) << 4) -#define ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC (((erts_aint32_t) 1) << 5) -#define ERTS_SSI_AUX_WORK_ASYNC_READY (((erts_aint32_t) 1) << 6) -#define ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN (((erts_aint32_t) 1) << 7) -#ifdef ERTS_SMP -#define ERTS_SSI_AUX_WORK_DD (((erts_aint32_t) 1) << 8) -#define ERTS_SSI_AUX_WORK_DD_THR_PRGR (((erts_aint32_t) 1) << 9) -#endif -#define ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK (((erts_aint32_t) 1) << 10) +/* + * Keep ERTS_SSI_AUX_WORK flags in expected frequency order relative + * eachother. Most frequent - lowest bit number. + */ -#if !HAVE_ERTS_MSEG -# undef ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK -#endif +#define ERTS_SSI_AUX_WORK_DD (((erts_aint32_t) 1) << 0) +#define ERTS_SSI_AUX_WORK_DD_THR_PRGR (((erts_aint32_t) 1) << 1) +#define ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC (((erts_aint32_t) 1) << 2) +#define ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM (((erts_aint32_t) 1) << 3) +#define ERTS_SSI_AUX_WORK_ASYNC_READY (((erts_aint32_t) 1) << 4) +#define ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN (((erts_aint32_t) 1) << 5) +#define ERTS_SSI_AUX_WORK_MISC_THR_PRGR (((erts_aint32_t) 1) << 6) +#define ERTS_SSI_AUX_WORK_MISC (((erts_aint32_t) 1) << 7) +#define ERTS_SSI_AUX_WORK_CHECK_CHILDREN (((erts_aint32_t) 1) << 8) +#define ERTS_SSI_AUX_WORK_SET_TMO (((erts_aint32_t) 1) << 9) +#define ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK (((erts_aint32_t) 1) << 10) typedef struct ErtsSchedulerSleepInfo_ ErtsSchedulerSleepInfo; -typedef struct { - erts_smp_spinlock_t lock; - ErtsSchedulerSleepInfo *list; -} ErtsSchedulerSleepList; - struct ErtsSchedulerSleepInfo_ { #ifdef ERTS_SMP ErtsSchedulerSleepInfo *next; @@ -339,10 +329,6 @@ struct ErtsRunQueue_ { erts_smp_mtx_t mtx; erts_smp_cnd_t cnd; -#ifdef ERTS_SMP - ErtsSchedulerSleepList sleepers; -#endif - ErtsSchedulerData *scheduler; int waiting; /* < 0 in sys schedule; > 0 on cnd variable */ int woken; @@ -388,7 +374,6 @@ typedef union { } ErtsAlignedRunQueue; extern ErtsAlignedRunQueue *erts_aligned_run_queues; -extern ErtsRunQueue *erts_common_run_queue; #define ERTS_PROC_REDUCTIONS_EXECUTED(RQ, PRIO, REDS, AREDS) \ do { \ @@ -406,9 +391,22 @@ do { \ } while (0) typedef struct { + int enabled; + Uint64 start; + struct { + Uint64 total; + Uint64 start; + int currently; + } working; +} ErtsSchedWallTime; + +typedef struct { int sched_id; ErtsSchedulerData *esdp; ErtsSchedulerSleepInfo *ssi; +#ifdef ERTS_SMP + ErtsThrPrgrVal current_thr_prgr; +#endif struct { int ix; #ifdef ERTS_SMP @@ -469,10 +467,7 @@ struct ErtsSchedulerData_ { ErtsSchedAllocData alloc_data; -#ifdef ERTS_SMP - /* NOTE: These fields are modified under held mutexes by other threads */ - erts_smp_atomic32_t chk_cpu_bind; /* Only used when common run queue */ -#endif + ErtsSchedWallTime sched_wall_time; #ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC erts_alloc_verify_func_t verify_unused_temp_alloc; @@ -1079,7 +1074,9 @@ extern struct erts_system_profile_flags_t erts_system_profile_flags; void erts_pre_init_process(void); void erts_late_init_process(void); void erts_early_init_scheduling(int); -void erts_init_scheduling(int, int, int); +void erts_init_scheduling(int, int); + +Eterm erts_sched_wall_time_request(Process *c_p, int set, int enable); ErtsProcList *erts_proclist_create(Process *); void erts_proclist_destroy(ErtsProcList *); @@ -1464,8 +1461,7 @@ erts_get_runq_proc(Process *p) ASSERT(p->run_queue); return p->run_queue; #else - ASSERT(erts_common_run_queue); - return erts_common_run_queue; + return ERTS_RUNQ_IX(0); #endif } @@ -1478,8 +1474,7 @@ erts_get_runq_current(ErtsSchedulerData *esdp) esdp = erts_get_scheduler_data(); return esdp->run_queue; #else - ASSERT(erts_common_run_queue); - return erts_common_run_queue; + return ERTS_RUNQ_IX(0); #endif } diff --git a/erts/emulator/beam/erl_process_lock.c b/erts/emulator/beam/erl_process_lock.c index b4d20480c5..a5a753b798 100644 --- a/erts/emulator/beam/erl_process_lock.c +++ b/erts/emulator/beam/erl_process_lock.c @@ -123,10 +123,10 @@ erts_init_proc_lock(int cpus) erts_smp_spinlock_init(&qs_lock, "proc_lck_qs_alloc"); for (i = 0; i < ERTS_NO_OF_PIX_LOCKS; i++) { #ifdef ERTS_ENABLE_LOCK_COUNT - erts_smp_spinlock_init_x(&erts_pix_locks[i].u.spnlck, - "pix_lock", make_small(i)); + erts_mtx_init_x(&erts_pix_locks[i].u.mtx, + "pix_lock", make_small(i)); #else - erts_smp_spinlock_init(&erts_pix_locks[i].u.spnlck, "pix_lock"); + erts_mtx_init(&erts_pix_locks[i].u.mtx, "pix_lock"); #endif } queue_free_list = NULL; diff --git a/erts/emulator/beam/erl_process_lock.h b/erts/emulator/beam/erl_process_lock.h index 97f250138e..97e554914e 100644 --- a/erts/emulator/beam/erl_process_lock.h +++ b/erts/emulator/beam/erl_process_lock.h @@ -255,8 +255,8 @@ void erts_proc_lc_unrequire_lock(Process *p, ErtsProcLocks locks); typedef struct { union { - erts_smp_spinlock_t spnlck; - char buf[64]; /* Try to get locks in different cache lines */ + erts_mtx_t mtx; + char buf[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(erts_mtx_t))]; } u; } erts_pix_lock_t; @@ -380,18 +380,18 @@ ERTS_GLB_INLINE void erts_proc_lock_op_debug(Process *, ErtsProcLocks, int); ERTS_GLB_INLINE void erts_pix_lock(erts_pix_lock_t *pixlck) { ERTS_LC_ASSERT(pixlck); - erts_smp_spin_lock(&pixlck->u.spnlck); + erts_mtx_lock(&pixlck->u.mtx); } ERTS_GLB_INLINE void erts_pix_unlock(erts_pix_lock_t *pixlck) { ERTS_LC_ASSERT(pixlck); - erts_smp_spin_unlock(&pixlck->u.spnlck); + erts_mtx_unlock(&pixlck->u.mtx); } ERTS_GLB_INLINE int erts_lc_pix_lock_is_locked(erts_pix_lock_t *pixlck) { - return erts_smp_lc_spinlock_is_locked(&pixlck->u.spnlck); + return erts_lc_mtx_is_locked(&pixlck->u.mtx); } /* diff --git a/erts/emulator/beam/erl_sched_spec_pre_alloc.c b/erts/emulator/beam/erl_sched_spec_pre_alloc.c index a7ccea7403..bff9d246a3 100644 --- a/erts/emulator/beam/erl_sched_spec_pre_alloc.c +++ b/erts/emulator/beam/erl_sched_spec_pre_alloc.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011. All Rights Reserved. + * Copyright Ericsson AB 2011-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -227,7 +227,6 @@ fetch_remote(erts_sspa_chunk_header_t *chdr, int max) ERTS_THR_MEMORY_BARRIER; else { chdr->head.next.unref_end = (erts_sspa_blk_t *) ilast; - ERTS_THR_MEMORY_BARRIER; chdr->head.next.thr_progress = erts_thr_progress_later(); erts_atomic32_set_relb(&chdr->tail.data.um_refc_ix, um_refc_ix); diff --git a/erts/emulator/beam/erl_smp.h b/erts/emulator/beam/erl_smp.h index 63179dfad4..a32e9d9d7c 100644 --- a/erts/emulator/beam/erl_smp.h +++ b/erts/emulator/beam/erl_smp.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2005-2011. All Rights Reserved. + * Copyright Ericsson AB 2005-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -61,6 +61,11 @@ typedef erts_spinlock_t erts_smp_spinlock_t; typedef erts_rwlock_t erts_smp_rwlock_t; void erts_thr_fatal_error(int, char *); /* implemented in erl_init.c */ +#define ERTS_SMP_MEMORY_BARRIER ERTS_THR_MEMORY_BARRIER +#define ERTS_SMP_WRITE_MEMORY_BARRIER ERTS_THR_WRITE_MEMORY_BARRIER +#define ERTS_SMP_READ_MEMORY_BARRIER ERTS_THR_READ_MEMORY_BARRIER +#define ERTS_SMP_DATA_DEPENDENCY_READ_MEMORY_BARRIER ERTS_THR_DATA_DEPENDENCY_READ_MEMORY_BARRIER + #else /* #ifdef ERTS_SMP */ #define ERTS_SMP_THR_OPTS_DEFAULT_INITER {0} @@ -95,6 +100,11 @@ typedef struct { int gcc_is_buggy; } erts_smp_spinlock_t; typedef struct { int gcc_is_buggy; } erts_smp_rwlock_t; #endif +#define ERTS_SMP_MEMORY_BARRIER +#define ERTS_SMP_WRITE_MEMORY_BARRIER +#define ERTS_SMP_READ_MEMORY_BARRIER +#define ERTS_SMP_DATA_DEPENDENCY_READ_MEMORY_BARRIER + #endif /* #ifdef ERTS_SMP */ ERTS_GLB_INLINE void erts_smp_thr_init(erts_smp_thr_init_data_t *id); @@ -206,13 +216,8 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig); #endif /* #ifdef ERTS_THR_HAVE_SIG_FUNCS */ /* - * Functions implementing atomic operations with with no (nob), - * full (mb), acquire (acqb), release (relb), read (rb), and - * write (wb) memory barriers. - * - * If SMP support has been disabled, they are mapped to functions - * that performs the same operation, but aren't atomic and don't - * imply memory barriers. + * See "Documentation of atomics and memory barriers" at the top + * of erl_threads.h for info on atomics. */ #ifdef ERTS_SMP @@ -239,6 +244,11 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig); #define erts_smp_dw_atomic_read_relb erts_dw_atomic_read_relb #define erts_smp_dw_atomic_cmpxchg_relb erts_dw_atomic_cmpxchg_relb +#define erts_smp_dw_atomic_init_ddrb erts_dw_atomic_init_ddrb +#define erts_smp_dw_atomic_set_ddrb erts_dw_atomic_set_ddrb +#define erts_smp_dw_atomic_read_ddrb erts_dw_atomic_read_ddrb +#define erts_smp_dw_atomic_cmpxchg_ddrb erts_dw_atomic_cmpxchg_ddrb + #define erts_smp_dw_atomic_init_rb erts_dw_atomic_init_rb #define erts_smp_dw_atomic_set_rb erts_dw_atomic_set_rb #define erts_smp_dw_atomic_read_rb erts_dw_atomic_read_rb @@ -307,6 +317,20 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig); #define erts_smp_atomic_xchg_relb erts_atomic_xchg_relb #define erts_smp_atomic_cmpxchg_relb erts_atomic_cmpxchg_relb +#define erts_smp_atomic_init_ddrb erts_atomic_init_ddrb +#define erts_smp_atomic_set_ddrb erts_atomic_set_ddrb +#define erts_smp_atomic_read_ddrb erts_atomic_read_ddrb +#define erts_smp_atomic_inc_read_ddrb erts_atomic_inc_read_ddrb +#define erts_smp_atomic_dec_read_ddrb erts_atomic_dec_read_ddrb +#define erts_smp_atomic_inc_ddrb erts_atomic_inc_ddrb +#define erts_smp_atomic_dec_ddrb erts_atomic_dec_ddrb +#define erts_smp_atomic_add_read_ddrb erts_atomic_add_read_ddrb +#define erts_smp_atomic_add_ddrb erts_atomic_add_ddrb +#define erts_smp_atomic_read_bor_ddrb erts_atomic_read_bor_ddrb +#define erts_smp_atomic_read_band_ddrb erts_atomic_read_band_ddrb +#define erts_smp_atomic_xchg_ddrb erts_atomic_xchg_ddrb +#define erts_smp_atomic_cmpxchg_ddrb erts_atomic_cmpxchg_ddrb + #define erts_smp_atomic_init_rb erts_atomic_init_rb #define erts_smp_atomic_set_rb erts_atomic_set_rb #define erts_smp_atomic_read_rb erts_atomic_read_rb @@ -393,6 +417,20 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig); #define erts_smp_atomic32_xchg_relb erts_atomic32_xchg_relb #define erts_smp_atomic32_cmpxchg_relb erts_atomic32_cmpxchg_relb +#define erts_smp_atomic32_init_ddrb erts_atomic32_init_ddrb +#define erts_smp_atomic32_set_ddrb erts_atomic32_set_ddrb +#define erts_smp_atomic32_read_ddrb erts_atomic32_read_ddrb +#define erts_smp_atomic32_inc_read_ddrb erts_atomic32_inc_read_ddrb +#define erts_smp_atomic32_dec_read_ddrb erts_atomic32_dec_read_ddrb +#define erts_smp_atomic32_inc_ddrb erts_atomic32_inc_ddrb +#define erts_smp_atomic32_dec_ddrb erts_atomic32_dec_ddrb +#define erts_smp_atomic32_add_read_ddrb erts_atomic32_add_read_ddrb +#define erts_smp_atomic32_add_ddrb erts_atomic32_add_ddrb +#define erts_smp_atomic32_read_bor_ddrb erts_atomic32_read_bor_ddrb +#define erts_smp_atomic32_read_band_ddrb erts_atomic32_read_band_ddrb +#define erts_smp_atomic32_xchg_ddrb erts_atomic32_xchg_ddrb +#define erts_smp_atomic32_cmpxchg_ddrb erts_atomic32_cmpxchg_ddrb + #define erts_smp_atomic32_init_rb erts_atomic32_init_rb #define erts_smp_atomic32_set_rb erts_atomic32_set_rb #define erts_smp_atomic32_read_rb erts_atomic32_read_rb @@ -445,6 +483,11 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig); #define erts_smp_dw_atomic_read_relb erts_no_dw_atomic_read #define erts_smp_dw_atomic_cmpxchg_relb erts_no_dw_atomic_cmpxchg +#define erts_smp_dw_atomic_init_ddrb erts_no_dw_atomic_init +#define erts_smp_dw_atomic_set_ddrb erts_no_dw_atomic_set +#define erts_smp_dw_atomic_read_ddrb erts_no_dw_atomic_read +#define erts_smp_dw_atomic_cmpxchg_ddrb erts_no_dw_atomic_cmpxchg + #define erts_smp_dw_atomic_init_rb erts_no_dw_atomic_init #define erts_smp_dw_atomic_set_rb erts_no_dw_atomic_set #define erts_smp_dw_atomic_read_rb erts_no_dw_atomic_read @@ -513,6 +556,20 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig); #define erts_smp_atomic_xchg_relb erts_no_atomic_xchg #define erts_smp_atomic_cmpxchg_relb erts_no_atomic_cmpxchg +#define erts_smp_atomic_init_ddrb erts_no_atomic_set +#define erts_smp_atomic_set_ddrb erts_no_atomic_set +#define erts_smp_atomic_read_ddrb erts_no_atomic_read +#define erts_smp_atomic_inc_read_ddrb erts_no_atomic_inc_read +#define erts_smp_atomic_dec_read_ddrb erts_no_atomic_dec_read +#define erts_smp_atomic_inc_ddrb erts_no_atomic_inc +#define erts_smp_atomic_dec_ddrb erts_no_atomic_dec +#define erts_smp_atomic_add_read_ddrb erts_no_atomic_add_read +#define erts_smp_atomic_add_ddrb erts_no_atomic_add +#define erts_smp_atomic_read_bor_ddrb erts_no_atomic_read_bor +#define erts_smp_atomic_read_band_ddrb erts_no_atomic_read_band +#define erts_smp_atomic_xchg_ddrb erts_no_atomic_xchg +#define erts_smp_atomic_cmpxchg_ddrb erts_no_atomic_cmpxchg + #define erts_smp_atomic_init_rb erts_no_atomic_set #define erts_smp_atomic_set_rb erts_no_atomic_set #define erts_smp_atomic_read_rb erts_no_atomic_read @@ -599,6 +656,20 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig); #define erts_smp_atomic32_xchg_relb erts_no_atomic32_xchg #define erts_smp_atomic32_cmpxchg_relb erts_no_atomic32_cmpxchg +#define erts_smp_atomic32_init_ddrb erts_no_atomic32_set +#define erts_smp_atomic32_set_ddrb erts_no_atomic32_set +#define erts_smp_atomic32_read_ddrb erts_no_atomic32_read +#define erts_smp_atomic32_inc_read_ddrb erts_no_atomic32_inc_read +#define erts_smp_atomic32_dec_read_ddrb erts_no_atomic32_dec_read +#define erts_smp_atomic32_inc_ddrb erts_no_atomic32_inc +#define erts_smp_atomic32_dec_ddrb erts_no_atomic32_dec +#define erts_smp_atomic32_add_read_ddrb erts_no_atomic32_add_read +#define erts_smp_atomic32_add_ddrb erts_no_atomic32_add +#define erts_smp_atomic32_read_bor_ddrb erts_no_atomic32_read_bor +#define erts_smp_atomic32_read_band_ddrb erts_no_atomic32_read_band +#define erts_smp_atomic32_xchg_ddrb erts_no_atomic32_xchg +#define erts_smp_atomic32_cmpxchg_ddrb erts_no_atomic32_cmpxchg + #define erts_smp_atomic32_init_rb erts_no_atomic32_set #define erts_smp_atomic32_set_rb erts_no_atomic32_set #define erts_smp_atomic32_read_rb erts_no_atomic32_read diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h index bc20b2d798..c270d13365 100644 --- a/erts/emulator/beam/erl_term.h +++ b/erts/emulator/beam/erl_term.h @@ -253,15 +253,15 @@ _ET_DECLARE_CHECKED(Eterm*,list_val,Wterm) #define SMALL_BITS (28) #define SMALL_DIGITS (8) #endif -#define MAX_SMALL ((1L << (SMALL_BITS-1))-1) -#define MIN_SMALL (-(1L << (SMALL_BITS-1))) +#define MAX_SMALL ((SWORD_CONSTANT(1) << (SMALL_BITS-1))-1) +#define MIN_SMALL (-(SWORD_CONSTANT(1) << (SMALL_BITS-1))) #define make_small(x) (((Uint)(x) << _TAG_IMMED1_SIZE) + _TAG_IMMED1_SMALL) #define is_small(x) (((x) & _TAG_IMMED1_MASK) == _TAG_IMMED1_SMALL) #define is_not_small(x) (!is_small((x))) #define is_byte(x) (((x) & ((~(Uint)0 << (_TAG_IMMED1_SIZE+8)) + _TAG_IMMED1_MASK)) == _TAG_IMMED1_SMALL) #define is_valid_bit_size(x) (((Sint)(x)) >= 0 && ((x) & 0x7F) == _TAG_IMMED1_SMALL) #define is_not_valid_bit_size(x) (!is_valid_bit_size((x))) -#define MY_IS_SSMALL(x) (((Uint) (((x) >> (SMALL_BITS-1)) + 1)) < 2) +#define MY_IS_SSMALL(x) (((Uint) ((((x)) >> (SMALL_BITS-1)) + 1)) < 2) #define _unchecked_unsigned_val(x) ((x) >> _TAG_IMMED1_SIZE) _ET_DECLARE_CHECKED(Uint,unsigned_val,Eterm) #define unsigned_val(x) _ET_APPLY(unsigned_val,(x)) diff --git a/erts/emulator/beam/erl_thr_progress.c b/erts/emulator/beam/erl_thr_progress.c index 9324bcde51..9ef83746c5 100644 --- a/erts/emulator/beam/erl_thr_progress.c +++ b/erts/emulator/beam/erl_thr_progress.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011. All Rights Reserved. + * Copyright Ericsson AB 2011-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -33,10 +33,11 @@ * This module keeps track of the progress of a set of managed threads. Only * threads that behave well can be allowed to be managed. A managed thread * should update its thread progress frequently. Currently only scheduler - * threads and the aux_thread are managed threads. We typically do not want - * any async threads as managed threads since they cannot guarantee a - * frequent update of thread progress, since they execute user implemented - * driver code. + * threads, the system-message-dispatcher threads, and the aux-thread are + * managed threads. We typically do not want any async threads as managed + * threads since they cannot guarantee a frequent update of thread progress, + * since they execute user implemented driver code that is assumed to be + * time consuming. * * erts_thr_progress_current() returns the global current thread progress * value of managed threads. I.e., the latest progress value that all @@ -80,12 +81,12 @@ #ifdef ERTS_SMP -/* - * We use a 64-bit value for thread progress. By this wrapping of - * the thread progress will more or less never occur. - * - * On 32-bit systems we therefore need a double word atomic. - */ +#define ERTS_THR_PRGR_DBG_CHK_WAKEUP_REQUEST_VALUE 0 + +#ifdef DEBUG +#undef ERTS_THR_PRGR_DBG_CHK_WAKEUP_REQUEST_VALUE +#define ERTS_THR_PRGR_DBG_CHK_WAKEUP_REQUEST_VALUE 1 +#endif #define ERTS_THR_PRGR_PRINT_LEADER 0 #define ERTS_THR_PRGR_PRINT_VAL 0 @@ -106,7 +107,16 @@ |ERTS_THR_PRGR_LFLG_ACTIVE_MASK)) \ == ERTS_THR_PRGR_LFLG_NO_LEADER) +/* + * We use a 64-bit value for thread progress. By this wrapping of + * the thread progress will more or less never occur. + * + * On 32-bit systems we therefore need a double word atomic. + */ +#undef read_acqb #define read_acqb erts_thr_prgr_read_acqb__ +#undef read_nob +#define read_nob erts_thr_prgr_read_nob__ #ifdef ARCH_64 @@ -122,12 +132,6 @@ set_nob(ERTS_THR_PRGR_ATOMIC *atmc, ErtsThrPrgrVal val) erts_atomic_set_nob(atmc, val); } -static ERTS_INLINE ErtsThrPrgrVal -read_nob(ERTS_THR_PRGR_ATOMIC *atmc) -{ - return (ErtsThrPrgrVal) erts_atomic_read_nob(atmc); -} - static ERTS_INLINE void init_nob(ERTS_THR_PRGR_ATOMIC *atmc, ErtsThrPrgrVal val) { @@ -136,52 +140,44 @@ init_nob(ERTS_THR_PRGR_ATOMIC *atmc, ErtsThrPrgrVal val) #else -#undef dw_sint_to_val -#define dw_sint_to_val erts_thr_prgr_dw_sint_to_val__ +#undef dw_aint_to_val +#define dw_aint_to_val erts_thr_prgr_dw_aint_to_val__ static void -val_to_dw_sint(ethr_dw_sint_t *dw_sint, ErtsThrPrgrVal val) +val_to_dw_aint(erts_dw_aint_t *dw_aint, ErtsThrPrgrVal val) { #ifdef ETHR_SU_DW_NAINT_T__ - dw_sint->dw_sint = (ETHR_SU_DW_NAINT_T__) val; + dw_aint->dw_sint = (ETHR_SU_DW_NAINT_T__) val; #else - dw_sint->sint[ETHR_DW_SINT_LOW_WORD] - = (ethr_sint_t) (val & 0xffffffff); - dw_sint->sint[ETHR_DW_SINT_HIGH_WORD] - = (ethr_sint_t) ((val >> 32) & 0xffffffff); + dw_aint->sint[ERTS_DW_AINT_LOW_WORD] + = (erts_aint_t) (val & 0xffffffff); + dw_aint->sint[ERTS_DW_AINT_HIGH_WORD] + = (erts_aint_t) ((val >> 32) & 0xffffffff); #endif } static ERTS_INLINE void set_mb(ERTS_THR_PRGR_ATOMIC *atmc, ErtsThrPrgrVal val) { - ethr_dw_sint_t dw_sint; - val_to_dw_sint(&dw_sint, val); - erts_dw_atomic_set_mb(atmc, &dw_sint); + erts_dw_aint_t dw_aint; + val_to_dw_aint(&dw_aint, val); + erts_dw_atomic_set_mb(atmc, &dw_aint); } static ERTS_INLINE void set_nob(ERTS_THR_PRGR_ATOMIC *atmc, ErtsThrPrgrVal val) { - ethr_dw_sint_t dw_sint; - val_to_dw_sint(&dw_sint, val); - erts_dw_atomic_set_nob(atmc, &dw_sint); -} - -static ERTS_INLINE ErtsThrPrgrVal -read_nob(ERTS_THR_PRGR_ATOMIC *atmc) -{ - ethr_dw_sint_t dw_sint; - erts_dw_atomic_read_nob(atmc, &dw_sint); - return erts_thr_prgr_dw_sint_to_val__(&dw_sint); + erts_dw_aint_t dw_aint; + val_to_dw_aint(&dw_aint, val); + erts_dw_atomic_set_nob(atmc, &dw_aint); } static ERTS_INLINE void init_nob(ERTS_THR_PRGR_ATOMIC *atmc, ErtsThrPrgrVal val) { - ethr_dw_sint_t dw_sint; - val_to_dw_sint(&dw_sint, val); - erts_dw_atomic_init_nob(atmc, &dw_sint); + erts_dw_aint_t dw_aint; + val_to_dw_aint(&dw_aint, val); + erts_dw_atomic_init_nob(atmc, &dw_aint); } #endif @@ -908,7 +904,7 @@ has_reached_wakeup(ErtsThrPrgrVal wakeup) if (limit == ERTS_THR_PRGR_VAL_WAITING) limit = 0; else if (limit < current) /* Wrapped */ - limit + 1; + limit += 1; if (!erts_thr_progress_has_passed__(limit, wakeup)) erl_exit(ERTS_ABORT_EXIT, @@ -937,8 +933,10 @@ request_wakeup_managed(ErtsThrPrgrData *tpd, ErtsThrPrgrVal value) ASSERT(tpd->is_managed); ASSERT(tpd->previous.local != ERTS_THR_PRGR_VAL_WAITING); - if (has_reached_wakeup(value)) + if (has_reached_wakeup(value)) { wakeup_managed(tpd->id); + return; + } wix = ERTS_THR_PRGR_WAKEUP_IX(value); if (tpd->wakeup_request[wix] == value) @@ -976,6 +974,10 @@ request_wakeup_managed(ErtsThrPrgrData *tpd, ErtsThrPrgrVal value) mwd = intrnl->managed.data[wix]; ix = erts_atomic32_inc_read_nob(&mwd->len) - 1; +#if ERTS_THR_PRGR_DBG_CHK_WAKEUP_REQUEST_VALUE + if (ix >= intrnl->managed.no) + erl_exit(ERTS_ABORT_EXIT, "Internal error: Too many wakeup requests\n"); +#endif mwd->id[ix] = tpd->id; ASSERT(!erts_thr_progress_has_reached(value)); @@ -1001,8 +1003,10 @@ request_wakeup_unmanaged(ErtsThrPrgrData *tpd, ErtsThrPrgrVal value) * we are writing the request. */ - if (has_reached_wakeup(value)) + if (has_reached_wakeup(value)) { wakeup_unmanaged(tpd->id); + return; + } wix = ERTS_THR_PRGR_WAKEUP_IX(value); @@ -1207,9 +1211,9 @@ erts_thr_progress_block(void) } void -erts_thr_progress_fatal_error_block(SWord timeout) +erts_thr_progress_fatal_error_block(SWord timeout, + ErtsThrPrgrData *tmp_tpd_bufp) { - ErtsThrPrgrData tpd_buf; ErtsThrPrgrData *tpd = perhaps_thr_prgr_data(NULL); erts_aint32_t bc; SWord time_left = timeout; @@ -1233,7 +1237,7 @@ erts_thr_progress_fatal_error_block(SWord timeout) * since we never complete an unblock after a fatal error * block. */ - tpd = &tpd_buf; + tpd = tmp_tpd_bufp; init_tmp_thr_prgr_data(tpd); } diff --git a/erts/emulator/beam/erl_thr_progress.h b/erts/emulator/beam/erl_thr_progress.h index 68d14174b9..a71724b813 100644 --- a/erts/emulator/beam/erl_thr_progress.h +++ b/erts/emulator/beam/erl_thr_progress.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011. All Rights Reserved. + * Copyright Ericsson AB 2011-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -44,7 +44,6 @@ #define erts_smp_thr_progress_unblock erts_thr_progress_unblock #define erts_smp_thr_progress_is_blocking erts_thr_progress_is_blocking -void erts_thr_progress_fatal_error_block(SWord timeout); void erts_thr_progress_block(void); void erts_thr_progress_unblock(void); int erts_thr_progress_is_blocking(void); @@ -73,6 +72,10 @@ typedef struct { ErtsThrPrgrVal current; } previous; } ErtsThrPrgrData; + +void erts_thr_progress_fatal_error_block(SWord timeout, + ErtsThrPrgrData *tmp_tpd_bufp); + #endif /* ERTS_SMP */ #endif @@ -86,6 +89,7 @@ typedef struct { #ifdef ERTS_SMP #define ERTS_THR_PRGR_VAL_WAITING (~((ErtsThrPrgrVal) 0)) +#define ERTS_THR_PRGR_INVALID (~((ErtsThrPrgrVal) 0)) extern erts_tsd_key_t erts_thr_prgr_data_key__; @@ -127,14 +131,20 @@ void erts_thr_progress_dbg_print_state(void); #ifdef ARCH_32 #define ERTS_THR_PRGR_ATOMIC erts_dw_atomic_t -ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_prgr_dw_sint_to_val__(ethr_dw_sint_t *dw_sint); +ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_prgr_dw_aint_to_val__(erts_dw_aint_t *dw_aint); #endif +ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_prgr_read_nob__(ERTS_THR_PRGR_ATOMIC *atmc); ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_prgr_read_acqb__(ERTS_THR_PRGR_ATOMIC *atmc); +ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_prgr_read_mb__(ERTS_THR_PRGR_ATOMIC *atmc); ERTS_GLB_INLINE int erts_thr_progress_is_managed_thread(void); +ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_progress_current_to_later__(ErtsThrPrgrVal val); +ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_progress_later_than(ErtsThrPrgrVal val); ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_progress_later(void); ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_progress_current(void); ERTS_GLB_INLINE int erts_thr_progress_has_passed__(ErtsThrPrgrVal val1, ErtsThrPrgrVal val2); +ERTS_GLB_INLINE int erts_thr_progress_has_reached_this(ErtsThrPrgrVal this, ErtsThrPrgrVal val); +ERTS_GLB_INLINE int erts_thr_progress_cmp(ErtsThrPrgrVal val1, ErtsThrPrgrVal val2); ERTS_GLB_INLINE int erts_thr_progress_has_reached(ErtsThrPrgrVal val); #if ERTS_GLB_INLINE_INCL_FUNC_DEF @@ -142,33 +152,61 @@ ERTS_GLB_INLINE int erts_thr_progress_has_reached(ErtsThrPrgrVal val); #ifdef ARCH_64 ERTS_GLB_INLINE ErtsThrPrgrVal +erts_thr_prgr_read_nob__(ERTS_THR_PRGR_ATOMIC *atmc) +{ + return (ErtsThrPrgrVal) erts_atomic_read_nob(atmc); +} + +ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_prgr_read_acqb__(ERTS_THR_PRGR_ATOMIC *atmc) { return (ErtsThrPrgrVal) erts_atomic_read_acqb(atmc); } +ERTS_GLB_INLINE ErtsThrPrgrVal +erts_thr_prgr_read_mb__(ERTS_THR_PRGR_ATOMIC *atmc) +{ + return (ErtsThrPrgrVal) erts_atomic_read_mb(atmc); +} + #else /* ARCH_32 */ ERTS_GLB_INLINE ErtsThrPrgrVal -erts_thr_prgr_dw_sint_to_val__(ethr_dw_sint_t *dw_sint) +erts_thr_prgr_dw_aint_to_val__(erts_dw_aint_t *dw_aint) { #ifdef ETHR_SU_DW_NAINT_T__ - return (ErtsThrPrgrVal) dw_sint->dw_sint; + return (ErtsThrPrgrVal) dw_aint->dw_sint; #else ErtsThrPrgrVal res; - res = (ErtsThrPrgrVal) ((Uint32) dw_sint->sint[ETHR_DW_SINT_HIGH_WORD]); + res = (ErtsThrPrgrVal) ((Uint32) dw_aint->sint[ERTS_DW_AINT_HIGH_WORD]); res <<= 32; - res |= (ErtsThrPrgrVal) ((Uint32) dw_sint->sint[ETHR_DW_SINT_LOW_WORD]); + res |= (ErtsThrPrgrVal) ((Uint32) dw_aint->sint[ERTS_DW_AINT_LOW_WORD]); return res; #endif } ERTS_GLB_INLINE ErtsThrPrgrVal +erts_thr_prgr_read_nob__(ERTS_THR_PRGR_ATOMIC *atmc) +{ + erts_dw_aint_t dw_aint; + erts_dw_atomic_read_nob(atmc, &dw_aint); + return erts_thr_prgr_dw_aint_to_val__(&dw_aint); +} + +ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_prgr_read_acqb__(ERTS_THR_PRGR_ATOMIC *atmc) { - ethr_dw_sint_t dw_sint; - erts_dw_atomic_read_acqb(atmc, &dw_sint); - return erts_thr_prgr_dw_sint_to_val__(&dw_sint); + erts_dw_aint_t dw_aint; + erts_dw_atomic_read_acqb(atmc, &dw_aint); + return erts_thr_prgr_dw_aint_to_val__(&dw_aint); +} + +ERTS_GLB_INLINE ErtsThrPrgrVal +erts_thr_prgr_read_mb__(ERTS_THR_PRGR_ATOMIC *atmc) +{ + erts_dw_aint_t dw_aint; + erts_dw_atomic_read_mb(atmc, &dw_aint); + return erts_thr_prgr_dw_aint_to_val__(&dw_aint); } #endif @@ -181,9 +219,8 @@ erts_thr_progress_is_managed_thread(void) } ERTS_GLB_INLINE ErtsThrPrgrVal -erts_thr_progress_later(void) +erts_thr_progress_current_to_later__(ErtsThrPrgrVal val) { - ErtsThrPrgrVal val = erts_thr_prgr_read_acqb__(&erts_thr_prgr__.current); if (val == (ERTS_THR_PRGR_VAL_WAITING-((ErtsThrPrgrVal)2))) return ((ErtsThrPrgrVal) 0); else if (val == (ERTS_THR_PRGR_VAL_WAITING-((ErtsThrPrgrVal)1))) @@ -193,9 +230,26 @@ erts_thr_progress_later(void) } ERTS_GLB_INLINE ErtsThrPrgrVal +erts_thr_progress_later_than(ErtsThrPrgrVal val) +{ + ERTS_THR_MEMORY_BARRIER; + return erts_thr_progress_current_to_later__(val); +} + +ERTS_GLB_INLINE ErtsThrPrgrVal +erts_thr_progress_later(void) +{ + ErtsThrPrgrVal val = erts_thr_prgr_read_mb__(&erts_thr_prgr__.current); + return erts_thr_progress_current_to_later__(val); +} + +ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_progress_current(void) { - return erts_thr_prgr_read_acqb__(&erts_thr_prgr__.current); + if (erts_thr_progress_is_managed_thread()) + return erts_thr_prgr_read_nob__(&erts_thr_prgr__.current); + else + return erts_thr_prgr_read_acqb__(&erts_thr_prgr__.current); } ERTS_GLB_INLINE int @@ -217,13 +271,29 @@ erts_thr_progress_has_passed__(ErtsThrPrgrVal val1, ErtsThrPrgrVal val0) } ERTS_GLB_INLINE int -erts_thr_progress_has_reached(ErtsThrPrgrVal val) +erts_thr_progress_has_reached_this(ErtsThrPrgrVal this, ErtsThrPrgrVal val) { - ErtsThrPrgrVal current; - current = erts_thr_prgr_read_acqb__(&erts_thr_prgr__.current); - if (current == val) + if (this == val) return 1; - return erts_thr_progress_has_passed__(current, val); + return erts_thr_progress_has_passed__(this, val); +} + +ERTS_GLB_INLINE int +erts_thr_progress_cmp(ErtsThrPrgrVal val1, ErtsThrPrgrVal val2) +{ + if (val1 == val2) + return 0; + if (erts_thr_progress_has_passed__(val1, val2)) + return 1; + else + return -1; +} + +ERTS_GLB_INLINE int +erts_thr_progress_has_reached(ErtsThrPrgrVal val) +{ + ErtsThrPrgrVal current = erts_thr_progress_current(); + return erts_thr_progress_has_reached_this(current, val); } #endif diff --git a/erts/emulator/beam/erl_thr_queue.c b/erts/emulator/beam/erl_thr_queue.c index 9ac4cd4b8e..70949ece76 100644 --- a/erts/emulator/beam/erl_thr_queue.c +++ b/erts/emulator/beam/erl_thr_queue.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011. All Rights Reserved. + * Copyright Ericsson AB 2011-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -418,10 +418,9 @@ clean(ErtsThrQ_t *q, int max_ops, int do_notify) } if (q->head.unref_end == (ErtsThrQElement_t *) ilast) - ERTS_THR_MEMORY_BARRIER; + ERTS_SMP_MEMORY_BARRIER; else { q->head.next.unref_end = (ErtsThrQElement_t *) ilast; - ERTS_THR_MEMORY_BARRIER; #ifdef ERTS_SMP q->head.next.thr_progress = erts_thr_progress_later(); #endif @@ -449,32 +448,44 @@ clean(ErtsThrQ_t *q, int max_ops, int do_notify) if (inext == (erts_aint_t) &q->tail.data.marker) { q->head.head.ptr->next.ptr = &q->tail.data.marker; q->head.head.ptr = &q->tail.data.marker; -#ifdef ERTS_SMP - if (!q->head.next.thr_progress_reached) - return ERTS_THR_Q_NEED_THR_PRGR; -#else - if (do_notify) - q->head.notify(q->head.arg); -#endif - return ERTS_THR_Q_DIRTY; + goto check_thr_progress; } } } + + if (q->q.finalizing) { + ilast = erts_atomic_read_nob(&q->tail.data.last); + if (q->head.first == ((ErtsThrQElement_t *) ilast) + && ((ErtsThrQElement_t *) ilast) == &q->tail.data.marker + && q->head.first == &q->tail.data.marker) { + destroy(q); + } + else { + goto dirty; + } + } return ERTS_THR_Q_CLEAN; } - if (q->head.first != q->head.unref_end) { - if (do_notify) - q->head.notify(q->head.arg); - return ERTS_THR_Q_DIRTY; - } + if (q->head.first != q->head.unref_end) + goto dirty; + +check_thr_progress: #ifdef ERTS_SMP - if (!q->head.next.thr_progress_reached) - return ERTS_THR_Q_NEED_THR_PRGR; + if (q->head.next.thr_progress_reached) #endif + { + int um_refc_ix = q->head.next.um_refc_ix; + if (erts_atomic_read_acqb(&q->tail.data.um_refc[um_refc_ix]) == 0) { + dirty: + if (do_notify) + q->head.notify(q->head.arg); + return ERTS_THR_Q_DIRTY; + } + } - return ERTS_THR_Q_CLEAN; /* Waiting for unmanaged threads to complete... */ + return ERTS_THR_Q_NEED_THR_PRGR; } #endif @@ -492,7 +503,9 @@ erts_thr_q_clean(ErtsThrQ_t *q) ErtsThrQCleanState_t erts_thr_q_inspect(ErtsThrQ_t *q, int ensure_empty) { -#ifdef USE_THREADS +#ifndef USE_THREADS + return ERTS_THR_Q_CLEAN; +#else if (ensure_empty) { erts_aint_t inext; inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc); @@ -523,11 +536,15 @@ erts_thr_q_inspect(ErtsThrQ_t *q, int ensure_empty) return ERTS_THR_Q_DIRTY; #ifdef ERTS_SMP - if (!q->head.next.thr_progress_reached) - return ERTS_THR_Q_NEED_THR_PRGR; + if (q->head.next.thr_progress_reached) #endif + { + int um_refc_ix = q->head.next.um_refc_ix; + if (erts_atomic_read_acqb(&q->tail.data.um_refc[um_refc_ix]) == 0) + return ERTS_THR_Q_DIRTY; + } + return ERTS_THR_Q_NEED_THR_PRGR; #endif - return ERTS_THR_Q_CLEAN; } static void diff --git a/erts/emulator/beam/erl_thr_queue.h b/erts/emulator/beam/erl_thr_queue.h index 407c23f5eb..edcf2c3823 100644 --- a/erts/emulator/beam/erl_thr_queue.h +++ b/erts/emulator/beam/erl_thr_queue.h @@ -96,9 +96,7 @@ typedef struct { typedef enum { ERTS_THR_Q_CLEAN, -#ifdef ERTS_SMP ERTS_THR_Q_NEED_THR_PRGR, -#endif ERTS_THR_Q_DIRTY, } ErtsThrQCleanState_t; diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h index 065e7077c0..ee47c98009 100644 --- a/erts/emulator/beam/erl_threads.h +++ b/erts/emulator/beam/erl_threads.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2001-2011. All Rights Reserved. + * Copyright Ericsson AB 2001-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -25,6 +25,235 @@ #ifndef ERL_THREAD_H__ #define ERL_THREAD_H__ +/* + * --- Documentation of atomics and memory barriers -------------------------- + * + * The following explicit memory barriers exist: + * + * - ERTS_THR_MEMORY_BARRIER + * Full memory barrier. Orders both loads, and stores. No + * load or store is allowed to be reordered over the + * barrier. + * - ERTS_THR_WRITE_MEMORY_BARRIER + * Write barrier. Orders *only* stores. These are not + * allowed to be reordered over the barrier. + * - ERTS_THR_READ_MEMORY_BARRIER + * Read barrier. Orders *only* loads. These are not + * allowed to be reordered over the barrier. + * - ERTS_THR_DATA_DEPENDENCY_READ_MEMORY_BARRIER + * Data dependency read barrier. Orders *only* loads + * according to data dependency across the barrier. + * + * If thread support has been disabled, these barriers will become no-ops. + * + * If the prefix ERTS_THR_ is replaced with ERTS_SMP_, the barriers will + * be enabled only in the SMP enabled runtime system. + * + * --- Atomic operations --- + * + * Atomics operations exist for 32-bit, word size, and double word size + * integers. Function prototypes are listed below. + * + * Each function implementing an atomic operation exist with the following + * implied memory barrier semantics. Not all combinations are useful, but + * all of them exist for simplicity. <B> is suffix in function name: + * + * - <B> - Description + * + * - mb - Full memory barrier. Orders both loads, and + * stores before, and after the atomic operation. + * No load or store is allowed to be reordered + * over the atomic operation. + * - relb - Release barrier. Orders both loads, and + * stores appearing *before* the atomic + * operation. These are not allowed to be + * reordered over the atomic operation. + * - acqb - Acquire barrier. Orders both loads, and stores + * appearing *after* the atomic operation. These + * are not allowed to be reordered over the + * atomic operation. + * - wb - Write barrier. Orders *only* stores. These are + * not allowed to be reordered over the barrier. + * Store in atomic operation is ordered *after* + * the barrier. + * - rb - Read barrier. Orders *only* loads. These are + * not allowed to be reordered over the barrier. + * Load in atomic operation is ordered *before* + * the barrier. + * - ddrb - Data dependency read barrier. Orders *only* + * loads according to data dependency across the + * barrier. Load in atomic operation is ordered + * before the barrier. + * + * If thread support has been disabled, these functions are mapped to + * functions that performs the same operation, but aren't atomic + * and don't imply any memory barriers. + * + * If the atomic operations are prefixed with erts_smp_ instead of only + * erts_ the atomic operations will only be atomic in the SMP enabled + * runtime system, and will be mapped to non-atomic operations without + * memory barriers in the runtime system without SMP support. Atomic + * operations with erts_smp_ prefix should use the atomic types + * erts_smp_atomic32_t, erts_smp_atomic_t, and erts_smp_dw_atomic_t + * instead of erts_atomic32_t, erts_atomic_t, and erts_dw_atomic_t. The + * integer data types erts_aint32_t, erts_aint_t, and erts_dw_atomic_t + * are the same. + * + * --- 32-bit atomic operations --- + * + * The following 32-bit atomic operations exist. <B> should be + * replaced with a supported memory barrier (see above). Note + * that sizeof(erts_atomic32_t) might be larger than 4! + * + * + * Initialize (not necessarily the same as the set operation): + * void erts_atomic32_init_<B>(erts_atomic32_t *atmc, + * erts_aint32_t val); + * + * Set value: + * void erts_atomic32_set_<B>(erts_atomic32_t *atmc, + * erts_aint32_t val); + * + * Read; returns current value: + * erts_aint32_t erts_atomic32_read_<B>(erts_atomic32_t *atmc); + * + * Increment; returns resulting value: + * erts_aint32_t erts_atomic32_inc_read_<B>(erts_atomic32_t *atmc); + * + * Decrement; returns resulting value: + * erts_aint32_t erts_atomic32_dec_read_<B>(erts_atomic32_t *atmc); + * + * Increment: + * void erts_atomic32_inc_<B>(erts_atomic32_t *atmc); + * + * Decrement: + * void erts_atomic32_dec_<B>(erts_atomic32_t *atmc); + * + * Add value; returns resulting value: + * erts_aint32_t erts_atomic32_add_read_<B>(erts_atomic32_t *atmc, + * erts_aint32_t val); + * + * Add value: + * void erts_atomic32_add_<B>(erts_atomic32_t *atmc, + * erts_aint32_t val); + * + * Bitwise-or; returns previous value: + * erts_aint32_t erts_atomic32_read_bor_<B>(erts_atomic32_t *atmc, + * erts_aint32_t val); + * + * Bitwise-and; returns previous value: + * erts_aint32_t erts_atomic32_read_band_<B>(erts_atomic32_t *atmc, + * erts_aint32_t val); + * + * Exchange; returns previous value: + * erts_aint32_t erts_atomic32_xchg_<B>(erts_atomic32_t *atmc, + * erts_aint32_t val); + * + * Compare and exchange; returns previous or current value. If + * returned value equals 'exp' the value was changed to 'new'; + * otherwise not: + * erts_aint32_t erts_atomic32_cmpxchg_<B>(erts_atomic32_t *a, + * erts_aint32_t new, + * erts_aint32_t exp); + * + * --- Word size atomic operations --- + * + * The following word size (same size as sizeof(void *)) atomic + * operations exist. <B> should be replaced with a supported + * memory barrier (see above). Note that sizeof(erts_atomic_t) + * might be larger than sizeof(void *)! + * + * Initialize (not necessarily the same as the set operation): + * void erts_atomic_init_<B>(erts_atomic_t *atmc, + * erts_aint_t val); + * + * Set value; + * void erts_atomic_set_<B>(erts_atomic_t *atmc, + * erts_aint_t val); + * + * Read; returns current value: + * erts_aint_t erts_atomic_read_<B>(erts_atomic_t *atmc); + * + * Increment; returns resulting value: + * erts_aint_t erts_atomic_inc_read_<B>(erts_atomic_t *atmc); + * + * Decrement; returns resulting value: + * erts_aint_t erts_atomic_dec_read_<B>(erts_atomic_t *atmc); + * + * Increment: + * void erts_atomic_inc_<B>(erts_atomic_t *atmc); + * + * Decrement: + * void erts_atomic_dec_<B>(erts_atomic_t *atmc); + * + * Add value; returns resulting value: + * erts_aint_t erts_atomic_add_read_<B>(erts_atomic_t *atmc, + * erts_aint_t val); + * + * Add value: + * void erts_atomic_add_<B>(erts_atomic_t *atmc, + * erts_aint_t val); + * + * Bitwise-or; returns previous value: + * erts_aint_t erts_atomic_read_bor_<B>(erts_atomic_t *atmc, + * erts_aint_t val); + * + * Bitwise-and; returns previous value: + * erts_aint_t erts_atomic_read_band_<B>(erts_atomic_t *atmc, + * erts_aint_t val); + * + * Exchange; returns previous value: + * erts_aint_t erts_atomic_xchg_<B>(erts_atomic_t *atmc, + * erts_aint_t val); + * + * Compare and exchange; returns previous or current value. If + * returned value equals 'exp' the value was changed to 'new'; + * otherwise not: + * erts_aint_t erts_atomic_cmpxchg_<B>(erts_atomic_t *a, + * erts_aint_t new, + * erts_aint_t exp); + * + * --- Double word size atomic operations --- + * + * The following double word atomic operations exist. <B> should be + * replaced with a supported memory barrier (see above). + * + * Note that sizeof(erts_dw_atomic_t) usually is larger than + * 2*sizeof(void *)! + * + * The erts_dw_aint_t data type should be accessed as if it was defined + * like this: + * + * typedef struct { + * erts_aint_t sint[2]; + * } erts_dw_aint_t; + * + * Most significant word is 'sint[ERTS_DW_AINT_HIGH_WORD]' and least + * significant word is 'sint[ERTS_DW_AINT_LOW_WORD]'. + * + * + * Initialize (not necessarily the same as the set operation): + * void erts_dw_atomic_init_<B>(erts_dw_atomic_t *var, + * erts_dw_aint_t *val); + * + * Set; value is written into 'val': + * void erts_dw_atomic_set_<B>(erts_dw_atomic_t *var, + * erts_dw_aint_t *val); + * + * Read; value is written into 'val': + * void erts_dw_atomic_read_<B>(erts_dw_atomic_t *var, + * erts_dw_aint_t *val); + * + * Compare and exchange; returns a value != 0 if exchange was + * made; otherwise 0. 'new_val' contains new value to set. If 'exp_act' + * contains the same value as in memory when the function is called, + * 'new' is written to memory; otherwise, not. If exchange was not + * made, 'exp_act' contains the actual value in memory: + * int erts_dw_atomic_cmpxchg_<B>(erts_dw_atomic_t *var, + * erts_dw_aint_t *new, + * erts_dw_aint_t *exp_act); + */ + #define ERTS_SPIN_BODY ETHR_SPIN_BODY #include "sys.h" @@ -52,6 +281,9 @@ typedef Sint32 erts_no_atomic32_t; #endif #define ERTS_THR_MEMORY_BARRIER ETHR_MEMORY_BARRIER +#define ERTS_THR_WRITE_MEMORY_BARRIER ETHR_WRITE_MEMORY_BARRIER +#define ERTS_THR_READ_MEMORY_BARRIER ETHR_READ_MEMORY_BARRIER +#define ERTS_THR_DATA_DEPENDENCY_READ_MEMORY_BARRIER ETHR_READ_DEPEND_MEMORY_BARRIER #ifdef ERTS_ENABLE_LOCK_COUNT #define erts_mtx_lock(L) erts_mtx_lock_x(L, __FILE__, __LINE__) @@ -113,6 +345,9 @@ typedef ethr_ts_event erts_tse_t; #define erts_aint32_t ethr_sint32_t #define erts_atomic32_t ethr_atomic32_t +#define ERTS_DW_AINT_HIGH_WORD ETHR_DW_SINT_HIGH_WORD +#define ERTS_DW_AINT_LOW_WORD ETHR_DW_SINT_LOW_WORD + /* spinlock */ typedef struct { ethr_spinlock_t slck; @@ -149,6 +384,9 @@ __decl_noreturn void __noreturn erts_thr_fatal_error(int, char *); #else /* #ifdef USE_THREADS */ #define ERTS_THR_MEMORY_BARRIER +#define ERTS_THR_WRITE_MEMORY_BARRIER +#define ERTS_THR_READ_MEMORY_BARRIER +#define ERTS_THR_DATA_DEPENDENCY_READ_MEMORY_BARRIER #define ERTS_THR_OPTS_DEFAULT_INITER 0 typedef int erts_thr_opts_t; @@ -361,18 +599,13 @@ ERTS_GLB_INLINE void erts_thr_sigmask(int how, const sigset_t *set, ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig); #endif /* #ifdef HAVE_ETHR_SIG_FUNCS */ +#ifdef USE_THREADS + /* - * Functions implementing atomic operations with with no (nob), - * full (mb), acquire (acqb), release (relb), read (rb), and - * write (wb) memory barriers. - * - * If thread support has been disabled, they are mapped to - * functions that performs the same operation, but aren't atomic - * and don't imply memory barriers. + * See "Documentation of atomics and memory barriers" at the top + * of this file for info on atomics. */ -#ifdef USE_THREADS - /* Double word size atomics */ #define erts_dw_atomic_init_nob ethr_dw_atomic_init @@ -395,6 +628,11 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig); #define erts_dw_atomic_read_relb ethr_dw_atomic_read_relb #define erts_dw_atomic_cmpxchg_relb ethr_dw_atomic_cmpxchg_relb +#define erts_dw_atomic_init_ddrb ethr_dw_atomic_init_ddrb +#define erts_dw_atomic_set_ddrb ethr_dw_atomic_set_ddrb +#define erts_dw_atomic_read_ddrb ethr_dw_atomic_read_ddrb +#define erts_dw_atomic_cmpxchg_ddrb ethr_dw_atomic_cmpxchg_ddrb + #define erts_dw_atomic_init_rb ethr_dw_atomic_init_rb #define erts_dw_atomic_set_rb ethr_dw_atomic_set_rb #define erts_dw_atomic_read_rb ethr_dw_atomic_read_rb @@ -463,6 +701,20 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig); #define erts_atomic_xchg_relb ethr_atomic_xchg_relb #define erts_atomic_cmpxchg_relb ethr_atomic_cmpxchg_relb +#define erts_atomic_init_ddrb ethr_atomic_init_ddrb +#define erts_atomic_set_ddrb ethr_atomic_set_ddrb +#define erts_atomic_read_ddrb ethr_atomic_read_ddrb +#define erts_atomic_inc_read_ddrb ethr_atomic_inc_read_ddrb +#define erts_atomic_dec_read_ddrb ethr_atomic_dec_read_ddrb +#define erts_atomic_inc_ddrb ethr_atomic_inc_ddrb +#define erts_atomic_dec_ddrb ethr_atomic_dec_ddrb +#define erts_atomic_add_read_ddrb ethr_atomic_add_read_ddrb +#define erts_atomic_add_ddrb ethr_atomic_add_ddrb +#define erts_atomic_read_bor_ddrb ethr_atomic_read_bor_ddrb +#define erts_atomic_read_band_ddrb ethr_atomic_read_band_ddrb +#define erts_atomic_xchg_ddrb ethr_atomic_xchg_ddrb +#define erts_atomic_cmpxchg_ddrb ethr_atomic_cmpxchg_ddrb + #define erts_atomic_init_rb ethr_atomic_init_rb #define erts_atomic_set_rb ethr_atomic_set_rb #define erts_atomic_read_rb ethr_atomic_read_rb @@ -549,6 +801,20 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig); #define erts_atomic32_xchg_relb ethr_atomic32_xchg_relb #define erts_atomic32_cmpxchg_relb ethr_atomic32_cmpxchg_relb +#define erts_atomic32_init_ddrb ethr_atomic32_init_ddrb +#define erts_atomic32_set_ddrb ethr_atomic32_set_ddrb +#define erts_atomic32_read_ddrb ethr_atomic32_read_ddrb +#define erts_atomic32_inc_read_ddrb ethr_atomic32_inc_read_ddrb +#define erts_atomic32_dec_read_ddrb ethr_atomic32_dec_read_ddrb +#define erts_atomic32_inc_ddrb ethr_atomic32_inc_ddrb +#define erts_atomic32_dec_ddrb ethr_atomic32_dec_ddrb +#define erts_atomic32_add_read_ddrb ethr_atomic32_add_read_ddrb +#define erts_atomic32_add_ddrb ethr_atomic32_add_ddrb +#define erts_atomic32_read_bor_ddrb ethr_atomic32_read_bor_ddrb +#define erts_atomic32_read_band_ddrb ethr_atomic32_read_band_ddrb +#define erts_atomic32_xchg_ddrb ethr_atomic32_xchg_ddrb +#define erts_atomic32_cmpxchg_ddrb ethr_atomic32_cmpxchg_ddrb + #define erts_atomic32_init_rb ethr_atomic32_init_rb #define erts_atomic32_set_rb ethr_atomic32_set_rb #define erts_atomic32_read_rb ethr_atomic32_read_rb @@ -601,6 +867,11 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig); #define erts_dw_atomic_read_relb erts_no_dw_atomic_read #define erts_dw_atomic_cmpxchg_relb erts_no_dw_atomic_cmpxchg +#define erts_dw_atomic_init_ddrb erts_no_dw_atomic_init +#define erts_dw_atomic_set_ddrb erts_no_dw_atomic_set +#define erts_dw_atomic_read_ddrb erts_no_dw_atomic_read +#define erts_dw_atomic_cmpxchg_ddrb erts_no_dw_atomic_cmpxchg + #define erts_dw_atomic_init_rb erts_no_dw_atomic_init #define erts_dw_atomic_set_rb erts_no_dw_atomic_set #define erts_dw_atomic_read_rb erts_no_dw_atomic_read @@ -669,6 +940,20 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig); #define erts_atomic_xchg_relb erts_no_atomic_xchg #define erts_atomic_cmpxchg_relb erts_no_atomic_cmpxchg +#define erts_atomic_init_ddrb erts_no_atomic_set +#define erts_atomic_set_ddrb erts_no_atomic_set +#define erts_atomic_read_ddrb erts_no_atomic_read +#define erts_atomic_inc_read_ddrb erts_no_atomic_inc_read +#define erts_atomic_dec_read_ddrb erts_no_atomic_dec_read +#define erts_atomic_inc_ddrb erts_no_atomic_inc +#define erts_atomic_dec_ddrb erts_no_atomic_dec +#define erts_atomic_add_read_ddrb erts_no_atomic_add_read +#define erts_atomic_add_ddrb erts_no_atomic_add +#define erts_atomic_read_bor_ddrb erts_no_atomic_read_bor +#define erts_atomic_read_band_ddrb erts_no_atomic_read_band +#define erts_atomic_xchg_ddrb erts_no_atomic_xchg +#define erts_atomic_cmpxchg_ddrb erts_no_atomic_cmpxchg + #define erts_atomic_init_rb erts_no_atomic_set #define erts_atomic_set_rb erts_no_atomic_set #define erts_atomic_read_rb erts_no_atomic_read @@ -755,6 +1040,20 @@ ERTS_GLB_INLINE void erts_thr_sigwait(const sigset_t *set, int *sig); #define erts_atomic32_xchg_relb erts_no_atomic32_xchg #define erts_atomic32_cmpxchg_relb erts_no_atomic32_cmpxchg +#define erts_atomic32_init_ddrb erts_no_atomic32_set +#define erts_atomic32_set_ddrb erts_no_atomic32_set +#define erts_atomic32_read_ddrb erts_no_atomic32_read +#define erts_atomic32_inc_read_ddrb erts_no_atomic32_inc_read +#define erts_atomic32_dec_read_ddrb erts_no_atomic32_dec_read +#define erts_atomic32_inc_ddrb erts_no_atomic32_inc +#define erts_atomic32_dec_ddrb erts_no_atomic32_dec +#define erts_atomic32_add_read_ddrb erts_no_atomic32_add_read +#define erts_atomic32_add_ddrb erts_no_atomic32_add +#define erts_atomic32_read_bor_ddrb erts_no_atomic32_read_bor +#define erts_atomic32_read_band_ddrb erts_no_atomic32_read_band +#define erts_atomic32_xchg_ddrb erts_no_atomic32_xchg +#define erts_atomic32_cmpxchg_ddrb erts_no_atomic32_cmpxchg + #define erts_atomic32_init_rb erts_no_atomic32_set #define erts_atomic32_set_rb erts_no_atomic32_set #define erts_atomic32_read_rb erts_no_atomic32_read diff --git a/erts/emulator/beam/erl_time.h b/erts/emulator/beam/erl_time.h index 7a09d30ff6..6c6e193818 100644 --- a/erts/emulator/beam/erl_time.h +++ b/erts/emulator/beam/erl_time.h @@ -20,7 +20,11 @@ #ifndef ERL_TIME_H__ #define ERL_TIME_H__ -extern erts_smp_atomic_t do_time; /* set at clock interrupt */ +#define ERTS_SHORT_TIME_T_MAX ERTS_AINT32_T_MAX +#define ERTS_SHORT_TIME_T_MIN ERTS_AINT32_T_MIN +typedef erts_aint32_t erts_short_time_t; + +extern erts_smp_atomic32_t do_time; /* set at clock interrupt */ extern SysTimeval erts_first_emu_time; /* @@ -71,22 +75,32 @@ void erts_cancel_smp_ptimer(ErtsSmpPTimer *ptimer); void erts_init_time(void); void erts_set_timer(ErlTimer*, ErlTimeoutProc, ErlCancelProc, void*, Uint); void erts_cancel_timer(ErlTimer*); -void erts_bump_timer(erts_aint_t); +void erts_bump_timer(erts_short_time_t); Uint erts_timer_wheel_memory_size(void); Uint erts_time_left(ErlTimer *); -erts_aint_t erts_next_time(void); +erts_short_time_t erts_next_time(void); #ifdef DEBUG void erts_p_slpq(void); #endif -ERTS_GLB_INLINE erts_aint_t erts_do_time_read_and_reset(void); -ERTS_GLB_INLINE void erts_do_time_add(long); +ERTS_GLB_INLINE erts_short_time_t erts_do_time_read_and_reset(void); +ERTS_GLB_INLINE void erts_do_time_add(erts_short_time_t); #if ERTS_GLB_INLINE_INCL_FUNC_DEF -ERTS_GLB_INLINE erts_aint_t erts_do_time_read_and_reset(void) { return erts_smp_atomic_xchg_acqb(&do_time, 0L); } -ERTS_GLB_INLINE void erts_do_time_add(long elapsed) { erts_smp_atomic_add_relb(&do_time, elapsed); } +ERTS_GLB_INLINE erts_short_time_t erts_do_time_read_and_reset(void) +{ + erts_short_time_t time = erts_smp_atomic32_xchg_acqb(&do_time, 0); + if (time < 0) + erl_exit(ERTS_ABORT_EXIT, "Internal time management error\n"); + return time; +} + +ERTS_GLB_INLINE void erts_do_time_add(erts_short_time_t elapsed) +{ + erts_smp_atomic32_add_relb(&do_time, elapsed); +} #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */ @@ -105,7 +119,7 @@ void erts_get_now_cpu(Uint* megasec, Uint* sec, Uint* microsec); #endif void erts_get_timeval(SysTimeval *tv); -long erts_get_time(void); +erts_time_t erts_get_time(void); void erts_get_emu_time(SysTimeval *); ERTS_GLB_INLINE int erts_cmp_timeval(SysTimeval *t1p, SysTimeval *t2p); diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index ca4b54188e..1d0735aa99 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2010. All Rights Reserved. + * Copyright Ericsson AB 1999-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -371,7 +371,7 @@ static void init_erts_deliver_time(const SysTimeval *inittv) static void do_erts_deliver_time(const SysTimeval *current) { SysTimeval cur_time; - long elapsed; + erts_time_t elapsed; /* calculate and deliver appropriate number of ticks */ cur_time = *current; @@ -385,7 +385,10 @@ static void do_erts_deliver_time(const SysTimeval *current) this by simply pretend as if the time stood still. :) */ if (elapsed > 0) { - erts_do_time_add(elapsed); + + ASSERT(elapsed < ((erts_time_t) ERTS_SHORT_TIME_T_MAX)); + + erts_do_time_add((erts_short_time_t) elapsed); last_delivered = cur_time; } } @@ -421,11 +424,11 @@ erts_init_time_sup(void) /* info functions */ void -elapsed_time_both(unsigned long *ms_user, unsigned long *ms_sys, - unsigned long *ms_user_diff, unsigned long *ms_sys_diff) +elapsed_time_both(UWord *ms_user, UWord *ms_sys, + UWord *ms_user_diff, UWord *ms_sys_diff) { - unsigned long prev_total_user, prev_total_sys; - unsigned long total_user, total_sys; + UWord prev_total_user, prev_total_sys; + UWord total_user, total_sys; SysTimes now; sys_times(&now); @@ -456,9 +459,9 @@ elapsed_time_both(unsigned long *ms_user, unsigned long *ms_sys, /* wall clock routines */ void -wall_clock_elapsed_time_both(unsigned long *ms_total, unsigned long *ms_diff) +wall_clock_elapsed_time_both(UWord *ms_total, UWord *ms_diff) { - unsigned long prev_total; + UWord prev_total; SysTimeval tv; erts_smp_mtx_lock(&erts_timeofday_mtx); @@ -491,7 +494,7 @@ get_time(int *hour, int *minute, int *second) the_clock = time((time_t *)0); #ifdef HAVE_LOCALTIME_R - localtime_r(&the_clock, (tm = &tmbuf)); + tm = localtime_r(&the_clock, &tmbuf); #else tm = localtime(&the_clock); #endif @@ -513,7 +516,7 @@ get_date(int *year, int *month, int *day) the_clock = time((time_t *)0); #ifdef HAVE_LOCALTIME_R - localtime_r(&the_clock, (tm = &tmbuf)); + tm = localtime_r(&the_clock, &tmbuf); #else tm = localtime(&the_clock); #endif @@ -583,7 +586,44 @@ static const int mdays[14] = {0, 31, 28, 31, 30, 31, 30, (((y) % 100) != 0)) || \ (((y) % 400) == 0)) -#define BASEYEAR 1970 +/* This is the earliest year we are sure to be able to handle + on all platforms w/o problems */ +#define BASEYEAR 1902 + +/* A more "clever" mktime + * return 1, if successful + * return -1, if not successful + */ + +static int erl_mktime(time_t *c, struct tm *tm) { + time_t clock; + + clock = mktime(tm); + + if (clock != -1) { + *c = clock; + return 1; + } + + /* in rare occasions mktime returns -1 + * when a correct value has been entered + * + * decrease seconds with one second + * if the result is -2, epochs should be -1 + */ + + tm->tm_sec = tm->tm_sec - 1; + clock = mktime(tm); + tm->tm_sec = tm->tm_sec + 1; + + *c = -1; + + if (clock == -2) { + return 1; + } + + return -1; +} /* * gregday @@ -592,10 +632,10 @@ static const int mdays[14] = {0, 31, 28, 31, 30, 31, 30, * greater of equal to 1600 , and month [1-12] and day [1-31] * are within range. Otherwise it returns -1. */ -static int long gregday(int year, int month, int day) +static time_t gregday(int year, int month, int day) { - int long ndays = 0; - int gyear, pyear, m; + Sint ndays = 0; + Sint gyear, pyear, m; /* number of days in previous years */ gyear = year - 1600; @@ -610,10 +650,72 @@ static int long gregday(int year, int month, int day) if (is_leap_year(year) && (month > 2)) ndays++; ndays += day - 1; - return ndays - 135140; /* 135140 = Jan 1, 1970 */ + return (time_t) (ndays - 135140); /* 135140 = Jan 1, 1970 */ +} + +#define SECONDS_PER_MINUTE (60) +#define SECONDS_PER_HOUR (60 * SECONDS_PER_MINUTE) +#define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR) + +int seconds_to_univ(Sint64 time, Sint *year, Sint *month, Sint *day, + Sint *hour, Sint *minute, Sint *second) { + + Sint y,mi; + Sint days = time / SECONDS_PER_DAY; + Sint secs = time % SECONDS_PER_DAY; + Sint tmp; + + if (secs < 0) { + days--; + secs += SECONDS_PER_DAY; + } + + tmp = secs % SECONDS_PER_HOUR; + + *hour = secs / SECONDS_PER_HOUR; + *minute = tmp / SECONDS_PER_MINUTE; + *second = tmp % SECONDS_PER_MINUTE; + + days += 719468; + y = (10000*((Sint64)days) + 14780) / 3652425; + tmp = days - (365 * y + y/4 - y/100 + y/400); + + if (tmp < 0) { + y--; + tmp = days - (365*y + y/4 - y/100 + y/400); + } + mi = (100 * tmp + 52)/3060; + *month = (mi + 2) % 12 + 1; + *year = y + (mi + 2) / 12; + *day = tmp - (mi * 306 + 5)/10 + 1; + + return 1; } +int univ_to_seconds(Sint year, Sint month, Sint day, Sint hour, Sint minute, Sint second, Sint64 *time) { + Sint days; + + if (!(IN_RANGE(1600, year, INT_MAX - 1) && + IN_RANGE(1, month, 12) && + IN_RANGE(1, day, (mdays[month] + + (month == 2 + && (year % 4 == 0) + && (year % 100 != 0 || year % 400 == 0)))) && + IN_RANGE(0, hour, 23) && + IN_RANGE(0, minute, 59) && + IN_RANGE(0, second, 59))) { + return 0; + } + + days = gregday(year, month, day); + *time = SECONDS_PER_DAY; + *time *= days; /* don't try overflow it, it hurts */ + *time += SECONDS_PER_HOUR * hour; + *time += SECONDS_PER_MINUTE * minute; + *time += second; + return 1; +} int local_to_univ(Sint *year, Sint *month, Sint *day, @@ -644,15 +746,18 @@ local_to_univ(Sint *year, Sint *month, Sint *day, t.tm_min = *minute; t.tm_sec = *second; t.tm_isdst = isdst; - the_clock = mktime(&t); - if (the_clock == -1) { + + /* the nature of mktime makes this a bit interesting, + * up to four mktime calls could happen here + */ + + if (erl_mktime(&the_clock, &t) < 0) { if (isdst) { /* If this is a timezone without DST and the OS (correctly) refuses to give us a DST time, we simulate the Linux/Solaris behaviour of giving the same data as if is_dst was not set. */ t.tm_isdst = 0; - the_clock = mktime(&t); - if (the_clock == -1) { + if (erl_mktime(&the_clock, &t)) { /* Failed anyway, something else is bad - will be a badarg */ return 0; } @@ -662,10 +767,13 @@ local_to_univ(Sint *year, Sint *month, Sint *day, } } #ifdef HAVE_GMTIME_R - gmtime_r(&the_clock, (tm = &tmbuf)); + tm = gmtime_r(&the_clock, &tmbuf); #else tm = gmtime(&the_clock); #endif + if (!tm) { + return 0; + } *year = tm->tm_year + 1900; *month = tm->tm_mon +1; *day = tm->tm_mday; @@ -719,17 +827,20 @@ univ_to_local(Sint *year, Sint *month, Sint *day, #endif #ifdef HAVE_LOCALTIME_R - localtime_r(&the_clock, (tm = &tmbuf)); + tm = localtime_r(&the_clock, &tmbuf); #else tm = localtime(&the_clock); #endif - *year = tm->tm_year + 1900; - *month = tm->tm_mon +1; - *day = tm->tm_mday; - *hour = tm->tm_hour; - *minute = tm->tm_min; - *second = tm->tm_sec; - return 1; + if (tm) { + *year = tm->tm_year + 1900; + *month = tm->tm_mon +1; + *day = tm->tm_mday; + *hour = tm->tm_hour; + *minute = tm->tm_min; + *second = tm->tm_sec; + return 1; + } + return 0; } @@ -798,13 +909,14 @@ void erts_deliver_time(void) { void erts_time_remaining(SysTimeval *rem_time) { - int ticks; + erts_time_t ticks; SysTimeval cur_time; - long elapsed; + erts_time_t elapsed; /* erts_next_time() returns no of ticks to next timeout or -1 if none */ - if ((ticks = erts_next_time()) == -1) { + ticks = (erts_time_t) erts_next_time(); + if (ticks == (erts_time_t) -1) { /* timer queue empty */ /* this will cause at most 100000000 ticks */ rem_time->tv_sec = 100000; @@ -839,7 +951,7 @@ void erts_get_timeval(SysTimeval *tv) erts_smp_mtx_unlock(&erts_timeofday_mtx); } -long +erts_time_t erts_get_time(void) { SysTimeval sys_tv; diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index b487dbf054..b1d1e1d9b0 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -544,7 +544,7 @@ send_to_port(Process *c_p, Eterm message, */ static void -profile_send(Eterm message) { +profile_send(Eterm from, Eterm message) { Uint sz = 0; ErlHeapFragment *bp = NULL; Uint *hp = NULL; @@ -554,6 +554,9 @@ profile_send(Eterm message) { Eterm profiler = erts_get_system_profile(); + /* do not profile profiler pid */ + if (from == profiler) return; + if (is_internal_port(profiler)) { Port *profiler_port = NULL; @@ -2617,7 +2620,7 @@ profile_scheduler(Eterm scheduler_id, Eterm state) { make_small(active_sched), timestamp); hp += 7; #ifndef ERTS_SMP - profile_send(msg); + profile_send(NIL, msg); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE #else @@ -2652,7 +2655,7 @@ profile_scheduler_q(Eterm scheduler_id, Eterm state, Eterm no_schedulers, Uint M timestamp = TUPLE3(hp, make_small(Ms), make_small(s), make_small(us)); hp += 4; msg = TUPLE6(hp, am_profile, am_scheduler, scheduler_id, state, no_schedulers, timestamp); hp += 7; #ifndef ERTS_SMP - profile_send(msg); + profile_send(NIL, msg); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE #else @@ -2919,11 +2922,11 @@ profile_runnable_port(Port *p, Eterm status) { msg = TUPLE5(hp, am_profile, p->id, status, count, timestamp); hp += 6; #ifndef ERTS_SMP - profile_send(msg); + profile_send(p->id, msg); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE #else - enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, NIL, NIL, msg, bp); + enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, p->id, NIL, msg, bp); #endif erts_smp_mtx_unlock(&smq_mtx); } @@ -2972,11 +2975,11 @@ profile_runnable_proc(Process *p, Eterm status){ timestamp = TUPLE3(hp, make_small(Ms), make_small(s), make_small(us)); hp += 4; msg = TUPLE5(hp, am_profile, p->id, status, where, timestamp); hp += 6; #ifndef ERTS_SMP - profile_send(msg); + profile_send(p->id, msg); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE #else - enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, NIL, NIL, msg, bp); + enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, p->id, NIL, msg, bp); #endif erts_smp_mtx_unlock(&smq_mtx); } diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c index 18d62dac1d..fb0ee99119 100644 --- a/erts/emulator/beam/export.c +++ b/erts/emulator/beam/export.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2010. All Rights Reserved. + * Copyright Ericsson AB 1996-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index 4b867f2b10..9d52ed4e98 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -46,7 +46,7 @@ #ifdef HIPE #include "hipe_mode_switch.h" #endif -#define in_area(ptr,start,nbytes) ((Uint)((char*)(ptr) - (char*)(start)) < (nbytes)) +#define in_area(ptr,start,nbytes) ((UWord)((char*)(ptr) - (char*)(start)) < (nbytes)) #define MAX_STRING_LEN 0xffff @@ -3118,6 +3118,9 @@ decoded_size(byte *ep, byte* endp, int internal_tags) case LARGE_BIG_EXT: CHKSIZE(4); n = get_int32(ep); + if (n > BIG_ARITY_MAX*sizeof(ErtsDigit)) { + return -1; + } SKIP2(n,4+1); /* skip, size,sign,digits */ heap_size += 1+1+(n+sizeof(Eterm)-1)/sizeof(Eterm); /* XXX: 1 too much? */ break; diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index b247576f1c..f1335f600d 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -47,7 +47,7 @@ typedef struct erts_driver_t_ erts_driver_t; #define SMALL_IO_QUEUE 5 /* Number of fixed elements */ typedef struct { - int size; /* total size in bytes */ + ErlDrvSizeT size; /* total size in bytes */ SysIOVec* v_start; SysIOVec* v_end; @@ -63,9 +63,9 @@ typedef struct { } ErlIOQueue; typedef struct line_buf { /* Buffer used in line oriented I/O */ - int bufsiz; /* Size of character buffer */ - int ovlen; /* Length of overflow data */ - int ovsiz; /* Actual size of overflow buffer */ + ErlDrvSizeT bufsiz; /* Size of character buffer */ + ErlDrvSizeT ovlen; /* Length of overflow data */ + ErlDrvSizeT ovsiz; /* Actual size of overflow buffer */ char data[1]; /* Starting point of buffer data, data[0] is a flag indicating an unprocess CR, The rest is the overflow buffer. */ @@ -172,7 +172,7 @@ struct port { DistEntry *dist_entry; /* Dist entry used in DISTRIBUTION */ char *name; /* String used in the open */ erts_driver_t* drv_ptr; - long drv_data; + UWord drv_data; ErtsProcList *suspended; /* List of suspended processes. */ LineBuf *linebuf; /* Buffer to hold data not ready for process to get (line oriented I/O)*/ @@ -205,7 +205,7 @@ erts_port_runq(Port *prt) rq1 = rq2; } #else - return erts_common_run_queue; + return ERTS_RUNQ_IX(0); #endif } @@ -323,12 +323,15 @@ struct erts_driver_t_ { void (*stop)(ErlDrvData drv_data); void (*finish)(void); void (*flush)(ErlDrvData drv_data); - void (*output)(ErlDrvData drv_data, char *buf, int len); + void (*output)(ErlDrvData drv_data, char *buf, ErlDrvSizeT len); void (*outputv)(ErlDrvData drv_data, ErlIOVec *ev); /* Might be NULL */ - int (*control)(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen); /* Might be NULL */ - int (*call)(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen, unsigned int *flags); /* Might be NULL */ + ErlDrvSSizeT (*control)(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen); /* Might be NULL */ + ErlDrvSSizeT (*call)(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, /* Might be NULL */ + unsigned int *flags); void (*event)(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_data); void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event); @@ -398,7 +401,7 @@ extern Eterm erts_ddll_monitor_driver(Process *p, typedef struct binary { ERTS_INTERNAL_BINARY_FIELDS - long orig_size; + SWord orig_size; char orig_bytes[1]; /* to be continued */ } Binary; @@ -407,7 +410,7 @@ typedef struct binary { typedef struct { ERTS_INTERNAL_BINARY_FIELDS - long orig_size; + SWord orig_size; void (*destructor)(Binary *); char magic_bin_data[1]; } ErtsMagicBinary; @@ -1053,7 +1056,8 @@ extern int erts_do_net_exits(DistEntry*, Eterm); extern int distribution_info(int, void *); extern int is_node_name_atom(Eterm a); -extern int erts_net_message(Port *, DistEntry *, byte *, int, byte *, int); +extern int erts_net_message(Port *, DistEntry *, + byte *, ErlDrvSizeT, byte *, ErlDrvSizeT); extern void init_dist(void); extern int stop_dist(void); @@ -1661,7 +1665,7 @@ do { \ #define ERTS_SMP_CHK_PEND_TRACE_MSGS(ESDP) #endif -void bin_write(int, void*, byte*, int); +void bin_write(int, void*, byte*, size_t); int intlist_to_buf(Eterm, char*, int); /* most callers pass plain char*'s */ struct Sint_buf { @@ -1677,7 +1681,7 @@ char* Sint_to_buf(Sint, struct Sint_buf*); #define ERTS_IOLIST_OVERFLOW 1 #define ERTS_IOLIST_TYPE 2 -Eterm buf_to_intlist(Eterm**, char*, int, Eterm); /* most callers pass plain char*'s */ +Eterm buf_to_intlist(Eterm**, char*, size_t, Eterm); /* most callers pass plain char*'s */ int io_list_to_buf(Eterm, char*, int); int io_list_to_buf2(Eterm, char*, int); int erts_iolist_size(Eterm, Uint *); diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 132dc78515..fe1a7ba345 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2011. All Rights Reserved. + * Copyright Ericsson AB 1996-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -164,8 +164,8 @@ erts_port_ioq_size(Port *pp) typedef struct line_buf_context { LineBuf **b; char *buf; - int left; - int retlen; + ErlDrvSizeT left; + ErlDrvSizeT retlen; } LineBufContext; #define LINEBUF_EMPTY 0 @@ -445,7 +445,7 @@ setup_port(Port* prt, Eterm pid, erts_driver_t *driver, prt->control_flags = 0; prt->connected = pid; - prt->drv_data = (long) drv_data; + prt->drv_data = (SWord) drv_data; prt->bytes_in = 0; prt->bytes_out = 0; prt->dist_entry = NULL; @@ -644,11 +644,10 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */ name, opts); erts_unblock_fpe(fpe_was_unmasked); port->caller = NIL; - erts_unblock_fpe(fpe_was_unmasked); if (IS_TRACED_FL(port, F_TRACE_SCHED_PORTS)) { trace_sched_ports_where(port, am_out, am_start); } - if (error_number_ptr && ((long) drv_data) == (long) -2) + if (error_number_ptr && ((SWord) drv_data) == (SWord) -2) *error_number_ptr = errno; #ifdef ERTS_SMP if (port->xports) @@ -657,10 +656,10 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */ #endif } - if (((long)drv_data) == -1 || - ((long)drv_data) == -2 || - ((long)drv_data) == -3) { - int res = (int) ((long) drv_data); + if (((SWord)drv_data) == -1 || + ((SWord)drv_data) == -2 || + ((SWord)drv_data) == -3) { + int res = (int) ((SWord) drv_data); if (res == -3 && error_number_ptr) { *error_number_ptr = BADARG; @@ -689,7 +688,7 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */ erts_port_release(port); return res; } - port->drv_data = (long) drv_data; + port->drv_data = (SWord) drv_data; return port_ix; } @@ -744,7 +743,7 @@ driver_create_port(ErlDrvPort creator_port_ix, /* Creating port */ return (ErlDrvTermData) -1; /* pid does not exist */ } if ((port_num = get_free_port()) < 0) { - errno = ENFILE; + errno = SYSTEM_LIMIT; erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK); erts_smp_mtx_unlock(&erts_driver_list_lock); return (ErlDrvTermData) -1; @@ -819,6 +818,11 @@ erts_smp_xports_unlock(Port *prt) #define SET_VEC(iov, bv, bin, ptr, len, vlen) do { \ (iov)->iov_base = (ptr); \ (iov)->iov_len = (len); \ + if (sizeof((iov)->iov_len) < sizeof(len) \ + /* Check if (len) overflowed (iov)->iov_len */ \ + && ((len) >> (sizeof((iov)->iov_len)*CHAR_BIT)) != 0) { \ + goto L_overflow; \ + } \ *(bv)++ = (bin); \ (iov)++; \ (vlen)++; \ @@ -829,13 +833,13 @@ io_list_to_vec(Eterm obj, /* io-list */ SysIOVec* iov, /* io vector */ ErlDrvBinary** binv, /* binary reference vector */ ErlDrvBinary* cbin, /* binary to store characters */ - int bin_limit) /* small binaries limit */ + ErlDrvSizeT bin_limit) /* small binaries limit */ { DECLARE_ESTACK(s); Eterm* objp; char *buf = cbin->orig_bytes; - int len = cbin->orig_size; - int csize = 0; + ErlDrvSizeT len = cbin->orig_size; + ErlDrvSizeT csize = 0; int vlen = 0; char* cptr = buf; @@ -875,7 +879,7 @@ io_list_to_vec(Eterm obj, /* io-list */ Eterm real_bin; Uint offset; Eterm* bptr; - int size; + ErlDrvSizeT size; int bitoffs; int bitsize; @@ -950,7 +954,7 @@ io_list_to_vec(Eterm obj, /* io-list */ #define IO_LIST_VEC_COUNT(obj) \ do { \ - int _size = binary_size(obj); \ + ErlDrvSizeT _size = binary_size(obj); \ Eterm _real; \ ERTS_DECLARE_DUMMY(Uint _offset); \ int _bitoffs; \ @@ -1105,7 +1109,7 @@ int erts_write_to_port(Eterm caller_id, Port *p, Eterm list) Uint csize; Uint pvsize; Uint pcsize; - int blimit; + ErlDrvSizeT blimit; SysIOVec iv[SMALL_WRITE_VEC]; ErlDrvBinary* bv[SMALL_WRITE_VEC]; SysIOVec* ivp; @@ -1147,11 +1151,21 @@ int erts_write_to_port(Eterm caller_id, Port *p, Eterm list) ivp[0].iov_len = 0; bvp[0] = NULL; ev.vsize = io_list_to_vec(list, ivp+1, bvp+1, cbin, blimit); + if (ev.vsize < 0) { + if (ivp != iv) { + erts_free(ERTS_ALC_T_TMP, (void *) ivp); + } + if (bvp != bv) { + erts_free(ERTS_ALC_T_TMP, (void *) bvp); + } + driver_free_binary(cbin); + goto bad_value; + } ev.vsize++; #if 0 /* This assertion may say something useful, but it can be falsified during the emulator test suites. */ - ASSERT((ev.vsize >= 0) && (ev.vsize == vsize)); + ASSERT(ev.vsize == vsize); #endif ev.size = size; /* total size */ ev.iov = ivp; @@ -1361,7 +1375,8 @@ int bufsiz; * buf - A buffer containing the data to be read and split to lines. * len - The number of bytes in buf. */ -static int init_linebuf_context(LineBufContext *lc, LineBuf **lb, char *buf, int len) +static int init_linebuf_context(LineBufContext *lc, LineBuf **lb, + char *buf, ErlDrvSizeT len) { if(lc == NULL || lb == NULL) return -1; @@ -1530,10 +1545,10 @@ deliver_result(Eterm sender, Eterm pid, Eterm res) */ static void deliver_read_message(Port* prt, Eterm to, - char *hbuf, int hlen, - char *buf, int len, int eol) + char *hbuf, ErlDrvSizeT hlen, + char *buf, ErlDrvSizeT len, int eol) { - int need; + ErlDrvSizeT need; Eterm listp; Eterm tuple; Process* rp; @@ -1613,8 +1628,8 @@ static void deliver_read_message(Port* prt, Eterm to, * deliver_read_message, and takes the same parameters. */ static void deliver_linebuf_message(Port* prt, Eterm to, - char* hbuf, int hlen, - char *buf, int len) + char* hbuf, ErlDrvSizeT hlen, + char *buf, ErlDrvSizeT len) { LineBufContext lc; int ret; @@ -1657,14 +1672,14 @@ static void deliver_vec_message(Port* prt, /* Port */ Eterm to, /* Receiving pid */ char* hbuf, /* "Header" buffer... */ - int hlen, /* ... and its length */ + ErlDrvSizeT hlen, /* ... and its length */ ErlDrvBinary** binv, /* Vector of binaries */ SysIOVec* iov, /* I/O vector */ int vsize, /* Size of binv & iov */ - int csize) /* Size of characters in + ErlDrvSizeT csize) /* Size of characters in iov (not hlen) */ { - int need; + ErlDrvSizeT need; Eterm listp; Eterm tuple; Process* rp; @@ -1745,7 +1760,7 @@ deliver_vec_message(Port* prt, /* Port */ } } - if (hlen > 0) { /* Prepend the header */ + if (hlen != 0) { /* Prepend the header */ Eterm* thp = hp; listp = buf_to_intlist(&thp, hbuf, hlen, listp); hp = thp; @@ -1765,10 +1780,10 @@ deliver_vec_message(Port* prt, /* Port */ static void deliver_bin_message(Port* prt, /* port */ Eterm to, /* receiving pid */ char* hbuf, /* "header" buffer */ - int hlen, /* and it's length */ + ErlDrvSizeT hlen, /* and it's length */ ErlDrvBinary* bin, /* binary data */ - int offs, /* offset into binary */ - int len) /* length of binary */ + ErlDrvSizeT offs, /* offset into binary */ + ErlDrvSizeT len) /* length of binary */ { SysIOVec vec; @@ -2156,8 +2171,9 @@ erts_port_control(Process* p, Port* prt, Uint command, Eterm iolist) int must_free = 0; /* True if the buffer should be freed. */ char port_result[ERL_ONHEAP_BIN_LIMIT]; /* Default buffer for result from port. */ char* port_resp; /* Pointer to result buffer. */ - int n; - int (*control)(ErlDrvData, unsigned, char*, int, char**, int); + ErlDrvSSizeT n; + ErlDrvSSizeT (*control) + (ErlDrvData, unsigned, char*, ErlDrvSizeT, char**, ErlDrvSizeT); int fpe_was_unmasked; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); @@ -3083,7 +3099,7 @@ driver_deliver_term(ErlDrvPort port, Binary* bp = erts_bin_nrml_alloc(size); ASSERT(bufp); bp->flags = 0; - bp->orig_size = (long) size; + bp->orig_size = (SWord) size; erts_refc_init(&bp->refc, 1); sys_memcpy((void *) bp->orig_bytes, (void *) bufp, size); pbp = (ProcBin *) hp; @@ -3240,8 +3256,8 @@ driver_send_term(ErlDrvPort ix, ErlDrvTermData to, ErlDrvTermData* data, int len * and data is len length of bin starting from offset offs. */ -int driver_output_binary(ErlDrvPort ix, char* hbuf, int hlen, - ErlDrvBinary* bin, int offs, int len) +int driver_output_binary(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen, + ErlDrvBinary* bin, ErlDrvSizeT offs, ErlDrvSizeT len) { Port* prt = erts_drvport2port(ix); @@ -3274,7 +3290,8 @@ int driver_output_binary(ErlDrvPort ix, char* hbuf, int hlen, ** Example: if hlen = 3 then the port owner will receive the data ** [H1,H2,H3 | T] */ -int driver_output2(ErlDrvPort ix, char* hbuf, int hlen, char* buf, int len) +int driver_output2(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen, + char* buf, ErlDrvSizeT len) { Port* prt = erts_drvport2port(ix); @@ -3311,27 +3328,29 @@ int driver_output2(ErlDrvPort ix, char* hbuf, int hlen, char* buf, int len) /* Interface functions available to driver writers */ -int driver_output(ErlDrvPort ix, char* buf, int len) +int driver_output(ErlDrvPort ix, char* buf, ErlDrvSizeT len) { ERTS_SMP_CHK_NO_PROC_LOCKS; return driver_output2(ix, NULL, 0, buf, len); } -int driver_outputv(ErlDrvPort ix, char* hbuf, int hlen, ErlIOVec* vec, int skip) +int driver_outputv(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen, + ErlIOVec* vec, ErlDrvSizeT skip) { int n; - int len; - int size; + ErlDrvSizeT len; + ErlDrvSizeT size; SysIOVec* iov; ErlDrvBinary** binv; Port* prt; ERTS_SMP_CHK_NO_PROC_LOCKS; - size = vec->size - skip; /* Size of remaining bytes in vector */ - ASSERT(size >= 0); - if (size <= 0) + ASSERT(vec->size >= skip); + if (vec->size <= skip) return driver_output2(ix, hbuf, hlen, NULL, 0); + size = vec->size - skip; /* Size of remaining bytes in vector */ + ASSERT(hlen >= 0); /* debug only */ if (hlen < 0) hlen = 0; @@ -3375,17 +3394,14 @@ int driver_outputv(ErlDrvPort ix, char* hbuf, int hlen, ErlIOVec* vec, int skip) ** input is a vector a buffer and a max length ** return bytes copied */ -int driver_vec_to_buf(vec, buf, len) -ErlIOVec* vec; -char* buf; -int len; +ErlDrvSizeT driver_vec_to_buf(ErlIOVec *vec, char *buf, ErlDrvSizeT len) { SysIOVec* iov = vec->iov; int n = vec->vsize; - int orig_len = len; + ErlDrvSizeT orig_len = len; while(n--) { - int ilen = iov->iov_len; + size_t ilen = iov->iov_len; if (ilen < len) { sys_memcpy(buf, iov->iov_base, ilen); len -= ilen; @@ -3437,43 +3453,34 @@ driver_binary_dec_refc(ErlDrvBinary *dbp) */ ErlDrvBinary* -driver_alloc_binary(int size) +driver_alloc_binary(ErlDrvSizeT size) { Binary* bin; - if (size < 0) - return NULL; - bin = erts_bin_drv_alloc_fnf((Uint) size); if (!bin) return NULL; /* The driver write must take action */ bin->flags = BIN_FLAG_DRV; erts_refc_init(&bin->refc, 1); - bin->orig_size = (long) size; + bin->orig_size = (SWord) size; return Binary2ErlDrvBinary(bin); } /* Reallocate space hold by binary */ -ErlDrvBinary* driver_realloc_binary(ErlDrvBinary* bin, int size) +ErlDrvBinary* driver_realloc_binary(ErlDrvBinary* bin, ErlDrvSizeT size) { Binary* oldbin; Binary* newbin; - if (!bin || size < 0) { + if (!bin) { erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf(); erts_dsprintf(dsbufp, - "Bad use of driver_realloc_binary(%p, %d): " + "Bad use of driver_realloc_binary(%p, %lu): " "called with ", - bin, size); + bin, (unsigned long)size); if (!bin) { erts_dsprintf(dsbufp, "NULL pointer as first argument"); - if (size < 0) - erts_dsprintf(dsbufp, ", and "); - } - if (size < 0) { - erts_dsprintf(dsbufp, "negative size as second argument"); - size = 0; } erts_send_warning_to_logger_nogl(dsbufp); if (!bin) @@ -3513,12 +3520,12 @@ ErlDrvBinary* dbin; * Allocation/deallocation of memory for drivers */ -void *driver_alloc(size_t size) +void *driver_alloc(ErlDrvSizeT size) { return erts_alloc_fnf(ERTS_ALC_T_DRV, (Uint) size); } -void *driver_realloc(void *ptr, size_t size) +void *driver_realloc(void *ptr, ErlDrvSizeT size) { return erts_realloc_fnf(ERTS_ALC_T_DRV, ptr, (Uint) size); } @@ -3780,11 +3787,11 @@ static int expandq(ErlIOQueue* q, int n, int tail) /* Put elements from vec at q tail */ -int driver_enqv(ErlDrvPort ix, ErlIOVec* vec, int skip) +int driver_enqv(ErlDrvPort ix, ErlIOVec* vec, ErlDrvSizeT skip) { int n; - int len; - int size; + size_t len; + ErlDrvSizeT size; SysIOVec* iov; ErlDrvBinary** binv; ErlDrvBinary* b; @@ -3793,10 +3800,10 @@ int driver_enqv(ErlDrvPort ix, ErlIOVec* vec, int skip) if (q == NULL) return -1; - size = vec->size - skip; - ASSERT(size >= 0); /* debug only */ - if (size <= 0) + ASSERT(vec->size >= skip); /* debug only */ + if (vec->size <= skip) return 0; + size = vec->size - skip; iov = vec->iov; binv = vec->binv; @@ -3846,11 +3853,11 @@ int driver_enqv(ErlDrvPort ix, ErlIOVec* vec, int skip) } /* Put elements from vec at q head */ -int driver_pushqv(ErlDrvPort ix, ErlIOVec* vec, int skip) +int driver_pushqv(ErlDrvPort ix, ErlIOVec* vec, ErlDrvSizeT skip) { int n; - int len; - int size; + size_t len; + ErlDrvSizeT size; SysIOVec* iov; ErlDrvBinary** binv; ErlDrvBinary* b; @@ -3859,8 +3866,10 @@ int driver_pushqv(ErlDrvPort ix, ErlIOVec* vec, int skip) if (q == NULL) return -1; - if ((size = vec->size - skip) <= 0) + if (vec->size <= skip) return 0; + size = vec->size - skip; + iov = vec->iov; binv = vec->binv; n = vec->vsize; @@ -3915,15 +3924,14 @@ int driver_pushqv(ErlDrvPort ix, ErlIOVec* vec, int skip) ** Remove size bytes from queue head ** Return number of bytes that remain in queue */ -int driver_deq(ErlDrvPort ix, int size) +ErlDrvSizeT driver_deq(ErlDrvPort ix, ErlDrvSizeT size) { ErlIOQueue* q = drvport2ioq(ix); - int len; - int sz; + ErlDrvSizeT len; - if ((q == NULL) || (sz = (q->size - size)) < 0) + if ((q == NULL) || (q->size < size)) return -1; - q->size = sz; + q->size -= size; while (size > 0) { ASSERT(q->v_head != q->v_tail); @@ -3946,16 +3954,16 @@ int driver_deq(ErlDrvPort ix, int size) q->v_head = q->v_tail = q->v_start; q->b_head = q->b_tail = q->b_start; } - return sz; + return q->size; } -int driver_peekqv(ErlDrvPort ix, ErlIOVec *ev) { +ErlDrvSizeT driver_peekqv(ErlDrvPort ix, ErlIOVec *ev) { ErlIOQueue *q = drvport2ioq(ix); ASSERT(ev); if (! q) { - return -1; + return (ErlDrvSizeT) -1; } else { if ((ev->vsize = q->v_tail - q->v_head) == 0) { ev->size = 0; @@ -3984,12 +3992,12 @@ SysIOVec* driver_peekq(ErlDrvPort ix, int* vlenp) /* length of io-vector */ } -int driver_sizeq(ErlDrvPort ix) +ErlDrvSizeT driver_sizeq(ErlDrvPort ix) { ErlIOQueue* q = drvport2ioq(ix); if (q == NULL) - return -1; + return (size_t) -1; return q->size; } @@ -3997,7 +4005,8 @@ int driver_sizeq(ErlDrvPort ix) /* Utils */ /* Enqueue a binary */ -int driver_enq_bin(ErlDrvPort ix, ErlDrvBinary* bin, int offs, int len) +int driver_enq_bin(ErlDrvPort ix, ErlDrvBinary* bin, + ErlDrvSizeT offs, ErlDrvSizeT len) { SysIOVec iov; ErlIOVec ev; @@ -4014,7 +4023,7 @@ int driver_enq_bin(ErlDrvPort ix, ErlDrvBinary* bin, int offs, int len) return driver_enqv(ix, &ev, 0); } -int driver_enq(ErlDrvPort ix, char* buffer, int len) +int driver_enq(ErlDrvPort ix, char* buffer, ErlDrvSizeT len) { int code; ErlDrvBinary* bin; @@ -4030,7 +4039,8 @@ int driver_enq(ErlDrvPort ix, char* buffer, int len) return code; } -int driver_pushq_bin(ErlDrvPort ix, ErlDrvBinary* bin, int offs, int len) +int driver_pushq_bin(ErlDrvPort ix, ErlDrvBinary* bin, + ErlDrvSizeT offs, ErlDrvSizeT len) { SysIOVec iov; ErlIOVec ev; @@ -4047,7 +4057,7 @@ int driver_pushq_bin(ErlDrvPort ix, ErlDrvBinary* bin, int offs, int len) return driver_pushqv(ix, &ev, 0); } -int driver_pushq(ErlDrvPort ix, char* buffer, int len) +int driver_pushq(ErlDrvPort ix, char* buffer, ErlDrvSizeT len) { int code; ErlDrvBinary* bin; @@ -4076,7 +4086,7 @@ drv_cancel_timer(Port *prt) erts_port_task_abort(prt->id, &prt->timeout_task); } -int driver_set_timer(ErlDrvPort ix, UWord t) +int driver_set_timer(ErlDrvPort ix, unsigned long t) { Port* prt = erts_drvport2port(ix); @@ -4768,7 +4778,7 @@ get_current_port(void) */ static void -no_output_callback(ErlDrvData drv_data, char *buf, int len) +no_output_callback(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { } @@ -4819,16 +4829,11 @@ static int init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle) { drv->name = de->driver_name; - if (de->extended_marker == ERL_DRV_EXTENDED_MARKER) { - drv->version.major = de->major_version; - drv->version.minor = de->minor_version; - drv->flags = de->driver_flags; - } - else { - drv->version.major = 0; - drv->version.minor = 0; - drv->flags = 0; - } + ASSERT(de->extended_marker == ERL_DRV_EXTENDED_MARKER); + ASSERT(de->major_version >= 2); + drv->version.major = de->major_version; + drv->version.minor = de->minor_version; + drv->flags = de->driver_flags; drv->handle = handle; #ifdef ERTS_SMP if (drv->flags & ERL_DRV_FLAG_USE_PORT_LOCKING) @@ -4861,11 +4866,8 @@ init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle) drv->ready_output = de->ready_output ? de->ready_output : no_ready_output_callback; drv->timeout = de->timeout ? de->timeout : no_timeout_callback; drv->ready_async = de->ready_async; - if (de->extended_marker == ERL_DRV_EXTENDED_MARKER) - drv->process_exit = de->process_exit; - else - drv->process_exit = NULL; - if (de->minor_version >= 3/*R13A*/ && de->stop_select) + drv->process_exit = de->process_exit; + if (de->stop_select) drv->stop_select = de->stop_select; else drv->stop_select = no_stop_select_callback; diff --git a/erts/emulator/beam/packet_parser.c b/erts/emulator/beam/packet_parser.c index a66d60aa22..f1cfa8df39 100644 --- a/erts/emulator/beam/packet_parser.c +++ b/erts/emulator/beam/packet_parser.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2010. All Rights Reserved. + * Copyright Ericsson AB 2008-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -301,7 +301,11 @@ int packet_get_length(enum PacketParseType htype, /* TCP_PB_LINE_LF: [Data ... \n] */ const char* ptr2; if ((ptr2 = memchr(ptr, '\n', n)) == NULL) { - if (n >= trunc_len && trunc_len!=0) { /* buffer full */ + if (n > max_plen && max_plen != 0) { /* packet full */ + DEBUGF((" => packet full (no NL)=%d\r\n", n)); + goto error; + } + else if (n >= trunc_len && trunc_len!=0) { /* buffer full */ DEBUGF((" => line buffer full (no NL)=%d\r\n", n)); return trunc_len; } @@ -309,6 +313,10 @@ int packet_get_length(enum PacketParseType htype, } else { int len = (ptr2 - ptr) + 1; /* including newline */ + if (len > max_plen && max_plen!=0) { + DEBUGF((" => packet_size %d exceeded\r\n", max_plen)); + goto error; + } if (len > trunc_len && trunc_len!=0) { DEBUGF((" => truncated line=%d\r\n", trunc_len)); return trunc_len; @@ -397,33 +405,50 @@ int packet_get_length(enum PacketParseType htype, const char* ptr1 = ptr; int len = plen; + if (!max_plen) { + /* This is for backward compatibility with old user of decode_packet + * that might use option 'line_length' to limit accepted length of + * http lines. + */ + max_plen = trunc_len; + } + while (1) { const char* ptr2 = memchr(ptr1, '\n', len); if (ptr2 == NULL) { - if (n >= trunc_len && trunc_len!=0) { /* buffer full */ - plen = trunc_len; - goto done; + if (max_plen != 0) { + if (n >= max_plen) /* packet full */ + goto error; } goto more; } else { plen = (ptr2 - ptr) + 1; - - if (*statep == 0) + + if (*statep == 0) { + if (max_plen != 0 && plen > max_plen) + goto error; goto done; - + } + if (plen < n) { if (SP(ptr2+1) && plen>2) { /* header field value continue on next line */ ptr1 = ptr2+1; len = n - plen; } - else + else { + if (max_plen != 0 && plen > max_plen) + goto error; goto done; + } } - else + else { + if (max_plen != 0 && plen > max_plen) + goto error; goto more; + } } } } diff --git a/erts/emulator/beam/register.h b/erts/emulator/beam/register.h index 97bab3ab71..bf15e63554 100644 --- a/erts/emulator/beam/register.h +++ b/erts/emulator/beam/register.h @@ -41,7 +41,7 @@ struct port; typedef struct reg_proc { HashBucket bucket; /* MUST BE LOCATED AT TOP OF STRUCT!!! */ - Process *p; /* The process registerd (only one of this and + Process *p; /* The process registered (only one of this and 'pt' is non-NULL */ struct port *pt; /* The port registered */ Eterm name; /* Atom name */ diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index 94c36c8c59..eb6f2f8516 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -221,7 +221,8 @@ int real_printf(const char *fmt, ...); */ #if !((SIZEOF_VOID_P >= 4) && (SIZEOF_VOID_P == SIZEOF_SIZE_T) \ - && ((SIZEOF_VOID_P == SIZEOF_INT) || (SIZEOF_VOID_P == SIZEOF_LONG))) + && ((SIZEOF_VOID_P == SIZEOF_INT) || (SIZEOF_VOID_P == SIZEOF_LONG) || \ + (SIZEOF_VOID_P == SIZEOF_LONG_LONG))) #error Cannot handle this combination of int/long/void*/size_t sizes #endif @@ -255,6 +256,7 @@ typedef unsigned int Eterm; typedef unsigned int Uint; typedef int Sint; #define ERTS_SIZEOF_ETERM SIZEOF_INT +#define ErtsStrToSint strtol #else #error Found no appropriate type to use for 'Eterm', 'Uint' and 'Sint' #endif @@ -262,9 +264,18 @@ typedef int Sint; #if SIZEOF_VOID_P == SIZEOF_LONG typedef unsigned long UWord; typedef long SWord; +#define SWORD_CONSTANT(Const) Const##L +#define UWORD_CONSTANT(Const) Const##UL #elif SIZEOF_VOID_P == SIZEOF_INT typedef unsigned int UWord; typedef int SWord; +#define SWORD_CONSTANT(Const) Const +#define UWORD_CONSTANT(Const) Const##U +#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG +typedef unsigned long long UWord; +typedef long long SWord; +#define SWORD_CONSTANT(Const) Const##LL +#define UWORD_CONSTANT(Const) Const##ULL #else #error Found no appropriate type to use for 'Eterm', 'Uint' and 'Sint' #endif @@ -275,12 +286,30 @@ typedef int SWord; typedef unsigned long Eterm; typedef unsigned long Uint; typedef long Sint; +#define SWORD_CONSTANT(Const) Const##L +#define UWORD_CONSTANT(Const) Const##UL #define ERTS_SIZEOF_ETERM SIZEOF_LONG +#define ErtsStrToSint strtol #elif SIZEOF_VOID_P == SIZEOF_INT typedef unsigned int Eterm; typedef unsigned int Uint; typedef int Sint; +#define SWORD_CONSTANT(Const) Const +#define UWORD_CONSTANT(Const) Const##U #define ERTS_SIZEOF_ETERM SIZEOF_INT +#define ErtsStrToSint strtol +#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG +typedef unsigned long long Eterm; +typedef unsigned long long Uint; +typedef long long Sint; +#define SWORD_CONSTANT(Const) Const##LL +#define UWORD_CONSTANT(Const) Const##ULL +#define ERTS_SIZEOF_ETERM SIZEOF_LONG_LONG +#if defined(__WIN32__) +#define ErtsStrToSint _strtoi64 +#else +#define ErtsStrToSint strtoll +#endif #else #error Found no appropriate type to use for 'Eterm', 'Uint' and 'Sint' #endif @@ -615,10 +644,11 @@ extern char *erts_sys_ddll_error(int code); /* * System interfaces for startup. */ +#include "erl_time.h" void erts_sys_schedule_interrupt(int set); #ifdef ERTS_SMP -void erts_sys_schedule_interrupt_timed(int set, long msec); +void erts_sys_schedule_interrupt_timed(int set, erts_short_time_t msec); void erts_sys_main_thread(void); #endif @@ -635,17 +665,24 @@ Preload* sys_preloaded(void); unsigned char* sys_preload_begin(Preload*); void sys_preload_end(Preload*); int sys_get_key(int); -void elapsed_time_both(unsigned long *ms_user, unsigned long *ms_sys, - unsigned long *ms_user_diff, unsigned long *ms_sys_diff); -void wall_clock_elapsed_time_both(unsigned long *ms_total, - unsigned long *ms_diff); +void elapsed_time_both(UWord *ms_user, UWord *ms_sys, + UWord *ms_user_diff, UWord *ms_sys_diff); +void wall_clock_elapsed_time_both(UWord *ms_total, + UWord *ms_diff); void get_time(int *hour, int *minute, int *second); void get_date(int *year, int *month, int *day); void get_localtime(int *year, int *month, int *day, int *hour, int *minute, int *second); void get_universaltime(int *year, int *month, int *day, int *hour, int *minute, int *second); -int univ_to_local(Sint *year, Sint *month, Sint *day, +int seconds_to_univ(Sint64 seconds, + Sint *year, Sint *month, Sint *day, + Sint *hour, Sint *minute, Sint *second); +int univ_to_seconds(Sint year, Sint month, Sint day, + Sint hour, Sint minute, Sint second, + Sint64* seconds); +int univ_to_local( + Sint *year, Sint *month, Sint *day, Sint *hour, Sint *minute, Sint *second); int local_to_univ(Sint *year, Sint *month, Sint *day, Sint *hour, Sint *minute, Sint *second, int isdst); @@ -968,6 +1005,19 @@ void erl_bin_write(unsigned char *, int, int); #endif +#ifdef __WIN32__ +#ifdef ARCH_64 +#define ERTS_ALLOC_ALIGN_BYTES 16 +#define ERTS_SMALL_ABS(Small) _abs64(Small) +#else +#define ERTS_ALLOC_ALIGN_BYTES 8 +#define ERTS_SMALL_ABS(Small) labs(Small) +#endif +#else +#define ERTS_ALLOC_ALIGN_BYTES 8 +#define ERTS_SMALL_ABS(Small) labs(Small) +#endif + #ifdef __WIN32__ diff --git a/erts/emulator/beam/time.c b/erts/emulator/beam/time.c index db9a24e0a3..932d157cd8 100644 --- a/erts/emulator/beam/time.c +++ b/erts/emulator/beam/time.c @@ -107,20 +107,31 @@ static ErlTimer *tiw_min_ptr; /* Actual interval time chosen by sys_init_time() */ static int itime; /* Constant after init */ -erts_smp_atomic_t do_time; /* set at clock interrupt */ -static ERTS_INLINE erts_aint_t do_time_read(void) { return erts_smp_atomic_read_acqb(&do_time); } -static ERTS_INLINE erts_aint_t do_time_update(void) { return do_time_read(); } -static ERTS_INLINE void do_time_init(void) { erts_smp_atomic_init_nob(&do_time, 0L); } +erts_smp_atomic32_t do_time; /* set at clock interrupt */ +static ERTS_INLINE erts_short_time_t do_time_read(void) +{ + return erts_smp_atomic32_read_acqb(&do_time); +} + +static ERTS_INLINE erts_short_time_t do_time_update(void) +{ + return do_time_read(); +} + +static ERTS_INLINE void do_time_init(void) +{ + erts_smp_atomic32_init_nob(&do_time, 0); +} /* get the time (in units of itime) to the next timeout, or -1 if there are no timeouts */ -static erts_aint_t next_time_internal(void) /* PRE: tiw_lock taken by caller */ +static erts_short_time_t next_time_internal(void) /* PRE: tiw_lock taken by caller */ { int i, tm, nto; - unsigned int min; + Uint32 min; ErlTimer* p; - erts_aint_t dt; + erts_short_time_t dt; if (tiw_nto == 0) return -1; /* no timeouts in wheel */ @@ -133,7 +144,7 @@ static erts_aint_t next_time_internal(void) /* PRE: tiw_lock taken by caller */ /* start going through wheel to find next timeout */ tm = nto = 0; - min = (unsigned int) -1; /* max unsigned int */ + min = (Uint32) -1; /* max Uint32 */ i = tiw_pos; do { p = tiw[i]; @@ -162,7 +173,11 @@ static erts_aint_t next_time_internal(void) /* PRE: tiw_lock taken by caller */ i = (i + 1) % TIW_SIZE; } while (i != tiw_pos); dt = do_time_read(); - return ((min >= dt) ? (min - dt) : 0); + if (min <= (Uint32) dt) + return 0; + if ((min - (Uint32) dt) > (Uint32) ERTS_SHORT_TIME_T_MAX) + return ERTS_SHORT_TIME_T_MAX; + return (erts_short_time_t) (min - (Uint32) dt); } static void remove_timer(ErlTimer *p) { @@ -191,9 +206,9 @@ static void remove_timer(ErlTimer *p) { } /* Private export to erl_time_sup.c */ -erts_aint_t erts_next_time(void) +erts_short_time_t erts_next_time(void) { - erts_aint_t ret; + erts_short_time_t ret; erts_smp_mtx_lock(&tiw_lock); (void)do_time_update(); @@ -202,7 +217,7 @@ erts_aint_t erts_next_time(void) return ret; } -static ERTS_INLINE void bump_timer_internal(erts_aint_t dt) /* PRE: tiw_lock is write-locked */ +static ERTS_INLINE void bump_timer_internal(erts_short_time_t dt) /* PRE: tiw_lock is write-locked */ { Uint keep_pos; Uint count; @@ -273,7 +288,7 @@ static ERTS_INLINE void bump_timer_internal(erts_aint_t dt) /* PRE: tiw_lock is } } -void erts_bump_timer(erts_aint_t dt) /* dt is value from do_time */ +void erts_bump_timer(erts_short_time_t dt) /* dt is value from do_time */ { erts_smp_mtx_lock(&tiw_lock); bump_timer_internal(dt); @@ -378,8 +393,8 @@ erts_set_timer(ErlTimer* p, ErlTimeoutProc timeout, ErlCancelProc cancel, insert_timer(p, t); erts_smp_mtx_unlock(&tiw_lock); #if defined(ERTS_SMP) - if (t <= (Uint) LONG_MAX) - erts_sys_schedule_interrupt_timed(1, (long) t); + if (t <= (Uint) ERTS_SHORT_TIME_T_MAX) + erts_sys_schedule_interrupt_timed(1, (erts_short_time_t) t); #endif } @@ -419,7 +434,7 @@ Uint erts_time_left(ErlTimer *p) { Uint left; - erts_aint_t dt; + erts_short_time_t dt; erts_smp_mtx_lock(&tiw_lock); diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index e4ad7dcb24..49b6618f73 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -45,6 +45,7 @@ #include "erl_thr_progress.h" #include "erl_thr_queue.h" #include "erl_sched_spec_pre_alloc.h" +#include "beam_bp.h" #undef M_TRIM_THRESHOLD #undef M_TOP_PAD @@ -2647,7 +2648,7 @@ tailrecur_ne: FloatDef f1, f2; Eterm big; #if HEAP_ON_C_STACK - Eterm big_buf[32]; /* If HEAP_ON_C_STACK */ + Eterm big_buf[CMP_TMP_HEAP_SIZE]; /* If HEAP_ON_C_STACK */ #else Eterm *big_buf = erts_get_scheduler_data()->cmp_tmp_heap; #endif @@ -2660,6 +2661,7 @@ tailrecur_ne: #endif #define MAX_LOSSLESS_FLOAT ((double)((1LL << 53) - 2)) #define MIN_LOSSLESS_FLOAT ((double)(((1LL << 53) - 2)*-1)) +#define BIG_ARITY_FLOAT_MAX (1024 / D_EXP) /* arity of max float as a bignum */ b_tag = tag_val_def(bw); switch(_NUMBER_CODE(a_tag, b_tag)) { @@ -2692,16 +2694,24 @@ tailrecur_ne: } #endif // ERTS_SIZEOF_ETERM == 8 break; + case FLOAT_BIG: + { + Wterm tmp = aw; + aw = bw; + bw = tmp; + }/* fall through */ case BIG_FLOAT: GET_DOUBLE(bw, f2); if ((f2.fd < (double) (MAX_SMALL + 1)) && (f2.fd > (double) (MIN_SMALL - 1))) { // Float is a Sint j = big_sign(aw) ? -1 : 1; - } else if ((pow(2.0,(big_arity(aw)-1.0)*D_EXP)-1.0) > fabs(f2.fd)) { + } else if (big_arity(aw) > BIG_ARITY_FLOAT_MAX + || pow(2.0,(big_arity(aw)-1)*D_EXP) > fabs(f2.fd)) { // If bignum size shows that it is bigger than the abs float j = big_sign(aw) ? -1 : 1; - } else if ((pow(2.0,(big_arity(aw))*D_EXP)-1.0) < fabs(f2.fd)) { + } else if (big_arity(aw) < BIG_ARITY_FLOAT_MAX + && (pow(2.0,(big_arity(aw))*D_EXP)-1.0) < fabs(f2.fd)) { // If bignum size shows that it is smaller than the abs float j = f2.fd < 0 ? 1 : -1; } else if (f2.fd < MAX_LOSSLESS_FLOAT && f2.fd > MIN_LOSSLESS_FLOAT) { @@ -2715,6 +2725,9 @@ tailrecur_ne: big = double_to_big(f2.fd, big_buf); j = big_comp(aw, big); } + if (_NUMBER_CODE(a_tag, b_tag) == FLOAT_BIG) { + j = -j; + } break; case FLOAT_SMALL: GET_DOUBLE(aw, f1); @@ -2739,29 +2752,6 @@ tailrecur_ne: } #endif // ERTS_SIZEOF_ETERM == 8 break; - case FLOAT_BIG: - GET_DOUBLE(aw, f1); - if ((f1.fd < (double) (MAX_SMALL + 1)) - && (f1.fd > (double) (MIN_SMALL - 1))) { // Float is a Sint - j = big_sign(bw) ? 1 : -1; - } else if ((pow(2.0, (big_arity(bw) - 1.0) * D_EXP) - 1.0) > fabs(f1.fd)) { - // If bignum size shows that it is bigger than the abs float - j = big_sign(bw) ? 1 : -1; - } else if ((pow(2.0,(big_arity(bw))*D_EXP)-1.0) < fabs(f1.fd)) { - // If bignum size shows that it is smaller than the abs float - j = f1.fd < 0 ? -1 : 1; - } else if (f1.fd < MAX_LOSSLESS_FLOAT && f1.fd > MIN_LOSSLESS_FLOAT) { - // Float is within the no loss limit - if (big_to_double(bw, &f2.fd) < 0) { - j = big_sign(bw) ? 1 : -1; - } else { - j = float_comp(f1.fd, f2.fd); - } - } else { - big = double_to_big(f1.fd, big_buf); - j = big_comp(big, bw); - } - break; default: j = b_tag - a_tag; } @@ -2875,9 +2865,9 @@ store_external_or_ref_in_proc_(Process *proc, Eterm ns) return store_external_or_ref_(&hp, &MSO(proc), ns); } -void bin_write(int to, void *to_arg, byte* buf, int sz) +void bin_write(int to, void *to_arg, byte* buf, size_t sz) { - int i; + size_t i; for (i=0;i<sz;i++) { if (IS_DIGIT(buf[i])) @@ -2952,15 +2942,15 @@ char* Sint_to_buf(Sint n, struct Sint_buf *buf) */ Eterm -buf_to_intlist(Eterm** hpp, char *buf, int len, Eterm tail) +buf_to_intlist(Eterm** hpp, char *buf, size_t len, Eterm tail) { Eterm* hp = *hpp; - int i = len - 1; + size_t i = len; - while(i >= 0) { + while(i != 0) { + --i; tail = CONS(hp, make_small((Uint)(byte)buf[i]), tail); hp += 2; - --i; } *hpp = hp; @@ -3469,11 +3459,9 @@ void erts_silence_warn_unused_result(long unused) * Handy functions when using a debugger - don't use in the code! */ -void upp(buf,sz) -byte* buf; -int sz; +void upp(byte *buf, size_t sz) { - bin_write(ERTS_PRINT_STDERR,NULL,buf,sz); + bin_write(ERTS_PRINT_STDERR, NULL, buf, sz); } void pat(Eterm atom) diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 901d98c09d..a251b064da 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -55,6 +55,7 @@ #define FILE_READ_LINE 29 #define FILE_FDATASYNC 30 #define FILE_FADVISE 31 +#define FILE_SENDFILE 32 /* Return codes */ @@ -98,7 +99,14 @@ # include "config.h" #endif #include <stdlib.h> + +// Need (NON)BLOCKING macros for sendfile +#ifndef WANT_NONBLOCKING +#define WANT_NONBLOCKING +#endif + #include "sys.h" + #include "erl_driver.h" #include "erl_efile.h" #include "erl_threads.h" @@ -140,6 +148,22 @@ static ErlDrvSysInfo sys_info; #define MUTEX_UNLOCK(m) #endif + +/** + * On DARWIN sendfile can deadlock with close if called in + * different threads. So until Apple fixes so that sendfile + * is not buggy we disable usage of the async pool for + * DARWIN. The testcase t_sendfile_crashduring reproduces + * this error when using +A 10. + */ +#if defined(__APPLE__) && defined(__MACH__) +#define USE_THRDS_FOR_SENDFILE 0 +#else +#define USE_THRDS_FOR_SENDFILE (sys_info.async_threads > 0) +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + + #if 0 /* Experimental, for forcing all file operations to use the same thread. */ static unsigned file_fixed_key = 1; @@ -217,17 +241,26 @@ typedef unsigned char uchar; static ErlDrvData file_start(ErlDrvPort port, char* command); static int file_init(void); static void file_stop(ErlDrvData); -static void file_output(ErlDrvData, char* buf, int len); -static int file_control(ErlDrvData, unsigned int command, - char* buf, int len, char **rbuf, int rlen); +static void file_output(ErlDrvData, char* buf, ErlDrvSizeT len); +static ErlDrvSSizeT file_control(ErlDrvData, unsigned int command, + char* buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen); static void file_timeout(ErlDrvData); static void file_outputv(ErlDrvData, ErlIOVec*); static void file_async_ready(ErlDrvData, ErlDrvThreadData); static void file_flush(ErlDrvData); +#ifdef HAVE_SENDFILE +static void file_ready_output(ErlDrvData data, ErlDrvEvent event); +static void file_stop_select(ErlDrvEvent event, void* _); +#endif /* HAVE_SENDFILE */ enum e_timer {timer_idle, timer_again, timer_write}; +#ifdef HAVE_SENDFILE +enum e_sendfile {sending, not_sending}; +static void free_sendfile(void *data); +#endif /* HAVE_SENDFILE */ struct t_data; @@ -242,6 +275,9 @@ typedef struct { struct t_data *cq_head; /* Queue of incoming commands */ struct t_data *cq_tail; /* -""- */ enum e_timer timer_state; +#ifdef HAVE_SENDFILE + enum e_sendfile sendfile_state; +#endif /* HAVE_SENDFILE */ size_t read_bufsize; ErlDrvBinary *read_binp; size_t read_offset; @@ -264,7 +300,11 @@ struct erl_drv_entry efile_driver_entry = { file_stop, file_output, NULL, +#ifdef HAVE_SENDFILE + file_ready_output, +#else NULL, +#endif /* HAVE_SENDFILE */ "efile", NULL, NULL, @@ -279,7 +319,13 @@ struct erl_drv_entry efile_driver_entry = { ERL_DRV_EXTENDED_MAJOR_VERSION, ERL_DRV_EXTENDED_MINOR_VERSION, ERL_DRV_FLAG_USE_PORT_LOCKING, + NULL, + NULL, +#ifdef HAVE_SENDFILE + file_stop_select +#else NULL +#endif /* HAVE_SENDFILE */ }; @@ -398,6 +444,16 @@ struct t_data Sint64 length; int advise; } fadvise; +#ifdef HAVE_SENDFILE + struct { + ErlDrvPort port; + ErlDrvPDL q_mtx; + int out_fd; + off_t offset; + Uint64 nbytes; + Uint64 written; + } sendfile; +#endif /* HAVE_SENDFILE */ } c; char b[1]; }; @@ -485,7 +541,6 @@ static void *ef_safe_realloc(void *op, Uint s) : 0) - #if 0 static void ev_clear(ErlIOVec *ev) { @@ -613,7 +668,6 @@ static struct t_data *cq_deq(file_descriptor *desc) { } - /********************************************************************* * Driver entry point -> init */ @@ -628,6 +682,7 @@ file_init(void) ? atoi(buf) : 0); driver_system_info(&sys_info, sizeof(ErlDrvSysInfo)); + return 0; } @@ -655,6 +710,9 @@ file_start(ErlDrvPort port, char* command) desc->cq_head = NULL; desc->cq_tail = NULL; desc->timer_state = timer_idle; +#ifdef HAVE_SENDFILE + desc->sendfile_state = not_sending; +#endif desc->read_bufsize = 0; desc->read_binp = NULL; desc->read_offset = 0; @@ -762,7 +820,16 @@ static void reply_Uint_posix_error(file_descriptor *desc, Uint num, driver_output2(desc->port, response, t-response, NULL, 0); } +static void reply_string_error(file_descriptor *desc, char* str) { + char response[256]; /* Response buffer. */ + char* s; + char* t; + response[0] = FILE_RESP_ERROR; + for (s = str, t = response+1; *s; s++, t++) + *t = tolower(*s); + driver_output2(desc->port, response, t-response, NULL, 0); +} static int reply_error(file_descriptor *desc, Efile_error *errInfo) /* The error codes. */ @@ -893,8 +960,6 @@ static int reply_eof(file_descriptor *desc) { driver_output2(desc->port, &c, 1, NULL, 0); return 0; } - - static void invoke_name(void *data, int (*f)(Efile_error *, char *)) { @@ -1013,7 +1078,7 @@ static void invoke_read_line(void *data) d->c.read_line.read_offset - d->c.read_line.read_size; if (size == 0) { /* Need more place */ - size_t need = (d->c.read_line.read_size >= DEFAULT_LINEBUF_SIZE) ? + ErlDrvSizeT need = (d->c.read_line.read_size >= DEFAULT_LINEBUF_SIZE) ? d->c.read_line.read_size + DEFAULT_LINEBUF_SIZE : DEFAULT_LINEBUF_SIZE; ErlDrvBinary *newbin = driver_alloc_binary(need); if (newbin == NULL) { @@ -1314,7 +1379,11 @@ static void invoke_writev(void *data) { size = d->c.writev.size; } - /* Copy the io vector to avoid locking the port que while writing */ + /* Copy the io vector to avoid locking the port que while writing, + * also, both we and efile_writev might/will change the SysIOVec + * when segmenting or due to partial write and we do not want to + * tamper with the actual queue that we get from driver_peekq + */ MUTEX_LOCK(d->c.writev.q_mtx); /* Lock before accessing the port queue */ iov0 = driver_peekq(d->c.writev.port, &iovlen); @@ -1353,7 +1422,7 @@ static void invoke_writev(void *data) { } else { d->result_ok = efile_writev(&d->errInfo, d->flags, (int) d->fd, - iov, iovcnt, size); + iov, iovcnt); } } else if (iovlen == 0) { d->result_ok = 1; @@ -1694,6 +1763,80 @@ static void invoke_fadvise(void *data) d->result_ok = efile_fadvise(&d->errInfo, fd, offset, length, advise); } +#ifdef HAVE_SENDFILE +static void invoke_sendfile(void *data) +{ + struct t_data *d = (struct t_data *)data; + int fd = d->fd; + int out_fd = (int)d->c.sendfile.out_fd; + Uint64 nbytes = d->c.sendfile.nbytes; + int result = 0; + d->again = 0; + + result = efile_sendfile(&d->errInfo, fd, out_fd, &d->c.sendfile.offset, &nbytes, NULL); + + d->c.sendfile.written += nbytes; + + if (result == 1 || (result == 0 && USE_THRDS_FOR_SENDFILE)) { + d->result_ok = 0; + } else if (result == 0 && (d->errInfo.posix_errno == EAGAIN + || d->errInfo.posix_errno == EINTR)) { + if ((d->c.sendfile.nbytes - nbytes) != 0) { + d->result_ok = 1; + if (d->c.sendfile.nbytes != 0) + d->c.sendfile.nbytes -= nbytes; + } else + d->result_ok = 0; + } else { + d->result_ok = -1; + } +} + +static void free_sendfile(void *data) { + struct t_data *d = (struct t_data *)data; + if (USE_THRDS_FOR_SENDFILE) { + SET_NONBLOCKING(d->c.sendfile.out_fd); + } else { + MUTEX_LOCK(d->c.sendfile.q_mtx); + driver_deq(d->c.sendfile.port,1); + MUTEX_UNLOCK(d->c.sendfile.q_mtx); + driver_select(d->c.sendfile.port, (ErlDrvEvent)(long)d->c.sendfile.out_fd, ERL_DRV_USE_NO_CALLBACK|ERL_DRV_WRITE, 0); + } + EF_FREE(data); +} + +static void file_ready_output(ErlDrvData data, ErlDrvEvent event) +{ + file_descriptor* fd = (file_descriptor*) data; + + switch (fd->d->command) { + case FILE_SENDFILE: + driver_select(fd->d->c.sendfile.port, event, + (int)ERL_DRV_WRITE,(int) 0); + invoke_sendfile((void *)fd->d); + file_async_ready(data, (ErlDrvThreadData)fd->d); + break; + default: + break; + } +} + +static void file_stop_select(ErlDrvEvent event, void* _) +{ + +} + +static int flush_sendfile(file_descriptor *desc,void *_) { + if (desc->sendfile_state == sending) { + desc->d->result_ok = -1; + desc->d->errInfo.posix_errno = ECONNABORTED; + file_async_ready((ErlDrvData)desc,(ErlDrvThreadData)desc->d); + } + return 1; +} +#endif /* HAVE_SENDFILE */ + + static void free_readdir(void *data) { struct t_data *d = (struct t_data *) data; @@ -1755,6 +1898,10 @@ static void cq_execute(file_descriptor *desc) { register void *void_ptr; /* Soft cast variable */ if (desc->timer_state == timer_again) return; +#ifdef HAVE_SENDFILE + if (desc->sendfile_state == sending) + return; +#endif if (! (d = cq_deq(desc))) return; TRACE_F(("x%i", (int) d->command)); @@ -2021,24 +2168,25 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) if (d->result_ok) { resbuf[0] = FILE_RESP_INFO; - put_int32(d->info.size_high, &resbuf[1 + (0 * 4)]); - put_int32(d->info.size_low, &resbuf[1 + (1 * 4)]); - put_int32(d->info.type, &resbuf[1 + (2 * 4)]); - - PUT_TIME(d->info.accessTime, resbuf + 1 + 3*4); - PUT_TIME(d->info.modifyTime, resbuf + 1 + 9*4); - PUT_TIME(d->info.cTime, resbuf + 1 + 15*4); - - put_int32(d->info.mode, &resbuf[1 + (21 * 4)]); - put_int32(d->info.links, &resbuf[1 + (22 * 4)]); - put_int32(d->info.major_device, &resbuf[1 + (23 * 4)]); - put_int32(d->info.minor_device, &resbuf[1 + (24 * 4)]); - put_int32(d->info.inode, &resbuf[1 + (25 * 4)]); - put_int32(d->info.uid, &resbuf[1 + (26 * 4)]); - put_int32(d->info.gid, &resbuf[1 + (27 * 4)]); - put_int32(d->info.access, &resbuf[1 + (28 * 4)]); - -#define RESULT_SIZE (1 + (29 * 4)) + put_int32(d->info.size_high, &resbuf[1 + ( 0 * 4)]); + put_int32(d->info.size_low, &resbuf[1 + ( 1 * 4)]); + put_int32(d->info.type, &resbuf[1 + ( 2 * 4)]); + + /* Note 64 bit indexing in resbuf here */ + put_int64(d->info.accessTime, &resbuf[1 + ( 3 * 4)]); + put_int64(d->info.modifyTime, &resbuf[1 + ( 5 * 4)]); + put_int64(d->info.cTime, &resbuf[1 + ( 7 * 4)]); + + put_int32(d->info.mode, &resbuf[1 + ( 9 * 4)]); + put_int32(d->info.links, &resbuf[1 + (10 * 4)]); + put_int32(d->info.major_device, &resbuf[1 + (11 * 4)]); + put_int32(d->info.minor_device, &resbuf[1 + (12 * 4)]); + put_int32(d->info.inode, &resbuf[1 + (13 * 4)]); + put_int32(d->info.uid, &resbuf[1 + (14 * 4)]); + put_int32(d->info.gid, &resbuf[1 + (15 * 4)]); + put_int32(d->info.access, &resbuf[1 + (16 * 4)]); + +#define RESULT_SIZE (1 + (17 * 4)) TRACE_C('R'); driver_output2(desc->port, resbuf, RESULT_SIZE, NULL, 0); #undef RESULT_SIZE @@ -2105,6 +2253,29 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) } free_preadv(data); break; +#ifdef HAVE_SENDFILE + case FILE_SENDFILE: + if (d->result_ok == -1) { + if (d->errInfo.posix_errno == ECONNRESET || + d->errInfo.posix_errno == ENOTCONN || + d->errInfo.posix_errno == EPIPE) + reply_string_error(desc,"closed"); + else + reply_error(desc, &d->errInfo); + desc->sendfile_state = not_sending; + free_sendfile(data); + } else if (d->result_ok == 0) { + reply_Sint64(desc, d->c.sendfile.written); + desc->sendfile_state = not_sending; + free_sendfile(data); + } else if (d->result_ok == 1) { // If we are using select to send the rest of the data + desc->sendfile_state = sending; + desc->d = d; + driver_select(desc->port, (ErlDrvEvent)(long)d->c.sendfile.out_fd, + ERL_DRV_USE_NO_CALLBACK|ERL_DRV_WRITE, 1); + } + break; +#endif default: abort(); } @@ -2120,7 +2291,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) * Driver entry point -> output */ static void -file_output(ErlDrvData e, char* buf, int count) +file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { file_descriptor* desc = (file_descriptor*)e; Efile_error errInfo; /* The error codes for the last operation. */ @@ -2355,15 +2526,16 @@ file_output(ErlDrvData e, char* buf, int count) case FILE_WRITE_INFO: { d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 - + FILENAME_BYTELEN(buf+21*4) + FILENAME_CHARSIZE); + + FILENAME_BYTELEN(buf + 9*4) + FILENAME_CHARSIZE); - d->info.mode = get_int32(buf + 0 * 4); - d->info.uid = get_int32(buf + 1 * 4); - d->info.gid = get_int32(buf + 2 * 4); - GET_TIME(d->info.accessTime, buf + 3 * 4); - GET_TIME(d->info.modifyTime, buf + 9 * 4); - GET_TIME(d->info.cTime, buf + 15 * 4); - FILENAME_COPY(d->b, buf+21*4); + d->info.mode = get_int32(buf + 0 * 4); + d->info.uid = get_int32(buf + 1 * 4); + d->info.gid = get_int32(buf + 2 * 4); + d->info.accessTime = (time_t)((Sint64)get_int64(buf + 3 * 4)); + d->info.modifyTime = (time_t)((Sint64)get_int64(buf + 5 * 4)); + d->info.cTime = (time_t)((Sint64)get_int64(buf + 7 * 4)); + + FILENAME_COPY(d->b, buf + 9*4); d->command = command; d->invoke = invoke_write_info; d->free = free_data; @@ -2478,6 +2650,10 @@ file_flush(ErlDrvData e) { TRACE_C('f'); +#ifdef HAVE_SENDFILE + flush_sendfile(desc, NULL); +#endif + #ifdef DEBUG r = #endif @@ -2496,9 +2672,9 @@ file_flush(ErlDrvData e) { /********************************************************************* * Driver entry point -> control */ -static int +static ErlDrvSSizeT file_control(ErlDrvData e, unsigned int command, - char* buf, int len, char **rbuf, int rlen) { + char* buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { /* * warning: variable ‘desc’ set but not used * [-Wunused-but-set-variable] @@ -2799,8 +2975,8 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { cq_enq(desc, d); } goto done; case FILE_WRITE: { - int skip = 1; - int size = ev->size - skip; + ErlDrvSizeT skip = 1; + ErlDrvSizeT size = ev->size - skip; if (lseek_flush_read(desc, &err) < 0) { reply_posix_error(desc, err); goto done; @@ -2809,7 +2985,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, EBADF); goto done; } - if (size <= 0) { + if (size == 0) { reply_Uint(desc, size); goto done; } @@ -2923,7 +3099,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { EF_FREE(d); reply_Uint(desc, 0); } else { - size_t skip = 1 + 4 + 8*(2*n); + ErlDrvSizeT skip = 1 + 4 + 8*(2*n); if (skip + total != ev->size) { /* Actual amount of data does not match * total of all pos/size specs @@ -3245,9 +3421,84 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } /* case FILE_OPT_DELAYED_WRITE: */ } ASSERT(0); goto done; /* case FILE_SETOPT: */ - + + case FILE_SENDFILE: { + +#ifdef HAVE_SENDFILE + struct t_data *d; + Uint32 out_fd, offsetH, offsetL, hd_len, tl_len; + Uint64 nbytes; + char flags; + + if (ev->size < 1 + 7 * sizeof(Uint32) + sizeof(char) + || !EV_GET_UINT32(ev, &out_fd, &p, &q) + || !EV_GET_CHAR(ev, &flags, &p, &q) + || !EV_GET_UINT32(ev, &offsetH, &p, &q) + || !EV_GET_UINT32(ev, &offsetL, &p, &q) + || !EV_GET_UINT64(ev, &nbytes, &p, &q) + || !EV_GET_UINT32(ev, &hd_len, &p, &q) + || !EV_GET_UINT32(ev, &tl_len, &p, &q)) { + /* Buffer has wrong length to contain all the needed values */ + reply_posix_error(desc, EINVAL); + goto done; + } + + if (hd_len != 0 || tl_len != 0 || flags != 0) { + // We do not allow header, trailers and/or flags right now + reply_posix_error(desc, EINVAL); + goto done; + } + + d = EF_SAFE_ALLOC(sizeof(struct t_data)); + d->fd = desc->fd; + d->command = command; + d->invoke = invoke_sendfile; + d->free = free_sendfile; + d->level = 2; + + d->c.sendfile.out_fd = (int) out_fd; + d->c.sendfile.written = 0; + d->c.sendfile.port = desc->port; + d->c.sendfile.q_mtx = desc->q_mtx; + + #if SIZEOF_OFF_T == 4 + if (offsetH != 0) { + reply_posix_error(desc, EINVAL); + goto done; + } + d->c.sendfile.offset = (off_t) offsetL; + #else + d->c.sendfile.offset = ((off_t) offsetH << 32) | offsetL; + #endif + + d->c.sendfile.nbytes = nbytes; + + if (USE_THRDS_FOR_SENDFILE) { + SET_BLOCKING(d->c.sendfile.out_fd); + } else { + /** + * Write a place holder to queue in order to force file_flush + * to be called before the driver is closed. + */ + char tmp[1] = ""; + MUTEX_LOCK(d->c.sendfile.q_mtx); + if (driver_enq(d->c.sendfile.port, tmp, 1)) { + MUTEX_UNLOCK(d->c.sendfile.q_mtx); + reply_posix_error(desc, ENOMEM); + goto done; + } + MUTEX_UNLOCK(d->c.sendfile.q_mtx); + } + + cq_enq(desc, d); +#else + reply_posix_error(desc, ENOTSUP); +#endif + goto done; + } /* case FILE_SENDFILE: */ + } /* switch(command) */ - + if (lseek_flush_read(desc, &err) < 0) { reply_posix_error(desc, err); goto done; diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h index 3097ded3f1..69ad02633c 100644 --- a/erts/emulator/drivers/common/erl_efile.h +++ b/erts/emulator/drivers/common/erl_efile.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2010. All Rights Reserved. + * Copyright Ericsson AB 1997-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -67,6 +67,11 @@ #define FILENAMES_16BIT 1 #endif +// We use sendfilev if it exist on solaris +#if !defined(HAVE_SENDFILE) && defined(HAVE_SENDFILEV) +#define HAVE_SENDFILE +#endif + /* * An handle to an open directory. To be cast to the correct type * in the system-dependent directory functions. @@ -85,14 +90,15 @@ typedef struct _Efile_error { /* * This structure contains date and time. */ -typedef struct _Efile_time { - unsigned year; /* (4 digits). */ - unsigned month; /* (1..12). */ - unsigned day; /* (1..31). */ - unsigned hour; /* (0..23). */ - unsigned minute; /* (0..59). */ - unsigned second; /* (0..59). */ -} Efile_time; + +//typedef struct _Efile_time { +// unsigned year; /* (4 digits). */ +// unsigned month; /* (1..12). */ +// unsigned day; /* (1..31). */ +// unsigned hour; /* (0..23). */ +// unsigned minute; /* (0..59). */ +// unsigned second; /* (0..59). */ +//} Efile_time; /* @@ -111,13 +117,26 @@ typedef struct _Efile_info { Uint32 inode; /* Inode number. */ Uint32 uid; /* User id of owner. */ Uint32 gid; /* Group id of owner. */ - Efile_time accessTime; /* Last time the file was accessed. */ - Efile_time modifyTime; /* Last time the file was modified. */ - Efile_time cTime; /* Creation time (Windows) or last + time_t accessTime; /* Last time the file was accessed. */ + time_t modifyTime; /* Last time the file was modified. */ + time_t cTime; /* Creation time (Windows) or last * inode change (Unix). */ } Efile_info; + +#ifdef HAVE_SENDFILE +/* + * Describes the structure of headers/trailers for sendfile + */ +struct t_sendfile_hdtl { + SysIOVec *headers; + int hdr_cnt; + SysIOVec *trailers; + int trl_cnt; +}; +#endif /* HAVE_SENDFILE */ + /* * Functions. */ @@ -143,7 +162,7 @@ int efile_write_info(Efile_error* errInfo, Efile_info* pInfo, char *name); int efile_write(Efile_error* errInfo, int flags, int fd, char* buf, size_t count); int efile_writev(Efile_error* errInfo, int flags, int fd, - SysIOVec* iov, int iovcnt, size_t size); + SysIOVec* iov, int iovcnt); int efile_read(Efile_error* errInfo, int flags, int fd, char* buf, size_t count, size_t* pBytesRead); int efile_seek(Efile_error* errInfo, int fd, @@ -162,3 +181,7 @@ int efile_symlink(Efile_error* errInfo, char* old, char* new); int efile_may_openfile(Efile_error* errInfo, char *name); int efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length, int advise); +#ifdef HAVE_SENDFILE +int efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, + off_t *offset, Uint64 *nbytes, struct t_sendfile_hdtl *hdtl); +#endif /* HAVE_SENDFILE */ diff --git a/erts/emulator/drivers/common/gzio.c b/erts/emulator/drivers/common/gzio.c index 741cb6ae20..a9303d55bc 100644 --- a/erts/emulator/drivers/common/gzio.c +++ b/erts/emulator/drivers/common/gzio.c @@ -27,7 +27,9 @@ #endif #ifdef __WIN32__ +#ifndef HAVE_CONFLICTING_FREAD_DECLARATION #define HAVE_CONFLICTING_FREAD_DECLARATION +#endif #define FILENAMES_16BIT 1 #endif diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 1fe9e04341..d1c2dbf94c 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -80,6 +80,13 @@ #endif #ifdef __WIN32__ +#define LLU "%I64u" +#else +#define LLU "%llu" +#endif +typedef unsigned long long llu_t; + +#ifdef __WIN32__ #define STRNCASECMP strncasecmp #define INCL_WINSOCK_API_TYPEDEFS 1 @@ -110,6 +117,77 @@ #undef EWOULDBLOCK #undef ETIMEDOUT +#ifdef EINPROGRESS +#undef EINPROGRESS +#endif +#ifdef EALREADY +#undef EALREADY +#endif +#ifdef ENOTSOCK +#undef ENOTSOCK +#endif +#ifdef EDESTADDRREQ +#undef EDESTADDRREQ +#endif +#ifdef EMSGSIZE +#undef EMSGSIZE +#endif +#ifdef EPROTOTYPE +#undef EPROTOTYPE +#endif +#ifdef ENOPROTOOPT +#undef ENOPROTOOPT +#endif +#ifdef EPROTONOSUPPORT +#undef EPROTONOSUPPORT +#endif +#ifdef EOPNOTSUPP +#undef EOPNOTSUPP +#endif +#ifdef EAFNOSUPPORT +#undef EAFNOSUPPORT +#endif +#ifdef EADDRINUSE +#undef EADDRINUSE +#endif +#ifdef EADDRNOTAVAIL +#undef EADDRNOTAVAIL +#endif +#ifdef ENETDOWN +#undef ENETDOWN +#endif +#ifdef ENETUNREACH +#undef ENETUNREACH +#endif +#ifdef ENETRESET +#undef ENETRESET +#endif +#ifdef ECONNABORTED +#undef ECONNABORTED +#endif +#ifdef ECONNRESET +#undef ECONNRESET +#endif +#ifdef ENOBUFS +#undef ENOBUFS +#endif +#ifdef EISCONN +#undef EISCONN +#endif +#ifdef ENOTCONN +#undef ENOTCONN +#endif +#ifdef ECONNREFUSED +#undef ECONNREFUSED +#endif +#ifdef ELOOP +#undef ELOOP +#endif +#ifdef EHOSTUNREACH +#undef EHOSTUNREACH +#endif + + #define HAVE_MULTICAST_SUPPORT #define ERRNO_BLOCK WSAEWOULDBLOCK @@ -445,6 +523,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) driver_select(port, e, mode | (on?ERL_DRV_USE:0), on) #define sock_select(d, flags, onoff) do { \ + ASSERT(!(d)->is_ignored); \ (d)->event_mask = (onoff) ? \ ((d)->event_mask | (flags)) : \ ((d)->event_mask & ~(flags)); \ @@ -467,6 +546,19 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) (((unsigned char*) (s))[1] << 8) | \ (((unsigned char*) (s))[0])) + +#ifdef VALGRIND +# include <valgrind/memcheck.h> +#else +# define VALGRIND_MAKE_MEM_DEFINED(ptr,size) +#endif + +/* + Magic errno value used locally for return of {error, system_limit} + - the emulator definition of SYSTEM_LIMIT is not available here. +*/ +#define INET_ERRNO_SYSTEM_LIMIT (15 << 8) + /*---------------------------------------------------------------------------- ** Interface constants. ** @@ -538,6 +630,8 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) #define INET_REQ_GETIFADDRS 25 #define INET_REQ_ACCEPT 26 #define INET_REQ_LISTEN 27 +#define INET_REQ_IGNOREFD 28 + /* TCP requests */ /* #define TCP_REQ_ACCEPT 40 MOVED */ /* #define TCP_REQ_LISTEN 41 MERGED */ @@ -725,6 +819,11 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) /* Max interface name */ #define INET_IFNAMSIZ 16 +/* INET Ignore states */ +#define INET_IGNORE_NONE 0 +#define INET_IGNORE_READ 1 +#define INET_IGNORE_WRITE 1 << 1 + /* Max length of Erlang Term Buffer (for outputting structured terms): */ #ifdef HAVE_SCTP #define PACKET_ERL_DRV_TERM_DATA_LEN 512 @@ -864,6 +963,9 @@ typedef struct { double send_avg; /* average packet size sent */ subs_list empty_out_q_subs; /* Empty out queue subscribers */ + int is_ignored; /* if a fd is ignored by the inet_drv. + This flag should be set to true when + the fd is used outside of inet_drv. */ } inet_descriptor; @@ -876,13 +978,14 @@ typedef struct { static int tcp_inet_init(void); static void tcp_inet_stop(ErlDrvData); -static void tcp_inet_command(ErlDrvData, char*, int); +static void tcp_inet_command(ErlDrvData, char*, ErlDrvSizeT); static void tcp_inet_commandv(ErlDrvData, ErlIOVec*); static void tcp_inet_flush(ErlDrvData drv_data); static void tcp_inet_drv_input(ErlDrvData, ErlDrvEvent); static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event); static ErlDrvData tcp_inet_start(ErlDrvPort, char* command); -static int tcp_inet_ctl(ErlDrvData, unsigned int, char*, int, char**, int); +static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData, unsigned int, + char*, ErlDrvSizeT, char**, ErlDrvSizeT); static void tcp_inet_timeout(ErlDrvData); static void tcp_inet_process_exit(ErlDrvData, ErlDrvMonitor *); static void inet_stop_select(ErlDrvEvent, void*); @@ -927,15 +1030,15 @@ static struct erl_drv_entry tcp_inet_driver_entry = static int packet_inet_init(void); static void packet_inet_stop(ErlDrvData); -static void packet_inet_command(ErlDrvData, char*, int); +static void packet_inet_command(ErlDrvData, char*, ErlDrvSizeT); static void packet_inet_drv_input(ErlDrvData data, ErlDrvEvent event); static void packet_inet_drv_output(ErlDrvData data, ErlDrvEvent event); static ErlDrvData udp_inet_start(ErlDrvPort, char* command); #ifdef HAVE_SCTP static ErlDrvData sctp_inet_start(ErlDrvPort, char* command); #endif -static int packet_inet_ctl(ErlDrvData, unsigned int, char*, - int, char**, int); +static ErlDrvSSizeT packet_inet_ctl(ErlDrvData, unsigned int, char*, + ErlDrvSizeT, char**, ErlDrvSizeT); static void packet_inet_timeout(ErlDrvData); #ifdef __WIN32__ static void packet_inet_event(ErlDrvData, ErlDrvEvent); @@ -1029,7 +1132,7 @@ typedef struct { } tcp_descriptor; /* send function */ -static int tcp_send(tcp_descriptor* desc, char* ptr, int len); +static int tcp_send(tcp_descriptor* desc, char* ptr, ErlDrvSizeT len); static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev); static int tcp_recv(tcp_descriptor* desc, int request_len); static int tcp_deliver(tcp_descriptor* desc, int len); @@ -1096,7 +1199,7 @@ static ErlDrvTermData am_tos; static int inet_init(void); -static int ctl_reply(int, char*, int, char**, int); +static ErlDrvSSizeT ctl_reply(int, char*, ErlDrvSizeT, char**, ErlDrvSizeT); struct erl_drv_entry inet_driver_entry = { @@ -1106,7 +1209,23 @@ struct erl_drv_entry inet_driver_entry = NULL, /* output */ NULL, /* ready_input */ NULL, /* ready_output */ - "inet" + "inet", + NULL, + NULL, /* handle */ + NULL, /* control */ + NULL, /* timeout */ + NULL, /* outputv */ + NULL, /* ready_async */ + NULL, /* flush */ + NULL, /* call */ + NULL, /* event */ + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL, }; /* XXX: is this a driver interface function ??? */ @@ -1120,7 +1239,7 @@ void erl_exit(int n, char*, ...); #ifdef FATAL_MALLOC -static void *alloc_wrapper(size_t size){ +static void *alloc_wrapper(ErlDrvSizeT size){ void *ret = driver_alloc(size); if(ret == NULL) erl_exit(1,"Out of virtual memory in malloc (%s)", __FILE__); @@ -1128,7 +1247,7 @@ static void *alloc_wrapper(size_t size){ } #define ALLOC(X) alloc_wrapper(X) -static void *realloc_wrapper(void *current, size_t size){ +static void *realloc_wrapper(void *current, ErlDrvSizeT size){ void *ret = driver_realloc(current,size); if(ret == NULL) erl_exit(1,"Out of virtual memory in realloc (%s)", __FILE__); @@ -1357,11 +1476,11 @@ static InetDrvBufStk *get_bufstk(void) return bs; } -static ErlDrvBinary* alloc_buffer(long minsz) +static ErlDrvBinary* alloc_buffer(ErlDrvSizeT minsz) { InetDrvBufStk *bs = get_bufstk(); - DEBUGF(("alloc_buffer: %ld\r\n", minsz)); + DEBUGF(("alloc_buffer: "LLU"\r\n", (llu_t)minsz)); if (bs && bs->buf.pos > 0) { long size; @@ -1437,7 +1556,7 @@ static void release_buffer(ErlDrvBinary* buf) } } -static ErlDrvBinary* realloc_buffer(ErlDrvBinary* buf, long newsz) +static ErlDrvBinary* realloc_buffer(ErlDrvBinary* buf, ErlDrvSizeT newsz) { return driver_realloc_binary(buf, newsz); } @@ -1466,8 +1585,9 @@ static ErlDrvData dummy_start(ErlDrvPort port, char* command) return (ErlDrvData)port; } -static int dummy_ctl(ErlDrvData data, unsigned int cmd, char* buf, int len, - char** rbuf, int rsize) +static ErlDrvSSizeT dummy_ctl(ErlDrvData data, unsigned int cmd, + char* buf, ErlDrvSizeT len, char** rbuf, + ErlDrvSizeT rsize) { static char error[] = "no_winsock2"; @@ -1475,7 +1595,7 @@ static int dummy_ctl(ErlDrvData data, unsigned int cmd, char* buf, int len, return ctl_reply(INET_REP_ERROR, error, sizeof(error), rbuf, rsize); } -static void dummy_command(ErlDrvData data, char* buf, int len) +static void dummy_command(ErlDrvData data, char* buf, ErlDrvSizeT len) { } @@ -1531,8 +1651,20 @@ static struct erl_drv_entry dummy_sctp_driver_entry = #endif +/* return lowercase string form of errno value */ +static char *errno_str(int err) +{ + switch (err) { + case INET_ERRNO_SYSTEM_LIMIT: + return "system_limit"; + default: + return erl_errno_id(err); + } +} + /* general control reply function */ -static int ctl_reply(int rep, char* buf, int len, char** rbuf, int rsize) +static ErlDrvSSizeT ctl_reply(int rep, char* buf, ErlDrvSizeT len, + char** rbuf, ErlDrvSizeT rsize) { char* ptr; @@ -1548,18 +1680,14 @@ static int ctl_reply(int rep, char* buf, int len, char** rbuf, int rsize) } /* general control error reply function */ -static int ctl_error(int err, char** rbuf, int rsize) +static ErlDrvSSizeT ctl_error(int err, char** rbuf, ErlDrvSizeT rsize) { - char response[256]; /* Response buffer. */ - char* s; - char* t; + char* s = errno_str(err); - for (s = erl_errno_id(err), t = response; *s; s++, t++) - *t = tolower(*s); - return ctl_reply(INET_REP_ERROR, response, t-response, rbuf, rsize); + return ctl_reply(INET_REP_ERROR, s, strlen(s), rbuf, rsize); } -static int ctl_xerror(char* xerr, char** rbuf, int rsize) +static ErlDrvSSizeT ctl_xerror(char* xerr, char** rbuf, ErlDrvSizeT rsize) { int n = strlen(xerr); return ctl_reply(INET_REP_ERROR, xerr, n, rbuf, rsize); @@ -1568,14 +1696,7 @@ static int ctl_xerror(char* xerr, char** rbuf, int rsize) static ErlDrvTermData error_atom(int err) { - char errstr[256]; - char* s; - char* t; - - for (s = erl_errno_id(err), t = errstr; *s; s++, t++) - *t = tolower(*s); - *t = '\0'; - return driver_mk_atom(errstr); + return driver_mk_atom(errno_str(err)); } @@ -3576,7 +3697,8 @@ static int inet_init() ** and is set to actual length of dst on return ** return NULL on error and ptr after port address on success */ -static char* inet_set_address(int family, inet_address* dst, char* src, int* len) +static char* inet_set_address(int family, inet_address* dst, + char* src, ErlDrvSizeT* len) { short port; @@ -3612,7 +3734,7 @@ static char* inet_set_address(int family, inet_address* dst, char* src, int* len ** src = [TAG,P1,P0,X1,X2,...] when TAG = INET_AF_INET | INET_AF_INET6 */ static char *inet_set_faddress(int family, inet_address* dst, - char *src, int* len) { + char *src, ErlDrvSizeT* len) { int tag; if (*len < 1) return NULL; @@ -3727,7 +3849,13 @@ static void desc_close(inet_descriptor* desc) desc->forced_events = 0; desc->send_would_block = 0; #endif - driver_select(desc->port, (ErlDrvEvent)(long)desc->event, ERL_DRV_USE, 0); + // We should close the fd here, but the other driver might still + // be selecting on it. + if (!desc->is_ignored) + driver_select(desc->port,(ErlDrvEvent)(long)desc->event, + ERL_DRV_USE, 0); + else + inet_stop_select((ErlDrvEvent)(long)desc->event,NULL); desc->event = INVALID_EVENT; /* closed by stop_select callback */ desc->s = INVALID_SOCKET; desc->event_mask = 0; @@ -3770,8 +3898,8 @@ static int erl_inet_close(inet_descriptor* desc) } -static int inet_ctl_open(inet_descriptor* desc, int domain, int type, - char** rbuf, int rsize) +static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, + char** rbuf, ErlDrvSizeT rsize) { if (desc->state != INET_STATE_CLOSED) return ctl_xerror(EXBADSEQ, rbuf, rsize); @@ -3791,8 +3919,8 @@ static int inet_ctl_open(inet_descriptor* desc, int domain, int type, /* as inet_open but pass in an open socket (MUST BE OF RIGHT TYPE) */ -static int inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, - SOCKET s, char** rbuf, int rsize) +static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, + SOCKET s, char** rbuf, ErlDrvSizeT rsize) { inet_address name; unsigned int sz = sizeof(name); @@ -3967,6 +4095,7 @@ static char* buf_to_sockaddr(char* ptr, char* end, struct sockaddr* addr) addr->sa_family = AF_INET; return ptr + sizeof(struct in_addr); } +#if defined(HAVE_IN6) && defined(AF_INET6) case INET_AF_INET6: { struct in6_addr *p = &((struct sockaddr_in6*)addr)->sin6_addr; buf_check(ptr,end,sizeof(struct in6_addr)); @@ -3974,6 +4103,7 @@ static char* buf_to_sockaddr(char* ptr, char* end, struct sockaddr* addr) addr->sa_family = AF_INET6; return ptr + sizeof(struct in6_addr); } +#endif } error: return NULL; @@ -3996,14 +4126,15 @@ static char* buf_to_sockaddr(char* ptr, char* end, struct sockaddr* addr) #if defined(__WIN32__) && defined(SIO_GET_INTERFACE_LIST) -static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize) +static ErlDrvSSizeT inet_ctl_getiflist(inet_descriptor* desc, + char** rbuf, ErlDrvSizeT rsize) { char ifbuf[BUFSIZ]; char sbuf[BUFSIZ]; char* sptr; INTERFACE_INFO* ifp; DWORD len; - int n; + ErlDrvSizeT n; int err; ifp = (INTERFACE_INFO*) ifbuf; @@ -4033,8 +4164,8 @@ static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize) /* input is an ip-address in string format i.e A.B.C.D ** scan the INTERFACE_LIST to get the options */ -static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, - char** rbuf, int rsize) +static ErlDrvSSizeT inet_ctl_ifget(inet_descriptor* desc, char* buf, + ErlDrvSizeT len, char** rbuf, ErlDrvSizeT rsize) { char ifbuf[BUFSIZ]; int n; @@ -4135,8 +4266,9 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, } /* not supported */ -static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len, - char** rbuf, int rsize) +static ErlDrvSSizeT inet_ctl_ifset(inet_descriptor* desc, + char* buf, ErlDrvSizeT len, + char** rbuf, ErlDrvSizeT rsize) { return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } @@ -4179,12 +4311,13 @@ static void free_ifconf(struct ifconf *ifcp) { FREE(ifcp->ifc_buf); } -static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize) +static ErlDrvSSizeT inet_ctl_getiflist(inet_descriptor* desc, + char** rbuf, ErlDrvSizeT rsize) { struct ifconf ifc; struct ifreq *ifrp; char *sbuf, *sp; - int i; + ErlDrvSizeT i; /* Courtesy of Per Bergqvist and W. Richard Stevens */ @@ -4196,7 +4329,7 @@ static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize) *sp++ = INET_REP_OK; i = 0; for (;;) { - int n; + ErlDrvSizeT n; ifrp = (struct ifreq *) VOIDP(ifc.ifc_buf + i); n = sizeof(ifrp->ifr_name) + SIZEA(ifrp->ifr_addr); @@ -4222,13 +4355,39 @@ static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize) return sp - sbuf; } +#ifdef HAVE_LIBDLPI_H +#include <libdlpi.h> +static int hwaddr_libdlpi_lookup(const char *ifnm, + uchar_t *addr, size_t *alen) +{ + dlpi_handle_t handle; + dlpi_info_t linkinfo; + int ret = -1; + + if (dlpi_open(ifnm, &handle, 0) != DLPI_SUCCESS) { + return -1; + } + + if (dlpi_get_physaddr(handle, DL_CURR_PHYS_ADDR, + addr, alen) == DLPI_SUCCESS && + dlpi_info(handle, &linkinfo, 0) == DLPI_SUCCESS) + { + ret = 0; + } + + dlpi_close(handle); + return ret; +} +#endif + /* FIXME: temporary hack */ #ifndef IFHWADDRLEN #define IFHWADDRLEN 6 #endif -static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, - char** rbuf, int rsize) +static ErlDrvSSizeT inet_ctl_ifget(inet_descriptor* desc, + char* buf, ErlDrvSizeT len, + char** rbuf, ErlDrvSizeT rsize) { char sbuf[BUFSIZ]; char* sptr; @@ -4257,7 +4416,24 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, break; case INET_IFOPT_HWADDR: { -#ifdef SIOCGIFHWADDR +#ifdef HAVE_LIBDLPI_H + /* + ** OpenSolaris have SIGCGIFHWADDR, but no ifr_hwaddr member.. + ** The proper way to get the mac address would be to + ** use libdlpi... + */ + uchar_t addr[DLPI_PHYSADDR_MAX]; + size_t alen = sizeof(addr); + + if (hwaddr_libdlpi_lookup(ifreq.ifr_name, addr, &alen) == 0) { + buf_check(sptr, s_end, 1+2+alen); + *sptr++ = INET_IFOPT_HWADDR; + put_int16(alen, sptr); + sptr += 2; + sys_memcpy(sptr, addr, alen); + sptr += alen; + } +#elif defined(SIOCGIFHWADDR) && defined(HAVE_STRUCT_IFREQ_IFR_HWADDR) if (ioctl(desc->s, SIOCGIFHWADDR, (char *)&ifreq) < 0) break; buf_check(sptr, s_end, 1+2+IFHWADDRLEN); @@ -4266,7 +4442,7 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, /* raw memcpy (fix include autoconf later) */ sys_memcpy(sptr, (char*)(&ifreq.ifr_hwaddr.sa_data), IFHWADDRLEN); sptr += IFHWADDRLEN; -#elif defined(SIOCGENADDR) +#elif defined(SIOCGENADDR) && defined(HAVE_STRUCT_IFREQ_IFR_ENADDR) if (ioctl(desc->s, SIOCGENADDR, (char *)&ifreq) < 0) break; buf_check(sptr, s_end, 1+2+sizeof(ifreq.ifr_enaddr)); @@ -4405,8 +4581,9 @@ static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, } -static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len, - char** rbuf, int rsize) +static ErlDrvSSizeT inet_ctl_ifset(inet_descriptor* desc, + char* buf, ErlDrvSizeT len, + char** rbuf, ErlDrvSizeT rsize) { struct ifreq ifreq; int namlen; @@ -4429,19 +4606,19 @@ static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len, break; case INET_IFOPT_HWADDR: { - unsigned int len; + unsigned int hwalen; buf_check(buf, b_end, 2); - len = get_int16(buf); buf += 2; - buf_check(buf, b_end, len); + hwalen = get_int16(buf); buf += 2; + buf_check(buf, b_end, hwalen); #ifdef SIOCSIFHWADDR /* raw memcpy (fix include autoconf later) */ sys_memset((char*)(&ifreq.ifr_hwaddr.sa_data), '\0', sizeof(ifreq.ifr_hwaddr.sa_data)); - sys_memcpy((char*)(&ifreq.ifr_hwaddr.sa_data), buf, len); + sys_memcpy((char*)(&ifreq.ifr_hwaddr.sa_data), buf, hwalen); (void) ioctl(desc->s, SIOCSIFHWADDR, (char *)&ifreq); #endif - buf += len; + buf += hwalen; break; } @@ -4527,21 +4704,24 @@ static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len, #else -static int inet_ctl_getiflist(inet_descriptor* desc, char** rbuf, int rsize) +static ErlDrvSSizeT inet_ctl_getiflist(inet_descriptor* desc, + char** rbuf, ErlDrvSizeT rsize) { return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } -static int inet_ctl_ifget(inet_descriptor* desc, char* buf, int len, - char** rbuf, int rsize) +static ErlDrvSSizeT inet_ctl_ifget(inet_descriptor* desc, + char* buf, ErlDrvSizeT len, + char** rbuf, ErlDrvSizeT rsize) { return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } -static int inet_ctl_ifset(inet_descriptor* desc, char* buf, int len, - char** rbuf, int rsize) +static ErlDrvSSizeT inet_ctl_ifset(inet_descriptor* desc, + char* buf, ErlDrvSizeT len, + char** rbuf, ErlDrvSizeT rsize) { return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); } @@ -4598,8 +4778,8 @@ int eq_masked_bytes(char *a, char *b, int pref_len) { return !0; } -static int inet_ctl_getifaddrs(inet_descriptor* desc_p, - char **rbuf_pp, int rsize) +static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, + char **rbuf_pp, ErlDrvSizeT rsize) { int i; DWORD ret, n; @@ -4609,7 +4789,7 @@ static int inet_ctl_getifaddrs(inet_descriptor* desc_p, char *buf_p; char *buf_alloc_p; - int buf_size =512; + ErlDrvSizeT buf_size = 512; # define BUF_ENSURE(Size) \ do { \ int NEED_, GOT_ = buf_p - buf_alloc_p; \ @@ -4983,12 +5163,12 @@ done: #elif defined(HAVE_GETIFADDRS) -static int inet_ctl_getifaddrs(inet_descriptor* desc_p, - char **rbuf_pp, int rsize) +static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, + char **rbuf_pp, ErlDrvSizeT rsize) { struct ifaddrs *ifa_p, *ifa_free_p; - int buf_size; + ErlDrvSizeT buf_size; char *buf_p; char *buf_alloc_p; @@ -5091,8 +5271,8 @@ static int inet_ctl_getifaddrs(inet_descriptor* desc_p, #else -static int inet_ctl_getifaddrs(inet_descriptor* desc_p, - char **rbuf_pp, int rsize) +static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p, + char **rbuf_pp, ErlDrvSizeT rsize) { return ctl_error(ENOTSUP, rbuf_pp, rsize); } @@ -5893,7 +6073,7 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) case SCTP_OPT_PRIMARY_ADDR: case SCTP_OPT_SET_PEER_PRIMARY_ADDR: { - int alen; + ErlDrvSizeT alen; char *after; CHKLEN(curr, ASSOC_ID_LEN); @@ -5935,7 +6115,7 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) } case SCTP_OPT_PEER_ADDR_PARAMS: { - int alen; + ErlDrvSizeT alen; char *after; # ifdef HAVE_STRUCT_SCTP_PADDRPARAMS_SPP_FLAGS int eflags, cflags, hb_enable, hb_disable, @@ -6022,6 +6202,7 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) type = SCTP_DEFAULT_SEND_PARAM; arg_ptr = (char*) (&arg.sri); arg_sz = sizeof ( arg.sri); + VALGRIND_MAKE_MEM_DEFINED(arg_ptr, arg_sz); /*suppress "uninitialised bytes"*/ break; } case SCTP_OPT_EVENTS: @@ -6065,7 +6246,7 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) proto = IPPROTO_SCTP; type = SCTP_DELAYED_ACK_TIME; arg_ptr = (char*) (&arg.av); - arg_sz = sizeof ( arg.es); + arg_sz = sizeof ( arg.av); break; } # endif @@ -6111,8 +6292,9 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) ** ptr should point to a buffer with 9*len +1 to be safe!! */ -static int inet_fill_opts(inet_descriptor* desc, - char* buf, int len, char** dest, int destlen) +static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, + char* buf, ErlDrvSizeT len, + char** dest, ErlDrvSizeT destlen) { int type; int proto; @@ -6122,8 +6304,8 @@ static int inet_fill_opts(inet_descriptor* desc, char* arg_ptr; unsigned int arg_sz; char *ptr = NULL; - int dest_used = 0; - int dest_allocated = destlen; + ErlDrvSizeT dest_used = 0; + ErlDrvSizeT dest_allocated = destlen; char *orig_dest = *dest; /* Ptr is a name parameter */ @@ -6138,7 +6320,7 @@ static int inet_fill_opts(inet_descriptor* desc, #define PLACE_FOR(Size,Ptr) \ do { \ - int need = dest_used + (Size); \ + ErlDrvSizeT need = dest_used + (Size); \ if (need > INET_MAX_OPT_BUFFER) { \ RETURN_ERROR(); \ } \ @@ -6159,7 +6341,7 @@ static int inet_fill_opts(inet_descriptor* desc, /* Ptr is a name parameter */ #define TRUNCATE_TO(Size,Ptr) \ do { \ - int new_need = ((Ptr) - (*dest)) + (Size); \ + ErlDrvSizeT new_need = ((Ptr) - (*dest)) + (Size); \ if (new_need > dest_used) { \ erl_exit(1,"Internal error in inet_drv, " \ "miscalculated buffer size"); \ @@ -6449,8 +6631,9 @@ static int load_paddrinfo (ErlDrvTermData * spec, int i, /* ** "sctp_fill_opts": Returns {ok, Results}, or an error: */ -static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen, - char** dest, int destlen) +static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, + char* buf, ErlDrvSizeT buflen, + char** dest, ErlDrvSizeT destlen) { /* In contrast to the generic "inet_fill_opts", the output here is represented by tuples/records, which are formed in the "spec": @@ -6840,7 +7023,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen, unsigned int sz = sizeof(ap); int n; char *after; - int alen; + ErlDrvSizeT alen; if (buflen < ASSOC_ID_LEN) RETURN_ERROR(spec, -EINVAL); ap.spp_assoc_id = GET_ASSOC_ID(buf); @@ -7080,7 +7263,7 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen, struct sctp_paddrinfo pai; unsigned int sz = sizeof(pai); char *after; - int alen; + ErlDrvSizeT alen; if (buflen < ASSOC_ID_LEN) RETURN_ERROR(spec, -EINVAL); pai.spinfo_assoc_id = GET_ASSOC_ID(buf); @@ -7137,7 +7320,8 @@ static int sctp_fill_opts(inet_descriptor* desc, char* buf, int buflen, /* fill statistics reply, op codes from src and result in dest ** dst area must be a least 5*len + 1 bytes */ -static int inet_fill_stat(inet_descriptor* desc, char* src, int len, char* dst) +static ErlDrvSSizeT inet_fill_stat(inet_descriptor* desc, + char* src, ErlDrvSizeT len, char* dst) { unsigned long val; int op; @@ -7170,7 +7354,7 @@ static int inet_fill_stat(inet_descriptor* desc, char* src, int len, char* dst) val = (unsigned long) desc->send_avg; break; case INET_STAT_SEND_PND: - val = driver_sizeq(desc->port); + val = (unsigned long) driver_sizeq(desc->port); break; case INET_STAT_RECV_OCT: put_int32(desc->recv_oct[1], dst); /* write high 32bit */ @@ -7215,7 +7399,8 @@ send_empty_out_q_msgs(inet_descriptor* desc) /* subscribe and fill subscription reply, op codes from src and ** result in dest dst area must be a least 5*len + 1 bytes */ -static int inet_subscribe(inet_descriptor* desc, char* src, int len, char* dst) +static ErlDrvSSizeT inet_subscribe(inet_descriptor* desc, + char* src, ErlDrvSizeT len, char* dst) { unsigned long val; int op; @@ -7302,6 +7487,8 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) sys_memzero((char *)&desc->remote,sizeof(desc->remote)); + desc->is_ignored = 0; + return (ErlDrvData)desc; } @@ -7313,14 +7500,14 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) /* ** common TCP/UDP/SCTP control command */ -static int inet_ctl(inet_descriptor* desc, int cmd, char* buf, int len, - char** rbuf, int rsize) +static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, + ErlDrvSizeT len, char** rbuf, ErlDrvSizeT rsize) { switch (cmd) { case INET_REQ_GETSTAT: { char* dst; - int i; + ErlDrvSizeT i; int dstlen = 1; /* Reply code */ for (i = 0; i < len; i++) { @@ -7360,7 +7547,7 @@ static int inet_ctl(inet_descriptor* desc, int cmd, char* buf, int len, } case INET_REQ_GETOPTS: { /* get options */ - int replen; + ErlDrvSSizeT replen; DEBUGF(("inet_ctl(%ld): GETOPTS\r\n", (long)desc->port)); #ifdef HAVE_SCTP if (IS_SCTP(desc)) @@ -7584,6 +7771,33 @@ static int inet_ctl(inet_descriptor* desc, int cmd, char* buf, int len, return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize); } + case INET_REQ_IGNOREFD: { + DEBUGF(("inet_ctl(%ld): IGNOREFD, IGNORED = %d\r\n", + (long)desc->port,(int)*buf)); + + /* + * FD can only be ignored for connected TCP connections for now, + * possible to add UDP and SCTP support if needed. + */ + if (!IS_CONNECTED(desc)) + return ctl_error(ENOTCONN, rbuf, rsize); + + if (!desc->stype == SOCK_STREAM) + return ctl_error(EINVAL, rbuf, rsize); + + if (*buf == 1 && !desc->is_ignored) { + sock_select(desc, (FD_READ|FD_WRITE|FD_CLOSE|ERL_DRV_USE_NO_CALLBACK), 0); + desc->is_ignored = INET_IGNORE_READ; + } else if (*buf == 0 && desc->is_ignored) { + int flags = (FD_READ|FD_CLOSE|((desc->is_ignored & INET_IGNORE_WRITE)?FD_WRITE:0)); + desc->is_ignored = INET_IGNORE_NONE; + sock_select(desc, flags, 1); + } else + return ctl_error(EINVAL, rbuf, rsize); + + return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); + } + #ifndef VXWORKS case INET_REQ_GETSERVBYNAME: { /* L1 Name-String L2 Proto-String */ @@ -7644,7 +7858,7 @@ static int inet_ctl(inet_descriptor* desc, int cmd, char* buf, int len, } /* update statistics on output packets */ -static void inet_output_count(inet_descriptor* desc, int len) +static void inet_output_count(inet_descriptor* desc, ErlDrvSizeT len) { unsigned long n = desc->send_cnt + 1; unsigned long t = desc->send_oct[0] + len; @@ -7664,7 +7878,7 @@ static void inet_output_count(inet_descriptor* desc, int len) } /* update statistics on input packets */ -static void inet_input_count(inet_descriptor* desc, int len) +static void inet_input_count(inet_descriptor* desc, ErlDrvSizeT len) { unsigned long n = desc->recv_cnt + 1; unsigned long t = desc->recv_oct[0] + len; @@ -7787,7 +8001,7 @@ static void tcp_clear_input(tcp_descriptor* desc) static void tcp_clear_output(tcp_descriptor* desc) { ErlDrvPort ix = desc->inet.port; - int qsz = driver_sizeq(ix); + ErlDrvSizeT qsz = driver_sizeq(ix); driver_deq(ix, qsz); send_empty_out_q_msgs(INETP(desc)); @@ -7845,7 +8059,7 @@ static ErlDrvData tcp_inet_start(ErlDrvPort port, char* args) /* Copy a descriptor, by creating a new port with same settings * as the descriptor desc. - * return NULL on error (ENFILE no ports avail) + * return NULL on error (SYSTEM_LIMIT no ports avail) */ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s, ErlDrvTermData owner, int* err) @@ -7884,7 +8098,7 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s, /* The new port will be linked and connected to the original caller */ port = driver_create_port(port, owner, "tcp_inet", (ErlDrvData) copy_desc); if ((long)port == -1) { - *err = ENFILE; + *err = INET_ERRNO_SYSTEM_LIMIT; FREE(copy_desc); return NULL; } @@ -7955,10 +8169,12 @@ static void tcp_inet_stop(ErlDrvData e) /* TCP requests from Erlang */ -static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len, - char** rbuf, int rsize) +static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, + char* buf, ErlDrvSizeT len, + char** rbuf, ErlDrvSizeT rsize) { tcp_descriptor* desc = (tcp_descriptor*)e; + switch(cmd) { case INET_REQ_OPEN: { /* open socket and return internal index */ int domain; @@ -8224,13 +8440,14 @@ static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len, if (enq_async(INETP(desc), tbuf, TCP_REQ_RECV) < 0) return ctl_error(EALREADY, rbuf, rsize); - if (tcp_recv(desc, n) == 0) { + if (INETP(desc)->is_ignored || tcp_recv(desc, n) == 0) { if (timeout == 0) async_error_am(INETP(desc), am_timeout); else { if (timeout != INET_INFINITY) - driver_set_timer(desc->inet.port, timeout); - sock_select(INETP(desc),(FD_READ|FD_CLOSE),1); + driver_set_timer(desc->inet.port, timeout); + if (!INETP(desc)->is_ignored) + sock_select(INETP(desc),(FD_READ|FD_CLOSE),1); } } return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize); @@ -8355,7 +8572,7 @@ static void tcp_inet_multi_timeout(ErlDrvData e, ErlDrvTermData caller) ** but distribution still uses the tcp_inet_command!! */ -static void tcp_inet_command(ErlDrvData e, char *buf, int len) +static void tcp_inet_command(ErlDrvData e, char *buf, ErlDrvSizeT len) { tcp_descriptor* desc = (tcp_descriptor*)e; desc->inet.caller = driver_caller(desc->inet.port); @@ -8574,8 +8791,15 @@ static int tcp_remain(tcp_descriptor* desc, int* len) else if (tlen == 0) { /* need unknown more */ *len = 0; if (nsz == 0) { - if (nfill == n) - goto error; + if (nfill == n) { + if (desc->inet.psize != 0 && desc->inet.psize > nfill) { + if (tcp_expand_buffer(desc, desc->inet.psize) < 0) + return -1; + return desc->inet.psize; + } + else + goto error; + } DEBUGF((" => restart more=%d\r\n", nfill - n)); return nfill - n; } @@ -8970,6 +9194,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event) #ifdef DEBUG long port = (long) desc->inet.port; /* Used after driver_exit() */ #endif + ASSERT(!INETP(desc)->is_ignored); DEBUGF(("tcp_inet_input(%ld) {s=%d\r\n", port, desc->inet.s)); if (desc->inet.state == INET_STATE_ACCEPTING) { SOCKET s; @@ -9176,12 +9401,12 @@ static int tcp_send_error(tcp_descriptor* desc, int err) */ static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev) { - int sz; + ErlDrvSizeT sz; char buf[4]; - int h_len; - int n; + ErlDrvSizeT h_len; + ssize_t n; ErlDrvPort ix = desc->inet.port; - int len = ev->size; + ErlDrvSizeT len = ev->size; switch(desc->inet.htype) { case TCP_PB_1: @@ -9229,9 +9454,13 @@ static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev) else { int vsize = (ev->vsize > MAX_VSIZE) ? MAX_VSIZE : ev->vsize; - DEBUGF(("tcp_sendv(%ld): s=%d, about to send %d,%d bytes\r\n", - (long)desc->inet.port, desc->inet.s, h_len, len)); - if (desc->tcp_add_flags & TCP_ADDF_DELAY_SEND) { + DEBUGF(("tcp_sendv(%ld): s=%d, about to send "LLU","LLU" bytes\r\n", + (long)desc->inet.port, desc->inet.s, (llu_t)h_len, (llu_t)len)); + + if (INETP(desc)->is_ignored) { + INETP(desc)->is_ignored |= INET_IGNORE_WRITE; + n = 0; + } else if (desc->tcp_add_flags & TCP_ADDF_DELAY_SEND) { n = 0; } else if (IS_SOCKET_ERROR(sock_sendv(desc->inet.s, ev->iov, vsize, &n, 0))) { @@ -9252,14 +9481,17 @@ static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev) return 0; } else { - DEBUGF(("tcp_sendv(%ld): s=%d, only sent %d/%d of %d/%d bytes/items\r\n", - (long)desc->inet.port, desc->inet.s, n, vsize, ev->size, ev->vsize)); + DEBUGF(("tcp_sendv(%ld): s=%d, only sent " + LLU"/%d of "LLU"/%d bytes/items\r\n", + (long)desc->inet.port, desc->inet.s, + (llu_t)n, vsize, (llu_t)ev->size, ev->vsize)); } DEBUGF(("tcp_sendv(%ld): s=%d, Send failed, queuing\r\n", (long)desc->inet.port, desc->inet.s)); driver_enqv(ix, ev, n); - sock_select(INETP(desc),(FD_WRITE|FD_CLOSE), 1); + if (!INETP(desc)->is_ignored) + sock_select(INETP(desc),(FD_WRITE|FD_CLOSE), 1); } return 0; } @@ -9267,7 +9499,7 @@ static int tcp_sendv(tcp_descriptor* desc, ErlIOVec* ev) /* ** Send non blocking data */ -static int tcp_send(tcp_descriptor* desc, char* ptr, int len) +static int tcp_send(tcp_descriptor* desc, char* ptr, ErlDrvSizeT len) { int sz; char buf[4]; @@ -9322,9 +9554,12 @@ static int tcp_send(tcp_descriptor* desc, char* ptr, int len) iov[1].iov_base = ptr; iov[1].iov_len = len; - DEBUGF(("tcp_send(%ld): s=%d, about to send %d,%d bytes\r\n", - (long)desc->inet.port, desc->inet.s, h_len, len)); - if (desc->tcp_add_flags & TCP_ADDF_DELAY_SEND) { + DEBUGF(("tcp_send(%ld): s=%d, about to send "LLU","LLU" bytes\r\n", + (long)desc->inet.port, desc->inet.s, (llu_t)h_len, (llu_t)len)); + if (INETP(desc)->is_ignored) { + INETP(desc)->is_ignored |= INET_IGNORE_WRITE; + n = 0; + } else if (desc->tcp_add_flags & TCP_ADDF_DELAY_SEND) { sock_send(desc->inet.s, buf, 0, 0); n = 0; } else if (IS_SOCKET_ERROR(sock_sendv(desc->inet.s,iov,2,&n,0))) { @@ -9355,7 +9590,8 @@ static int tcp_send(tcp_descriptor* desc, char* ptr, int len) n -= h_len; driver_enq(ix, ptr+n, len-n); } - sock_select(INETP(desc),(FD_WRITE|FD_CLOSE), 1); + if (!INETP(desc)->is_ignored) + sock_select(INETP(desc),(FD_WRITE|FD_CLOSE), 1); } return 0; } @@ -9379,6 +9615,7 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) int ret = 0; ErlDrvPort ix = desc->inet.port; + ASSERT(!INETP(desc)->is_ignored); DEBUGF(("tcp_inet_output(%ld) {s=%d\r\n", (long)desc->inet.port, desc->inet.s)); if (desc->inet.state == INET_STATE_CONNECTING) { @@ -9430,7 +9667,7 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) else if (IS_CONNECTED(INETP(desc))) { for (;;) { int vsize; - int n; + ssize_t n; SysIOVec* iov; if ((iov = driver_peekq(ix, &vsize)) == NULL) { @@ -9641,10 +9878,10 @@ static int packet_error(udp_descriptor* udesc, int err) /* ** Various functions accessible via "port_control" on the Erlang side: */ -static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len, - char** rbuf, int rsize) +static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, + ErlDrvSizeT len, char** rbuf, ErlDrvSizeT rsize) { - int replen; + ErlDrvSSizeT replen; udp_descriptor * udesc = (udp_descriptor *) e; inet_descriptor* desc = INETP(udesc); int type = SOCK_DGRAM; @@ -9754,7 +9991,6 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len, DEBUGF(("packet_inet_ctl(%ld): CLOSE\r\n", (long)desc->port)); erl_inet_close(desc); return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize); - return 0; case INET_REQ_CONNECT: { @@ -9900,7 +10136,7 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len, /* List item format: Port(2), IP(4|16) -- compatible with "inet_set_address": */ inet_address tmp; - int alen = buf + len - curr; + ErlDrvSizeT alen = buf + len - curr; curr = inet_set_address(desc->sfamily, &tmp, curr, &alen); if (curr == NULL) return ctl_error(EINVAL, rbuf, rsize); @@ -10025,13 +10261,13 @@ static void packet_inet_timeout(ErlDrvData e) ** There is no destination address -- SCTYP send is performed over ** an existing association, using "sctp_sndrcvinfo" specified. */ -static void packet_inet_command(ErlDrvData e, char* buf, int len) +static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) { udp_descriptor * udesc= (udp_descriptor*) e; inet_descriptor* desc = INETP(udesc); char* ptr = buf; char* qtr; - int sz; + ErlDrvSizeT sz; int code; inet_address other; @@ -10049,7 +10285,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, int len) #ifdef HAVE_SCTP if (IS_SCTP(desc)) { - int data_len; + ErlDrvSizeT data_len; struct iovec iov[1]; /* For real data */ struct msghdr mhdr; /* Message wrapper */ struct sctp_sndrcvinfo *sri; /* The actual ancilary data */ @@ -10085,6 +10321,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, int len) mhdr.msg_iovlen = 1; mhdr.msg_control = cmsg.ancd; /* For ancilary data */ mhdr.msg_controllen = cmsg.hdr.cmsg_len; + VALGRIND_MAKE_MEM_DEFINED(mhdr.msg_control, mhdr.msg_controllen); /*suppress "uninitialised bytes"*/ mhdr.msg_flags = 0; /* Not used with "sendmsg" */ /* Now do the actual sending. NB: "flags" in "sendmsg" itself are NOT @@ -10269,6 +10506,7 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event) int code; void * extra = NULL; char * ptr; + int nsz; inet_input_count(desc, n); udesc->i_ptr += n; @@ -10282,17 +10520,19 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event) ptr = udesc->i_buf->orig_bytes + sizeof(other) - len; sys_memcpy(ptr, abuf, len); + nsz = udesc->i_ptr - ptr; + /* Check if we need to reallocate binary */ - if ((desc->mode == INET_MODE_BINARY) && - (desc->hsz < (udesc->i_ptr - ptr)) && - ((udesc->i_ptr - ptr) + BIN_REALLOC_MARGIN(desc->bufsz) >= - udesc->i_bufsz)) { + if ((desc->mode == INET_MODE_BINARY) + && (desc->hsz < (nsz - len)) + && (nsz + BIN_REALLOC_MARGIN(desc->bufsz) < udesc->i_bufsz)) { ErlDrvBinary* tmp; int bufsz; bufsz = udesc->i_ptr - udesc->i_buf->orig_bytes; if ((tmp = realloc_buffer(udesc->i_buf, bufsz)) != NULL) { udesc->i_buf = tmp; udesc->i_bufsz = bufsz; + udesc->i_ptr = NULL; /* not used from here */ } } #ifdef HAVE_SCTP @@ -10300,8 +10540,8 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event) #endif /* Actual parsing and return of the data received, occur here: */ code = packet_reply_binary_data(desc, len, udesc->i_buf, - ptr - udesc->i_buf->orig_bytes, - udesc->i_ptr - ptr, + (sizeof(other) - len), + nsz, extra); free_buffer(udesc->i_buf); udesc->i_buf = NULL; @@ -10793,7 +11033,7 @@ int erts_sock_connect(erts_sock_t socket, byte *ip_addr, int len, Uint16 port) { SOCKET s = (SOCKET) socket; char buf[2 + 4]; - int blen = 6; + ErlDrvSizeT blen = 6; inet_address addr; if (socket == ERTS_SOCK_INVALID_SOCKET || len != 4) diff --git a/erts/emulator/drivers/common/ram_file_drv.c b/erts/emulator/drivers/common/ram_file_drv.c index abedcc933a..a109e40333 100644 --- a/erts/emulator/drivers/common/ram_file_drv.c +++ b/erts/emulator/drivers/common/ram_file_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2010. All Rights Reserved. + * Copyright Ericsson AB 1997-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -98,7 +98,7 @@ typedef unsigned char uchar; static ErlDrvData rfile_start(ErlDrvPort, char*); static int rfile_init(void); static void rfile_stop(ErlDrvData); -static void rfile_command(ErlDrvData, char*, int); +static void rfile_command(ErlDrvData, char*, ErlDrvSizeT); struct erl_drv_entry ram_file_driver_entry = { @@ -108,7 +108,23 @@ struct erl_drv_entry ram_file_driver_entry = { rfile_command, NULL, NULL, - "ram_file_drv" + "ram_file_drv", + NULL, + NULL, /* handle */ + NULL, /* control */ + NULL, /* timeout */ + NULL, /* outputv */ + NULL, /* ready_async */ + NULL, /* flush */ + NULL, /* call */ + NULL, /* event */ + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL, }; /* A File is represented as a array of bytes, this array is @@ -121,9 +137,9 @@ typedef struct ram_file { int flags; /* flags read/write */ ErlDrvBinary* bin; /* binary to hold binary file */ char* buf; /* buffer start (in binary) */ - int size; /* buffer size (allocated) */ - int cur; /* current position in buffer */ - int end; /* end position in buffer */ + ErlDrvSSizeT size; /* buffer size (allocated) */ + ErlDrvSSizeT cur; /* current position in buffer */ + ErlDrvSSizeT end; /* end position in buffer */ } RamFile; #ifdef LOADABLE @@ -211,7 +227,7 @@ static int reply(RamFile *f, int ok, int err) return 0; } -static int numeric_reply(RamFile *f, int result) +static int numeric_reply(RamFile *f, ErlDrvSSizeT result) { char tmp[5]; @@ -231,7 +247,8 @@ static int numeric_reply(RamFile *f, int result) /* install bin as the new binary reset all pointer */ -static void ram_file_set(RamFile *f, ErlDrvBinary *bin, int bsize, int len) +static void ram_file_set(RamFile *f, ErlDrvBinary *bin, + ErlDrvSSizeT bsize, ErlDrvSSizeT len) { f->size = bsize; f->buf = bin->orig_bytes; @@ -240,9 +257,9 @@ static void ram_file_set(RamFile *f, ErlDrvBinary *bin, int bsize, int len) f->bin = bin; } -static int ram_file_init(RamFile *f, char *buf, int count, int *error) +static int ram_file_init(RamFile *f, char *buf, ErlDrvSSizeT count, int *error) { - int bsize; + ErlDrvSSizeT bsize; ErlDrvBinary* bin; if (count < 0) { @@ -268,9 +285,9 @@ static int ram_file_init(RamFile *f, char *buf, int count, int *error) return count; } -static int ram_file_expand(RamFile *f, int size, int *error) +static ErlDrvSSizeT ram_file_expand(RamFile *f, ErlDrvSSizeT size, int *error) { - int bsize; + ErlDrvSSizeT bsize; ErlDrvBinary* bin; if (size < 0) { @@ -298,10 +315,10 @@ static int ram_file_expand(RamFile *f, int size, int *error) } -static int ram_file_write(RamFile *f, char *buf, int len, - int *location, int *error) +static ErlDrvSSizeT ram_file_write(RamFile *f, char *buf, ErlDrvSSizeT len, + ErlDrvSSizeT *location, int *error) { - int cur = f->cur; + ErlDrvSSizeT cur = f->cur; if (!(f->flags & RAM_FILE_MODE_WRITE)) { *error = EBADF; @@ -322,11 +339,11 @@ static int ram_file_write(RamFile *f, char *buf, int len, return len; } -static int ram_file_read(RamFile *f, int len, ErlDrvBinary **bp, - int *location, int *error) +static ErlDrvSSizeT ram_file_read(RamFile *f, ErlDrvSSizeT len, ErlDrvBinary **bp, + ErlDrvSSizeT *location, int *error) { ErlDrvBinary* bin; - int cur = f->cur; + ErlDrvSSizeT cur = f->cur; if (!(f->flags & RAM_FILE_MODE_READ)) { *error = EBADF; @@ -352,9 +369,10 @@ static int ram_file_read(RamFile *f, int len, ErlDrvBinary **bp, return len; } -static int ram_file_seek(RamFile *f, int offset, int whence, int *error) +static ErlDrvSSizeT ram_file_seek(RamFile *f, ErlDrvSSizeT offset, int whence, + int *error) { - int pos; + ErlDrvSSizeT pos; if (f->flags == 0) { *error = EBADF; @@ -389,13 +407,13 @@ static int ram_file_seek(RamFile *f, int offset, int whence, int *error) static int ram_file_uuencode(RamFile *f) { - int code_len = UULINE(UNIX_LINE); - int len = f->end; - int usize = 4*((len+2)/3) + 2*((len+code_len-1)/code_len) + 2; + ErlDrvSSizeT code_len = UULINE(UNIX_LINE); + ErlDrvSSizeT len = f->end; + ErlDrvSSizeT usize = 4*((len+2)/3) + 2*((len+code_len-1)/code_len) + 2; ErlDrvBinary* bin; uchar* inp; uchar* outp; - int count = 0; + ErlDrvSSizeT count = 0; if ((bin = driver_alloc_binary(usize)) == NULL) return error_reply(f, ENOMEM); @@ -447,8 +465,8 @@ static int ram_file_uuencode(RamFile *f) static int ram_file_uudecode(RamFile *f) { - int len = f->end; - int usize = ( (len+3) / 4 ) * 3; + ErlDrvSSizeT len = f->end; + ErlDrvSSizeT usize = ( (len+3) / 4 ) * 3; ErlDrvBinary* bin; uchar* inp; uchar* outp; @@ -510,7 +528,7 @@ static int ram_file_uudecode(RamFile *f) static int ram_file_compress(RamFile *f) { - int size = f->end; + ErlDrvSSizeT size = f->end; ErlDrvBinary* bin; if ((bin = erts_gzdeflate_buffer(f->buf, size)) == NULL) { @@ -528,7 +546,7 @@ static int ram_file_compress(RamFile *f) static int ram_file_uncompress(RamFile *f) { - int size = f->end; + ErlDrvSSizeT size = f->end; ErlDrvBinary* bin; if ((bin = erts_gzinflate_buffer(f->buf, size)) == NULL) { @@ -541,15 +559,15 @@ static int ram_file_uncompress(RamFile *f) } -static void rfile_command(ErlDrvData e, char* buf, int count) +static void rfile_command(ErlDrvData e, char* buf, ErlDrvSizeT count) { RamFile* f = (RamFile*)e; int error = 0; ErlDrvBinary* bin; char header[5]; /* result code + count */ - int offset; - int origin; /* Origin of seek. */ - int n; + ErlDrvSSizeT offset; + ErlDrvSSizeT origin; /* Origin of seek. */ + ErlDrvSSizeT n; count--; switch(*(uchar*)buf++) { diff --git a/erts/emulator/drivers/common/zlib_drv.c b/erts/emulator/drivers/common/zlib_drv.c index f50899a730..a4b02b845e 100644 --- a/erts/emulator/drivers/common/zlib_drv.c +++ b/erts/emulator/drivers/common/zlib_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2010. All Rights Reserved. + * Copyright Ericsson AB 2003-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -64,8 +64,9 @@ static int zlib_init(void); static ErlDrvData zlib_start(ErlDrvPort port, char* buf); static void zlib_stop(ErlDrvData e); -static int zlib_ctl(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen); +static void zlib_flush(ErlDrvData e); +static ErlDrvSSizeT zlib_ctl(ErlDrvData drv_data, unsigned int command, char *buf, + ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen); static void zlib_outputv(ErlDrvData drv_data, ErlIOVec *ev); ErlDrvEntry zlib_driver_entry = { @@ -82,7 +83,7 @@ ErlDrvEntry zlib_driver_entry = { NULL, /* timeout */ zlib_outputv, NULL, /* read_async */ - NULL, /* flush */ + zlib_flush, NULL, /* call */ NULL, /* event */ ERL_DRV_EXTENDED_MARKER, @@ -162,12 +163,12 @@ static char* zlib_reason(int code, int* err) } -static int zlib_return(int code, char** rbuf, int rlen) +static ErlDrvSSizeT zlib_return(int code, char** rbuf, ErlDrvSizeT rlen) { int msg_code = 0; /* 0=ok, 1=error */ char* dst = *rbuf; char* src; - int len = 0; + ErlDrvSizeT len = 0; src = zlib_reason(code, &msg_code); *dst++ = msg_code; @@ -182,7 +183,8 @@ static int zlib_return(int code, char** rbuf, int rlen) return len; } -static int zlib_value2(int msg_code, int value, char** rbuf, int rlen) +static ErlDrvSSizeT zlib_value2(int msg_code, int value, + char** rbuf, ErlDrvSizeT rlen) { char* dst = *rbuf; @@ -197,7 +199,7 @@ static int zlib_value2(int msg_code, int value, char** rbuf, int rlen) return 5; } -static int zlib_value(int value, char** rbuf, int rlen) +static ErlDrvSSizeT zlib_value(int value, char** rbuf, ErlDrvSizeT rlen) { return zlib_value2(2, value, rbuf, rlen); } @@ -409,8 +411,15 @@ static void zlib_stop(ErlDrvData e) driver_free(d); } -static int zlib_ctl(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen) +static void zlib_flush(ErlDrvData drv_data) +{ + ZLibData* d = (ZLibData*) drv_data; + + driver_deq(d->port, driver_sizeq(d->port)); +} + +static ErlDrvSSizeT zlib_ctl(ErlDrvData drv_data, unsigned int command, char *buf, + ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { ZLibData* d = (ZLibData*)drv_data; int res; diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c index 45d39a559f..b29f80a8ba 100644 --- a/erts/emulator/drivers/unix/ttsl_drv.c +++ b/erts/emulator/drivers/unix/ttsl_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2010. All Rights Reserved. + * Copyright Ericsson AB 1996-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -106,7 +106,7 @@ static int lpos; /* The current "cursor position" in the line buf /* Main interface functions. */ static void ttysl_stop(ErlDrvData); -static void ttysl_from_erlang(ErlDrvData, char*, int); +static void ttysl_from_erlang(ErlDrvData, char*, ErlDrvSizeT); static void ttysl_from_tty(ErlDrvData, ErlDrvEvent); static void ttysl_stop_select(ErlDrvEvent, void*); static Sint16 get_sint16(char*); @@ -141,7 +141,8 @@ static void update_cols(void); static int tty_init(int,int,int,int); static int tty_set(int); static int tty_reset(int); -static int ttysl_control(ErlDrvData, unsigned int, char *, int, char **, int); +static ErlDrvSSizeT ttysl_control(ErlDrvData, unsigned int, + char *, ErlDrvSizeT, char **, ErlDrvSizeT); #ifdef ERTS_NOT_USED static RETSIGTYPE suspend(int); #endif @@ -345,13 +346,13 @@ static void ttysl_get_window_size(Uint32 *width, Uint32 *height) *height = DEF_HEIGHT; } -static int ttysl_control(ErlDrvData drv_data, - unsigned int command, - char *buf, int len, - char **rbuf, int rlen) +static ErlDrvSSizeT ttysl_control(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) { char resbuff[2*sizeof(Uint32)]; - int res_size; + ErlDrvSizeT res_size; switch (command) { case CTRL_OP_GET_WINSIZE: { @@ -633,14 +634,14 @@ static int check_buf_size(byte *s, int n) } -static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, int count) +static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT count) { if (lpos > MAXSIZE) put_chars((byte*)"\n", 1); switch (buf[0]) { case OP_PUTC: - DEBUGLOG(("OP: Putc(%d)",count-1)); + DEBUGLOG(("OP: Putc(%lu)",(unsigned long) count-1)); if (check_buf_size((byte*)buf+1, count-1) == 0) return; put_chars((byte*)buf+1, count-1); diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 4b3934657c..dfb6cece14 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2010. All Rights Reserved. + * Copyright Ericsson AB 1997-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -33,6 +33,9 @@ #include <sys/types.h> #include <sys/uio.h> #endif +#if defined(HAVE_SENDFILE) && (defined(__linux__) || (defined(__sun) && defined(__SVR4))) +#include <sys/sendfile.h> +#endif #if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) #define DARWIN 1 @@ -813,7 +816,6 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, char* name, int info_for_link) { struct stat statbuf; /* Information about the file */ - struct tm *timep; /* Broken-apart filetime. */ int result; #ifdef VXWORKS @@ -880,40 +882,17 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, else pInfo->type = FT_OTHER; -#if defined(HAVE_LOCALTIME_R) || defined(VXWORKS) - { - /* Use the reentrant version of localtime() */ - static struct tm local_tm; -#define localtime(a) (localtime_r((a), &local_tm), &local_tm) -#endif - - -#define GET_TIME(dst, src) \ - timep = localtime(&statbuf.src); \ - (dst).year = timep->tm_year+1900; \ - (dst).month = timep->tm_mon+1; \ - (dst).day = timep->tm_mday; \ - (dst).hour = timep->tm_hour; \ - (dst).minute = timep->tm_min; \ - (dst).second = timep->tm_sec - - GET_TIME(pInfo->accessTime, st_atime); - GET_TIME(pInfo->modifyTime, st_mtime); - GET_TIME(pInfo->cTime, st_ctime); - -#undef GET_TIME + pInfo->accessTime = statbuf.st_atime; + pInfo->modifyTime = statbuf.st_mtime; + pInfo->cTime = statbuf.st_ctime; -#if defined(HAVE_LOCALTIME_R) || defined(VXWORKS) - } -#endif - - pInfo->mode = statbuf.st_mode; - pInfo->links = statbuf.st_nlink; + pInfo->mode = statbuf.st_mode; + pInfo->links = statbuf.st_nlink; pInfo->major_device = statbuf.st_dev; pInfo->minor_device = statbuf.st_rdev; - pInfo->inode = statbuf.st_ino; - pInfo->uid = statbuf.st_uid; - pInfo->gid = statbuf.st_gid; + pInfo->inode = statbuf.st_ino; + pInfo->uid = statbuf.st_uid; + pInfo->gid = statbuf.st_gid; return 1; } @@ -921,6 +900,8 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, int efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) { + struct utimbuf tval; + CHECK_PATHLEN(name, errInfo); #ifdef VXWORKS @@ -973,38 +954,18 @@ efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name) #endif /* !VXWORKS */ - if (pInfo->accessTime.year != -1 && pInfo->modifyTime.year != -1) { - struct utimbuf tval; - struct tm timebuf; - -#define MKTIME(tb, ts) \ - timebuf.tm_year = ts.year-1900; \ - timebuf.tm_mon = ts.month-1; \ - timebuf.tm_mday = ts.day; \ - timebuf.tm_hour = ts.hour; \ - timebuf.tm_min = ts.minute; \ - timebuf.tm_sec = ts.second; \ - timebuf.tm_isdst = -1; \ - if ((tb = mktime(&timebuf)) == (time_t) -1) { \ - errno = EINVAL; \ - return check_error(-1, errInfo); \ - } + tval.actime = pInfo->accessTime; + tval.modtime = pInfo->modifyTime; - MKTIME(tval.actime, pInfo->accessTime); - MKTIME(tval.modtime, pInfo->modifyTime); -#undef MKTIME - #ifdef VXWORKS - /* VxWorks' utime doesn't work when the file is a nfs mounted - * one, don't report error if utime fails. - */ - utime(name, &tval); - return 1; + /* VxWorks' utime doesn't work when the file is a nfs mounted + * one, don't report error if utime fails. + */ + utime(name, &tval); + return 1; #else - return check_error(utime(name, &tval), errInfo); + return check_error(utime(name, &tval), errInfo); #endif - } - return 1; } @@ -1043,13 +1004,11 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ * opened */ int fd, /* File descriptor to write to */ SysIOVec* iov, /* Vector of buffer structs. - * The structs are unchanged - * after the call */ - int iovcnt, /* Number of structs in vector */ - size_t size) /* Number of bytes to write */ + * The structs may be changed i.e. + * due to incomplete writes */ + int iovcnt) /* Number of structs in vector */ { int cnt = 0; /* Buffers so far written */ - int p = 0; /* Position in next buffer */ ASSERT(iovcnt >= 0); @@ -1060,66 +1019,47 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ #endif while (cnt < iovcnt) { + if ((! iov[cnt].iov_base) || (iov[cnt].iov_len <= 0)) { + /* Empty buffer - skip */ + cnt++; + } else { /* Non-empty buffer */ + ssize_t w; /* Bytes written in this call */ #ifdef HAVE_WRITEV - int w; /* Bytes written in this call */ - int b = iovcnt - cnt; /* Buffers to write */ - if (b > MAXIOV) - b = MAXIOV; - if (iov[cnt].iov_base && iov[cnt].iov_len > 0) { - if (b == 1) { - /* Degenerated io vector */ - do { - w = write(fd, iov[cnt].iov_base + p, iov[cnt].iov_len - p); - } while (w < 0 && errno == EINTR); - } else { - /* Non-empty vector first. - * Adjust pos in first buffer in case of - * previous incomplete writev */ - iov[cnt].iov_base += p; - iov[cnt].iov_len -= p; + int b = iovcnt - cnt; /* Buffers to write */ + /* Use as many buffers as MAXIOV allows */ + if (b > MAXIOV) + b = MAXIOV; + if (b > 1) { do { w = writev(fd, &iov[cnt], b); } while (w < 0 && errno == EINTR); - iov[cnt].iov_base -= p; - iov[cnt].iov_len += p; - } - if (w < 0) - return check_error(-1, errInfo); - } else { - /* Empty vector first - skip */ - cnt++; - continue; - } - ASSERT(w >= 0); - /* Move forward to next vector to write */ - for (; cnt < iovcnt; cnt++) { - if (iov[cnt].iov_base && iov[cnt].iov_len > 0) { - if (w < iov[cnt].iov_len) - break; - else - w -= iov[cnt].iov_len; - } - } - ASSERT(w >= 0); - p = w > 0 ? w : 0; /* Skip p bytes next writev */ -#else /* #ifdef HAVE_WRITEV */ - if (iov[cnt].iov_base && iov[cnt].iov_len > 0) { - /* Non-empty vector */ - int w; /* Bytes written in this call */ - while (p < iov[cnt].iov_len) { - do { - w = write(fd, iov[cnt].iov_base + p, iov[cnt].iov_len - p); - } while (w < 0 && errno == EINTR); - if (w < 0) - return check_error(-1, errInfo); - p += w; + } else + /* Degenerated io vector - use regular write */ +#endif + { + do { + w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len); + } while (w < 0 && errno == EINTR); + ASSERT(w <= iov[cnt].iov_len); + } + if (w < 0) return check_error(-1, errInfo); + /* Move forward to next buffer to write */ + for (; cnt < iovcnt && w > 0; cnt++) { + if (iov[cnt].iov_base && iov[cnt].iov_len > 0) { + if (w < iov[cnt].iov_len) { + /* Adjust the buffer for next write */ + iov[cnt].iov_len -= w; + iov[cnt].iov_base += w; + w = 0; + break; + } else { + w -= iov[cnt].iov_len; + } + } } - } - cnt++; - p = 0; -#endif /* #ifdef HAVE_WRITEV */ + ASSERT(w == 0); + } /* else Non-empty buffer */ } /* while (cnt< iovcnt) */ - size = 0; /* Avoid compiler warning */ return 1; } @@ -1464,3 +1404,115 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, return check_error(0, errInfo); #endif } + +#ifdef HAVE_SENDFILE +// For some reason the maximum size_t cannot be used as the max size +// 3GB seems to work on all platforms +#define SENDFILE_CHUNK_SIZE ((1UL << 30) -1) + +/* + * sendfile: The implementation of the sendfile system call varies + * a lot on different *nix platforms so to make the api similar in all + * we have to emulate some things in linux and play with variables on + * bsd/darwin. + * + * All of the calls will split a command which tries to send more than + * SENDFILE_CHUNK_SIZE of data at once. + * + * On platforms where *nbytes of 0 does not mean the entire file, this is + * simulated. + * + * It could be possible to implement header/trailer in sendfile. Though + * you would have to emulate it in linux and on BSD/Darwin some complex + * calculations have to be made when using a non blocking socket to figure + * out how much of the header/file/trailer was sent in each command. + * + * The semantics of the API is this: + * Return value: 1 if all data was sent and the function does not need to + * be called again. 0 if an error occures OR if there is more data which + * has to be sent (EAGAIN or EINTR will be set appropriately) + * + * The amount of data written in a call is returned through nbytes. + * + */ + +int +efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, + off_t *offset, Uint64 *nbytes, struct t_sendfile_hdtl* hdtl) +{ + Uint64 written = 0; +#if defined(__linux__) + ssize_t retval; + do { + // check if *nbytes is 0 or greater than chunk size + if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE) + retval = sendfile(out_fd, in_fd, offset, SENDFILE_CHUNK_SIZE); + else + retval = sendfile(out_fd, in_fd, offset, *nbytes); + if (retval > 0) { + written += retval; + *nbytes -= retval; + } + } while (retval == SENDFILE_CHUNK_SIZE); + if (written != 0) { + // -1 is not returned by the linux API so we have to simulate it + retval = -1; + errno = EAGAIN; + } +#elif defined(__sun) && defined(__SVR4) && defined(HAVE_SENDFILEV) + ssize_t retval; + size_t len; + sendfilevec_t fdrec; + fdrec.sfv_fd = in_fd; + fdrec.sfv_flag = 0; + do { + fdrec.sfv_off = *offset; + len = 0; + // check if *nbytes is 0 or greater than chunk size + if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE) + fdrec.sfv_len = SENDFILE_CHUNK_SIZE; + else + fdrec.sfv_len = *nbytes; + retval = sendfilev(out_fd, &fdrec, 1, &len); + if (retval != -1 || errno == EAGAIN || errno == EINTR) { + *offset += len; + *nbytes -= len; + written += len; + } + } while (len == SENDFILE_CHUNK_SIZE); +#elif defined(DARWIN) + int retval; + off_t len; + do { + // check if *nbytes is 0 or greater than chunk size + if(*nbytes > SENDFILE_CHUNK_SIZE) + len = SENDFILE_CHUNK_SIZE; + else + len = *nbytes; + retval = sendfile(in_fd, out_fd, *offset, &len, NULL, 0); + if (retval != -1 || errno == EAGAIN || errno == EINTR) { + *offset += len; + *nbytes -= len; + written += len; + } + } while (len == SENDFILE_CHUNK_SIZE); +#elif defined(__FreeBSD__) || defined(__DragonFly__) + off_t len; + int retval; + do { + if (*nbytes > SENDFILE_CHUNK_SIZE) + retval = sendfile(in_fd, out_fd, *offset, SENDFILE_CHUNK_SIZE, + NULL, &len, 0); + else + retval = sendfile(in_fd, out_fd, *offset, *nbytes, NULL, &len, 0); + if (retval != -1 || errno == EAGAIN || errno == EINTR) { + *offset += len; + *nbytes -= len; + written += len; + } + } while(len == SENDFILE_CHUNK_SIZE); +#endif + *nbytes = written; + return check_error(retval, errInfo); +} +#endif /* HAVE_SENDFILE */ diff --git a/erts/emulator/drivers/win32/registry_drv.c b/erts/emulator/drivers/win32/registry_drv.c index 05fd2ea55f..1fad34e380 100644 --- a/erts/emulator/drivers/win32/registry_drv.c +++ b/erts/emulator/drivers/win32/registry_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * Copyright Ericsson AB 1997-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -84,7 +84,7 @@ static int maperror(DWORD error); static int reg_init(void); static ErlDrvData reg_start(ErlDrvPort, char*); static void reg_stop(ErlDrvData); -static void reg_from_erlang(ErlDrvData, char*, int); +static void reg_from_erlang(ErlDrvData, char*, ErlDrvSizeT); struct erl_drv_entry registry_driver_entry = { reg_init, @@ -95,10 +95,21 @@ struct erl_drv_entry registry_driver_entry = { NULL, "registry__drv__", NULL, + NULL, /* handle */ + NULL, /* control */ + NULL, /* timeout */ + NULL, /* outputv */ + NULL, /* ready_async */ + NULL, /* flush */ + NULL, /* call */ + NULL, /* event */ + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, NULL, NULL, NULL, - NULL }; static int @@ -158,7 +169,7 @@ reg_stop(ErlDrvData clientData) } static void -reg_from_erlang(ErlDrvData clientData, char* buf, int count) +reg_from_erlang(ErlDrvData clientData, char* buf, ErlDrvSizeT count) { RegPort* rp = (RegPort *) clientData; int cmd; @@ -301,7 +312,7 @@ reg_from_erlang(ErlDrvData clientData, char* buf, int count) buf = (char *) &dword; ASSERT(count == 4); } - result = RegSetValueEx(rp->hkey, name, 0, type, buf, count); + result = RegSetValueEx(rp->hkey, name, 0, type, buf, (DWORD)count); reply(rp, result); } break; diff --git a/erts/emulator/drivers/win32/ttsl_drv.c b/erts/emulator/drivers/win32/ttsl_drv.c index fd88dafd34..1a74d21e99 100644 --- a/erts/emulator/drivers/win32/ttsl_drv.c +++ b/erts/emulator/drivers/win32/ttsl_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2009. All Rights Reserved. + * Copyright Ericsson AB 1996-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -21,6 +21,9 @@ * smart line for output. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include "sys.h" #include <ctype.h> #include <stdlib.h> @@ -80,8 +83,9 @@ int lpos; /* The current "cursor position" in the line buf static int ttysl_init(void); static ErlDrvData ttysl_start(ErlDrvPort, char*); static void ttysl_stop(ErlDrvData); -static int ttysl_control(ErlDrvData, unsigned int, char *, int, char **, int); -static void ttysl_from_erlang(ErlDrvData, char*, int); +static ErlDrvSSizeT ttysl_control(ErlDrvData, unsigned int, + char *, ErlDrvSizeT, char **, ErlDrvSizeT); +static void ttysl_from_erlang(ErlDrvData, char*, ErlDrvSizeT); static void ttysl_from_tty(ErlDrvData, ErlDrvEvent); static Sint16 get_sint16(char *s); @@ -117,7 +121,19 @@ struct erl_drv_entry ttsl_driver_entry = { NULL, NULL, ttysl_control, - NULL + NULL, /* timeout */ + NULL, /* outputv */ + NULL, /* ready_async */ + NULL, /* flush */ + NULL, /* call */ + NULL, /* event */ + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL, }; static int utf8_mode = 0; @@ -151,13 +167,13 @@ static void ttysl_get_window_size(Uint32 *width, Uint32 *height) } -static int ttysl_control(ErlDrvData drv_data, +static ErlDrvSSizeT ttysl_control(ErlDrvData drv_data, unsigned int command, - char *buf, int len, - char **rbuf, int rlen) + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) { char resbuff[2*sizeof(Uint32)]; - int res_size; + ErlDrvSizeT res_size; switch (command) { case CTRL_OP_GET_WINSIZE: { @@ -173,7 +189,7 @@ static int ttysl_control(ErlDrvData drv_data, res_size = 1; break; case CTRL_OP_SET_UNICODE_STATE: - if (len > 0) { + if (len != 0) { int m = (int) *buf; *resbuff = (utf8_mode) ? 1 : 0; res_size = 1; @@ -435,14 +451,14 @@ static int check_buf_size(byte *s, int n) } -static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, int count) +static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, ErlDrvSizeT count) { if (lpos > MAXSIZE) put_chars((byte*)"\n", 1); switch (buf[0]) { case OP_PUTC: - DEBUGLOG(("OP: Putc(%d)",count-1)); + DEBUGLOG(("OP: Putc(%I64u)",(unsigned long long)count-1)); if (check_buf_size((byte*)buf+1, count-1) == 0) return; put_chars((byte*)buf+1, count-1); diff --git a/erts/emulator/drivers/win32/win_con.c b/erts/emulator/drivers/win32/win_con.c index c788ad409d..6b45b92cbe 100644 --- a/erts/emulator/drivers/win32/win_con.c +++ b/erts/emulator/drivers/win32/win_con.c @@ -21,6 +21,9 @@ #define _UNICODE 1 #include <tchar.h> #include <stdio.h> +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include "sys.h" #include <windowsx.h> #include "resource.h" @@ -34,6 +37,23 @@ #define REALLOC(X,Y) realloc(X,Y) #define FREE(X) free(X) +#if SIZEOF_VOID_P == 8 +#define WIN64 1 +#ifndef GCL_HBRBACKGROUND +#define GCL_HBRBACKGROUND GCLP_HBRBACKGROUND +#endif +#define DIALOG_PROC_RET INT_PTR +#define CF_HOOK_RET INT_PTR +#define CC_HOOK_RET INT_PTR +#define OFN_HOOK_RET INT_PTR +#else +#define DIALOG_PROC_RET BOOL +#define CF_HOOK_RET UINT +#define CC_HOOK_RET UINT +#define OFN_HOOK_RET UINT +#endif + + #ifndef STATE_SYSTEM_INVISIBLE /* Mingw problem with oleacc.h and WIN32_LEAN_AND_MEAN */ #define STATE_SYSTEM_INVISIBLE 0x00008000 @@ -150,7 +170,7 @@ static TCHAR *erlang_window_title = TEXT("Erlang"); static unsigned __stdcall ConThreadInit(LPVOID param); static LRESULT CALLBACK ClientWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); -static BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam); +static DIALOG_PROC_RET CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam); static ScreenLine_t *ConNewLine(void); static void DeleteTopLine(void); static void ensure_line_below(void); @@ -1608,7 +1628,7 @@ OnEditSelAll(HWND hwnd) InvalidateRect(hwnd, NULL, TRUE); } -UINT APIENTRY CFHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam) +CF_HOOK_RET APIENTRY CFHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam) { /* Hook procedure for font dialog box */ HWND hOwner; @@ -1626,11 +1646,11 @@ UINT APIENTRY CFHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam) OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom); SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2), rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE); - return 1; + return (CF_HOOK_RET) 1; default: break; } - return 0; /* Let the default procedure process the message */ + return (CF_HOOK_RET) 0; /* Let the default procedure process the message */ } static BOOL @@ -1705,7 +1725,7 @@ ConSetFont(HWND hwnd) InvalidateRect(hwnd, NULL, TRUE); } -UINT APIENTRY +CC_HOOK_RET APIENTRY CCHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam) { /* Hook procedure for choose color dialog box */ @@ -1724,11 +1744,11 @@ CCHookProc(HWND hDlg,UINT iMsg,WPARAM wParam,LPARAM lParam) OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom); SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2), rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE); - return 1; + return (CC_HOOK_RET) 1; default: break; } - return 0; /* Let the default procedure process the message */ + return (CC_HOOK_RET) 0; /* Let the default procedure process the message */ } void ConChooseColor(HWND hwnd) @@ -1758,7 +1778,8 @@ void ConChooseColor(HWND hwnd) } } -UINT APIENTRY OFNHookProc(HWND hwndDlg,UINT iMsg,WPARAM wParam,LPARAM lParam) +OFN_HOOK_RET APIENTRY OFNHookProc(HWND hwndDlg,UINT iMsg, + WPARAM wParam,LPARAM lParam) { /* Hook procedure for open file dialog box */ HWND hOwner,hDlg; @@ -1777,11 +1798,11 @@ UINT APIENTRY OFNHookProc(HWND hwndDlg,UINT iMsg,WPARAM wParam,LPARAM lParam) OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom); SetWindowPos(hDlg,HWND_TOP,rcOwner.left + (rc.right / 2), rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE); - return 1; + return (OFN_HOOK_RET) 1; default: break; } - return 0; /* the let default procedure process the message */ + return (OFN_HOOK_RET) 0; /* the let default procedure process the message */ } static void @@ -1933,7 +1954,7 @@ write_outbuf(TCHAR *data, int num_chars) return num_chars; } -BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) +DIALOG_PROC_RET CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) { HWND hOwner; RECT rc,rcOwner,rcDlg; @@ -1953,17 +1974,17 @@ BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) rcOwner.top + (rc.bottom / 2),0,0,SWP_NOSIZE); SetDlgItemText(hDlg, ID_VERSIONSTRING, TEXT("Erlang emulator version ") TEXT(ERLANG_VERSION)); - return TRUE; + return (DIALOG_PROC_RET) TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: EndDialog(hDlg,0); - return TRUE; + return (DIALOG_PROC_RET) TRUE; } break; } - return FALSE; + return (DIALOG_PROC_RET) FALSE; } static void @@ -2117,7 +2138,7 @@ AddToCmdHistory(void) } } -static TBBUTTON tbb[] = +/*static TBBUTTON tbb[] = { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, @@ -2149,6 +2170,39 @@ static TBBUTTON tbb[] = 2, IDMENU_FONT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 0, 0, 0, 3, IDMENU_ABOUT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, 0, 0, 0, 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0, 0, + };*/ +static TBBUTTON tbb[] = +{ + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP}, + {0, IDMENU_COPY, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE}, + {1, IDMENU_PASTE, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE}, + {2, IDMENU_FONT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE}, + {3, IDMENU_ABOUT, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE}, + {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP} }; static TBADDBITMAP tbbitmap = @@ -2156,6 +2210,17 @@ static TBADDBITMAP tbbitmap = HINST_COMMCTRL, IDB_STD_SMALL_COLOR, }; +#ifdef HARDDEBUG +/* For really hard GUI startup debugging, place DEBUGBOX() macros in code + and get modal message boxes with the line number. */ +static void debug_box(int line) { + TCHAR buff[1024]; + swprintf(buff,1024,TEXT("DBG:%d"),line); + MessageBox(NULL,buff,TEXT("DBG"),MB_OK|MB_APPLMODAL); +} + +#define DEBUGBOX() debug_box(__LINE__) +#endif static HWND InitToolBar(HWND hwndParent) @@ -2169,7 +2234,6 @@ InitToolBar(HWND hwndParent) COLORMAP colorMap; colorMap.from = RGB(192, 192, 192); colorMap.to = backgroundColor; - /* Create toolbar window with tooltips */ hwndTB = CreateWindowEx(0,TOOLBARCLASSNAME,(TCHAR *)NULL, WS_CHILD|CCS_TOP|WS_CLIPSIBLINGS|TBSTYLE_TOOLTIPS, @@ -2180,9 +2244,10 @@ InitToolBar(HWND hwndParent) tbbitmap.hInst = NULL; tbbitmap.nID = (UINT) CreateMappedBitmap(beam_module, 1,0, &colorMap, 1); SendMessage(hwndTB, TB_ADDBITMAP, (WPARAM) 4, - (WPARAM) &tbbitmap); + (LPARAM) &tbbitmap); + SendMessage(hwndTB,TB_ADDBUTTONS, (WPARAM) 30, - (LPARAM) (LPTBBUTTON) tbb); + (LPARAM) tbb); if (toolbarVisible) ShowWindow(hwndTB, SW_SHOW); diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index 931bb196f1..606fa1d7de 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -21,6 +21,9 @@ */ #include <windows.h> +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include "sys.h" #include <ctype.h> #include <wchar.h> @@ -42,6 +45,26 @@ #define INVALID_FILE_ATTRIBUTES ((DWORD) 0xFFFFFFFF) #endif +#define TICKS_PER_SECOND (10000000ULL) +#define EPOCH_DIFFERENCE (11644473600LL) + +#define FILETIME_TO_EPOCH(epoch, ft) \ + do { \ + ULARGE_INTEGER ull; \ + ull.LowPart = (ft).dwLowDateTime; \ + ull.HighPart = (ft).dwHighDateTime; \ + (epoch) = ((ull.QuadPart / TICKS_PER_SECOND) - EPOCH_DIFFERENCE); \ + } while(0) + +#define EPOCH_TO_FILETIME(ft, epoch) \ + do { \ + ULARGE_INTEGER ull; \ + ull.QuadPart = (((epoch) + EPOCH_DIFFERENCE) * TICKS_PER_SECOND); \ + (ft).dwLowDateTime = ull.LowPart; \ + (ft).dwHighDateTime = ull.HighPart; \ + } while(0) + + static int check_error(int result, Efile_error* errInfo); static int set_error(Efile_error* errInfo); static int is_root_unc_name(const WCHAR *path); @@ -861,14 +884,7 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, findbuf.cFileName[0] = L'\0'; pInfo->links = 1; - pInfo->modifyTime.year = 1980; - pInfo->modifyTime.month = 1; - pInfo->modifyTime.day = 1; - pInfo->modifyTime.hour = 0; - pInfo->modifyTime.minute = 0; - pInfo->modifyTime.second = 0; - - pInfo->accessTime = pInfo->modifyTime; + pInfo->cTime = pInfo->accessTime = pInfo->modifyTime = 0; } else { SYSTEMTIME SystemTime; FILETIME LocalFTime; @@ -902,34 +918,21 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo, } } -#define GET_TIME(dst, src) \ -if (!FileTimeToLocalFileTime(&findbuf.src, &LocalFTime) || \ - !FileTimeToSystemTime(&LocalFTime, &SystemTime)) { \ - return set_error(errInfo); \ -} \ -(dst).year = SystemTime.wYear; \ -(dst).month = SystemTime.wMonth; \ -(dst).day = SystemTime.wDay; \ -(dst).hour = SystemTime.wHour; \ -(dst).minute = SystemTime.wMinute; \ -(dst).second = SystemTime.wSecond; - - GET_TIME(pInfo->modifyTime, ftLastWriteTime); + FILETIME_TO_EPOCH(pInfo->modifyTime, findbuf.ftLastWriteTime); if (findbuf.ftLastAccessTime.dwLowDateTime == 0 && findbuf.ftLastAccessTime.dwHighDateTime == 0) { pInfo->accessTime = pInfo->modifyTime; } else { - GET_TIME(pInfo->accessTime, ftLastAccessTime); + FILETIME_TO_EPOCH(pInfo->accessTime, findbuf.ftLastAccessTime); } if (findbuf.ftCreationTime.dwLowDateTime == 0 && findbuf.ftCreationTime.dwHighDateTime == 0) { pInfo->cTime = pInfo->modifyTime; } else { - GET_TIME(pInfo->cTime, ftCreationTime); + FILETIME_TO_EPOCH(pInfo->cTime ,findbuf.ftCreationTime); } -#undef GET_TIME FindClose(findhandle); } @@ -965,17 +968,12 @@ efile_write_info(Efile_error* errInfo, char* name) { SYSTEMTIME timebuf; - FILETIME LocalFileTime; FILETIME ModifyFileTime; FILETIME AccessFileTime; FILETIME CreationFileTime; HANDLE fd; - FILETIME* mtime = NULL; - FILETIME* atime = NULL; - FILETIME* ctime = NULL; DWORD attr; DWORD tempAttr; - BOOL modifyTime = FALSE; WCHAR *wname = (WCHAR *) name; /* @@ -1000,57 +998,36 @@ efile_write_info(Efile_error* errInfo, * Construct all file times. */ -#define MKTIME(tb, ts, ptr) \ - timebuf.wYear = ts.year; \ - timebuf.wMonth = ts.month; \ - timebuf.wDay = ts.day; \ - timebuf.wHour = ts.hour; \ - timebuf.wMinute = ts.minute; \ - timebuf.wSecond = ts.second; \ - timebuf.wMilliseconds = 0; \ - if (ts.year != -1) { \ - modifyTime = TRUE; \ - ptr = &tb; \ - if (!SystemTimeToFileTime(&timebuf, &LocalFileTime ) || \ - !LocalFileTimeToFileTime(&LocalFileTime, &tb)) { \ - errno = EINVAL; \ - return check_error(-1, errInfo); \ - } \ - } - - MKTIME(ModifyFileTime, pInfo->modifyTime, mtime); - MKTIME(AccessFileTime, pInfo->accessTime, atime); - MKTIME(CreationFileTime, pInfo->cTime, ctime); -#undef MKTIME + EPOCH_TO_FILETIME(ModifyFileTime, pInfo->modifyTime); + EPOCH_TO_FILETIME(AccessFileTime, pInfo->accessTime); + EPOCH_TO_FILETIME(CreationFileTime, pInfo->cTime); /* * If necessary, set the file times. */ - if (modifyTime) { - /* - * If the has read only access, we must temporarily turn on - * write access (this is necessary for native filesystems, - * but not for NFS filesystems). - */ + /* + * If the has read only access, we must temporarily turn on + * write access (this is necessary for native filesystems, + * but not for NFS filesystems). + */ - if (tempAttr & FILE_ATTRIBUTE_READONLY) { - tempAttr &= ~FILE_ATTRIBUTE_READONLY; - if (!SetFileAttributesW(wname, tempAttr)) { - return set_error(errInfo); - } + if (tempAttr & FILE_ATTRIBUTE_READONLY) { + tempAttr &= ~FILE_ATTRIBUTE_READONLY; + if (!SetFileAttributesW(wname, tempAttr)) { + return set_error(errInfo); } + } - fd = CreateFileW(wname, GENERIC_READ|GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (fd != INVALID_HANDLE_VALUE) { - BOOL result = SetFileTime(fd, ctime, atime, mtime); - if (!result) { - return set_error(errInfo); - } - CloseHandle(fd); + fd = CreateFileW(wname, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (fd != INVALID_HANDLE_VALUE) { + BOOL result = SetFileTime(fd, &CreationFileTime, &AccessFileTime, &ModifyFileTime); + if (!result) { + return set_error(errInfo); } + CloseHandle(fd); } /* @@ -1138,8 +1115,7 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ SysIOVec* iov, /* Vector of buffer structs. * The structs are unchanged * after the call */ - int iovcnt, /* Number of structs in vector */ - size_t size) /* Number of bytes to write */ + int iovcnt) /* Number of structs in vector */ { int cnt; /* Buffers so far written */ OVERLAPPED overlapped; diff --git a/erts/emulator/hipe/hipe_arm.c b/erts/emulator/hipe/hipe_arm.c index d52f429a9b..e20a8a7969 100644 --- a/erts/emulator/hipe/hipe_arm.c +++ b/erts/emulator/hipe/hipe_arm.c @@ -71,7 +71,7 @@ static struct segment { } curseg; #define in_area(ptr,start,nbytes) \ - ((unsigned long)((char*)(ptr) - (char*)(start)) < (nbytes)) + ((UWord)((char*)(ptr) - (char*)(start)) < (nbytes)) static void *new_code_mapping(void) { diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index cec22b3836..28e4382835 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -174,8 +174,13 @@ static inline unsigned char *bytearray_lvalue(Eterm bin, Eterm idx) { Sint i; unsigned char *bytes; +#ifndef DEBUG + ERTS_DECLARE_DUMMY(Uint bitoffs); + ERTS_DECLARE_DUMMY(Uint bitsize); +#else Uint bitoffs; Uint bitsize; +#endif if (is_not_binary(bin) || is_not_small(idx) || @@ -235,9 +240,15 @@ BIF_RETTYPE hipe_bifs_bitarray_2(BIF_ALIST_2) BIF_RETTYPE hipe_bifs_bitarray_update_3(BIF_ALIST_3) { unsigned char *bytes, bytemask; - Uint bitoffs, bitsize; Uint bitnr, bytenr; int set; +#ifndef DEBUG + ERTS_DECLARE_DUMMY(Uint bitoffs); + ERTS_DECLARE_DUMMY(Uint bitsize); +#else + Uint bitoffs; + Uint bitsize; +#endif if (is_not_binary(BIF_ARG_1)) BIF_ERROR(BIF_P, BADARG); @@ -267,8 +278,15 @@ BIF_RETTYPE hipe_bifs_bitarray_update_3(BIF_ALIST_3) BIF_RETTYPE hipe_bifs_bitarray_sub_2(BIF_ALIST_2) { unsigned char *bytes, bytemask; - Uint bitoffs, bitsize; Uint bitnr, bytenr; +#ifndef DEBUG + ERTS_DECLARE_DUMMY(Uint bitoffs); + ERTS_DECLARE_DUMMY(Uint bitsize); +#else + Uint bitoffs; + Uint bitsize; +#endif + if (is_not_binary(BIF_ARG_1)) BIF_ERROR(BIF_P, BADARG); @@ -397,10 +415,15 @@ BIF_RETTYPE hipe_bifs_enter_code_2(BIF_ALIST_2) Uint nrbytes; void *bytes; void *address; - Uint bitoffs; - Uint bitsize; Eterm trampolines; Eterm *hp; +#ifndef DEBUG + ERTS_DECLARE_DUMMY(Uint bitoffs); + ERTS_DECLARE_DUMMY(Uint bitsize); +#else + Uint bitoffs; + Uint bitsize; +#endif if (is_not_binary(BIF_ARG_1)) BIF_ERROR(BIF_P, BADARG); diff --git a/erts/emulator/hipe/hipe_gc.c b/erts/emulator/hipe/hipe_gc.c index 0199dea99e..e0575c35ff 100644 --- a/erts/emulator/hipe/hipe_gc.c +++ b/erts/emulator/hipe/hipe_gc.c @@ -46,9 +46,14 @@ Eterm *fullsweep_nstack(Process *p, Eterm *n_htop) char *src, *oh; Uint src_size, oh_size; + if (!p->hipe.nstack) { + ASSERT(!p->hipe.nsp && !p->hipe.nstend); + return n_htop; + } if (!nstack_walk_init_check(p)) return n_htop; + ASSERT(p->hipe.nsp && p->hipe.nstend); nsp = nstack_walk_nsp_begin(p); nsp_end = p->hipe.nstgraylim; if (nsp_end) @@ -136,9 +141,14 @@ void gensweep_nstack(Process *p, Eterm **ptr_old_htop, Eterm **ptr_n_htop) char *heap; Uint heap_size, mature_size; + if (!p->hipe.nstack) { + ASSERT(!p->hipe.nsp && !p->hipe.nstend); + return; + } if (!nstack_walk_init_check(p)) return; + ASSERT(p->hipe.nsp && p->hipe.nstend); nsp = nstack_walk_nsp_begin(p); nsp_end = p->hipe.nstgraylim; if (nsp_end) { diff --git a/erts/emulator/hipe/hipe_mode_switch.c b/erts/emulator/hipe/hipe_mode_switch.c index 4d75883fc5..6a3ce5608f 100644 --- a/erts/emulator/hipe/hipe_mode_switch.c +++ b/erts/emulator/hipe/hipe_mode_switch.c @@ -337,14 +337,22 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[]) * stack: to this end hipe_${ARCH}_glue.S stores the BIF's * arity in p->hipe.narity. * - * If the BIF emptied the stack (typically hibernate), p->hipe.nsp is - * NULL and there is no need to get rid of stacked parameters. + * If the BIF emptied the stack (typically hibernate), p->hipe.nstack + * is NULL and there is no need to get rid of stacked parameters. */ unsigned int i, is_recursive = 0; - if (p->hipe.nsp != NULL) { + if (p->hipe.nstack != NULL) { + ASSERT(p->hipe.nsp != NULL); is_recursive = hipe_trap_from_native_is_recursive(p); } + else { + /* Some architectures (risc) need this re-reset of nsp as the + * BIF wrapper do not detect stack change and causes an obsolete + * stack pointer to be saved in p->hipe.nsp before return to us. + */ + p->hipe.nsp = NULL; + } /* Schedule next process if current process was hibernated or is waiting for messages */ diff --git a/erts/emulator/hipe/hipe_mode_switch.h b/erts/emulator/hipe/hipe_mode_switch.h index dbc2386e14..a3e908a3b3 100644 --- a/erts/emulator/hipe/hipe_mode_switch.h +++ b/erts/emulator/hipe/hipe_mode_switch.h @@ -49,7 +49,7 @@ #include "error.h" -int hipe_modeswitch_debug; +extern int hipe_modeswitch_debug; void hipe_mode_switch_init(void); void hipe_set_call_trap(Uint *bfun, void *nfun, int is_closure); diff --git a/erts/emulator/hipe/hipe_ppc.c b/erts/emulator/hipe/hipe_ppc.c index bc25061a16..2d8fd61e1e 100644 --- a/erts/emulator/hipe/hipe_ppc.c +++ b/erts/emulator/hipe/hipe_ppc.c @@ -80,7 +80,7 @@ static struct segment { } curseg; #define in_area(ptr,start,nbytes) \ - ((unsigned long)((char*)(ptr) - (char*)(start)) < (nbytes)) + ((UWord)((char*)(ptr) - (char*)(start)) < (nbytes)) /* Darwin breakage */ #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) diff --git a/erts/emulator/pcre/pcre.mk b/erts/emulator/pcre/pcre.mk index b752c11459..352137b341 100644 --- a/erts/emulator/pcre/pcre.mk +++ b/erts/emulator/pcre/pcre.mk @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2011. All Rights Reserved. +# Copyright Ericsson AB 2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -17,8 +17,6 @@ # %CopyrightEnd% # -ARFLAGS = rc - PCRE_O = \ pcre_latin_1_table.o \ pcre_compile.o \ @@ -43,7 +41,7 @@ pcre_xclass.o PCRE_OBJS = $(PCRE_O:%=$(PCRE_OBJDIR)/%) -GENINC = pcre/pcre_exec_loop_break_cases.inc +PCRE_GENINC = $(ERL_TOP)/erts/emulator/pcre/pcre_exec_loop_break_cases.inc PCRE_OBJDIR = $(ERL_TOP)/erts/emulator/pcre/obj/$(TARGET)/$(TYPE) @@ -61,12 +59,12 @@ endif $(PCRE_OBJDIR)/%.o: pcre/%.c $(CC) -c $(PCRE_CFLAGS) -o $@ $< -$(GENINC): pcre/pcre_exec.c +$(PCRE_GENINC): pcre/pcre_exec.c for x in `grep -n COST_CHK pcre/pcre_exec.c | grep -v 'COST_CHK(N)' | awk -F: '{print $$1}'`; \ do \ N=`expr $$x + 100`; \ echo "case $$N: goto L_LOOP_COUNT_$${x};"; \ - done > $(GENINC) + done > $(PCRE_GENINC) # Dependencies. @@ -79,7 +77,7 @@ $(PCRE_OBJDIR)/pcre_config.o: pcre/pcre_config.c pcre/pcre_internal.h \ $(PCRE_OBJDIR)/pcre_dfa_exec.o: pcre/pcre_dfa_exec.c pcre/pcre_internal.h \ pcre/local_config.h pcre/pcre.h pcre/ucp.h $(PCRE_OBJDIR)/pcre_exec.o: pcre/pcre_exec.c pcre/pcre_internal.h \ - pcre/local_config.h pcre/pcre.h pcre/ucp.h $(GENINC) + pcre/local_config.h pcre/pcre.h pcre/ucp.h $(PCRE_GENINC) $(PCRE_OBJDIR)/pcre_fullinfo.o: pcre/pcre_fullinfo.c pcre/pcre_internal.h \ pcre/local_config.h pcre/pcre.h pcre/ucp.h $(PCRE_OBJDIR)/pcre_get.o: pcre/pcre_get.c pcre/pcre_internal.h \ diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c index ba88fd1d39..23a4bf1b04 100644 --- a/erts/emulator/sys/common/erl_check_io.c +++ b/erts/emulator/sys/common/erl_check_io.c @@ -314,7 +314,7 @@ forget_removed(struct pollset_info* psi) erts_smp_mtx_unlock(mtx); if (drv_ptr) { int was_unmasked = erts_block_fpe(); - (*drv_ptr->stop_select) (fd, NULL); + (*drv_ptr->stop_select) ((ErlDrvEvent) fd, NULL); erts_unblock_fpe(was_unmasked); if (drv_ptr->handle) { erts_ddll_dereference_driver(drv_ptr->handle); @@ -1134,7 +1134,8 @@ ERTS_CIO_EXPORT(erts_check_io_interrupt)(int set) } void -ERTS_CIO_EXPORT(erts_check_io_interrupt_timed)(int set, long msec) +ERTS_CIO_EXPORT(erts_check_io_interrupt_timed)(int set, + erts_short_time_t msec) { ERTS_CIO_POLL_INTR_TMD(pollset.ps, set, msec); } diff --git a/erts/emulator/sys/common/erl_check_io.h b/erts/emulator/sys/common/erl_check_io.h index 7cc1658062..edab7947ba 100644 --- a/erts/emulator/sys/common/erl_check_io.h +++ b/erts/emulator/sys/common/erl_check_io.h @@ -46,8 +46,8 @@ void erts_check_io_async_sig_interrupt_nkp(void); #endif void erts_check_io_interrupt_kp(int); void erts_check_io_interrupt_nkp(int); -void erts_check_io_interrupt_timed_kp(int, long); -void erts_check_io_interrupt_timed_nkp(int, long); +void erts_check_io_interrupt_timed_kp(int, erts_short_time_t); +void erts_check_io_interrupt_timed_nkp(int, erts_short_time_t); void erts_check_io_kp(int); void erts_check_io_nkp(int); void erts_init_check_io_kp(void); @@ -64,7 +64,7 @@ int erts_check_io_max_files(void); void erts_check_io_async_sig_interrupt(void); #endif void erts_check_io_interrupt(int); -void erts_check_io_interrupt_timed(int, long); +void erts_check_io_interrupt_timed(int, erts_short_time_t); void erts_check_io(int); void erts_init_check_io(void); diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c index 80db2055a2..3817b1e4d5 100644 --- a/erts/emulator/sys/common/erl_poll.c +++ b/erts/emulator/sys/common/erl_poll.c @@ -1949,7 +1949,7 @@ check_fd_events(ErtsPollSet ps, SysTimeval *tv, int max_res) */ struct dvpoll poll_res; int nfds = (int) erts_smp_atomic_read_nob(&ps->no_of_user_fds); -#ifdef ERTS_SMP +#if ERTS_POLL_USE_WAKEUP_PIPE nfds++; /* Wakeup pipe */ #endif if (timeout > INT_MAX) @@ -2171,7 +2171,7 @@ ERTS_POLL_EXPORT(erts_poll_async_sig_interrupt)(ErtsPollSet ps) void ERTS_POLL_EXPORT(erts_poll_interrupt_timed)(ErtsPollSet ps, int set, - long msec) + erts_short_time_t msec) { #if ERTS_POLL_ASYNC_INTERRUPT_SUPPORT || defined(ERTS_SMP) if (!set) @@ -2487,7 +2487,7 @@ ERTS_POLL_EXPORT(erts_poll_info)(ErtsPollSet ps, ErtsPollInfo *pip) pip->memory_size = size; pip->poll_set_size = (int) erts_smp_atomic_read_nob(&ps->no_of_user_fds); -#ifdef ERTS_SMP +#if ERTS_POLL_USE_WAKEUP_PIPE pip->poll_set_size++; /* Wakeup pipe */ #endif diff --git a/erts/emulator/sys/common/erl_poll.h b/erts/emulator/sys/common/erl_poll.h index e0296c6a33..8dde619105 100644 --- a/erts/emulator/sys/common/erl_poll.h +++ b/erts/emulator/sys/common/erl_poll.h @@ -223,7 +223,7 @@ void ERTS_POLL_EXPORT(erts_poll_interrupt)(ErtsPollSet, int); void ERTS_POLL_EXPORT(erts_poll_interrupt_timed)(ErtsPollSet, int, - long); + erts_short_time_t); ErtsPollEvents ERTS_POLL_EXPORT(erts_poll_control)(ErtsPollSet, ErtsSysFdType, ErtsPollEvents, diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h index 9a5ed9f5bc..c8fcec8547 100644 --- a/erts/emulator/sys/unix/erl_unix_sys.h +++ b/erts/emulator/sys/unix/erl_unix_sys.h @@ -146,6 +146,7 @@ typedef void *GETENV_STATE; /* ** For the erl_timer_sup module. */ +typedef time_t erts_time_t; typedef struct timeval SysTimeval; diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index c6b63350e5..f94e0f2296 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -265,7 +265,7 @@ struct { int (*event)(ErlDrvPort, ErlDrvEvent, ErlDrvEventData); void (*check_io_as_interrupt)(void); void (*check_io_interrupt)(int); - void (*check_io_interrupt_tmd)(int, long); + void (*check_io_interrupt_tmd)(int, erts_short_time_t); void (*check_io)(int); Uint (*size)(void); Eterm (*info)(void *); @@ -371,7 +371,7 @@ erts_sys_schedule_interrupt(int set) #ifdef ERTS_SMP void -erts_sys_schedule_interrupt_timed(int set, long msec) +erts_sys_schedule_interrupt_timed(int set, erts_short_time_t msec) { ERTS_CHK_IO_INTR_TMD(set, msec); } @@ -1033,14 +1033,15 @@ static struct driver_data { /* Driver interfaces */ static ErlDrvData spawn_start(ErlDrvPort, char*, SysDriverOpts*); static ErlDrvData fd_start(ErlDrvPort, char*, SysDriverOpts*); -static int fd_control(ErlDrvData, unsigned int, char *, int, char **, int); +static ErlDrvSSizeT fd_control(ErlDrvData, unsigned int, char *, ErlDrvSizeT, + char **, ErlDrvSizeT); static ErlDrvData vanilla_start(ErlDrvPort, char*, SysDriverOpts*); static int spawn_init(void); static void fd_stop(ErlDrvData); static void stop(ErlDrvData); static void ready_input(ErlDrvData, ErlDrvEvent); static void ready_output(ErlDrvData, ErlDrvEvent); -static void output(ErlDrvData, char*, int); +static void output(ErlDrvData, char*, ErlDrvSizeT); static void outputv(ErlDrvData, ErlIOVec*); static void stop_select(ErlDrvEvent, void*); @@ -1726,10 +1727,10 @@ static int fd_get_window_size(int fd, Uint32 *width, Uint32 *height) return -1; } -static int fd_control(ErlDrvData drv_data, - unsigned int command, - char *buf, int len, - char **rbuf, int rlen) +static ErlDrvSSizeT fd_control(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) { int fd = (int)(long)drv_data; char resbuff[2*sizeof(Uint32)]; @@ -2001,18 +2002,20 @@ static void outputv(ErlDrvData e, ErlIOVec* ev) int ix = driver_data[fd].port_num; int pb = driver_data[fd].packet_bytes; int ofd = driver_data[fd].ofd; - int n; - int sz; + ssize_t n; + ErlDrvSizeT sz; char lb[4]; char* lbp; - int len = ev->size; + ErlDrvSizeT len = ev->size; /* (len > ((unsigned long)-1 >> (4-pb)*8)) */ + /* if (pb >= 0 && (len & (((ErlDrvSizeT)1 << (pb*8))) - 1) != len) {*/ if (((pb == 2) && (len > 0xffff)) || (pb == 1 && len > 0xff)) { driver_failure_posix(ix, EINVAL); return; /* -1; */ } - put_int32(len, lb); + /* Handles 0 <= pb <= 4 only */ + put_int32((Uint32) len, lb); lbp = lb + (4-pb); ev->iov[0].iov_base = lbp; @@ -2043,14 +2046,14 @@ static void outputv(ErlDrvData e, ErlIOVec* ev) } -static void output(ErlDrvData e, char* buf, int len) +static void output(ErlDrvData e, char* buf, ErlDrvSizeT len) { int fd = (int)(long)e; int ix = driver_data[fd].port_num; int pb = driver_data[fd].packet_bytes; int ofd = driver_data[fd].ofd; - int n; - int sz; + ssize_t n; + ErlDrvSizeT sz; char lb[4]; char* lbp; struct iovec iv[2]; diff --git a/erts/emulator/sys/vxworks/erl_vxworks_sys.h b/erts/emulator/sys/vxworks/erl_vxworks_sys.h index ae46403600..3d53238ea6 100644 --- a/erts/emulator/sys/vxworks/erl_vxworks_sys.h +++ b/erts/emulator/sys/vxworks/erl_vxworks_sys.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * Copyright Ericsson AB 1997-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -158,6 +158,7 @@ typedef struct _vxworks_tms { typedef long long SysHrTime; +typedef time_t erts_time_t; typedef struct timeval SysTimeval; extern int sys_init_hrtime(void); diff --git a/erts/emulator/sys/vxworks/sys.c b/erts/emulator/sys/vxworks/sys.c index d6d1fe64e0..739b026fb1 100644 --- a/erts/emulator/sys/vxworks/sys.c +++ b/erts/emulator/sys/vxworks/sys.c @@ -565,7 +565,7 @@ static void fd_stop(ErlDrvData); static void stop(ErlDrvData); static void ready_input(ErlDrvData fd, ErlDrvEvent ready_fd); static void ready_output(ErlDrvData fd, ErlDrvEvent ready_fd); -static void output(ErlDrvData fd, char *buf, int len); +static void output(ErlDrvData fd, char *buf, ErlDrvSizeT len); static void stop_select(ErlDrvEvent, void*); struct erl_drv_entry spawn_driver_entry = { @@ -1187,7 +1187,7 @@ static int sched_write(int port_num,int fd, char *buf, int len, int pb) } /* Fd is the value returned as drv_data by the start func */ -static void output(ErlDrvData drv_data, char *buf, int len) +static void output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { int buf_done, port_num, wval, pb, ofd; byte lb[4]; diff --git a/erts/emulator/sys/win32/erl_poll.c b/erts/emulator/sys/win32/erl_poll.c index ab4ef05118..7a1d129cd5 100644 --- a/erts/emulator/sys/win32/erl_poll.c +++ b/erts/emulator/sys/win32/erl_poll.c @@ -442,8 +442,8 @@ poll_wait_timeout(ErtsPollSet ps, SysTimeval *tvp) if (erts_atomic32_read_nob(&ps->wakeup_state) != ERTS_POLL_NOT_WOKEN) return (DWORD) 0; - if (timeout > ERTS_AINT32_T_MAX) /* Also prevents DWORD overflow */ - timeout = ERTS_AINT32_T_MAX; + if (timeout > ((time_t) ERTS_AINT32_T_MAX)) + timeout = ERTS_AINT32_T_MAX; /* Also prevents DWORD overflow */ erts_smp_atomic32_set_relb(&ps->timeout, (erts_aint32_t) timeout); return (DWORD) timeout; @@ -1012,7 +1012,7 @@ void erts_poll_interrupt(ErtsPollSet ps, int set /* bool */) void erts_poll_interrupt_timed(ErtsPollSet ps, int set /* bool */, - long msec) + erts_short_time_t msec) { HARDTRACEF(("In erts_poll_interrupt_timed(%d,%ld)",set,msec)); if (!set) diff --git a/erts/emulator/sys/win32/erl_win32_sys_ddll.c b/erts/emulator/sys/win32/erl_win32_sys_ddll.c index a19f49af10..d00eed932b 100644 --- a/erts/emulator/sys/win32/erl_win32_sys_ddll.c +++ b/erts/emulator/sys/win32/erl_win32_sys_ddll.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2006-2009. All Rights Reserved. + * Copyright Ericsson AB 2006-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -25,6 +25,9 @@ #include <windows.h> #define GET_ERTS_ALC_TEST +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include "sys.h" #include "global.h" #include "erl_alloc.h" diff --git a/erts/emulator/sys/win32/erl_win_dyn_driver.h b/erts/emulator/sys/win32/erl_win_dyn_driver.h index ecb06868d5..ec5141838a 100644 --- a/erts/emulator/sys/win32/erl_win_dyn_driver.h +++ b/erts/emulator/sys/win32/erl_win_dyn_driver.h @@ -39,11 +39,11 @@ WDD_TYPEDEF(int, driver_exit, (ErlDrvPort, int)); WDD_TYPEDEF(int, driver_failure_eof, (ErlDrvPort)); WDD_TYPEDEF(int, driver_select, (ErlDrvPort, ErlDrvEvent, int, int)); WDD_TYPEDEF(int, driver_event, (ErlDrvPort, ErlDrvEvent,ErlDrvEventData)); -WDD_TYPEDEF(int, driver_output, (ErlDrvPort, char *, int)); -WDD_TYPEDEF(int, driver_output2, (ErlDrvPort, char *, int,char *, int)); -WDD_TYPEDEF(int, driver_output_binary, (ErlDrvPort, char *, int,ErlDrvBinary*, int, int)); -WDD_TYPEDEF(int, driver_outputv, (ErlDrvPort, char*, int, ErlIOVec *,int)); -WDD_TYPEDEF(int, driver_vec_to_buf, (ErlIOVec *, char *, int)); +WDD_TYPEDEF(int, driver_output, (ErlDrvPort, char *, ErlDrvSizeT)); +WDD_TYPEDEF(int, driver_output2, (ErlDrvPort, char *, ErlDrvSizeT ,char *, ErlDrvSizeT)); +WDD_TYPEDEF(int, driver_output_binary, (ErlDrvPort, char *, ErlDrvSizeT, ErlDrvBinary*, ErlDrvSizeT, ErlDrvSizeT)); +WDD_TYPEDEF(int, driver_outputv, (ErlDrvPort, char*, ErlDrvSizeT, ErlIOVec *, ErlDrvSizeT)); +WDD_TYPEDEF(ErlDrvSizeT, driver_vec_to_buf, (ErlIOVec *, char *, ErlDrvSizeT)); WDD_TYPEDEF(int, driver_set_timer, (ErlDrvPort, unsigned long)); WDD_TYPEDEF(int, driver_cancel_timer, (ErlDrvPort)); WDD_TYPEDEF(int, driver_read_timer, (ErlDrvPort, unsigned long *)); @@ -51,22 +51,22 @@ WDD_TYPEDEF(char *, erl_errno_id, (int)); WDD_TYPEDEF(void, set_busy_port, (ErlDrvPort, int)); WDD_TYPEDEF(void, set_port_control_flags, (ErlDrvPort, int)); WDD_TYPEDEF(int, get_port_flags, (ErlDrvPort)); -WDD_TYPEDEF(ErlDrvBinary *, driver_alloc_binary, (int)); -WDD_TYPEDEF(ErlDrvBinary *, driver_realloc_binary, (ErlDrvBinary *, int)); +WDD_TYPEDEF(ErlDrvBinary *, driver_alloc_binary, (ErlDrvSizeT)); +WDD_TYPEDEF(ErlDrvBinary *, driver_realloc_binary, (ErlDrvBinary *, ErlDrvSizeT)); WDD_TYPEDEF(void, driver_free_binary, (ErlDrvBinary *)); -WDD_TYPEDEF(void *, driver_alloc, (size_t)); -WDD_TYPEDEF(void *, driver_realloc, (void *, size_t)); +WDD_TYPEDEF(void *, driver_alloc, (ErlDrvSizeT)); +WDD_TYPEDEF(void *, driver_realloc, (void *, ErlDrvSizeT)); WDD_TYPEDEF(void, driver_free, (void *)); -WDD_TYPEDEF(int, driver_enq, (ErlDrvPort, char*, int)); -WDD_TYPEDEF(int, driver_pushq, (ErlDrvPort, char*, int)); -WDD_TYPEDEF(int, driver_deq, (ErlDrvPort, int)); -WDD_TYPEDEF(int, driver_sizeq, (ErlDrvPort)); -WDD_TYPEDEF(int, driver_enq_bin, (ErlDrvPort, ErlDrvBinary *, int,int)); -WDD_TYPEDEF(int, driver_pushq_bin, (ErlDrvPort, ErlDrvBinary *, int,int)); -WDD_TYPEDEF(int, driver_peekqv, (ErlDrvPort, ErlIOVec *)); +WDD_TYPEDEF(int, driver_enq, (ErlDrvPort, char*, ErlDrvSizeT)); +WDD_TYPEDEF(int, driver_pushq, (ErlDrvPort, char*, ErlDrvSizeT)); +WDD_TYPEDEF(ErlDrvSizeT, driver_deq, (ErlDrvPort, ErlDrvSizeT)); +WDD_TYPEDEF(ErlDrvSizeT, driver_sizeq, (ErlDrvPort)); +WDD_TYPEDEF(int, driver_enq_bin, (ErlDrvPort, ErlDrvBinary *, ErlDrvSizeT, ErlDrvSizeT)); +WDD_TYPEDEF(int, driver_pushq_bin, (ErlDrvPort, ErlDrvBinary *, ErlDrvSizeT, ErlDrvSizeT)); +WDD_TYPEDEF(ErlDrvSizeT, driver_peekqv, (ErlDrvPort, ErlIOVec *)); WDD_TYPEDEF(SysIOVec *, driver_peekq, (ErlDrvPort, int *)); -WDD_TYPEDEF(int, driver_enqv, (ErlDrvPort, ErlIOVec *, int)); -WDD_TYPEDEF(int, driver_pushqv, (ErlDrvPort, ErlIOVec *, int)); +WDD_TYPEDEF(int, driver_enqv, (ErlDrvPort, ErlIOVec *, ErlDrvSizeT)); +WDD_TYPEDEF(int, driver_pushqv, (ErlDrvPort, ErlIOVec *, ErlDrvSizeT)); WDD_TYPEDEF(void, add_driver_entry, (ErlDrvEntry *)); WDD_TYPEDEF(int, remove_driver_entry, (ErlDrvEntry *)); WDD_TYPEDEF(ErlDrvTermData, driver_mk_atom, (char*)); @@ -83,10 +83,10 @@ WDD_TYPEDEF(void *, driver_dl_open, (char *)); WDD_TYPEDEF(void *, driver_dl_sym, (void *, char *)); WDD_TYPEDEF(int, driver_dl_close, (void *)); WDD_TYPEDEF(char *, driver_dl_error, (void)); -WDD_TYPEDEF(unsigned long, erts_alc_test, (unsigned long, - unsigned long, - unsigned long, - unsigned long)); +WDD_TYPEDEF(ErlDrvUInt, erts_alc_test, (ErlDrvUInt, + ErlDrvUInt, + ErlDrvUInt, + ErlDrvUInt)); WDD_TYPEDEF(ErlDrvSInt, driver_binary_get_refc, (ErlDrvBinary *dbp)); WDD_TYPEDEF(ErlDrvSInt, driver_binary_inc_refc, (ErlDrvBinary *dbp)); WDD_TYPEDEF(ErlDrvSInt, driver_binary_dec_refc, (ErlDrvBinary *dbp)); diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h index 92d8577537..03298a6c54 100644 --- a/erts/emulator/sys/win32/erl_win_sys.h +++ b/erts/emulator/sys/win32/erl_win_sys.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * Copyright Ericsson AB 1997-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -117,9 +117,30 @@ int erts_check_io_debug(void); #define SYS_CLK_TCK 1000 #define SYS_CLOCK_RESOLUTION 1 +#if SIZEOF_TIME_T != 8 +# error "Unexpected sizeof(time_t)" +#endif + +/* + * gcc uses a 4 byte time_t and vc++ uses an 8 byte time_t. + * Types seen in beam_emu.c *need* to have the same size + * as in the rest of the system... + */ +typedef __int64 erts_time_t; + +struct tm *sys_localtime_r(time_t *epochs, struct tm *ptm); +struct tm *sys_gmtime_r(time_t *epochs, struct tm *ptm); +time_t sys_mktime( struct tm *ptm); + +#define localtime_r sys_localtime_r +#define HAVE_LOCALTIME_R 1 +#define gmtime_r sys_gmtime_r +#define HAVE_GMTIME_R +#define mktime sys_mktime + typedef struct { - long tv_sec; - long tv_usec; + erts_time_t tv_sec; + erts_time_t tv_usec; } SysTimeval; typedef struct { @@ -169,10 +190,12 @@ void erts_sys_env_init(void); extern volatile int erl_fp_exception; #include <float.h> -#if defined (__GNUC__) +/* I suspect this test isn't right, it might depend on the version of GCC + rather than if it's a MINGW gcc, but I havent been able to pinpoint the + exact point where _finite was added to the headers in cygwin... */ +#if defined (__GNUC__) && !defined(__MINGW32__) int _finite(double x); #endif -#endif /*#define NO_FPE_SIGNALS*/ #define erts_get_current_fp_exception() NULL @@ -191,13 +214,6 @@ int _finite(double x); #define erts_sys_block_fpe() 0 #define erts_sys_unblock_fpe(x) do{}while(0) -#define SIZEOF_SHORT 2 -#define SIZEOF_INT 4 -#define SIZEOF_LONG 4 -#define SIZEOF_VOID_P 4 -#define SIZEOF_SIZE_T 4 -#define SIZEOF_OFF_T 4 - /* * Seems to be missing. */ @@ -210,3 +226,4 @@ typedef long ssize_t; int init_async(int); int exit_async(void); #endif +#endif diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c index 6f33ef7ad6..b106f0932d 100644..100755 --- a/erts/emulator/sys/win32/sys.c +++ b/erts/emulator/sys/win32/sys.c @@ -474,7 +474,7 @@ static int spawn_init(void); static int fd_init(void); static void fd_stop(ErlDrvData); static void stop(ErlDrvData); -static void output(ErlDrvData, char*, int); +static void output(ErlDrvData, char*, ErlDrvSizeT); static void ready_input(ErlDrvData, ErlDrvEvent); static void ready_output(ErlDrvData, ErlDrvEvent); static void stop_select(ErlDrvEvent, void*); @@ -1634,17 +1634,6 @@ create_child_process WaitForSingleObject(hProcess, 50); } - /* - * When an application spawns a process repeatedly, a new thread - * instance will be created for each process but the previous - * instances may not be cleaned up. This results in a significant - * virtual memory loss each time the process is spawned. If there - * is a WaitForInputIdle() call between CreateProcess() and - * CloseHandle(), the problem does not occur. PSS ID Number: Q124121 - */ - - WaitForInputIdle(piProcInfo.hProcess, 5000); - return ok; } @@ -2442,13 +2431,13 @@ threaded_exiter(LPVOID param) */ static void -output(ErlDrvData drv_data, char* buf, int len) +output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len) /* long drv_data; /* The slot to use in the driver data table. * For Windows NT, this is *NOT* a file handle. * The handle is found in the driver data. */ -/* char *buf; /* Pointer to data to write to the port program. */ -/* int len; /* Number of bytes to write. */ +/* char *buf; /* Pointer to data to write to the port program. */ +/* ErlDrvSizeT len; /* Number of bytes to write. */ { DriverData* dp; int pb; /* The header size for this port. */ @@ -3301,7 +3290,7 @@ erts_sys_schedule_interrupt(int set) #ifdef ERTS_SMP void -erts_sys_schedule_interrupt_timed(int set, long msec) +erts_sys_schedule_interrupt_timed(int set, erts_short_time_t msec) { erts_check_io_interrupt_timed(set, msec); } diff --git a/erts/emulator/sys/win32/sys_env.c b/erts/emulator/sys/win32/sys_env.c index 7acc7f07ee..064745d418 100644 --- a/erts/emulator/sys/win32/sys_env.c +++ b/erts/emulator/sys/win32/sys_env.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2002-2010. All Rights Reserved. + * Copyright Ericsson AB 2002-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in diff --git a/erts/emulator/sys/win32/sys_float.c b/erts/emulator/sys/win32/sys_float.c index 9e67ca7f48..6558ad2d99 100644 --- a/erts/emulator/sys/win32/sys_float.c +++ b/erts/emulator/sys/win32/sys_float.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * Copyright Ericsson AB 1997-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -18,6 +18,9 @@ */ /* Float conversions */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include "sys.h" #include "signal.h" diff --git a/erts/emulator/sys/win32/sys_interrupt.c b/erts/emulator/sys/win32/sys_interrupt.c index 93aaa23f97..347c31053b 100644 --- a/erts/emulator/sys/win32/sys_interrupt.c +++ b/erts/emulator/sys/win32/sys_interrupt.c @@ -19,6 +19,9 @@ /* * Purpose: Interrupt handling in windows. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include "sys.h" #include "erl_alloc.h" #include "erl_thr_progress.h" diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c index 50e43065b5..b5123dc45d 100644 --- a/erts/emulator/sys/win32/sys_time.c +++ b/erts/emulator/sys/win32/sys_time.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * Copyright Ericsson AB 1997-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -20,6 +20,9 @@ * Purpose: System-dependent time functions. */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include "sys.h" #include "assert.h" @@ -32,28 +35,336 @@ /******************* Routines for time measurement *********************/ #define EPOCH_JULIAN_DIFF LL_LITERAL(11644473600) +#define TICKS_PER_SECOND LL_LITERAL(10000000) +#define SECONDS_PER_DAY LL_LITERAL(86400) + +#define ULI_TO_FILETIME(ft,ull) \ + do { \ + (ft).dwLowDateTime = (ull).LowPart; \ + (ft).dwHighDateTime = (ull).HighPart; \ + } while (0) + +#define FILETIME_TO_ULI(ull,ft) \ + do { \ + (ull).LowPart = (ft).dwLowDateTime; \ + (ull).HighPart = (ft).dwHighDateTime; \ + } while (0) + +#define EPOCH_TO_FILETIME(ft, epoch) \ + do { \ + ULARGE_INTEGER ull; \ + ull.QuadPart = (((epoch) + EPOCH_JULIAN_DIFF) * TICKS_PER_SECOND); \ + ULI_TO_FILETIME(ft,ull); \ + } while(0) + +#define FILETIME_TO_EPOCH(epoch, ft) \ + do { \ + ULARGE_INTEGER ull; \ + FILETIME_TO_ULI(ull,ft); \ + (epoch) = ((ull.QuadPart / TICKS_PER_SECOND) - EPOCH_JULIAN_DIFF); \ + } while(0) + static SysHrTime wrap = 0; static DWORD last_tick_count = 0; +/* Getting timezone information is a heavy operation, so we want to do this + only once */ + +static TIME_ZONE_INFORMATION static_tzi; +static int have_static_tzi = 0; + +static int days_in_month[2][13] = { + {0,31,28,31,30,31,30,31,31,30,31,30,31}, + {0,31,29,31,30,31,30,31,31,30,31,30,31}}; + int sys_init_time(void) { + if(GetTimeZoneInformation(&static_tzi) && + static_tzi.StandardDate.wMonth != 0 && + static_tzi.DaylightDate.wMonth != 0) { + have_static_tzi = 1; + } return 1; } +/* Returns a switchtimes for DST as UTC filetimes given data from a + TIME_ZONE_INFORMATION, see sys_localtime_r for usage. */ +static void +get_dst_switchtime(DWORD year, + SYSTEMTIME dstinfo, LONG bias, + FILETIME *utc_switchtime) +{ + DWORD occu; + DWORD weekday,wday_1st; + DWORD day, days_in; + FILETIME tmp,tmp2; + ULARGE_INTEGER ull; + int leap_year = 0; + if (dstinfo.wYear != 0) { + /* A year specific transition, in which case the data in the structure + is already properly set for a specific year. Compare year + with parameter and see if they correspond, in that case generate a + filetime directly, otherwise set the filetime to 0 */ + if (year != dstinfo.wYear) { + utc_switchtime->dwLowDateTime = utc_switchtime->dwHighDateTime = 0; + return; + } + } else { + occu = dstinfo.wDay; + weekday = dstinfo.wDayOfWeek; + + dstinfo.wDayOfWeek = 0; + dstinfo.wDay = 1; + dstinfo.wYear = year; + + SystemTimeToFileTime(&dstinfo,&tmp); + ull.LowPart = tmp.dwLowDateTime; + ull.HighPart = tmp.dwHighDateTime; + + ull.QuadPart /= (TICKS_PER_SECOND*SECONDS_PER_DAY); /* Julian Day */ + wday_1st = (DWORD) ((ull.QuadPart + LL_LITERAL(1)) % LL_LITERAL(7)); + day = (weekday >= wday_1st) ? + weekday - wday_1st + 1 : + weekday - wday_1st + 8; + --occu; + if (((dstinfo.wYear % 4) == 0 && (dstinfo.wYear % 100) > 0) || + ((dstinfo.wYear % 400) == 0)) { + leap_year = 1; + } + days_in = days_in_month[leap_year][dstinfo.wMonth]; + while (occu > 0 && (day + 7 <= days_in)) { + --occu; + day += 7; + } + dstinfo.wDay = day; + } + SystemTimeToFileTime(&dstinfo,&tmp); + /* correct for bias */ + ull.LowPart = tmp.dwLowDateTime; + ull.HighPart = tmp.dwHighDateTime; + ull.QuadPart += (((LONGLONG) bias) * LL_LITERAL(60) * TICKS_PER_SECOND); + utc_switchtime->dwLowDateTime = ull.LowPart; + utc_switchtime->dwHighDateTime = ull.HighPart; + return; +} + +/* This function gives approximately the correct year from a FILETIME + Around the actual new year, it may return the wrong value, but that's OK + as DST never switches around new year. */ +static DWORD +approx_year(FILETIME ft) +{ + ULARGE_INTEGER ull; + FILETIME_TO_ULI(ull,ft); + ull.QuadPart /= LL_LITERAL(1000); + ull.QuadPart /= SECONDS_PER_DAY; + ull.QuadPart /= LL_LITERAL(3652425); + ull.QuadPart += 1601; + return (DWORD) ull.QuadPart; +} + +struct tm * +sys_localtime_r(time_t *epochs, struct tm *ptm) +{ + FILETIME ft,lft; + SYSTEMTIME st; + + if ((((*epochs) + EPOCH_JULIAN_DIFF) * TICKS_PER_SECOND) < 0LL) { + fprintf(stderr,"1\r\n"); fflush(stderr); + return NULL; + } + + EPOCH_TO_FILETIME(ft,*epochs); + ptm->tm_isdst = 0; + if (have_static_tzi) { + FILETIME dst_start, dst_stop; + ULARGE_INTEGER ull; + DWORD year = approx_year(ft); + get_dst_switchtime(year,static_tzi.DaylightDate, + static_tzi.Bias+static_tzi.StandardBias,&dst_start); + get_dst_switchtime(year,static_tzi.StandardDate, + static_tzi.Bias+static_tzi.StandardBias+ + static_tzi.DaylightBias, + &dst_stop); + FILETIME_TO_ULI(ull,ft); + + if (CompareFileTime(&ft,&dst_start) >= 0 && + CompareFileTime(&ft,&dst_stop) < 0) { + ull.QuadPart -= + ((LONGLONG) static_tzi.Bias+static_tzi.StandardBias+ + static_tzi.DaylightBias) * + LL_LITERAL(60) * TICKS_PER_SECOND; + ptm->tm_isdst = 1; + } else { + ull.QuadPart -= + ((LONGLONG) static_tzi.Bias+static_tzi.StandardBias) + * LL_LITERAL(60) * TICKS_PER_SECOND; + } + ULI_TO_FILETIME(ft,ull); + } else { + if (!FileTimeToLocalFileTime(&ft,&lft)) { + return NULL; + } + ft = lft; + } + + if (!FileTimeToSystemTime(&ft,&st)) { + return NULL; + } + + ptm->tm_year = (int) st.wYear - 1900; + ptm->tm_mon = (int) st.wMonth - 1; + ptm->tm_mday = (int) st.wDay; + ptm->tm_hour = (int) st.wHour; + ptm->tm_min = (int) st.wMinute; + ptm->tm_sec = (int) st.wSecond; + ptm->tm_wday = (int) st.wDayOfWeek; + { + int yday = ptm->tm_mday - 1; + int m = ptm->tm_mon; + int leap_year = 0; + if (((st.wYear % 4) == 0 && (st.wYear % 100) > 0) || + ((st.wYear % 400) == 0)) { + leap_year = 1; + } + while (m > 0) { + yday +=days_in_month[leap_year][m]; + --m; + } + ptm->tm_yday = yday; + } + return ptm; +} + +struct tm * +sys_gmtime_r(time_t *epochs, struct tm *ptm) +{ + FILETIME ft; + SYSTEMTIME st; + + if ((((*epochs) + EPOCH_JULIAN_DIFF) * TICKS_PER_SECOND) < 0LL) { + return NULL; + } + + EPOCH_TO_FILETIME(ft,*epochs); + + if (!FileTimeToSystemTime(&ft,&st)) { + return NULL; + } + + ptm->tm_year = (int) st.wYear - 1900; + ptm->tm_mon = (int) st.wMonth - 1; + ptm->tm_mday = (int) st.wDay; + ptm->tm_hour = (int) st.wHour; + ptm->tm_min = (int) st.wMinute; + ptm->tm_sec = (int) st.wSecond; + ptm->tm_wday = (int) st.wDayOfWeek; + ptm->tm_isdst = 0; + { + int yday = ptm->tm_mday - 1; + int m = ptm->tm_mon; + int leap_year = 0; + if (((st.wYear % 4) == 0 && (st.wYear % 100) > 0) || + ((st.wYear % 400) == 0)) { + leap_year = 1; + } + while (m > 0) { + yday +=days_in_month[leap_year][m]; + --m; + } + ptm->tm_yday = yday; + } + + return ptm; +} + +time_t +sys_mktime(struct tm *ptm) +{ + FILETIME ft; + SYSTEMTIME st; + int dst = 0; + time_t epochs; + + memset(&st,0,sizeof(st)); + /* Convert relevant parts of truct tm to SYSTEMTIME */ + st.wYear = (USHORT) (ptm->tm_year + 1900); + st.wMonth = (USHORT) (ptm->tm_mon + 1); + st.wDay = (USHORT) ptm->tm_mday; + st.wHour = (USHORT) ptm->tm_hour; + st.wMinute = (USHORT) ptm->tm_min; + st.wSecond = (USHORT) ptm->tm_sec; + + SystemTimeToFileTime(&st,&ft); + + /* ft is now some kind of local file time, but it may be wrong depending + on what is in the tm_dst field. We need to manually convert it to + UTC before turning it into epochs */ + + if (have_static_tzi) { + FILETIME dst_start, dst_stop; + ULARGE_INTEGER ull_start,ull_stop,ull_ft; + + FILETIME_TO_ULI(ull_ft,ft); + + /* Correct everything except DST */ + ull_ft.QuadPart += (static_tzi.Bias+static_tzi.StandardBias) + * LL_LITERAL(60) * TICKS_PER_SECOND; + + /* Determine if DST is active */ + if (ptm->tm_isdst >= 0) { + dst = ptm->tm_isdst; + } else if (static_tzi.DaylightDate.wMonth != 0){ + /* This is how windows mktime does it, meaning it does not + take nonexisting local times into account */ + get_dst_switchtime(st.wYear,static_tzi.DaylightDate, + static_tzi.Bias+static_tzi.StandardBias, + &dst_start); + get_dst_switchtime(st.wYear,static_tzi.StandardDate, + static_tzi.Bias+static_tzi.StandardBias+ + static_tzi.DaylightBias, + &dst_stop); + FILETIME_TO_ULI(ull_start,dst_start); + FILETIME_TO_ULI(ull_stop,dst_stop); + if ((ull_ft.QuadPart >= ull_start.QuadPart) && + (ull_ft.QuadPart < ull_stop.QuadPart)) { + /* We are in DST */ + dst = 1; + } + } + /* Correct for DST */ + if (dst) { + ull_ft.QuadPart += static_tzi.DaylightBias * + LL_LITERAL(60) * TICKS_PER_SECOND; + } + epochs = ((ull_ft.QuadPart / TICKS_PER_SECOND) - EPOCH_JULIAN_DIFF); + } else { + /* No DST, life is easy... */ + FILETIME lft; + LocalFileTimeToFileTime(&ft,&lft); + FILETIME_TO_EPOCH(epochs,lft); + } + /* Normalize the struct tm */ + sys_localtime_r(&epochs,ptm); + return epochs; +} + void sys_gettimeofday(SysTimeval *tv) { SYSTEMTIME t; FILETIME ft; - LONGLONG lft; + ULARGE_INTEGER ull; GetSystemTime(&t); SystemTimeToFileTime(&t, &ft); - memcpy(&lft, &ft, sizeof(lft)); - tv->tv_usec = (long) ((lft / LL_LITERAL(10)) % LL_LITERAL(1000000)); - tv->tv_sec = (long) ((lft / LL_LITERAL(10000000)) - EPOCH_JULIAN_DIFF); + FILETIME_TO_ULI(ull,ft); + tv->tv_usec = (long) ((ull.QuadPart / LL_LITERAL(10)) % + LL_LITERAL(1000000)); + tv->tv_sec = (long) ((ull.QuadPart / LL_LITERAL(10000000)) - + EPOCH_JULIAN_DIFF); } SysHrTime @@ -88,9 +399,3 @@ sys_times(SysTimes *buffer) { buffer->tms_stime = (clock_t) (system & LL_LITERAL(0x7FFFFFFF)); return kernel_ticks; } - - - - - - diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile index 4d0c87bf12..a3dcbc4cf3 100644 --- a/erts/emulator/test/Makefile +++ b/erts/emulator/test/Makefile @@ -61,7 +61,7 @@ MODULES= \ exception_SUITE \ float_SUITE \ fun_SUITE \ - fun_r12_SUITE \ + fun_r13_SUITE \ gc_SUITE \ guard_SUITE \ hash_SUITE \ @@ -88,6 +88,7 @@ MODULES= \ send_term_SUITE \ sensitive_SUITE \ signal_SUITE \ + smoke_test_SUITE \ statistics_SUITE \ system_info_SUITE \ system_profile_SUITE \ diff --git a/erts/emulator/test/a_SUITE_data/timer_driver.c b/erts/emulator/test/a_SUITE_data/timer_driver.c index ef4dcdf501..44be94e0f0 100644 --- a/erts/emulator/test/a_SUITE_data/timer_driver.c +++ b/erts/emulator/test/a_SUITE_data/timer_driver.c @@ -17,7 +17,9 @@ #define CANCELLED 4 static ErlDrvData timer_start(ErlDrvPort, char*); -static void timer_stop(ErlDrvData), timer_read(ErlDrvData, char*, int), timer(ErlDrvData); +static void timer_stop(ErlDrvData), + timer_read(ErlDrvData, char*, ErlDrvSizeT), + timer(ErlDrvData); static ErlDrvEntry timer_driver_entry = { @@ -33,6 +35,16 @@ static ErlDrvEntry timer_driver_entry = NULL, timer, NULL, + NULL, + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, NULL }; @@ -47,8 +59,9 @@ static ErlDrvData timer_start(ErlDrvPort port, char *buf) } /* set the timer, this is monitored from erlang measuring the time */ -static void timer_read(ErlDrvData port, char *buf, int len) +static void timer_read(ErlDrvData p, char *buf, ErlDrvSizeT len) { + ErlDrvPort port = (ErlDrvPort) p; char reply[1]; if (buf[0] == START_TIMER) { @@ -62,8 +75,9 @@ static void timer_read(ErlDrvData port, char *buf, int len) } } -static void timer_stop(ErlDrvData port) +static void timer_stop(ErlDrvData p) { + ErlDrvPort port = (ErlDrvPort) p; driver_cancel_timer(port); } diff --git a/erts/emulator/test/alloc_SUITE_data/allocator_test.h b/erts/emulator/test/alloc_SUITE_data/allocator_test.h index 8b34375980..cd4a91d34a 100644 --- a/erts/emulator/test/alloc_SUITE_data/allocator_test.h +++ b/erts/emulator/test/alloc_SUITE_data/allocator_test.h @@ -19,7 +19,7 @@ #ifndef ALLOCATOR_TEST_H__ #define ALLOCATOR_TEST_H__ -typedef unsigned long Ulong; +typedef ErlDrvUInt Ulong; #ifndef __WIN32__ Ulong erts_alc_test(Ulong, Ulong, Ulong, Ulong); diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c index 1e98844838..66971654a2 100644 --- a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c +++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c @@ -50,13 +50,32 @@ typedef struct { ErlDrvData testcase_drv_start(ErlDrvPort port, char *command); void testcase_drv_stop(ErlDrvData drv_data); -void testcase_drv_run(ErlDrvData drv_data, char *buf, int len); +void testcase_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len); static ErlDrvEntry testcase_drv_entry = { NULL, testcase_drv_start, testcase_drv_stop, - testcase_drv_run + testcase_drv_run, + NULL, + NULL, + "testcase_drv", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL }; @@ -92,7 +111,7 @@ testcase_drv_stop(ErlDrvData drv_data) } void -testcase_drv_run(ErlDrvData drv_data, char *buf, int len) +testcase_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) drv_data; ErlDrvTermData result_atom; diff --git a/erts/emulator/test/big_SUITE.erl b/erts/emulator/test/big_SUITE.erl index 3487917677..413bd3bcae 100644 --- a/erts/emulator/test/big_SUITE.erl +++ b/erts/emulator/test/big_SUITE.erl @@ -26,7 +26,7 @@ shift_limit_1/1, powmod/1, system_limit/1, otp_6692/1]). %% Internal exports. --export([eval/1, funcall/2]). +-export([eval/1]). -export([init/3]). -export([fac/1, fib/1, pow/2, gcd/2, lcm/2]). @@ -162,12 +162,15 @@ multi_match([Node|Ns], Expr, Rs) -> multi_match([], _, Rs) -> Rs. eval(Expr) -> - Fun = {?MODULE,funcall}, - {value,V,_} = erl_eval:expr(Expr, [], Fun), %Applied arithmetic BIFs. - V = eval(Expr, Fun), %Real arithmetic instructions. - V. + LFH = fun(Name, As) -> apply(?MODULE, Name, As) end, + + %% Applied arithmetic BIFs. + {value,V,_} = erl_eval:expr(Expr, [], {value,LFH}), -funcall(F, As) -> apply(?MODULE, F, As). + %% Real arithmetic instructions. + V = eval(Expr, LFH), + + V. %% Like a subset of erl_eval:expr/3, but uses real arithmetic instructions instead of %% applying them (it does make a difference). diff --git a/erts/emulator/test/busy_port_SUITE_data/busy_drv.c b/erts/emulator/test/busy_port_SUITE_data/busy_drv.c index 1273d610ba..75106d3757 100644 --- a/erts/emulator/test/busy_port_SUITE_data/busy_drv.c +++ b/erts/emulator/test/busy_port_SUITE_data/busy_drv.c @@ -11,7 +11,8 @@ #define YES 1 static ErlDrvData busy_start(ErlDrvPort, char*); -static void busy_stop(ErlDrvData), busy_from_erlang(ErlDrvData, char*, int); +static void busy_stop(ErlDrvData), + busy_from_erlang(ErlDrvData, char*, ErlDrvSizeT); ErlDrvEntry busy_driver_entry = { @@ -23,6 +24,20 @@ ErlDrvEntry busy_driver_entry = NULL, "busy_drv", NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, NULL }; @@ -73,7 +88,7 @@ static void busy_stop(ErlDrvData port) } static void -busy_from_erlang(ErlDrvData port, char* buf, int count) +busy_from_erlang(ErlDrvData port, char* buf, ErlDrvSizeT count) { if ((ErlDrvPort)port == slave_port) { set_busy_port(slave_port, next_slave_state); diff --git a/erts/emulator/test/busy_port_SUITE_data/hs_busy_drv.c b/erts/emulator/test/busy_port_SUITE_data/hs_busy_drv.c index 35919da2d0..9f6bd310c6 100644 --- a/erts/emulator/test/busy_port_SUITE_data/hs_busy_drv.c +++ b/erts/emulator/test/busy_port_SUITE_data/hs_busy_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2009. All Rights Reserved. + * Copyright Ericsson AB 2009-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -21,9 +21,9 @@ #include "erl_driver.h" ErlDrvData start(ErlDrvPort port, char *command); -void output(ErlDrvData drv_data, char *buf, int len); -int control(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen); +void output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len); +ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf, + ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen); static ErlDrvEntry busy_drv_entry = { NULL /* init */, @@ -61,7 +61,7 @@ ErlDrvData start(ErlDrvPort port, char *command) return (ErlDrvData) port; } -void output(ErlDrvData drv_data, char *buf, int len) +void output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { int res; ErlDrvPort port = (ErlDrvPort) drv_data; @@ -76,8 +76,8 @@ void output(ErlDrvData drv_data, char *buf, int len) driver_failure_atom(port, "driver_output_term failed"); } -int control(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen) +ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf, + ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { switch (command) { case 'B': /* busy */ diff --git a/erts/emulator/test/call_trace_SUITE.erl b/erts/emulator/test/call_trace_SUITE.erl index 3e2bee06d1..7030ebed3f 100644 --- a/erts/emulator/test/call_trace_SUITE.erl +++ b/erts/emulator/test/call_trace_SUITE.erl @@ -165,10 +165,14 @@ worker_loop() -> worker_foo(_Arg) -> ok. -basic(doc) -> - "Basic test of the call tracing (we trace one process)."; -basic(suite) -> []; -basic(Config) when is_list(Config) -> +%% Basic test of the call tracing (we trace one process). +basic(_Config) -> + case test_server:is_native(lists) of + true -> {skip,"lists is native"}; + false -> basic() + end. + +basic() -> ?line start_tracer(), ?line trace_info(self(), flags), ?line trace_info(self(), tracer), @@ -263,9 +267,15 @@ foo() -> foo0. foo(X) -> X+1. foo(X, Y) -> X+Y. -flags(doc) -> "Test flags (arity, timestamp) for call_trace/3. " - "Also, test the '{tracer,Pid}' option."; -flags(Config) when is_list(Config) -> +%% Test flags (arity, timestamp) for call_trace/3. +%% Also, test the '{tracer,Pid}' option. +flags(_Config) -> + case test_server:is_native(filename) of + true -> {skip,"filename is native"}; + false -> flags() + end. + +flags() -> ?line Tracer = start_tracer_loop(), ?line trace_pid(self(), true, [call,{tracer,Tracer}]), @@ -428,9 +438,14 @@ pam_foo(A, B) -> {ok,A,B}. -change_pam(doc) -> "Test changing PAM programs for a function."; -change_pam(suite) -> []; -change_pam(Config) when is_list(Config) -> +%% Test changing PAM programs for a function. +change_pam(_Config) -> + case test_server:is_native(lists) of + true -> {skip,"lists is native"}; + false -> change_pam() + end. + +change_pam() -> ?line start_tracer(), ?line Self = self(), @@ -468,10 +483,11 @@ change_pam_trace(Prog) -> {match_spec,Prog} = trace_info({erlang,process_info,2}, match_spec), ok. -return_trace(doc) -> "Test the new return trace."; -return_trace(suite) -> []; -return_trace(Config) when is_list(Config) -> - return_trace(). +return_trace(_Config) -> + case test_server:is_native(lists) of + true -> {skip,"lists is native"}; + false -> return_trace() + end. return_trace() -> X = {save,me}, @@ -521,7 +537,7 @@ return_trace() -> ?line {match_spec,Prog2} = trace_info({erlang,atom_to_list,1}, match_spec), ?line lists:seq(2, 7), - ?line atom_to_list(non_literal(nisse)), + ?line _ = atom_to_list(non_literal(nisse)), ?line expect({trace,Self,return_from,{lists,seq,2},[2,3,4,5,6,7]}), ?line expect({trace,Self,return_from,{erlang,atom_to_list,1},"nisse"}), @@ -539,10 +555,11 @@ return_trace() -> nasty() -> exit(good_bye). -exception_trace(doc) -> "Test the new exception trace."; -exception_trace(suite) -> []; -exception_trace(Config) when is_list(Config) -> - exception_trace(). +exception_trace(_Config) -> + case test_server:is_native(lists) of + true -> {skip,"lists is native"}; + false -> exception_trace() + end. exception_trace() -> X = {save,me}, @@ -600,7 +617,7 @@ exception_trace() -> trace_info({erlang,atom_to_list,1}, match_spec), ?line lists:seq(2, 7), - ?line atom_to_list(non_literal(nisse)), + ?line _ = atom_to_list(non_literal(nisse)), ?line expect({trace,Self,return_from,{lists,seq,2},[2,3,4,5,6,7]}), ?line expect({trace,Self,return_from,{erlang,atom_to_list,1},"nisse"}), diff --git a/erts/emulator/test/code_SUITE.erl b/erts/emulator/test/code_SUITE.erl index 2f9b01cc92..25ce94096f 100644 --- a/erts/emulator/test/code_SUITE.erl +++ b/erts/emulator/test/code_SUITE.erl @@ -20,7 +20,7 @@ -module(code_SUITE). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, - new_binary_types/1, + versions/1,new_binary_types/1, t_check_process_code/1,t_check_old_code/1, t_check_process_code_ets/1, external_fun/1,get_chunk/1,module_md5/1,make_stub/1, @@ -33,7 +33,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [new_binary_types, t_check_process_code, + [versions, new_binary_types, t_check_process_code, t_check_process_code_ets, t_check_old_code, external_fun, get_chunk, module_md5, make_stub, make_stub_many_funs, constant_pools, constant_refc_binaries, false_dependency, @@ -56,6 +56,60 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. +%% Make sure that only two versions of a module can be loaded. +versions(Config) when is_list(Config) -> + V1 = compile_version(1, Config), + V2 = compile_version(2, Config), + V3 = compile_version(3, Config), + + {ok,P1,1} = load_version(V1, 1), + {ok,P2,2} = load_version(V2, 2), + {error,not_purged} = load_version(V2, 2), + {error,not_purged} = load_version(V3, 3), + + 1 = check_version(P1), + 2 = check_version(P2), + 2 = versions:version(), + + %% Kill processes, unload code. + P1 ! P2 ! done, + _ = monitor(process, P1), + _ = monitor(process, P2), + receive + {'DOWN',_,process,P1,normal} -> ok + end, + receive + {'DOWN',_,process,P2,normal} -> ok + end, + true = erlang:purge_module(versions), + true = erlang:delete_module(versions), + true = erlang:purge_module(versions), + ok. + +compile_version(Version, Config) -> + Data = ?config(data_dir, Config), + File = filename:join(Data, "versions"), + {ok,versions,Bin} = compile:file(File, [{d,'VERSION',Version}, + binary,report]), + Bin. + +load_version(Code, Ver) -> + case erlang:load_module(versions, Code) of + {module,versions} -> + Pid = spawn_link(versions, loop, []), + Ver = versions:version(), + Ver = check_version(Pid), + {ok,Pid,Ver}; + Error -> + Error + end. + +check_version(Pid) -> + Pid ! {self(),version}, + receive + {Pid,version,Version} -> + Version + end. new_binary_types(Config) when is_list(Config) -> ?line Data = ?config(data_dir, Config), diff --git a/erts/emulator/test/code_SUITE_data/literals.erl b/erts/emulator/test/code_SUITE_data/literals.erl index d9cb8938db..658427095e 100644 --- a/erts/emulator/test/code_SUITE_data/literals.erl +++ b/erts/emulator/test/code_SUITE_data/literals.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/erts/emulator/test/code_SUITE_data/versions.erl b/erts/emulator/test/code_SUITE_data/versions.erl new file mode 100644 index 0000000000..7a6fd8847d --- /dev/null +++ b/erts/emulator/test/code_SUITE_data/versions.erl @@ -0,0 +1,33 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(versions). +-export([loop/0,version/0]). + +loop() -> + receive + {Pid,version} -> + Pid ! {self(),version,version()}, + loop(); + done -> + ok + end. + +version() -> + ?VERSION. diff --git a/erts/emulator/test/ddll_SUITE_data/dummy_drv.c b/erts/emulator/test/ddll_SUITE_data/dummy_drv.c index e0d5067743..86f2abf1b1 100644 --- a/erts/emulator/test/ddll_SUITE_data/dummy_drv.c +++ b/erts/emulator/test/ddll_SUITE_data/dummy_drv.c @@ -7,7 +7,7 @@ static ErlDrvPort erlang_port; static ErlDrvData dummy_start(ErlDrvPort, char*); -static void dummy_read(ErlDrvData port, char *buf, int count); +static void dummy_read(ErlDrvData port, char *buf, ErlDrvSizeT count); static void dummy_stop(ErlDrvData), easy_read(ErlDrvData, char*, int); static ErlDrvEntry dummy_driver_entry = { @@ -18,6 +18,21 @@ static ErlDrvEntry dummy_driver_entry = { NULL, NULL, "dummy_drv", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, NULL }; @@ -37,7 +52,7 @@ static ErlDrvData dummy_start(ErlDrvPort port,char *buf) return (ErlDrvData)port; } -static void dummy_read(ErlDrvData port, char *buf, int count) +static void dummy_read(ErlDrvData port, char *buf, ErlDrvSizeT count) { driver_output(erlang_port, buf, count); } diff --git a/erts/emulator/test/ddll_SUITE_data/echo_drv.c b/erts/emulator/test/ddll_SUITE_data/echo_drv.c index edf78a979d..2b3510c641 100644 --- a/erts/emulator/test/ddll_SUITE_data/echo_drv.c +++ b/erts/emulator/test/ddll_SUITE_data/echo_drv.c @@ -3,9 +3,10 @@ static ErlDrvPort erlang_port; static ErlDrvData echo_start(ErlDrvPort, char *); -static void from_erlang(ErlDrvData, char*, int); -static int echo_call(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen, unsigned *ret_flags); +static void from_erlang(ErlDrvData, char*, ErlDrvSizeT); +static ErlDrvSSizeT echo_call(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, unsigned *ret_flags); static ErlDrvEntry echo_driver_entry = { NULL, /* Init */ echo_start, @@ -21,7 +22,15 @@ static ErlDrvEntry echo_driver_entry = { NULL, NULL, NULL, - echo_call + echo_call, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL }; DRIVER_INIT(echo_drv) @@ -36,14 +45,15 @@ echo_start(ErlDrvPort port, char *buf) } static void -from_erlang(ErlDrvData data, char *buf, int count) +from_erlang(ErlDrvData data, char *buf, ErlDrvSizeT count) { driver_output((ErlDrvPort) data, buf, count); } -static int -echo_call(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen, unsigned *ret_flags) +static ErlDrvSSizeT +echo_call(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen, + unsigned *ret_flags) { *rbuf = buf; *ret_flags |= DRIVER_CALL_KEEP_BUFFER; diff --git a/erts/emulator/test/ddll_SUITE_data/echo_drv_fail_init.c b/erts/emulator/test/ddll_SUITE_data/echo_drv_fail_init.c index 3b2a44d907..26aa03a012 100644 --- a/erts/emulator/test/ddll_SUITE_data/echo_drv_fail_init.c +++ b/erts/emulator/test/ddll_SUITE_data/echo_drv_fail_init.c @@ -3,9 +3,10 @@ static ErlDrvPort erlang_port; static ErlDrvData echo_start(ErlDrvPort, char *); -static void from_erlang(ErlDrvData, char*, int); -static int echo_call(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen, unsigned *ret_flags); +static void from_erlang(ErlDrvData, char*, ErlDrvSizeT); +static ErlDrvSSizeT echo_call(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, unsigned *ret_flags); static int echo_failing_init(void); static ErlDrvEntry echo_driver_entry = { @@ -23,7 +24,15 @@ static ErlDrvEntry echo_driver_entry = { NULL, NULL, NULL, - echo_call + echo_call, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL }; DRIVER_INIT(echo_drv) @@ -43,14 +52,15 @@ echo_start(ErlDrvPort port, char *buf) } static void -from_erlang(ErlDrvData data, char *buf, int count) +from_erlang(ErlDrvData data, char *buf, ErlDrvSizeT count) { driver_output((ErlDrvPort) data, buf, count); } -static int -echo_call(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen, unsigned *ret_flags) +static ErlDrvSSizeT +echo_call(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen, + unsigned *ret_flags) { *rbuf = buf; *ret_flags |= DRIVER_CALL_KEEP_BUFFER; diff --git a/erts/emulator/test/ddll_SUITE_data/initfail_drv.c b/erts/emulator/test/ddll_SUITE_data/initfail_drv.c index b676ff5121..ad241b9c4f 100644 --- a/erts/emulator/test/ddll_SUITE_data/initfail_drv.c +++ b/erts/emulator/test/ddll_SUITE_data/initfail_drv.c @@ -3,7 +3,7 @@ static ErlDrvPort erlang_port; static ErlDrvData easy_start(ErlDrvPort, char*); -static void easy_stop(ErlDrvData), easy_read(ErlDrvData, char*, int); +static void easy_stop(ErlDrvData), easy_read(ErlDrvData, char*, ErlDrvSizeT); static ErlDrvEntry easy_driver_entry = { @@ -14,6 +14,21 @@ static ErlDrvEntry easy_driver_entry = NULL, NULL, "easy", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, NULL }; @@ -34,7 +49,7 @@ static ErlDrvData easy_start(ErlDrvPort port, char *buf) return (ErlDrvData)port; } -static void easy_read(ErlDrvData port, char *buf, int count) +static void easy_read(ErlDrvData port, char *buf, ErlDrvSizeT count) { driver_output(erlang_port, buf, count); } diff --git a/erts/emulator/test/ddll_SUITE_data/lock_drv.c b/erts/emulator/test/ddll_SUITE_data/lock_drv.c index 2ec8fa3a29..d2605c5bfc 100644 --- a/erts/emulator/test/ddll_SUITE_data/lock_drv.c +++ b/erts/emulator/test/ddll_SUITE_data/lock_drv.c @@ -3,9 +3,10 @@ static ErlDrvPort erlang_port; static ErlDrvData echo_start(ErlDrvPort, char *); -static void from_erlang(ErlDrvData, char*, int); -static int echo_call(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen, unsigned *ret_flags); +static void from_erlang(ErlDrvData, char*, ErlDrvSizeT); +static ErlDrvSSizeT echo_call(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, unsigned *ret_flags); static ErlDrvEntry echo_driver_entry = { NULL, /* Init */ echo_start, @@ -21,7 +22,15 @@ static ErlDrvEntry echo_driver_entry = { NULL, NULL, NULL, - echo_call + echo_call, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL }; DRIVER_INIT(echo_drv) @@ -37,14 +46,15 @@ echo_start(ErlDrvPort port, char *buf) } static void -from_erlang(ErlDrvData data, char *buf, int count) +from_erlang(ErlDrvData data, char *buf, ErlDrvSizeT count) { driver_output((ErlDrvPort) data, buf, count); } -static int -echo_call(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen, unsigned *ret_flags) +static ErlDrvSSizeT +echo_call(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen, + unsigned *ret_flags) { ErlDrvPort port = (ErlDrvPort) drv_data; driver_lock_driver(port); diff --git a/erts/emulator/test/ddll_SUITE_data/noinit_drv.c b/erts/emulator/test/ddll_SUITE_data/noinit_drv.c index 931386a305..5abf5c4dc6 100644 --- a/erts/emulator/test/ddll_SUITE_data/noinit_drv.c +++ b/erts/emulator/test/ddll_SUITE_data/noinit_drv.c @@ -3,7 +3,7 @@ static ErlDrvPort erlang_port; static ErlDrvData easy_start(ErlDrvPort, char*); -static void easy_stop(ErlDrvData), easy_read(ErlDrvData, char*, int); +static void easy_stop(ErlDrvData), easy_read(ErlDrvData, char*, ErlDrvSizeT); static ErlDrvEntry easy_driver_entry = { @@ -14,6 +14,21 @@ static ErlDrvEntry easy_driver_entry = NULL, NULL, "easy", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, NULL }; @@ -28,7 +43,7 @@ DRIVER_INIT(noinit_drv) /* * Provoke an error when loading the module. */ -int no_driver_init(void *handle) +ErlDrvEntry* no_driver_init(void *handle) #endif { erlang_port = (ErlDrvPort)-1; @@ -46,7 +61,7 @@ static ErlDrvData easy_start(ErlDrvPort port,char *buf) return (ErlDrvData)port; } -static void easy_read(ErlDrvData port, char *buf, int count) +static void easy_read(ErlDrvData port, char *buf, ErlDrvSizeT count) { driver_output(erlang_port, buf, count); } diff --git a/erts/emulator/test/ddll_SUITE_data/wrongname_drv.c b/erts/emulator/test/ddll_SUITE_data/wrongname_drv.c index 3a35820ee7..ac7efa30de 100644 --- a/erts/emulator/test/ddll_SUITE_data/wrongname_drv.c +++ b/erts/emulator/test/ddll_SUITE_data/wrongname_drv.c @@ -7,7 +7,7 @@ static ErlDrvPort erlang_port; static ErlDrvData easy_start(ErlDrvPort, char*); -static void easy_stop(ErlDrvData), easy_read(ErlDrvData, char*, int); +static void easy_stop(ErlDrvData), easy_read(ErlDrvData, char*, ErlDrvSizeT); static ErlDrvEntry easy_driver_entry = { @@ -18,6 +18,21 @@ static ErlDrvEntry easy_driver_entry = NULL, NULL, "easy", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, NULL }; @@ -38,7 +53,7 @@ static ErlDrvData easy_start(ErlDrvPort port,char *buf) return (ErlDrvData)port; } -static void easy_read(ErlDrvData port, char *buf, int count) +static void easy_read(ErlDrvData port, char *buf, ErlDrvSizeT count) { driver_output(erlang_port, buf, count); } diff --git a/erts/emulator/test/decode_packet_SUITE.erl b/erts/emulator/test/decode_packet_SUITE.erl index c0499554eb..4acbe8c6e0 100644 --- a/erts/emulator/test/decode_packet_SUITE.erl +++ b/erts/emulator/test/decode_packet_SUITE.erl @@ -26,12 +26,14 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, - basic/1, packet_size/1, neg/1, http/1, line/1, ssl/1, otp_8536/1]). + basic/1, packet_size/1, neg/1, http/1, line/1, ssl/1, otp_8536/1, + otp_9389/1, otp_9389_line/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [basic, packet_size, neg, http, line, ssl, otp_8536]. + [basic, packet_size, neg, http, line, ssl, otp_8536, + otp_9389, otp_9389_line]. groups() -> []. @@ -251,6 +253,28 @@ packet_size(Config) when is_list(Config) -> ?line {error,_} = decode_pkt(4,<<Size:32,Packet/binary>>) end, lists:seq(-10,-1)), + + %% Test OTP-9389, long HTTP header lines. + Opts = [{packet_size, 128}], + Pkt = list_to_binary(["GET / HTTP/1.1\r\nHost: localhost\r\nLink: /", + string:chars($Y, 64), "\r\n\r\n"]), + <<Pkt1:50/binary, Pkt2/binary>> = Pkt, + ?line {ok, {http_request,'GET',{abs_path,"/"},{1,1}}, Rest1} = + erlang:decode_packet(http, Pkt1, Opts), + ?line {ok, {http_header,_,'Host',_,"localhost"}, Rest2} = + erlang:decode_packet(httph, Rest1, Opts), + ?line {more, undefined} = erlang:decode_packet(httph, Rest2, Opts), + ?line {ok, {http_header,_,"Link",_,_}, _} = + erlang:decode_packet(httph, list_to_binary([Rest2, Pkt2]), Opts), + + Pkt3 = list_to_binary(["GET / HTTP/1.1\r\nHost: localhost\r\nLink: /", + string:chars($Y, 129), "\r\n\r\n"]), + ?line {ok, {http_request,'GET',{abs_path,"/"},{1,1}}, Rest3} = + erlang:decode_packet(http, Pkt3, Opts), + ?line {ok, {http_header,_,'Host',_,"localhost"}, Rest4} = + erlang:decode_packet(httph, Rest3, Opts), + ?line {error, invalid} = erlang:decode_packet(httph, Rest4, Opts), + ok. @@ -557,3 +581,35 @@ decode_pkt(Type,Bin,Opts) -> %%io:format(" -> ~p\n",[Res]), Res. +otp_9389(doc) -> ["Verify line_length works correctly for HTTP headers"]; +otp_9389(suite) -> []; +otp_9389(Config) when is_list(Config) -> + Opts = [{packet_size, 16384}, {line_length, 3000}], + Pkt = list_to_binary(["GET / HTTP/1.1\r\nHost: localhost\r\nLink: /", + string:chars($X, 8192), + "\r\nContent-Length: 0\r\n\r\n"]), + <<Pkt1:5000/binary, Pkt2/binary>> = Pkt, + {ok, {http_request,'GET',{abs_path,"/"},{1,1}}, Rest1} = + erlang:decode_packet(http, Pkt1, Opts), + {ok, {http_header,_,'Host',_,"localhost"}, Rest2} = + erlang:decode_packet(httph, Rest1, Opts), + {more, undefined} = erlang:decode_packet(httph, Rest2, Opts), + {ok, {http_header,_,"Link",_,Link}, Rest3} = + erlang:decode_packet(httph, list_to_binary([Rest2, Pkt2]), Opts), + true = (length(Link) > 8000), + {ok, {http_header,_,'Content-Length',_,"0"}, <<"\r\n">>} = + erlang:decode_packet(httph, Rest3, Opts), + ok. + +otp_9389_line(doc) -> ["Verify packet_size works correctly for line mode"]; +otp_9389_line(suite) -> []; +otp_9389_line(Config) when is_list(Config) -> + Opts = [{packet_size, 20}], + Line1 = <<"0123456789012345678\n">>, + Line2 = <<"0123456789\n">>, + Line3 = <<"01234567890123456789\n">>, + Pkt = list_to_binary([Line1, Line2, Line3]), + ?line {ok, Line1, Rest1} = erlang:decode_packet(line, Pkt, Opts), + ?line {ok, Line2, Rest2} = erlang:decode_packet(line, Rest1, Opts), + ?line {error, invalid} = erlang:decode_packet(line, Rest2, Opts), + ok. diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl index 19281f6d58..08308629fe 100644 --- a/erts/emulator/test/distribution_SUITE.erl +++ b/erts/emulator/test/distribution_SUITE.erl @@ -18,7 +18,7 @@ %% -module(distribution_SUITE). --compile(r12). +-compile(r13). %% Tests distribution and the tcp driver. @@ -37,7 +37,7 @@ dist_auto_connect_never/1, dist_auto_connect_once/1, dist_parallel_send/1, atom_roundtrip/1, - atom_roundtrip_r12b/1, + atom_roundtrip_r13b/1, contended_atom_cache_entry/1, bad_dist_structure/1, bad_dist_ext_receive/1, @@ -62,7 +62,7 @@ all() -> link_to_dead_new_node, applied_monitor_node, ref_port_roundtrip, nil_roundtrip, stop_dist, {group, trap_bif}, {group, dist_auto_connect}, - dist_parallel_send, atom_roundtrip, atom_roundtrip_r12b, + dist_parallel_send, atom_roundtrip, atom_roundtrip_r13b, contended_atom_cache_entry, bad_dist_structure, {group, bad_dist_ext}]. groups() -> @@ -1100,17 +1100,17 @@ atom_roundtrip(Config) when is_list(Config) -> ?line stop_node(Node), ?line ok. -atom_roundtrip_r12b(Config) when is_list(Config) -> - case ?t:is_release_available("r12b") of +atom_roundtrip_r13b(Config) when is_list(Config) -> + case ?t:is_release_available("r13b") of true -> ?line AtomData = atom_data(), ?line verify_atom_data(AtomData), - ?line {ok, Node} = start_node(Config, [], "r12b"), + ?line {ok, Node} = start_node(Config, [], "r13b"), ?line do_atom_roundtrip(Node, AtomData), ?line stop_node(Node), ?line ok; false -> - ?line {skip,"No OTP R12B available"} + ?line {skip,"No OTP R13B available"} end. do_atom_roundtrip(Node, AtomData) -> diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl index c07dbc5871..643357263c 100644 --- a/erts/emulator/test/driver_SUITE.erl +++ b/erts/emulator/test/driver_SUITE.erl @@ -47,8 +47,8 @@ fd_change/1, steal_control/1, otp_6602/1, - 'driver_system_info_ver1.0'/1, - 'driver_system_info_ver1.1'/1, + driver_system_info_base_ver/1, + driver_system_info_prev_ver/1, driver_system_info_current_ver/1, driver_monitor/1, @@ -135,8 +135,8 @@ all() -> [outputv_errors, outputv_echo, queue_echo, {group, timer}, driver_unloaded, io_ready_exit, use_fallback_pollset, bad_fd_in_pollset, driver_event, fd_change, - steal_control, otp_6602, 'driver_system_info_ver1.0', - 'driver_system_info_ver1.1', + steal_control, otp_6602, driver_system_info_base_ver, + driver_system_info_prev_ver, driver_system_info_current_ver, driver_monitor, {group, ioq_exit}, zero_extended_marker_garb_drv, invalid_extended_marker_drv, larger_major_vsn_drv, @@ -1083,19 +1083,19 @@ otp_6602(Config) when is_list(Config) -> -define(EXPECTED_SYSTEM_INFO_NAMES, ?EXPECTED_SYSTEM_INFO_NAMES2). -'driver_system_info_ver1.0'(doc) -> +'driver_system_info_base_ver'(doc) -> []; -'driver_system_info_ver1.0'(suite) -> +'driver_system_info_base_ver'(suite) -> []; -'driver_system_info_ver1.0'(Config) when is_list(Config) -> - ?line driver_system_info_test(Config, sys_info_1_0_drv). +'driver_system_info_base_ver'(Config) when is_list(Config) -> + ?line driver_system_info_test(Config, sys_info_base_drv). -'driver_system_info_ver1.1'(doc) -> +'driver_system_info_prev_ver'(doc) -> []; -'driver_system_info_ver1.1'(suite) -> +'driver_system_info_prev_ver'(suite) -> []; -'driver_system_info_ver1.1'(Config) when is_list(Config) -> - ?line driver_system_info_test(Config, sys_info_1_1_drv). +'driver_system_info_prev_ver'(Config) when is_list(Config) -> + ?line driver_system_info_test(Config, sys_info_prev_drv). driver_system_info_current_ver(doc) -> []; @@ -1796,7 +1796,7 @@ driver_select_use0(Config) -> thread_mseg_alloc_cache_clean(Config) when is_list(Config) -> case {erlang:system_info(threads), - mseg_inst_info(0), + erlang:system_info({allocator,mseg_alloc}), driver_alloc_sbct()} of {_, false, _} -> ?line {skipped, "No mseg_alloc"}; @@ -2185,6 +2185,14 @@ wait_deallocations() -> end. driver_alloc_size() -> + case erlang:system_info(smp_support) of + true -> + ok; + false -> + %% driver_alloc also used by elements in lock-free queues, + %% give these some time to be deallocated... + receive after 100 -> ok end + end, wait_deallocations(), case erlang:system_info({allocator_sizes, driver_alloc}) of false -> diff --git a/erts/emulator/test/driver_SUITE_data/Makefile.src b/erts/emulator/test/driver_SUITE_data/Makefile.src index dd48f6a0f7..9cc107cc66 100644 --- a/erts/emulator/test/driver_SUITE_data/Makefile.src +++ b/erts/emulator/test/driver_SUITE_data/Makefile.src @@ -16,8 +16,8 @@ MISC_DRVS = outputv_drv@dll@ \ thr_free_drv@dll@ \ async_blast_drv@dll@ -SYS_INFO_DRVS = sys_info_1_0_drv@dll@ \ - sys_info_1_1_drv@dll@ \ +SYS_INFO_DRVS = sys_info_base_drv@dll@ \ + sys_info_prev_drv@dll@ \ sys_info_curr_drv@dll@ VSN_MISMATCH_DRVS = zero_extended_marker_garb_drv@dll@ \ diff --git a/erts/emulator/test/driver_SUITE_data/async_blast_drv.c b/erts/emulator/test/driver_SUITE_data/async_blast_drv.c index 3821f7e3dc..c2086c5860 100644 --- a/erts/emulator/test/driver_SUITE_data/async_blast_drv.c +++ b/erts/emulator/test/driver_SUITE_data/async_blast_drv.c @@ -25,7 +25,7 @@ static void stop(ErlDrvData drv_data); static ErlDrvData start(ErlDrvPort port, char *command); static void output(ErlDrvData drv_data, - char *buf, int len); + char *buf, ErlDrvSizeT len); static void ready_async(ErlDrvData drv_data, ErlDrvThreadData thread_data); @@ -107,7 +107,7 @@ static void ready_async(ErlDrvData drv_data, } static void output(ErlDrvData drv_data, - char *buf, int len) + char *buf, ErlDrvSizeT len) { async_blast_data_t *abd = (async_blast_data_t *) drv_data; if (abd->counter == 0) { diff --git a/erts/emulator/test/driver_SUITE_data/caller_drv.c b/erts/emulator/test/driver_SUITE_data/caller_drv.c index a78d51966f..1ed20b0638 100644 --- a/erts/emulator/test/driver_SUITE_data/caller_drv.c +++ b/erts/emulator/test/driver_SUITE_data/caller_drv.c @@ -23,17 +23,17 @@ static ErlDrvData start(ErlDrvPort port, char *command); static void output(ErlDrvData drv_data, - char *buf, int len); + char *buf, ErlDrvSizeT len); static void outputv(ErlDrvData drv_data, ErlIOVec *ev); -static int control(ErlDrvData drv_data, - unsigned int command, char *buf, - int len, char **rbuf, int rlen); -static int call(ErlDrvData drv_data, - unsigned int command, - char *buf, int len, - char **rbuf, int rlen, - unsigned int *flags); +static ErlDrvSSizeT control(ErlDrvData drv_data, + unsigned int command, char *buf, + ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen); +static ErlDrvSSizeT call(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, + unsigned int *flags); static ErlDrvEntry caller_drv_entry = { NULL /* init */, @@ -98,7 +98,7 @@ start(ErlDrvPort port, char *command) } static void -output(ErlDrvData drv_data, char *buf, int len) +output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { send_caller(drv_data, "output"); } @@ -109,20 +109,20 @@ outputv(ErlDrvData drv_data, ErlIOVec *ev) send_caller(drv_data, "outputv"); } -static int +static ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen) + ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { send_caller(drv_data, "control"); return 0; } -static int +static ErlDrvSSizeT call(ErlDrvData drv_data, unsigned int command, - char *buf, int len, - char **rbuf, int rlen, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, unsigned int *flags) { /* echo call */ diff --git a/erts/emulator/test/driver_SUITE_data/chkio_drv.c b/erts/emulator/test/driver_SUITE_data/chkio_drv.c index bbdb09cfcb..40f1ad4fea 100644 --- a/erts/emulator/test/driver_SUITE_data/chkio_drv.c +++ b/erts/emulator/test/driver_SUITE_data/chkio_drv.c @@ -141,8 +141,8 @@ static void chkio_drv_stop(ErlDrvData); static void chkio_drv_ready_input(ErlDrvData, ErlDrvEvent); static void chkio_drv_ready_output(ErlDrvData, ErlDrvEvent); static void chkio_drv_ready_event(ErlDrvData, ErlDrvEvent, ErlDrvEventData); -static int chkio_drv_control(ErlDrvData, unsigned int, - char *, int, char **, int); +static ErlDrvSSizeT chkio_drv_control(ErlDrvData, unsigned int, + char *, ErlDrvSizeT, char **, ErlDrvSizeT); static void chkio_drv_timeout(ErlDrvData); static void chkio_drv_stop_select(ErlDrvEvent, void*); @@ -188,7 +188,7 @@ stop_use_fallback_pollset(ChkioDrvData *cddp) for (i = 0; i < CHKIO_FALLBACK_FDS; i++) { if (cbdp->dev_null[i].fd >= 0) { if (driver_select(cddp->port, - (ErlDrvEvent) cbdp->dev_null[i].fd, + (ErlDrvEvent) (ErlDrvSInt) cbdp->dev_null[i].fd, DO_WRITE, 0) != 0) { fprintf(stderr, @@ -200,7 +200,7 @@ stop_use_fallback_pollset(ChkioDrvData *cddp) } if (cbdp->dev_zero[i].fd >= 0) { if (driver_select(cddp->port, - (ErlDrvEvent) cbdp->dev_zero[i].fd, + (ErlDrvEvent) (ErlDrvSInt) cbdp->dev_zero[i].fd, DO_READ, 0) != 0) { fprintf(stderr, @@ -212,7 +212,7 @@ stop_use_fallback_pollset(ChkioDrvData *cddp) } if (cbdp->pipe_in[i].fd >= 0) { if (driver_select(cddp->port, - (ErlDrvEvent) cbdp->pipe_in[i].fd, + (ErlDrvEvent) (ErlDrvSInt) cbdp->pipe_in[i].fd, DO_READ, 0) != 0) { fprintf(stderr, @@ -224,7 +224,7 @@ stop_use_fallback_pollset(ChkioDrvData *cddp) } if (cbdp->pipe_out[i].fd >= 0) { if (driver_select(cddp->port, - (ErlDrvEvent) cbdp->pipe_out[i].fd, + (ErlDrvEvent) (ErlDrvSInt) cbdp->pipe_out[i].fd, DO_WRITE, 0) != 0) { fprintf(stderr, @@ -249,11 +249,11 @@ stop_driver_event(ChkioDrvData *cddp) cddp->test_data = NULL; if (cdep->in_fd >= 0) { - driver_event(cddp->port, (ErlDrvEvent) cdep->in_fd, NULL); + driver_event(cddp->port, (ErlDrvEvent) (ErlDrvSInt) cdep->in_fd, NULL); close(cdep->in_fd); } if (cdep->out_fd >= 0) { - driver_event(cddp->port, (ErlDrvEvent) cdep->out_fd, NULL); + driver_event(cddp->port, (ErlDrvEvent) (ErlDrvSInt) cdep->out_fd, NULL); close(cdep->out_fd); } driver_free(cdep); @@ -268,7 +268,7 @@ stop_fd_change(ChkioDrvData *cddp) cddp->test_data = NULL; driver_cancel_timer(cddp->port); if (cfcp->fds[0] >= 0) { - driver_select(cddp->port, (ErlDrvEvent) cfcp->fds[0], DO_READ, 0); + driver_select(cddp->port, (ErlDrvEvent) (ErlDrvSInt) cfcp->fds[0], DO_READ, 0); close(cfcp->fds[0]); close(cfcp->fds[1]); } @@ -282,8 +282,8 @@ stop_bad_fd_in_pollset(ChkioDrvData *cddp) if (cddp->test_data) { ChkioBadFdInPollset *bfipp = (ChkioBadFdInPollset *) cddp->test_data; cddp->test_data = NULL; - driver_select(cddp->port, (ErlDrvEvent) bfipp->fds[0], DO_WRITE, 0); - driver_select(cddp->port, (ErlDrvEvent) bfipp->fds[1], DO_READ, 0); + driver_select(cddp->port, (ErlDrvEvent) (ErlDrvSInt) bfipp->fds[0], DO_WRITE, 0); + driver_select(cddp->port, (ErlDrvEvent) (ErlDrvSInt) bfipp->fds[1], DO_READ, 0); driver_free((void *) bfipp); } } @@ -296,21 +296,21 @@ stop_steal(ChkioDrvData *cddp) cddp->test_data = NULL; if (csp->driver_select_fds[0] >= 0) driver_select(cddp->port, - (ErlDrvEvent) csp->driver_select_fds[0], + (ErlDrvEvent) (ErlDrvSInt) csp->driver_select_fds[0], DO_READ, 0); if (csp->driver_select_fds[1] >= 0) driver_select(cddp->port, - (ErlDrvEvent) csp->driver_select_fds[1], + (ErlDrvEvent) (ErlDrvSInt) csp->driver_select_fds[1], DO_WRITE, 0); if (csp->driver_event_fds[0] >= 0) driver_event(cddp->port, - (ErlDrvEvent) csp->driver_event_fds[0], + (ErlDrvEvent) (ErlDrvSInt) csp->driver_event_fds[0], NULL); if (csp->driver_event_fds[1] >= 0) driver_event(cddp->port, - (ErlDrvEvent) csp->driver_event_fds[1], + (ErlDrvEvent) (ErlDrvSInt) csp->driver_event_fds[1], NULL); driver_free(csp); } @@ -353,7 +353,7 @@ static void free_smp_select(ChkioSmpSelect* pip, ErlDrvPort port) abort(); } case Selected: - driver_select(port, (ErlDrvEvent)pip->read_fd, DO_READ, 0); + driver_select(port, (ErlDrvEvent)(ErlDrvSInt)pip->read_fd, DO_READ, 0); /*fall through*/ case Opened: close(pip->read_fd); @@ -475,8 +475,8 @@ chkio_drv_stop(ErlDrvData drv_data) { fprintf(stderr, "%s:%d: Failed to open /dev/null\n", __FILE__, __LINE__); } - driver_select(cddp->port, (ErlDrvEvent) fd, DO_WRITE, 1); - driver_select(cddp->port, (ErlDrvEvent) fd, DO_WRITE, 0); + driver_select(cddp->port, (ErlDrvEvent) (ErlDrvSInt) fd, DO_WRITE, 1); + driver_select(cddp->port, (ErlDrvEvent) (ErlDrvSInt) fd, DO_WRITE, 0); close(fd); @@ -491,7 +491,7 @@ chkio_drv_ready_output(ErlDrvData drv_data, ErlDrvEvent event) { #ifdef UNIX ChkioDrvData *cddp = (ChkioDrvData *) drv_data; - int fd = (int) event; + int fd = (int) (ErlDrvSInt) event; switch (cddp->test) { case CHKIO_USE_FALLBACK_POLLSET: { @@ -533,7 +533,7 @@ chkio_drv_ready_input(ErlDrvData drv_data, ErlDrvEvent event) { #ifdef UNIX ChkioDrvData *cddp = (ChkioDrvData *) drv_data; - int fd = (int) event; + int fd = (int) (ErlDrvSInt) event; switch (cddp->test) { case CHKIO_USE_FALLBACK_POLLSET: { @@ -630,7 +630,7 @@ chkio_drv_ready_event(ErlDrvData drv_data, case CHKIO_DRIVER_EVENT: { #ifdef HAVE_POLL_H ChkioDriverEvent *cdep = cddp->test_data; - int fd = (int) event; + int fd = (int) (ErlDrvSInt) event; if (fd == cdep->in_fd) { if (event_data->events == POLLIN && event_data->revents == POLLIN) { @@ -679,7 +679,7 @@ chkio_drv_timeout(ErlDrvData drv_data) int in_fd = cfcp->fds[0]; int out_fd = cfcp->fds[1]; if (in_fd >= 0) { - if (driver_select(cddp->port, (ErlDrvEvent) in_fd, DO_READ, 0) < 0) + if (driver_select(cddp->port, (ErlDrvEvent) (ErlDrvSInt) in_fd, DO_READ, 0) < 0) driver_failure_atom(cddp->port, "deselect_failed"); (void) write(out_fd, (void *) "!", 1); close(out_fd); @@ -689,7 +689,7 @@ chkio_drv_timeout(ErlDrvData drv_data) driver_failure_posix(cddp->port, errno); } else { - if (driver_select(cddp->port, (ErlDrvEvent) cfcp->fds[0], + if (driver_select(cddp->port, (ErlDrvEvent) (ErlDrvSInt) cfcp->fds[0], DO_READ, 1) < 0) driver_failure_atom(cddp->port, "select_failed"); if (cfcp->fds[0] == in_fd) @@ -709,14 +709,14 @@ chkio_drv_timeout(ErlDrvData drv_data) #endif /* UNIX */ } -static int +static ErlDrvSSizeT chkio_drv_control(ErlDrvData drv_data, unsigned int command, - char *buf, int len, - char **rbuf, int rlen) + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) { char *res_str; - int res_len = -1; + ErlDrvSSizeT res_len = -1; #ifndef UNIX #ifdef __WIN32__ res_str = "skip: windows_different"; @@ -854,7 +854,7 @@ chkio_drv_control(ErlDrvData drv_data, int fds[2]; cbdp->dev_null[i].fd = open("/dev/null", O_WRONLY); if (driver_select(cddp->port, - (ErlDrvEvent) cbdp->dev_null[i].fd, + (ErlDrvEvent) (ErlDrvSInt) cbdp->dev_null[i].fd, DO_WRITE, 1) != 0) { driver_failure_posix(cddp->port, errno); @@ -862,7 +862,7 @@ chkio_drv_control(ErlDrvData drv_data, } cbdp->dev_zero[i].fd = open("/dev/zero", O_RDONLY); if (driver_select(cddp->port, - (ErlDrvEvent) cbdp->dev_zero[i].fd, + (ErlDrvEvent) (ErlDrvSInt) cbdp->dev_zero[i].fd, DO_READ, 1) != 0) { driver_failure_posix(cddp->port, errno); @@ -873,7 +873,7 @@ chkio_drv_control(ErlDrvData drv_data, cbdp->pipe_in[i].fd = fds[0]; cbdp->pipe_out[i].fd = fds[1]; if (driver_select(cddp->port, - (ErlDrvEvent) cbdp->pipe_in[i].fd, + (ErlDrvEvent) (ErlDrvSInt) cbdp->pipe_in[i].fd, DO_READ, 1) != 0) { driver_failure_posix(cddp->port, EIO); @@ -882,7 +882,7 @@ chkio_drv_control(ErlDrvData drv_data, if (i % 2 == 0) (void) write(cbdp->pipe_out[i].fd, "!", 1); if (driver_select(cddp->port, - (ErlDrvEvent) cbdp->pipe_out[i].fd, + (ErlDrvEvent) (ErlDrvSInt) cbdp->pipe_out[i].fd, DO_WRITE, 1) != 0) { driver_failure_posix(cddp->port, EIO); @@ -928,8 +928,8 @@ chkio_drv_control(ErlDrvData drv_data, bfipp->fds[0] = fds[9]; bfipp->fds[1] = fds[10]; cddp->test_data = (void *) bfipp; - driver_select(cddp->port, (ErlDrvEvent) fds[9], DO_WRITE, 1); - driver_select(cddp->port, (ErlDrvEvent) fds[10], DO_READ, 1); + driver_select(cddp->port, (ErlDrvEvent) (ErlDrvSInt) fds[9], DO_WRITE, 1); + driver_select(cddp->port, (ErlDrvEvent) (ErlDrvSInt) fds[10], DO_READ, 1); } } res_str = "ok"; @@ -965,7 +965,7 @@ chkio_drv_control(ErlDrvData drv_data, cdep->in_ok = 0; res = driver_event(cddp->port, - (ErlDrvEvent) in_fd, + (ErlDrvEvent) (ErlDrvSInt) in_fd, &cdep->in_data); if (res < 0) { res_str = "skip: driver_event() not supported"; @@ -985,7 +985,7 @@ chkio_drv_control(ErlDrvData drv_data, cdep->out_ok = 0; res = driver_event(cddp->port, - (ErlDrvEvent) out_fd, + (ErlDrvEvent) (ErlDrvSInt) out_fd, &cdep->out_data); if (res < 0) { close(out_fd); @@ -1062,7 +1062,7 @@ chkio_drv_control(ErlDrvData drv_data, csp->event_data[0].events = POLLIN; csp->event_data[0].revents = 0; res = driver_event(cddp->port, - (ErlDrvEvent) csp->driver_event_fds[0], + (ErlDrvEvent) (ErlDrvSInt) csp->driver_event_fds[0], &csp->event_data[0]); if (res < 0) driver_failure_atom(cddp->port, @@ -1071,7 +1071,7 @@ chkio_drv_control(ErlDrvData drv_data, csp->event_data[1].events = POLLOUT; csp->event_data[1].revents = 0; res = driver_event(cddp->port, - (ErlDrvEvent) csp->driver_event_fds[1], + (ErlDrvEvent) (ErlDrvSInt) csp->driver_event_fds[1], &csp->event_data[1]); if (res < 0) driver_failure_atom(cddp->port, @@ -1083,7 +1083,7 @@ chkio_drv_control(ErlDrvData drv_data, /* Steal with driver_select() */ if (res >= 0) { res = driver_select(cddp->port, - (ErlDrvEvent) csp->driver_select_fds[0], + (ErlDrvEvent) (ErlDrvSInt) csp->driver_select_fds[0], DO_READ, 1); if (res < 0) @@ -1092,7 +1092,7 @@ chkio_drv_control(ErlDrvData drv_data, } if (res >= 0) { res = driver_select(cddp->port, - (ErlDrvEvent) csp->driver_select_fds[1], + (ErlDrvEvent) (ErlDrvSInt) csp->driver_select_fds[1], DO_WRITE, 1); if (res < 0) @@ -1159,14 +1159,14 @@ chkio_drv_control(ErlDrvData drv_data, csap->driver_event_fds[1] = write_fds[1]; res = driver_select(cddp->port, - (ErlDrvEvent) csap->driver_select_fds[0], + (ErlDrvEvent) (ErlDrvSInt) csap->driver_select_fds[0], DO_READ, 1); if (res < 0) driver_failure_atom(cddp->port, "driver_select_failed"); if (res >= 0) { res = driver_select(cddp->port, - (ErlDrvEvent) csap->driver_select_fds[1], + (ErlDrvEvent) (ErlDrvSInt) csap->driver_select_fds[1], DO_WRITE, 1); if (res < 0) @@ -1177,7 +1177,7 @@ chkio_drv_control(ErlDrvData drv_data, csap->event_data[0].events = POLLIN; csap->event_data[0].revents = 0; res = driver_event(cddp->port, - (ErlDrvEvent) csap->driver_event_fds[0], + (ErlDrvEvent) (ErlDrvSInt) csap->driver_event_fds[0], &csap->event_data[0]); if (res < 0) { close(csap->driver_event_fds[0]); @@ -1190,7 +1190,7 @@ chkio_drv_control(ErlDrvData drv_data, csap->event_data[1].events = POLLOUT; csap->event_data[1].revents = 0; res = driver_event(cddp->port, - (ErlDrvEvent) csap->driver_event_fds[1], + (ErlDrvEvent) (ErlDrvSInt) csap->driver_event_fds[1], &csap->event_data[1]); if (res < 0) driver_failure_atom(cddp->port, @@ -1285,7 +1285,7 @@ chkio_drv_control(ErlDrvData drv_data, } else { TRACEF(("%T: Select on pipe [%d->%d]\n", cddp->id, pip->write_fd, pip->read_fd)); - if (driver_select(cddp->port, (ErlDrvEvent)pip->read_fd, DO_READ, 1)) { + if (driver_select(cddp->port, (ErlDrvEvent)(ErlDrvSInt)pip->read_fd, DO_READ, 1)) { fprintf(stderr, "driver_select failed for fd=%d\n", pip->read_fd); abort(); } @@ -1314,7 +1314,7 @@ chkio_drv_control(ErlDrvData drv_data, op >>= 1; if (op & 1) { TRACEF(("%T: Deselect on pipe [%d->%d]\n", cddp->id, pip->write_fd, pip->read_fd)); - if (driver_select(cddp->port, (ErlDrvEvent)pip->read_fd, DO_READ, 0)) { + if (driver_select(cddp->port, (ErlDrvEvent)(ErlDrvSInt)pip->read_fd, DO_READ, 0)) { fprintf(stderr, "driver_(de)select failed for fd=%d\n", pip->read_fd); abort(); } diff --git a/erts/emulator/test/driver_SUITE_data/io_ready_exit_drv.c b/erts/emulator/test/driver_SUITE_data/io_ready_exit_drv.c index 6afa46b3a2..e6a3edcd74 100644 --- a/erts/emulator/test/driver_SUITE_data/io_ready_exit_drv.c +++ b/erts/emulator/test/driver_SUITE_data/io_ready_exit_drv.c @@ -40,8 +40,9 @@ static void io_ready_exit_ready_input(ErlDrvData, ErlDrvEvent); static void io_ready_exit_ready_output(ErlDrvData, ErlDrvEvent); static void io_ready_exit_drv_output(ErlDrvData, char *, int); static void io_ready_exit_drv_finish(void); -static int io_ready_exit_drv_control(ErlDrvData, unsigned int, - char *, int, char **, int); +static ErlDrvSSizeT io_ready_exit_drv_control(ErlDrvData, unsigned int, + char *, ErlDrvSizeT, + char **, ErlDrvSizeT); static ErlDrvEntry io_ready_exit_drv_entry = { NULL, /* init */ @@ -56,7 +57,17 @@ static ErlDrvEntry io_ready_exit_drv_entry = { io_ready_exit_drv_control, NULL, /* timeout */ NULL, /* outputv */ - NULL /* ready_async */ + NULL, /* ready_async */ + NULL, /* flush */ + NULL, /* call */ + NULL, /* event */ + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, /* ERL_DRV_FLAGs */ + NULL, /* handle2 */ + NULL, /* process_exit */ + NULL /* stop_select */ }; /* ------------------------------------------------------------------------- @@ -83,7 +94,7 @@ io_ready_exit_drv_stop(ErlDrvData drv_data) { #ifdef UNIX if (oeddp->fds[0] >= 0) { driver_select(oeddp->port, - (ErlDrvEvent) oeddp->fds[0], + (ErlDrvEvent) (ErlDrvSInt) oeddp->fds[0], DO_READ|DO_WRITE, 0); close(oeddp->fds[0]); @@ -109,15 +120,15 @@ io_ready_exit_ready_input(ErlDrvData drv_data, ErlDrvEvent event) driver_failure_atom(oeddp->port, "ready_input_driver_failure"); } -static int +static ErlDrvSSizeT io_ready_exit_drv_control(ErlDrvData drv_data, unsigned int command, - char *buf, int len, - char **rbuf, int rlen) + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) { char *abuf; char *res_str; - int res_len; + ErlDrvSSizeT res_len; IOReadyExitDrvData *oeddp = (IOReadyExitDrvData *) drv_data; #ifndef UNIX res_str = "nyiftos"; @@ -127,9 +138,9 @@ io_ready_exit_drv_control(ErlDrvData drv_data, } else { res_str = "ok"; - write(oeddp->fds[1], "!", 1); + (void) write(oeddp->fds[1], "!", 1); driver_select(oeddp->port, - (ErlDrvEvent) oeddp->fds[0], + (ErlDrvEvent) (ErlDrvSInt) oeddp->fds[0], DO_READ|DO_WRITE, 1); } diff --git a/erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c b/erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c index e49de388b4..b2cc1e785a 100644 --- a/erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c +++ b/erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2007-2010. All Rights Reserved. + * Copyright Ericsson AB 2007-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -91,7 +91,8 @@ static ErlDrvData start(ErlDrvPort port, char *command); static void stop(ErlDrvData drv_data); static void ready_input(ErlDrvData drv_data, ErlDrvEvent event); static void ready_output(ErlDrvData drv_data, ErlDrvEvent event); -static int control(ErlDrvData, unsigned int, char *, int, char **, int); +static ErlDrvSSizeT control(ErlDrvData, unsigned int, + char *, ErlDrvSizeT, char **, ErlDrvSizeT); static void timeout(ErlDrvData drv_data); static void ready_async(ErlDrvData drv_data, ErlDrvThreadData thread_data); static void flush(ErlDrvData drv_data); @@ -155,10 +156,10 @@ start(ErlDrvPort port, char *command) return (ErlDrvData) ddp; } -static int control(ErlDrvData drv_data, - unsigned int command, - char *buf, int len, - char **rbuf, int rlen) +static ErlDrvSSizeT control(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) { IOQExitDrvData *ddp = (IOQExitDrvData *) drv_data; char *res_str = "nyiftos"; @@ -227,7 +228,7 @@ static int control(ErlDrvData drv_data, res_str = "ok"; done: { - int res_len = strlen(res_str); + ErlDrvSSizeT res_len = strlen(res_str); if (res_len > rlen) { char *abuf = driver_alloc(sizeof(char)*res_len); if (!abuf) diff --git a/erts/emulator/test/driver_SUITE_data/many_events_drv.c b/erts/emulator/test/driver_SUITE_data/many_events_drv.c index 7417dbf7f8..a34432a8fe 100644 --- a/erts/emulator/test/driver_SUITE_data/many_events_drv.c +++ b/erts/emulator/test/driver_SUITE_data/many_events_drv.c @@ -3,14 +3,17 @@ #endif #include <stdio.h> +#include <string.h> #include "erl_driver.h" static ErlDrvPort erlang_port; static ErlDrvData many_events_start(ErlDrvPort, char *); -static void from_erlang(ErlDrvData, char*, int); +static void from_erlang(ErlDrvData, char*, ErlDrvSizeT); static void from_port(ErlDrvData drv_data, ErlDrvEvent event); -static int many_events_call(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen, unsigned *ret_flags); +static ErlDrvSSizeT many_events_call(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, + unsigned *ret_flags); static ErlDrvEntry many_events_driver_entry = { NULL, /* Init */ many_events_start, @@ -26,7 +29,15 @@ static ErlDrvEntry many_events_driver_entry = { NULL, NULL, NULL, - many_events_call + many_events_call, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL }; DRIVER_INIT(many_events_drv) @@ -41,7 +52,7 @@ many_events_start(ErlDrvPort port, char *buf) } static void -from_erlang(ErlDrvData data, char *buf, int count) +from_erlang(ErlDrvData data, char *buf, ErlDrvSizeT count) { int i; int num; @@ -87,9 +98,10 @@ static void from_port(ErlDrvData data, ErlDrvEvent ev) return; } -static int -many_events_call(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen, unsigned *ret_flags) +static ErlDrvSSizeT +many_events_call(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen, + unsigned *ret_flags) { *rbuf = buf; *ret_flags |= DRIVER_CALL_KEEP_BUFFER; diff --git a/erts/emulator/test/driver_SUITE_data/monitor_drv.c b/erts/emulator/test/driver_SUITE_data/monitor_drv.c index 1da6a56a72..3da067fd09 100644 --- a/erts/emulator/test/driver_SUITE_data/monitor_drv.c +++ b/erts/emulator/test/driver_SUITE_data/monitor_drv.c @@ -21,8 +21,9 @@ #include "erl_driver.h" static ErlDrvData monitor_drv_start(ErlDrvPort, char *); -static int monitor_drv_control(ErlDrvData, unsigned int, - char *, int, char **, int); +static void monitor_drv_stop(ErlDrvData data); +static ErlDrvSSizeT monitor_drv_control(ErlDrvData, unsigned int, + char *, ErlDrvSizeT, char **, ErlDrvSizeT); static void handle_monitor(ErlDrvData drv_data, ErlDrvMonitor *monitor); #define OP_I_AM_IPID 1 @@ -50,7 +51,7 @@ typedef struct { static ErlDrvEntry monitor_drv_entry = { NULL /* init */, monitor_drv_start, - NULL /* stop */, + monitor_drv_stop, NULL /* output */, NULL /* ready_input */, NULL /* ready_output */, @@ -122,16 +123,16 @@ static void handle_monitor(ErlDrvData drv_data, ErlDrvMonitor *monitor) return; } -static int +static ErlDrvSSizeT monitor_drv_control(ErlDrvData drv_data, unsigned int command, - char *ibuf, int ilen, - char **rbuf, int rlen) + char *ibuf, ErlDrvSizeT ilen, + char **rbuf, ErlDrvSizeT rlen) { MyDrvData *data = (MyDrvData *) drv_data; char *answer = NULL; char buff[64]; - int alen; + ErlDrvSSizeT alen; switch (command) { case OP_I_AM_IPID: diff --git a/erts/emulator/test/driver_SUITE_data/otp_6879_drv.c b/erts/emulator/test/driver_SUITE_data/otp_6879_drv.c index 8c0a9aadfd..ff44145ca7 100644 --- a/erts/emulator/test/driver_SUITE_data/otp_6879_drv.c +++ b/erts/emulator/test/driver_SUITE_data/otp_6879_drv.c @@ -20,11 +20,11 @@ #include <string.h> #include "erl_driver.h" -static int call(ErlDrvData drv_data, - unsigned int command, - char *buf, int len, - char **rbuf, int rlen, - unsigned int *flags); +static ErlDrvSSizeT call(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, + unsigned int *flags); static ErlDrvEntry otp_6879_drv_entry = { NULL /* init */, @@ -57,11 +57,11 @@ DRIVER_INIT(otp_6879_drv) } -static int call(ErlDrvData drv_data, - unsigned int command, - char *buf, int len, - char **rbuf, int rlen, - unsigned int *flags) +static ErlDrvSSizeT call(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, + unsigned int *flags) { /* echo call */ if (len > rlen) diff --git a/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c b/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c index beee1b735f..221fd0ce51 100644 --- a/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c +++ b/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c @@ -28,7 +28,7 @@ static void stop(ErlDrvData drv_data); static ErlDrvData start(ErlDrvPort port, char *command); static void output(ErlDrvData drv_data, - char *buf, int len); + char *buf, ErlDrvSizeT len); static void ready_async(ErlDrvData drv_data, ErlDrvThreadData thread_data); @@ -196,13 +196,13 @@ static void ready_async(ErlDrvData drv_data, } static void output(ErlDrvData drv_data, - char *buf, int len) + char *buf, ErlDrvSizeT len) { Otp9302Data *data = (Otp9302Data *) drv_data; ErlDrvTermData td_port = driver_mk_port(data->port); ErlDrvTermData td_receiver = driver_caller(data->port); ErlDrvTermData td_job = driver_mk_atom("job"); - unsigned int key = (unsigned int) data->port; + unsigned int key = (unsigned int) (ErlDrvSInt) data->port; long id[5]; Otp9302AsyncData *ad[5]; int i; diff --git a/erts/emulator/test/driver_SUITE_data/outputv_drv.c b/erts/emulator/test/driver_SUITE_data/outputv_drv.c index 87f66ae413..3e3d4a3a03 100644 --- a/erts/emulator/test/driver_SUITE_data/outputv_drv.c +++ b/erts/emulator/test/driver_SUITE_data/outputv_drv.c @@ -3,7 +3,9 @@ static ErlDrvPort erlang_port; static ErlDrvData outputv_start(ErlDrvPort, char*); -static void outputv_stop(ErlDrvData), outputv_read(ErlDrvData, char*, int), outputv(ErlDrvData, ErlIOVec*); +static void outputv_stop(ErlDrvData), + outputv_read(ErlDrvData, char*, ErlDrvSizeT), + outputv(ErlDrvData, ErlIOVec*); static ErlDrvEntry outputv_driver_entry = { @@ -19,6 +21,16 @@ static ErlDrvEntry outputv_driver_entry = NULL, NULL, outputv, + NULL, + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, NULL }; @@ -38,7 +50,7 @@ static ErlDrvData outputv_start(ErlDrvPort port, char *buf) return (ErlDrvData)port; } -static void outputv_read(ErlDrvData port, char *buf, int count) +static void outputv_read(ErlDrvData port, char *buf, ErlDrvSizeT count) { erlang_port = (ErlDrvPort)-1; } diff --git a/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c b/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c index 3a5b5af13a..8e203f74ec 100644 --- a/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c +++ b/erts/emulator/test/driver_SUITE_data/peek_non_existing_queue_drv.c @@ -66,7 +66,8 @@ typedef struct { static ErlDrvData start(ErlDrvPort, char *); static void stop(ErlDrvData); -static int control(ErlDrvData, unsigned int, char *, int, char **, int); +static ErlDrvSSizeT control(ErlDrvData, unsigned int, + char *, ErlDrvSizeT, char **, ErlDrvSizeT); static void ready_async(ErlDrvData, ErlDrvThreadData); static void async_test(void *); static void async_wait(void *); @@ -121,10 +122,10 @@ static void stop(ErlDrvData drv_data) driver_free(drv_data); } -static int control(ErlDrvData drv_data, - unsigned int command, - char *buf, int len, - char **rbuf, int rlen) +static ErlDrvSSizeT control(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) { PeekNonXQDrvData *dp = (PeekNonXQDrvData *) drv_data; unsigned int key = 0; @@ -158,7 +159,7 @@ static int control(ErlDrvData drv_data, } done: { - int res_len = strlen(res_str); + ErlDrvSSizeT res_len = strlen(res_str); if (res_len > rlen) { char *abuf = driver_alloc(sizeof(char)*res_len); if (!abuf) diff --git a/erts/emulator/test/driver_SUITE_data/queue_drv.c b/erts/emulator/test/driver_SUITE_data/queue_drv.c index ded69f89f9..a02b57dc9a 100644 --- a/erts/emulator/test/driver_SUITE_data/queue_drv.c +++ b/erts/emulator/test/driver_SUITE_data/queue_drv.c @@ -1,4 +1,5 @@ #include <stdio.h> +#include <string.h> #include "erl_driver.h" #define put_int32(i, s) {((char*)(s))[0] = (char)((i) >> 24) & 0xff; \ @@ -33,9 +34,10 @@ static ErlDrvPort erlang_port; static unsigned opcode; /* Opcode for next operation. */ static ErlDrvData queue_start(ErlDrvPort, char*); -static void queue_stop(ErlDrvData), queue_read(ErlDrvData, char*, int); +static void queue_stop(ErlDrvData), queue_read(ErlDrvData, char*, ErlDrvSizeT); static void queue_outputv(ErlDrvData, ErlIOVec*); -static int control(ErlDrvData, unsigned int, char*, int, char**, int); +static ErlDrvSSizeT control(ErlDrvData, unsigned int, + char*, ErlDrvSizeT, char**, ErlDrvSizeT); static ErlDrvBinary* read_head(ErlDrvPort, int bytes); static ErlDrvEntry queue_driver_entry = @@ -52,6 +54,16 @@ static ErlDrvEntry queue_driver_entry = control, NULL, queue_outputv, + NULL, + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, NULL }; @@ -73,7 +85,7 @@ static ErlDrvData queue_start(ErlDrvPort port, char *buf) } /* messages from Erlang */ -static void queue_read(ErlDrvData port, char *buf, int len) +static void queue_read(ErlDrvData port, char *buf, ErlDrvSizeT len) { } @@ -82,8 +94,9 @@ static void queue_stop(ErlDrvData port) erlang_port = (ErlDrvPort) -1; } -static int -control(ErlDrvData drv_data, unsigned command, char* buf, int len, char** rbuf, int rlen) +static ErlDrvSSizeT +control(ErlDrvData drv_data, unsigned command, + char* buf, ErlDrvSizeT len, char** rbuf, ErlDrvSizeT rlen) { ErlDrvBinary* b; diff --git a/erts/emulator/test/driver_SUITE_data/sys_info_1_0_drv.c b/erts/emulator/test/driver_SUITE_data/sys_info_base_drv.c index 0504778086..c22a415c59 100644 --- a/erts/emulator/test/driver_SUITE_data/sys_info_1_0_drv.c +++ b/erts/emulator/test/driver_SUITE_data/sys_info_base_drv.c @@ -3,34 +3,35 @@ * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' - * + * * $Id$ */ /* * Author: Rickard Green * - * Description: Driver that fakes driver version 1.0 and tests + * Description: Driver that fakes driver version 2.0 and tests * driver_system_info(). * */ #include "sys_info_drv_impl.h" -#define SYS_INFO_DRV_MAJOR_VSN 1 +#define SYS_INFO_DRV_MAJOR_VSN 2 #define SYS_INFO_DRV_MINOR_VSN 0 -#define SYS_INFO_DRV_NAME_STR "sys_info_1_0_drv" -#define SYS_INFO_DRV_NAME sys_info_1_0_drv +#define SYS_INFO_DRV_NAME_STR "sys_info_base_drv" +#define SYS_INFO_DRV_NAME sys_info_base_drv #define SYS_INFO_DRV_LAST_FIELD smp_support +#define ERL_DRV_SYS_INFO_SIZE sizeof(ErlDrvSysInfo) #define SYS_INFO_DRV_RES_FORMAT "ok: " \ "drv_drv_vsn=%d.%d " \ @@ -38,8 +39,9 @@ "erts_vsn=%s " \ "otp_vsn=%s " \ "thread=%s " \ - "smp=%s" - + "smp=%s " \ + "async_thrs=%d " \ + "sched_thrs=%d" static size_t sys_info_drv_max_res_len(ErlDrvSysInfo *sip) @@ -51,6 +53,8 @@ sys_info_drv_max_res_len(ErlDrvSysInfo *sip) slen += strlen(sip->otp_release) + 1; slen += 5; /* threads */ slen += 5; /* smp */ + slen += 20; /* async_thrs */ + slen += 20; /* sched_thrs */ return slen; } @@ -66,7 +70,9 @@ sys_info_drv_sprintf_sys_info(ErlDrvSysInfo *sip, char *str) sip->erts_version, sip->otp_release, sip->thread_support ? "true" : "false", - sip->smp_support ? "true" : "false"); + sip->smp_support ? "true" : "false", + sip->async_threads, + sip->scheduler_threads); } #include "sys_info_drv_impl.c" diff --git a/erts/emulator/test/driver_SUITE_data/sys_info_drv_impl.c b/erts/emulator/test/driver_SUITE_data/sys_info_drv_impl.c index 2d3203ae5d..c6c70a2075 100644 --- a/erts/emulator/test/driver_SUITE_data/sys_info_drv_impl.c +++ b/erts/emulator/test/driver_SUITE_data/sys_info_drv_impl.c @@ -46,7 +46,8 @@ #endif static ErlDrvData start(ErlDrvPort, char *); -static int control(ErlDrvData, unsigned int, char *, int, char **, int); +static ErlDrvSSizeT control(ErlDrvData, unsigned int, + char *, ErlDrvSizeT, char **, ErlDrvSizeT); static ErlDrvEntry drv_entry = { NULL /* init */, @@ -84,13 +85,13 @@ start(ErlDrvPort port, char *command) return (ErlDrvData) port; } -static int +static ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, - char *buf, int len, - char **rbuf, int rlen) + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) { - int res; + ErlDrvSSizeT res; char *str; size_t slen, slen2; ErlDrvPort port = (ErlDrvPort) drv_data; diff --git a/erts/emulator/test/driver_SUITE_data/sys_info_1_1_drv.c b/erts/emulator/test/driver_SUITE_data/sys_info_prev_drv.c index fa21828284..815d96cc97 100644 --- a/erts/emulator/test/driver_SUITE_data/sys_info_1_1_drv.c +++ b/erts/emulator/test/driver_SUITE_data/sys_info_prev_drv.c @@ -3,34 +3,35 @@ * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. - * + * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. - * + * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' - * + * * $Id$ */ /* * Author: Rickard Green * - * Description: Driver that fakes driver version 1.1 and tests + * Description: Driver that fakes driver version 2.0 and tests * driver_system_info(). * */ #include "sys_info_drv_impl.h" -#define SYS_INFO_DRV_MAJOR_VSN 1 -#define SYS_INFO_DRV_MINOR_VSN 1 -#define SYS_INFO_DRV_NAME_STR "sys_info_1_1_drv" -#define SYS_INFO_DRV_NAME sys_info_1_1_drv +#define SYS_INFO_DRV_MAJOR_VSN 2 +#define SYS_INFO_DRV_MINOR_VSN 0 +#define SYS_INFO_DRV_NAME_STR "sys_info_prev_drv" +#define SYS_INFO_DRV_NAME sys_info_prev_drv #define SYS_INFO_DRV_LAST_FIELD scheduler_threads +#define ERL_DRV_SYS_INFO_SIZE sizeof(ErlDrvSysInfo) #define SYS_INFO_DRV_RES_FORMAT "ok: " \ "drv_drv_vsn=%d.%d " \ @@ -42,7 +43,6 @@ "async_thrs=%d " \ "sched_thrs=%d" - static size_t sys_info_drv_max_res_len(ErlDrvSysInfo *sip) { @@ -76,5 +76,3 @@ sys_info_drv_sprintf_sys_info(ErlDrvSysInfo *sip, char *str) } #include "sys_info_drv_impl.c" - - diff --git a/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c b/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c index c7edbba7f6..95a6ae9bdf 100644 --- a/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c +++ b/erts/emulator/test/driver_SUITE_data/thr_alloc_drv.c @@ -21,14 +21,8 @@ #include "erl_driver.h" ErlDrvData start(ErlDrvPort port, char *command); -int control(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen); - -static int call(ErlDrvData drv_data, - unsigned int command, - char *buf, int len, - char **rbuf, int rlen, - unsigned int *flags); +ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf, + ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen); static ErlDrvEntry thr_alloc_drv_entry = { NULL /* init */, @@ -76,12 +70,12 @@ ErlDrvData start(ErlDrvPort port, char *command) return (ErlDrvData) port; } -int control(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen) +ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf, + ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { ErlDrvPort port = (ErlDrvPort) drv_data; char *result = "failure"; - int result_len; + ErlDrvSSizeT result_len; if (len <= 20) { int res; ErlDrvTid tid; diff --git a/erts/emulator/test/driver_SUITE_data/thr_free_drv.c b/erts/emulator/test/driver_SUITE_data/thr_free_drv.c index 622a62ebea..439fe6a184 100644 --- a/erts/emulator/test/driver_SUITE_data/thr_free_drv.c +++ b/erts/emulator/test/driver_SUITE_data/thr_free_drv.c @@ -45,8 +45,8 @@ typedef struct { static ErlDrvData start(ErlDrvPort port, char *command); static void stop(ErlDrvData data); -static int control(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen); +static ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf, + ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen); static ErlDrvEntry thr_free_drv_entry = { NULL /* init */, @@ -175,7 +175,7 @@ fail: driver_free(ttd[t].blocks[b]); } } - + driver_free(td); return ERL_DRV_ERROR_GENERAL; } @@ -194,14 +194,14 @@ static void stop(ErlDrvData drv_data) driver_free(td); } -static int control(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen) +static ErlDrvSSizeT control(ErlDrvData drv_data, unsigned int command, char *buf, + ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen) { test_data *td = (test_data *) drv_data; char *result = "failure"; int i, b; int res; - int result_len; + ErlDrvSSizeT result_len; if (td->b == -1) { erl_drv_mutex_lock(td->ttd[0].mtx); diff --git a/erts/emulator/test/driver_SUITE_data/timer_drv.c b/erts/emulator/test/driver_SUITE_data/timer_drv.c index b96a95dd4c..8c3f203a64 100644 --- a/erts/emulator/test/driver_SUITE_data/timer_drv.c +++ b/erts/emulator/test/driver_SUITE_data/timer_drv.c @@ -22,7 +22,9 @@ static ErlDrvPort erlang_port; static ErlDrvData timer_start(ErlDrvPort, char*); -static void timer_stop(ErlDrvData), timer_read(ErlDrvData, char*, int), timer(ErlDrvData); +static void timer_stop(ErlDrvData); +static void timer_read(ErlDrvData, char*, ErlDrvSizeT); +static void timer(ErlDrvData); static ErlDrvEntry timer_driver_entry = { @@ -38,6 +40,16 @@ static ErlDrvEntry timer_driver_entry = NULL, timer, NULL, + NULL, + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, NULL }; @@ -57,8 +69,9 @@ static ErlDrvData timer_start(ErlDrvPort port, char *buf) } /* set the timer, this is monitored from erlang measuring the time */ -static void timer_read(ErlDrvData port, char *buf, int len) +static void timer_read(ErlDrvData p, char *buf, ErlDrvSizeT len) { + ErlDrvPort port = (ErlDrvPort) p; char reply[1]; if (buf[0] == START_TIMER) { diff --git a/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.c b/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.c index 1e98844838..b4542f3e36 100644 --- a/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.c +++ b/erts/emulator/test/erl_drv_thread_SUITE_data/testcase_driver.c @@ -50,13 +50,33 @@ typedef struct { ErlDrvData testcase_drv_start(ErlDrvPort port, char *command); void testcase_drv_stop(ErlDrvData drv_data); -void testcase_drv_run(ErlDrvData drv_data, char *buf, int len); +void testcase_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len); static ErlDrvEntry testcase_drv_entry = { NULL, testcase_drv_start, testcase_drv_stop, - testcase_drv_run + testcase_drv_run, + NULL, + NULL, + NULL, + NULL, + NULL, /* handle */ + NULL, /* control */ + NULL, /* timeout */ + NULL, /* outputv */ + NULL, /* ready_async */ + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL, + }; @@ -92,7 +112,7 @@ testcase_drv_stop(ErlDrvData drv_data) } void -testcase_drv_run(ErlDrvData drv_data, char *buf, int len) +testcase_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) drv_data; ErlDrvTermData result_atom; diff --git a/erts/emulator/test/erts_debug_SUITE.erl b/erts/emulator/test/erts_debug_SUITE.erl index 4dc2fbaae2..76667772c7 100644 --- a/erts/emulator/test/erts_debug_SUITE.erl +++ b/erts/emulator/test/erts_debug_SUITE.erl @@ -23,13 +23,13 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, - flat_size/1,flat_size_big/1,df/1, + test_size/1,flat_size_big/1,df/1, instructions/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [flat_size, flat_size_big, df, instructions]. + [test_size, flat_size_big, df, instructions]. groups() -> []. @@ -55,16 +55,58 @@ end_per_testcase(_Func, Config) -> Dog=?config(watchdog, Config), ?t:timetrap_cancel(Dog). -flat_size(Config) when is_list(Config) -> - 0 = erts_debug:flat_size([]), - 0 = erts_debug:flat_size(42), - 2 = erts_debug:flat_size([a|b]), - 1 = erts_debug:flat_size({}), - 2 = erts_debug:flat_size({[]}), - 3 = erts_debug:flat_size({a,b}), - 7 = erts_debug:flat_size({a,[b,c]}), +test_size(Config) when is_list(Config) -> + ConsCell1 = id([a|b]), + ConsCell2 = id(ConsCell1), + ConsCellSz = 2, + + 0 = do_test_size([]), + 0 = do_test_size(42), + ConsCellSz = do_test_size(ConsCell1), + 1 = do_test_size({}), + 2 = do_test_size({[]}), + 3 = do_test_size({a,b}), + 7 = do_test_size({a,[b,c]}), + + %% Test internal consistency of sizes, but without testing + %% exact sizes. + Const = id(42), + AnotherConst = id(7), + + %% Fun environment size = 0 (the smallest fun possible) + SimplestFun = fun() -> ok end, + FunSz0 = do_test_size(SimplestFun), + + %% Fun environment size = 1 + FunSz1 = do_test_size(fun() -> Const end), + FunSz1 = FunSz0 + 1, + + %% Fun environment size = 2 + FunSz2 = do_test_size(fun() -> Const+AnotherConst end), + FunSz2 = FunSz1 + 1, + + FunSz1 = do_test_size(fun() -> ConsCell1 end) - do_test_size(ConsCell1), + + %% Test shared data structures. + do_test_size([ConsCell1|ConsCell1], + 3*ConsCellSz, + 2*ConsCellSz), + do_test_size(fun() -> {ConsCell1,ConsCell2} end, + FunSz2 + 2*ConsCellSz, + FunSz2 + ConsCellSz), + do_test_size({SimplestFun,SimplestFun}, + 2*FunSz0+do_test_size({a,b}), + FunSz0+do_test_size({a,b})), ok. +do_test_size(Term) -> + Sz = erts_debug:flat_size(Term), + Sz = erts_debug:size(Term). + +do_test_size(Term, FlatSz, Sz) -> + FlatSz = erts_debug:flat_size(Term), + Sz = erts_debug:size(Term). + flat_size_big(Config) when is_list(Config) -> %% Build a term whose external size only fits in a big num (on 32-bit CPU). flat_size_big_1(16#11111111111111117777777777777777888889999, 0, 16#FFFFFFF). @@ -96,3 +138,6 @@ instructions(Config) when is_list(Config) -> ?line Is = erts_debug:instructions(), ?line _ = [list_to_atom(I) || I <- Is], ok. + +id(I) -> + I. diff --git a/erts/emulator/test/float_SUITE_data/fp_drv.c b/erts/emulator/test/float_SUITE_data/fp_drv.c index eb453f6cd6..b80385c3f9 100644 --- a/erts/emulator/test/float_SUITE_data/fp_drv.c +++ b/erts/emulator/test/float_SUITE_data/fp_drv.c @@ -22,6 +22,7 @@ # define PRINTF(X) #endif +#include <string.h> #include <math.h> #ifdef __WIN32__ #include <float.h> @@ -37,7 +38,8 @@ int _finite(double x); #define ERTS_FP_CONTROL_TEST 0 #define ERTS_FP_THREAD_TEST 1 -static int control(ErlDrvData, unsigned int, char *, int, char **, int); +static ErlDrvSSizeT control(ErlDrvData, unsigned int, char *, + ErlDrvSizeT, char **, ErlDrvSizeT); static ErlDrvEntry fp_drv_entry = { NULL /* init */, @@ -97,10 +99,10 @@ do_test(void *unused) return "ok"; } -static int control(ErlDrvData drv_data, - unsigned int command, - char *buf, int len, - char **rbuf, int rlen) +static ErlDrvSSizeT control(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) { char *res_str; PRINTF(("control(%p, %d, ...) called\r\n", drv_data, command)); diff --git a/erts/emulator/test/fun_r12_SUITE.erl b/erts/emulator/test/fun_r13_SUITE.erl index 3b1dfc9825..76ddf9fec9 100644 --- a/erts/emulator/test/fun_r12_SUITE.erl +++ b/erts/emulator/test/fun_r13_SUITE.erl @@ -17,10 +17,10 @@ %% %CopyrightEnd% %% --module(fun_r12_SUITE). --compile(r12). +-module(fun_r13_SUITE). +-compile(r13). --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2,dist_old_release/1]). @@ -29,10 +29,10 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. -all() -> +all() -> [dist_old_release]. -groups() -> +groups() -> []. init_per_suite(Config) -> diff --git a/erts/emulator/test/mtx_SUITE.erl b/erts/emulator/test/mtx_SUITE.erl index 879d2f61dd..024c3456a8 100644 --- a/erts/emulator/test/mtx_SUITE.erl +++ b/erts/emulator/test/mtx_SUITE.erl @@ -122,7 +122,7 @@ long_rwlock(Config) when is_list(Config) -> %% A very short run time is expected, since %% threads in the test mostly wait ?t:format("RunTime=~p~n", [RunTime]), - ?line true = RunTime < 100, + ?line true = RunTime < 400, ?line RunTimeStr = "Run-time during test was "++integer_to_list(RunTime)++" ms.", case LLRes of ok -> @@ -281,7 +281,7 @@ hammer_sched_rwlock_test(FreqRead, LockCheck, Blocking, WaitLocked, WaitUnlocked _ -> {_, RunTime} = statistics(runtime), ?t:format("RunTime=~p~n", [RunTime]), - ?line true = RunTime < 500, + ?line true = RunTime < 700, {comment, "Run-time during test was " ++ integer_to_list(RunTime) diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index 370363bf9e..6bd7361612 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -859,7 +859,13 @@ resource_holder(Pid,Reply,List) -> threading(doc) -> ["Test the threading API functions (reuse tests from driver API)"]; -threading(Config) when is_list(Config) -> +threading(Config) when is_list(Config) -> + case erlang:system_info(threads) of + true -> threading_do(Config); + false -> {skipped,"No thread support"} + end. + +threading_do(Config) -> ?line Data = ?config(data_dir, Config), ?line File = filename:join(Data, "tester"), ?line {ok,tester,ModBin} = compile:file(File, [binary,return_errors]), diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 7d7903af25..03092fef5e 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -345,8 +345,13 @@ static int test_double(ErlNifEnv* env, double d1) #define TAG_BITS 4 #define SMALL_BITS (sizeof(void*)*8 - TAG_BITS) +#ifdef _WIN64 +#define MAX_SMALL ((1LL << (SMALL_BITS-1))-1) +#define MIN_SMALL (-(1LL << (SMALL_BITS-1))) +#else #define MAX_SMALL ((1L << (SMALL_BITS-1))-1) #define MIN_SMALL (-(1L << (SMALL_BITS-1))) +#endif static ERL_NIF_TERM type_test(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { diff --git a/erts/emulator/test/nif_SUITE_data/tester.c b/erts/emulator/test/nif_SUITE_data/tester.c index 08466d0f18..257b116322 100644 --- a/erts/emulator/test/nif_SUITE_data/tester.c +++ b/erts/emulator/test/nif_SUITE_data/tester.c @@ -61,6 +61,7 @@ static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) static ERL_NIF_TERM run(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { testcase_run(NULL); + testcase_cleanup(NULL); return enif_make_atom(env, "ok"); } diff --git a/erts/emulator/test/port_SUITE_data/echo_drv.c b/erts/emulator/test/port_SUITE_data/echo_drv.c index 25eda116fe..1d39c6a00c 100644 --- a/erts/emulator/test/port_SUITE_data/echo_drv.c +++ b/erts/emulator/test/port_SUITE_data/echo_drv.c @@ -1,4 +1,5 @@ #include <stdio.h> +#include <string.h> #include "erl_driver.h" @@ -17,11 +18,9 @@ typedef struct _erl_drv_data EchoDrvData; static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command); static void echo_drv_stop(EchoDrvData *data_p); -static void echo_drv_output(EchoDrvData *data_p, char *buf, int len); +static void echo_drv_output(ErlDrvData drv_data, char *buf, + ErlDrvSizeT len); static void echo_drv_finish(void); -static int echo_drv_control(EchoDrvData *data_p, unsigned int command, - char *buf, int len, - char **rbuf, int rlen); static ErlDrvEntry echo_drv_entry = { NULL, /* init */ @@ -33,10 +32,20 @@ static ErlDrvEntry echo_drv_entry = { "echo_drv", echo_drv_finish, NULL, /* handle */ - echo_drv_control, + NULL, /* control */ NULL, /* timeout */ NULL, /* outputv */ - NULL /* ready_async */ + NULL, /* ready_async */ + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL, }; @@ -68,7 +77,8 @@ static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command) { static void echo_drv_stop(EchoDrvData *data_p) { } -static void echo_drv_output(EchoDrvData *data_p, char *buf, int len) { +static void echo_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { + EchoDrvData *data_p = (EchoDrvData *) drv_data; void *void_ptr; ErlDrvPort port = void_ptr = data_p; @@ -77,9 +87,3 @@ static void echo_drv_output(EchoDrvData *data_p, char *buf, int len) { static void echo_drv_finish() { } - -static int echo_drv_control(EchoDrvData *data_p, unsigned int command, - char *buf, int len, - char **rbuf, int rlen) { - return 0; -} diff --git a/erts/emulator/test/port_SUITE_data/exit_drv.c b/erts/emulator/test/port_SUITE_data/exit_drv.c index 60f1b321bd..5f366b3545 100644 --- a/erts/emulator/test/port_SUITE_data/exit_drv.c +++ b/erts/emulator/test/port_SUITE_data/exit_drv.c @@ -5,11 +5,9 @@ typedef struct _erl_drv_data ExitDrvData; static ExitDrvData *exit_drv_start(ErlDrvPort port, char *command); static void exit_drv_stop(ExitDrvData *data_p); -static void exit_drv_output(ExitDrvData *data_p, char *buf, int len); +static void exit_drv_output(ExitDrvData *data_p, char *buf, + ErlDrvSizeT len); static void exit_drv_finish(void); -static int exit_drv_control(ExitDrvData *data_p, unsigned int command, - char *buf, int len, - char **rbuf, int rlen); static ErlDrvEntry exit_drv_entry = { NULL, /* init */ @@ -21,10 +19,20 @@ static ErlDrvEntry exit_drv_entry = { "exit_drv", exit_drv_finish, NULL, /* handle */ - exit_drv_control, + NULL, /* control */ NULL, /* timeout */ NULL, /* outputv */ - NULL /* ready_async */ + NULL, /* ready_async */ + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL, }; DRIVER_INIT(exit_drv) @@ -45,7 +53,7 @@ exit_drv_stop(ExitDrvData *datap) } static void -exit_drv_output(ExitDrvData *datap, char *buf, int len) +exit_drv_output(ExitDrvData *datap, char *buf, ErlDrvSizeT len) { driver_exit((ErlDrvPort) datap, 0); } @@ -55,14 +63,3 @@ exit_drv_finish(void) { } - -static int -exit_drv_control(ExitDrvData *datap, - unsigned int command, - char *buf, - int len, - char **rbuf, - int rlen) -{ - return 0; -} diff --git a/erts/emulator/test/port_SUITE_data/failure_drv.c b/erts/emulator/test/port_SUITE_data/failure_drv.c index 34d48e00f8..5826e6d5a9 100644 --- a/erts/emulator/test/port_SUITE_data/failure_drv.c +++ b/erts/emulator/test/port_SUITE_data/failure_drv.c @@ -5,10 +5,8 @@ typedef struct _erl_drv_data FailureDrvData; static FailureDrvData *failure_drv_start(ErlDrvPort, char *); static void failure_drv_stop(FailureDrvData *); -static void failure_drv_output(FailureDrvData *, char *, int); +static void failure_drv_output(ErlDrvData, char *, ErlDrvSizeT); static void failure_drv_finish(void); -static int failure_drv_control(FailureDrvData *, unsigned int, - char *, int, char **, int); static ErlDrvEntry failure_drv_entry = { NULL, /* init */ @@ -18,12 +16,22 @@ static ErlDrvEntry failure_drv_entry = { NULL, /* ready_input */ NULL, /* ready_output */ "failure_drv", - failure_drv_finish, + NULL, /* finish */ NULL, /* handle */ - failure_drv_control, + NULL, /* control */ NULL, /* timeout */ NULL, /* outputv */ - NULL /* ready_async */ + NULL, /* ready_async */ + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL, }; @@ -46,7 +54,8 @@ static FailureDrvData *failure_drv_start(ErlDrvPort port, char *command) { static void failure_drv_stop(FailureDrvData *data_p) { } -static void failure_drv_output(FailureDrvData *data_p, char *buf, int len) { +static void failure_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { + FailureDrvData *data_p = (FailureDrvData *) drv_data; void *void_ptr; ErlDrvPort port = void_ptr = data_p; @@ -55,9 +64,3 @@ static void failure_drv_output(FailureDrvData *data_p, char *buf, int len) { static void failure_drv_finish() { } - -static int failure_drv_control(FailureDrvData *data_p, unsigned int command, - char *buf, int len, - char **rbuf, int rlen) { - return 0; -} diff --git a/erts/emulator/test/port_bif_SUITE_data/control_drv.c b/erts/emulator/test/port_bif_SUITE_data/control_drv.c index e9f57a887a..b937a8bb15 100644 --- a/erts/emulator/test/port_bif_SUITE_data/control_drv.c +++ b/erts/emulator/test/port_bif_SUITE_data/control_drv.c @@ -1,13 +1,15 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include "erl_driver.h" static ErlDrvPort erlang_port; static ErlDrvData control_start(ErlDrvPort, char*); static void control_stop(ErlDrvData); -static void control_read(ErlDrvData, char*, int); -static int control_control(ErlDrvData, unsigned int, char*, int, char**, int); +static void control_read(ErlDrvData, char*, ErlDrvSizeT); +static ErlDrvSSizeT control_control(ErlDrvData, unsigned int, char*, + ErlDrvSizeT, char**, ErlDrvSizeT); static ErlDrvEntry control_driver_entry = { @@ -21,9 +23,19 @@ static ErlDrvEntry control_driver_entry = NULL, NULL, control_control, + NULL, /* timeout */ + NULL, /* outputv */ + NULL, /* ready_async */ + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, NULL, NULL, - NULL }; DRIVER_INIT(control_drv) @@ -41,7 +53,7 @@ static ErlDrvData control_start(ErlDrvPort port,char *buf) return (ErlDrvData)port; } -static void control_read(ErlDrvData port, char *buf, int count) +static void control_read(ErlDrvData port, char *buf, ErlDrvSizeT count) { driver_output(erlang_port, buf, count); } @@ -51,8 +63,9 @@ static void control_stop(ErlDrvData port) erlang_port = (ErlDrvPort)-1; } -static int control_control(ErlDrvData port, unsigned command, char* buf, int count, - char** res, int res_size) +static ErlDrvSSizeT control_control(ErlDrvData port, unsigned command, + char* buf, ErlDrvSizeT count, + char** res, ErlDrvSizeT res_size) { switch (command) { case 'e': diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl index debb54579b..8931562828 100644 --- a/erts/emulator/test/scheduler_SUITE.erl +++ b/erts/emulator/test/scheduler_SUITE.erl @@ -55,7 +55,7 @@ scheduler_suspend/1, reader_groups/1]). --define(DEFAULT_TIMEOUT, ?t:minutes(10)). +-define(DEFAULT_TIMEOUT, ?t:minutes(15)). -define(MIN_SCHEDULER_TEST_TIMEOUT, ?t:minutes(1)). @@ -519,16 +519,18 @@ bound_loop(NS, N, M, Sched) -> bindings(Node, BindType) -> Parent = self(), Ref = make_ref(), - spawn_link(Node, - fun () -> - enable_internal_state(), - Res = (catch erts_debug:get_internal_state( - {fake_scheduler_bindings, BindType})), - Parent ! {Ref, Res} - end), + Pid = spawn_link(Node, + fun () -> + enable_internal_state(), + Res = (catch erts_debug:get_internal_state( + {fake_scheduler_bindings, + BindType})), + Parent ! {Ref, Res} + end), receive {Ref, Res} -> ?t:format("~p: ~p~n", [BindType, Res]), + unlink(Pid), Res end. @@ -1684,7 +1686,7 @@ do_it(Tracer, Low, Normal, High, Max, RedsPerSchedLimit) -> EndWait = now(), BalanceWait = timer:now_diff(EndWait,StartWait) div 1000, erlang:display({balance_wait, BalanceWait}), - Timeout = ?DEFAULT_TIMEOUT - ?t:seconds(10) - BalanceWait, + Timeout = ?DEFAULT_TIMEOUT - ?t:minutes(4) - BalanceWait, Res = case Timeout < ?MIN_SCHEDULER_TEST_TIMEOUT of true -> stop_work(Low, Normal, High, Max), diff --git a/erts/emulator/test/send_term_SUITE_data/send_term_drv.c b/erts/emulator/test/send_term_SUITE_data/send_term_drv.c index 165cce2e9d..b3feca79f0 100644 --- a/erts/emulator/test/send_term_SUITE_data/send_term_drv.c +++ b/erts/emulator/test/send_term_SUITE_data/send_term_drv.c @@ -24,7 +24,7 @@ static ErlDrvPort erlang_port; static ErlDrvData send_term_drv_start(ErlDrvPort port, char *command); static void send_term_drv_stop(ErlDrvData drv_data); -static void send_term_drv_run(ErlDrvData drv_data, char *buf, int len); +static void send_term_drv_run(ErlDrvData drv_data, char *buf, ErlDrvSizeT len); static int make_ext_term_list(ErlDrvTermData *td, int bad); @@ -39,6 +39,22 @@ static ErlDrvEntry send_term_drv_entry = { NULL, NULL, "send_term_drv", + NULL, + NULL, /* handle */ + NULL, /* control */ + NULL, /* timeout */ + NULL, /* outputv */ + NULL, /* ready_async */ + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL, }; DRIVER_INIT(send_term_drv) @@ -64,7 +80,7 @@ static void send_term_drv_stop(ErlDrvData drv_data) static void output_term(ErlDrvTermData* msg, int len); static void fail_term(ErlDrvTermData* msg, int len, int line); -static void send_term_drv_run(ErlDrvData port, char *buf, int count) +static void send_term_drv_run(ErlDrvData port, char *buf, ErlDrvSizeT count) { char buf7[1024]; ErlDrvTermData spec[1024]; diff --git a/erts/emulator/test/sensitive_SUITE.erl b/erts/emulator/test/sensitive_SUITE.erl index 634df367ca..e073eab596 100644 --- a/erts/emulator/test/sensitive_SUITE.erl +++ b/erts/emulator/test/sensitive_SUITE.erl @@ -160,8 +160,7 @@ recv_trace(Config) when is_list(Config) -> ?line {messages,Messages} = process_info(Tracer, messages), [{trace,Parent,'receive',a}, {trace,Parent,'receive',{trace_delivered,_,_}}, - {trace,Parent,'receive',c}, - {trace,Parent,'receive',{trace_delivered,_,_}}] = Messages, + {trace,Parent,'receive',c}|_] = Messages, ?line unlink(Tracer), exit(Tracer, kill), ?line unlink(Sender), exit(Sender, kill), diff --git a/erts/emulator/test/smoke_test_SUITE.erl b/erts/emulator/test/smoke_test_SUITE.erl new file mode 100644 index 0000000000..98f1cf1ad5 --- /dev/null +++ b/erts/emulator/test/smoke_test_SUITE.erl @@ -0,0 +1,139 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(smoke_test_SUITE). + +-include_lib("test_server/include/test_server.hrl"). + +%-compile(export_all). +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_group/2,end_per_group/2, + init_per_testcase/2, end_per_testcase/2]). + +-export([boot_combo/1]). + +-define(DEFAULT_TIMEOUT, ?t:minutes(2)). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [boot_combo]. + +groups() -> + []. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +init_per_testcase(Case, Config) when is_list(Config) -> + Dog = ?t:timetrap(?DEFAULT_TIMEOUT), + [{testcase, Case},{watchdog, Dog}|Config]. + +end_per_testcase(_Case, Config) when is_list(Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +%%% +%%% The test cases ------------------------------------------------------------- +%%% + +boot_combo(Config) when is_list(Config) -> + ZFlags = os:getenv("ERL_ZFLAGS"), + NOOP = fun () -> ok end, + A42 = fun () -> + case erlang:system_info(threads) of + true -> + 42 = erlang:system_info(thread_pool_size); + false -> + ok + end + end, + SMPDisable = fun () -> false = erlang:system_info(smp_support) end, + try + chk_boot(Config, "+Ktrue", NOOP), + chk_boot(Config, "+A42", A42), + chk_boot(Config, "-smp disable", SMPDisable), + chk_boot(Config, "+Ktrue +A42", A42), + chk_boot(Config, "-smp disable +A42", + fun () -> SMPDisable(), A42() end), + chk_boot(Config, "-smp disable +Ktrue", SMPDisable), + chk_boot(Config, "-smp disable +Ktrue +A42", + fun () -> SMPDisable(), A42() end), + %% A lot more combos could be implemented... + ok + after + os:putenv("ERL_ZFLAGS", case ZFlags of + false -> ""; + _ -> ZFlags + end) + end. + +%%% +%%% Aux functions -------------------------------------------------------------- +%%% + +chk_boot(Config, Args, Fun) -> + true = os:putenv("ERL_ZFLAGS", Args), + Success = make_ref(), + Parent = self(), + ?t:format("--- Testing ~s~n", [Args]), + {ok, Node} = start_node(Config), + Pid = spawn_link(Node, fun () -> + Fun(), + Parent ! {self(), Success} + end), + receive + {Pid, Success} -> + Node = node(Pid), + stop_node(Node), + ?t:format("--- Success!~n", []), + ok + end. + +start_node(Config) -> + start_node(Config, ""). + +start_node(Config, Args) when is_list(Config) -> + ?line Pa = filename:dirname(code:which(?MODULE)), + ?line {A, B, C} = now(), + ?line Name = list_to_atom(atom_to_list(?MODULE) + ++ "-" + ++ atom_to_list(?config(testcase, Config)) + ++ "-" + ++ integer_to_list(A) + ++ "-" + ++ integer_to_list(B) + ++ "-" + ++ integer_to_list(C)), + ?line ?t:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]). + +stop_node(Node) -> + ?t:stop_node(Node). + diff --git a/erts/emulator/test/statistics_SUITE.erl b/erts/emulator/test/statistics_SUITE.erl index 0392312a6f..a93dd309c1 100644 --- a/erts/emulator/test/statistics_SUITE.erl +++ b/erts/emulator/test/statistics_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -29,6 +29,7 @@ runtime_zero_diff/1, runtime_update/1, runtime_diff/1, run_queue_one/1, + scheduler_wall_time/1, reductions/1, reductions_big/1, garbage_collection/1, io/1, badarg/1]). @@ -51,8 +52,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [{group, wall_clock}, {group, runtime}, reductions, - reductions_big, {group, run_queue}, garbage_collection, - io, badarg]. + reductions_big, {group, run_queue}, scheduler_wall_time, + garbage_collection, io, badarg]. groups() -> [{wall_clock, [], @@ -266,11 +267,10 @@ run_queue_one(Config) when is_list(Config) -> run_queue_one_test(Config) when is_list(Config) -> - ?line Hog = spawn_link(?MODULE, hog, [self()]), + ?line _Hog = spawn_link(?MODULE, hog, [self()]), ?line receive - hog_started -> - Hog ! go - end, + hog_started -> ok + end, ?line receive after 100 -> ok end, % Give hog a head start. ?line case statistics(run_queue) of N when N >= 1 -> ok; @@ -280,18 +280,88 @@ run_queue_one_test(Config) when is_list(Config) -> %% CPU-bound process, going at low priority. It will always be ready %% to run. - + hog(Pid) -> ?line process_flag(priority, low), ?line Pid ! hog_started, - ?line receive - go -> hog_iter(0) + ?line Mon = erlang:monitor(process, Pid), + ?line hog_iter(0, Mon). + +hog_iter(N, Mon) when N > 0 -> + receive + {'DOWN', Mon, _, _, _} -> ok + after 0 -> + ?line hog_iter(N-1, Mon) + end; +hog_iter(0, Mon) -> + ?line hog_iter(10000, Mon). + +%%% Tests of statistics(scheduler_wall_time). + +scheduler_wall_time(doc) -> + "Tests that statistics(scheduler_wall_time) works as intended"; +scheduler_wall_time(Config) when is_list(Config) -> + %% Should return undefined if system_flag is not turned on yet + undefined = statistics(scheduler_wall_time), + %% Turn on statistics + false = erlang:system_flag(scheduler_wall_time, true), + try + Schedulers = erlang:system_info(schedulers_online), + %% Let testserver and everyone else finish their work + timer:sleep(500), + %% Empty load + EmptyLoad = get_load(), + {false, _} = {lists:any(fun(Load) -> Load > 50 end, EmptyLoad),EmptyLoad}, + MeMySelfAndI = self(), + StartHog = fun() -> + Pid = spawn(?MODULE, hog, [self()]), + receive hog_started -> MeMySelfAndI ! go end, + Pid + end, + P1 = StartHog(), + %% Max on one, the other schedulers empty (hopefully) + %% Be generous the process can jump between schedulers + %% which is ok and we don't want the test to fail for wrong reasons + _L1 = [S1Load|EmptyScheds1] = get_load(), + {true,_} = {S1Load > 50,S1Load}, + {false,_} = {lists:any(fun(Load) -> Load > 50 end, EmptyScheds1),EmptyScheds1}, + {true,_} = {lists:sum(EmptyScheds1) < 60,EmptyScheds1}, + + %% 50% load + HalfHogs = [StartHog() || _ <- lists:seq(1, (Schedulers-1) div 2)], + HalfLoad = lists:sum(get_load()) div Schedulers, + if Schedulers < 2, HalfLoad > 80 -> ok; %% Ok only one scheduler online and one hog + %% We want roughly 50% load + HalfLoad > 40, HalfLoad < 60 -> ok; + true -> exit({halfload, HalfLoad}) + end, + + %% 100% load + LastHogs = [StartHog() || _ <- lists:seq(1, Schedulers div 2)], + FullScheds = get_load(), + {false,_} = {lists:any(fun(Load) -> Load < 80 end, FullScheds),FullScheds}, + FullLoad = lists:sum(FullScheds) div Schedulers, + if FullLoad > 90 -> ok; + true -> exit({fullload, FullLoad}) + end, + + [exit(Pid, kill) || Pid <- [P1|HalfHogs++LastHogs]], + AfterLoad = get_load(), + {false,_} = {lists:any(fun(Load) -> Load > 5 end, AfterLoad),AfterLoad}, + true = erlang:system_flag(scheduler_wall_time, false) + after + erlang:system_flag(scheduler_wall_time, false) end. -hog_iter(N) when N > 0 -> - ?line hog_iter(N-1); -hog_iter(0) -> - ?line hog_iter(10000). +get_load() -> + Start = erlang:statistics(scheduler_wall_time), + timer:sleep(500), + End = erlang:statistics(scheduler_wall_time), + lists:reverse(lists:sort(load_percentage(lists:sort(Start),lists:sort(End)))). + +load_percentage([{Id, WN, TN}|Ss], [{Id, WP, TP}|Ps]) -> + [100*(WN-WP) div (TN-TP)|load_percentage(Ss, Ps)]; +load_percentage([], []) -> []. garbage_collection(doc) -> diff --git a/erts/emulator/test/system_profile_SUITE.erl b/erts/emulator/test/system_profile_SUITE.erl index 32089e8872..659e43f81d 100644 --- a/erts/emulator/test/system_profile_SUITE.erl +++ b/erts/emulator/test/system_profile_SUITE.erl @@ -27,6 +27,7 @@ system_profile_on_and_off/1, runnable_procs/1, runnable_ports/1, + dont_profile_profiler/1, scheduler/1 ]). @@ -40,7 +41,7 @@ -define(default_timeout, ?t:minutes(1)). init_per_testcase(_Case, Config) -> - ?line Dog=?t:timetrap(?default_timeout), + Dog=?t:timetrap(?default_timeout), [{watchdog, Dog}|Config]. end_per_testcase(_Case, Config) -> Dog=?config(watchdog, Config), @@ -51,7 +52,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [system_profile_on_and_off, runnable_procs, - runnable_ports, scheduler]. + runnable_ports, scheduler, dont_profile_profiler]. groups() -> []. @@ -77,31 +78,31 @@ system_profile_on_and_off(suite) -> system_profile_on_and_off(doc) -> ["Tests switching system_profiling on and off."]; system_profile_on_and_off(Config) when is_list(Config) -> - ?line Pid = start_profiler_process(), + Pid = start_profiler_process(), % Test runnable_ports on and off - ?line undefined = erlang:system_profile(Pid, [runnable_ports]), - ?line {Pid, [runnable_ports]} = erlang:system_profile(), - ?line {Pid, [runnable_ports]} = erlang:system_profile(undefined, []), + undefined = erlang:system_profile(Pid, [runnable_ports]), + {Pid, [runnable_ports]} = erlang:system_profile(), + {Pid, [runnable_ports]} = erlang:system_profile(undefined, []), % Test runnable_procs on and off - ?line undefined = erlang:system_profile(Pid, [runnable_procs]), - ?line {Pid, [runnable_procs]} = erlang:system_profile(), - ?line {Pid, [runnable_procs]} = erlang:system_profile(undefined, []), + undefined = erlang:system_profile(Pid, [runnable_procs]), + {Pid, [runnable_procs]} = erlang:system_profile(), + {Pid, [runnable_procs]} = erlang:system_profile(undefined, []), % Test scheduler on and off - ?line undefined = erlang:system_profile(Pid, [scheduler]), - ?line {Pid, [scheduler]} = erlang:system_profile(), - ?line {Pid, [scheduler]} = erlang:system_profile(undefined, []), + undefined = erlang:system_profile(Pid, [scheduler]), + {Pid, [scheduler]} = erlang:system_profile(), + {Pid, [scheduler]} = erlang:system_profile(undefined, []), % Test combined runnable_ports, runnable_procs, scheduler; on and off - ?line undefined = erlang:system_profile(Pid, [scheduler, runnable_procs, runnable_ports]), - ?line {Pid, [scheduler,runnable_procs,runnable_ports]} = erlang:system_profile(), - ?line {Pid, [scheduler,runnable_procs,runnable_ports]} = erlang:system_profile(undefined, []), + undefined = erlang:system_profile(Pid, [scheduler, runnable_procs, runnable_ports]), + {Pid, [scheduler,runnable_procs,runnable_ports]} = erlang:system_profile(), + {Pid, [scheduler,runnable_procs,runnable_ports]} = erlang:system_profile(undefined, []), % Test turned off and kill process - ?line undefined = erlang:system_profile(), - ?line exit(Pid,kill), + undefined = erlang:system_profile(), + exit(Pid,kill), ok. %% Test runnable_procs @@ -111,25 +112,25 @@ runnable_procs(suite) -> runnable_procs(doc) -> ["Tests system_profiling with runnable_procs."]; runnable_procs(Config) when is_list(Config) -> - ?line Pid = start_profiler_process(), + Pid = start_profiler_process(), % start a ring of processes % FIXME: Set #laps and #nodes in config file Nodes = 10, Laps = 10, - ?line Master = ring(Nodes), - ?line undefined = erlang:system_profile(Pid, [runnable_procs]), + Master = ring(Nodes), + undefined = erlang:system_profile(Pid, [runnable_procs]), % loop a message - ?line ok = ring_message(Master, message, Laps), - ?line Events = get_profiler_events(), - ?line kill_em_all = kill_ring(Master), - ?line erlang:system_profile(undefined, []), + ok = ring_message(Master, message, Laps), + Events = get_profiler_events(), + kill_em_all = kill_ring(Master), + erlang:system_profile(undefined, []), put(master, Master), put(laps, Laps), - ?line true = has_runnable_event(Events), + true = has_runnable_event(Events), Pids = sort_events_by_pid(Events), - ?line ok = check_events(Pids), + ok = check_events(Pids), erase(), - ?line exit(Pid,kill), + exit(Pid,kill), ok. runnable_ports(suite) -> @@ -137,21 +138,21 @@ runnable_ports(suite) -> runnable_ports(doc) -> ["Tests system_profiling with runnable_port."]; runnable_ports(Config) when is_list(Config) -> - ?line Pid = start_profiler_process(), - ?line undefined = erlang:system_profile(Pid, [runnable_ports]), - ?line EchoPid = echo(Config), + Pid = start_profiler_process(), + undefined = erlang:system_profile(Pid, [runnable_ports]), + EchoPid = echo(Config), % FIXME: Set config to number_of_echos Laps = 10, put(laps, Laps), - ?line ok = echo_message(EchoPid, Laps, message), - ?line Events = get_profiler_events(), - ?line kill_em_all = kill_echo(EchoPid), - ?line erlang:system_profile(undefined, []), - ?line true = has_runnable_event(Events), + ok = echo_message(EchoPid, Laps, message), + Events = get_profiler_events(), + kill_em_all = kill_echo(EchoPid), + erlang:system_profile(undefined, []), + true = has_runnable_event(Events), Pids = sort_events_by_pid(Events), - ?line ok = check_events(Pids), + ok = check_events(Pids), erase(), - ?line exit(Pid,kill), + exit(Pid,kill), ok. scheduler(suite) -> @@ -160,46 +161,68 @@ scheduler(doc) -> ["Tests system_profiling with scheduler."]; scheduler(Config) when is_list(Config) -> case {erlang:system_info(smp_support), erlang:system_info(schedulers_online)} of - {false,_} -> ?line {skipped, "No need for scheduler test when smp support is disabled."}; - {_, 1} -> ?line {skipped, "No need for scheduler test when only one scheduler online."}; + {false,_} -> {skipped, "No need for scheduler test when smp support is disabled."}; + {_, 1} -> {skipped, "No need for scheduler test when only one scheduler online."}; _ -> Nodes = 10, - ?line ok = check_block_system(Nodes), - ?line ok = check_multi_scheduling_block(Nodes), - ok + ok = check_block_system(Nodes), + ok = check_multi_scheduling_block(Nodes) end. +% the profiler pid should not be profiled +dont_profile_profiler(suite) -> + []; +dont_profile_profiler(doc) -> + ["Ensure system profiler process is not profiled."]; +dont_profile_profiler(Config) when is_list(Config) -> + Pid = start_profiler_process(), + + Nodes = 10, + Laps = 10, + Master = ring(Nodes), + undefined = erlang:system_profile(Pid, [runnable_procs]), + % loop a message + ok = ring_message(Master, message, Laps), + erlang:system_profile(undefined, []), + kill_em_all = kill_ring(Master), + Events = get_profiler_events(), + false = has_profiler_pid_event(Events, Pid), + + exit(Pid,kill), + ok. + + %%% Check scheduler profiling check_multi_scheduling_block(Nodes) -> - ?line Pid = start_profiler_process(), - ?line undefined = erlang:system_profile(Pid, [scheduler]), - ?line {ok, Supervisor} = start_load(Nodes), - ?line erlang:system_flag(multi_scheduling, block), - ?line erlang:system_flag(multi_scheduling, unblock), - ?line {Pid, [scheduler]} = erlang:system_profile(undefined, []), - ?line Events = get_profiler_events(), - ?line true = has_scheduler_event(Events), + Pid = start_profiler_process(), + undefined = erlang:system_profile(Pid, [scheduler]), + {ok, Supervisor} = start_load(Nodes), + erlang:system_flag(multi_scheduling, block), + erlang:system_flag(multi_scheduling, unblock), + {Pid, [scheduler]} = erlang:system_profile(undefined, []), + Events = get_profiler_events(), + true = has_scheduler_event(Events), stop_load(Supervisor), - ?line exit(Pid,kill), + exit(Pid,kill), erase(), ok. check_block_system(Nodes) -> - ?line Dummy = spawn(?MODULE, profiler_process, [[]]), - ?line Pid = start_profiler_process(), - ?line undefined = erlang:system_profile(Pid, [scheduler]), - ?line {ok, Supervisor} = start_load(Nodes), + Dummy = spawn(?MODULE, profiler_process, [[]]), + Pid = start_profiler_process(), + undefined = erlang:system_profile(Pid, [scheduler]), + {ok, Supervisor} = start_load(Nodes), % FIXME: remove wait !! wait(300), - ?line undefined = erlang:system_monitor(Dummy, [busy_port]), - ?line {Dummy, [busy_port]} = erlang:system_monitor(undefined, []), - ?line {Pid, [scheduler]} = erlang:system_profile(undefined, []), - ?line Events = get_profiler_events(), - ?line true = has_scheduler_event(Events), + undefined = erlang:system_monitor(Dummy, [busy_port]), + {Dummy, [busy_port]} = erlang:system_monitor(undefined, []), + {Pid, [scheduler]} = erlang:system_profile(undefined, []), + Events = get_profiler_events(), + true = has_scheduler_event(Events), stop_load(Supervisor), - ?line exit(Pid,kill), - ?line exit(Dummy,kill), + exit(Pid,kill), + exit(Dummy,kill), erase(), ok. @@ -211,17 +234,17 @@ check_events([Pid | Pids]) -> Laps = get(laps), CheckPids = get(pids), {Events, N} = get_pid_events(Pid), - ?line ok = check_event_flow(Events), - ?line ok = check_event_ts(Events), + ok = check_event_flow(Events), + ok = check_event_ts(Events), IsMember = lists:member(Pid, CheckPids), case Pid of Master -> io:format("Expected ~p and got ~p profile events from ~p: ok~n", [Laps*2+2, N, Pid]), - ?line N = Laps*2 + 2, + N = Laps*2 + 2, check_events(Pids); Pid when IsMember == true -> io:format("Expected ~p and got ~p profile events from ~p: ok~n", [Laps*2, N, Pid]), - ?line N = Laps*2, + N = Laps*2, check_events(Pids); Pid -> check_events(Pids) @@ -448,6 +471,12 @@ has_runnable_event(Events) -> end end, Events). +has_profiler_pid_event([], _) -> false; +has_profiler_pid_event([{profile, Pid, _Activity, _MFA, _TS}|Events], Pid) -> true; +has_profiler_pid_event([_|Events], Pid) -> + has_profiler_pid_event(Events, Pid). + + wait(Time) -> receive after Time -> ok end. %%% diff --git a/erts/emulator/test/system_profile_SUITE_data/echo_drv.c b/erts/emulator/test/system_profile_SUITE_data/echo_drv.c index d968ff06f9..e0b6ff804c 100644 --- a/erts/emulator/test/system_profile_SUITE_data/echo_drv.c +++ b/erts/emulator/test/system_profile_SUITE_data/echo_drv.c @@ -9,11 +9,9 @@ static EchoDrvData echo_drv_data, *echo_drv_data_p; static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command); static void echo_drv_stop(EchoDrvData *data_p); -static void echo_drv_output(EchoDrvData *data_p, char *buf, int len); +static void echo_drv_output(ErlDrvData drv_data, char *buf, + ErlDrvSizeT len); static void echo_drv_finish(void); -static int echo_drv_control(EchoDrvData *data_p, unsigned int command, - char *buf, int len, - char **rbuf, int rlen); static ErlDrvEntry echo_drv_entry = { NULL, /* init */ @@ -25,10 +23,21 @@ static ErlDrvEntry echo_drv_entry = { "echo_drv", echo_drv_finish, NULL, /* handle */ - echo_drv_control, + NULL, /* control */ NULL, /* timeout */ NULL, /* outputv */ - NULL /* ready_async */ + NULL, /* ready_async */ + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL + }; DRIVER_INIT(echo_drv) @@ -51,16 +60,11 @@ static void echo_drv_stop(EchoDrvData *data_p) { echo_drv_data_p = NULL; } -static void echo_drv_output(EchoDrvData *data_p, char *buf, int len) { +static void echo_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { + EchoDrvData* data_p = (EchoDrvData *) drv_data; driver_output(data_p->erlang_port, buf, len); } static void echo_drv_finish() { echo_drv_data_p = NULL; } - -static int echo_drv_control(EchoDrvData *data_p, unsigned int command, - char *buf, int len, - char **rbuf, int rlen) { - return 0; -} diff --git a/erts/emulator/test/time_SUITE.erl b/erts/emulator/test/time_SUITE.erl index bd48a0a7db..4d12e3449c 100644 --- a/erts/emulator/test/time_SUITE.erl +++ b/erts/emulator/test/time_SUITE.erl @@ -32,6 +32,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, univ_to_local/1, local_to_univ/1, bad_univ_to_local/1, bad_local_to_univ/1, + univ_to_seconds/1, seconds_to_univ/1, consistency/1, now_unique/1, now_update/1, timestamp/1]). @@ -59,7 +60,9 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [univ_to_local, local_to_univ, local_to_univ_utc, - bad_univ_to_local, bad_local_to_univ, consistency, + bad_univ_to_local, bad_local_to_univ, + univ_to_seconds, seconds_to_univ, + consistency, {group, now}, timestamp]. groups() -> @@ -162,6 +165,30 @@ bad_test_local_to_univ([Local|Rest]) -> bad_test_local_to_univ([]) -> ok. + +%% Test universaltime to seconds conversions +univ_to_seconds(Config) when is_list(Config) -> + test_univ_to_seconds(ok_utc_seconds()). + +test_univ_to_seconds([{Datetime, Seconds}|DSs]) -> + io:format("universaltime = ~p -> seconds = ~p", [Datetime, Seconds]), + Seconds = erlang:universaltime_to_posixtime(Datetime), + test_univ_to_seconds(DSs); +test_univ_to_seconds([]) -> + ok. + +%% Test seconds to universaltime conversions +seconds_to_univ(Config) when is_list(Config) -> + test_seconds_to_univ(ok_utc_seconds()). + +test_seconds_to_univ([{Datetime, Seconds}|DSs]) -> + io:format("universaltime = ~p <- seconds = ~p", [Datetime, Seconds]), + Datetime = erlang:posixtime_to_universaltime(Seconds), + test_seconds_to_univ(DSs); +test_seconds_to_univ([]) -> + ok. + + %% Test that the the different time functions return %% consistent results. (See the test case for assumptions %% and limitations.) @@ -453,6 +480,32 @@ dst_dates() -> {1998, 06, 3}, {1999, 06, 4}]. +%% exakt utc {date(), time()} which corresponds to the same seconds since 1 jan 1970 +%% negative seconds are ok +%% generated with date --date='1979-05-28 12:30:35 UTC' +%s +ok_utc_seconds() -> [ + { {{1970, 1, 1},{ 0, 0, 0}}, 0 }, + { {{1970, 1, 1},{ 0, 0, 1}}, 1 }, + { {{1969,12,31},{23,59,59}}, -1 }, + { {{1920,12,31},{23,59,59}}, -1546300801 }, + { {{1600,02,19},{15,14,08}}, -11671807552 }, + { {{1979,05,28},{12,30,35}}, 296742635 }, + { {{1999,12,31},{23,59,59}}, 946684799 }, + { {{2000, 1, 1},{ 0, 0, 0}}, 946684800 }, + { {{2000, 1, 1},{ 0, 0, 1}}, 946684801 }, + + { {{2038, 1,19},{03,14,07}}, 2147483647 }, % Sint32 full - 1 + { {{2038, 1,19},{03,14,08}}, 2147483648 }, % Sint32 full + { {{2038, 1,19},{03,14,09}}, 2147483649 }, % Sint32 full + 1 + + { {{2106, 2, 7},{ 6,28,14}}, 4294967294 }, % Uint32 full 0xFFFFFFFF - 1 + { {{2106, 2, 7},{ 6,28,15}}, 4294967295 }, % Uint32 full 0xFFFFFFFF + { {{2106, 2, 7},{ 6,28,16}}, 4294967296 }, % Uint32 full 0xFFFFFFFF + 1 + { {{2012,12, 6},{16,28,08}}, 1354811288 }, + { {{2412,12, 6},{16,28,08}}, 13977592088 } + ]. + + %% The following dates should not be near the end or beginning of %% a month, because they will be used to test when the dates are %% different in UTC and local time. diff --git a/erts/emulator/test/trace_port_SUITE.erl b/erts/emulator/test/trace_port_SUITE.erl index 0026da4979..b0ce6f81db 100644 --- a/erts/emulator/test/trace_port_SUITE.erl +++ b/erts/emulator/test/trace_port_SUITE.erl @@ -77,7 +77,8 @@ end_per_testcase(_Func, Config) -> call_trace(doc) -> "Test sending call trace messages to a port."; call_trace(Config) when is_list(Config) -> - case test_server:is_native(?MODULE) of + case test_server:is_native(?MODULE) orelse + test_server:is_native(lists) of true -> {skip,"Native code"}; false -> @@ -128,7 +129,8 @@ bs_sum_c(<<>>, Acc) -> Acc. return_trace(doc) -> "Test the new return trace."; return_trace(Config) when is_list(Config) -> - case test_server:is_native(?MODULE) of + case test_server:is_native(?MODULE) orelse + test_server:is_native(lists) of true -> {skip,"Native code"}; false -> diff --git a/erts/emulator/test/trace_port_SUITE_data/echo_drv.c b/erts/emulator/test/trace_port_SUITE_data/echo_drv.c index 15c4ca11fe..a8d4ede4fe 100644 --- a/erts/emulator/test/trace_port_SUITE_data/echo_drv.c +++ b/erts/emulator/test/trace_port_SUITE_data/echo_drv.c @@ -25,12 +25,14 @@ static EchoDrvData echo_drv_data, *echo_drv_data_p; **/ static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command); -static void echo_drv_stop(EchoDrvData *data_p); -static void echo_drv_output(EchoDrvData *data_p, char *buf, int len); +static void echo_drv_stop(ErlDrvData drv_data); +static void echo_drv_output(ErlDrvData drv_data, char *buf, + ErlDrvSizeT len); static void echo_drv_finish(void); -static int echo_drv_control(EchoDrvData *data_p, unsigned int command, - char *buf, int len, - char **rbuf, int rlen); +static ErlDrvSSizeT echo_drv_control(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen); static ErlDrvEntry echo_drv_entry = { NULL, /* init */ @@ -45,11 +47,19 @@ static ErlDrvEntry echo_drv_entry = { echo_drv_control, NULL, /* timeout */ NULL, /* outputv */ - NULL /* ready_async */ + NULL, /* ready_async */ + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL }; - - /* ------------------------------------------------------------------------- ** Entry functions **/ @@ -75,7 +85,8 @@ static void echo_drv_stop(EchoDrvData *data_p) { echo_drv_data_p = NULL; } -static void echo_drv_output(EchoDrvData *data_p, char *buf, int len) { +static void echo_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) { + EchoDrvData* data_p = (EchoDrvData *) drv_data; driver_output(data_p->erlang_port, buf, len); switch (data_p->heavy) { case heavy_off: @@ -95,9 +106,11 @@ static void echo_drv_finish() { echo_drv_data_p = NULL; } -static int echo_drv_control(EchoDrvData *data_p, unsigned int command, - char *buf, int len, - char **rbuf, int rlen) { +static ErlDrvSSizeT echo_drv_control(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) { + EchoDrvData* data_p = (EchoDrvData *) drv_data; switch (command) { case 'h': data_p->heavy = heavy_set; diff --git a/erts/emulator/utils/make_preload b/erts/emulator/utils/make_preload index d22f08f993..13019d4062 100755 --- a/erts/emulator/utils/make_preload +++ b/erts/emulator/utils/make_preload @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2009. All Rights Reserved. +# Copyright Ericsson AB 1999-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -39,6 +39,7 @@ use File::Basename; my $gen_rc = 0; my $gen_old = 0; my $windres = 0; +my $msys = 0; my $file; my $progname = basename($0); @@ -49,6 +50,8 @@ while (@ARGV && $ARGV[0] =~ /^-(\w+)/) { $gen_rc = 1; } elsif ($opt eq '-windres') { $windres = 1; + } elsif ($opt eq '-msys') { + $msys = 1; } elsif ($opt eq '-old') { $gen_old = 1; } else { @@ -68,7 +71,12 @@ foreach $file (@ARGV) { unless $file =~ /\.beam$/; my $module = basename($file, ".beam"); if ($gen_rc) { - my ($win_file) = split("\n", `(cygpath -d $file 2>/dev/null || cygpath -w $file)`); + my $win_file; + if ($msys) { + ($win_file) = split("\n", `(msys2win_path.sh $file)`); + } else { + ($win_file) = split("\n", `(cygpath -d $file 2>/dev/null || cygpath -w $file)`); + } $win_file =~ s&\\&\\\\&g; print "$num ERLANG_CODE \"$win_file\"\n"; push(@modules, " ", -s $file, "L, $num, ", diff --git a/erts/emulator/valgrind/suppress.patched.3.6.0 b/erts/emulator/valgrind/suppress.patched.3.6.0 index 2647949672..8cf4cba2c8 100644 --- a/erts/emulator/valgrind/suppress.patched.3.6.0 +++ b/erts/emulator/valgrind/suppress.patched.3.6.0 @@ -305,3 +305,46 @@ fun:erl_init fun:erl_start fun:main } + +{ +Permanent cache aligned malloc for array of mseg allocators +Memcheck:Leak +PossiblyLost +fun:malloc +fun:erts_mseg_init +fun:erts_alloc_init +fun:early_init +fun:erl_start +fun:main +} + +{ +Early permanent cache aligned erl_process:aux_work_tmo +Memcheck:Leak +PossiblyLost +fun:malloc +fun:aux_work_timeout_early_init +fun:erts_early_init_scheduling +fun:early_init +fun:erl_start +fun:main +} + +{ +Early permanent cache aligned ts_event_pool +Memcheck:Leak +PossiblyLost +fun:malloc +fun:erts_sys_alloc +fun:erts_alloc_fnf +fun:ethr_std_alloc +fun:ts_event_pool +fun:init_ts_event_alloc +fun:ethr_late_init_common__ +fun:ethr_late_init +fun:erts_thr_late_init +fun:early_init +fun:erl_start +fun:main +} + diff --git a/erts/emulator/valgrind/suppress.standard b/erts/emulator/valgrind/suppress.standard index d759038c97..26e34e3757 100644 --- a/erts/emulator/valgrind/suppress.standard +++ b/erts/emulator/valgrind/suppress.standard @@ -266,3 +266,43 @@ fun:erl_init fun:erl_start fun:main } + +{ +Permanent cache aligned malloc for array of mseg allocators +Memcheck:Leak +fun:malloc +fun:erts_mseg_init +fun:erts_alloc_init +fun:early_init +fun:erl_start +fun:main +} + +{ +Early permanent cache aligned erl_process:aux_work_tmo +Memcheck:Leak +fun:malloc +fun:aux_work_timeout_early_init +fun:erts_early_init_scheduling +fun:early_init +fun:erl_start +fun:main +} + +{ +Early permanent cache aligned ts_event_pool +Memcheck:Leak +fun:malloc +fun:erts_sys_alloc +fun:erts_alloc_fnf +fun:ethr_std_alloc +fun:ts_event_pool +fun:init_ts_event_alloc +fun:ethr_late_init_common__ +fun:ethr_late_init +fun:erts_thr_late_init +fun:early_init +fun:erl_start +fun:main +} + diff --git a/erts/emulator/zlib/Makefile.in b/erts/emulator/zlib/Makefile.in deleted file mode 100644 index b44a87551d..0000000000 --- a/erts/emulator/zlib/Makefile.in +++ /dev/null @@ -1,102 +0,0 @@ -# Makefile for zlib -# Copyright (C) 1995-1996 Jean-loup Gailly. -# For conditions of distribution and use, see copyright notice in zlib.h - -# %ExternalCopyright% - -# To compile and test, type: -# ./configure; make test -# The call of configure is optional if you don't have special requirements - -# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: -# make install -# To install in $HOME instead of /usr/local, use: -# make install prefix=$HOME - -ARFLAGS = rc -CFLAGS = $(subst -O2, -O3, @CFLAGS@ @DEFS@ @EMU_THR_DEFS@) -#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 -#CFLAGS=-g -DDEBUG -#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ -# -Wstrict-prototypes -Wmissing-prototypes - -VER=1.0.4 - -O = adler32.o compress.o crc32.o uncompr.o deflate.o trees.o \ - zutil.o inflate.o inftrees.o inffast.o -OBJS = $(O:%=$(OBJDIR)/%) - - -#### Begin OTP targets - -include $(ERL_TOP)/make/target.mk - -ifeq ($(TYPE),gcov) -CFLAGS = -O0 -fprofile-arcs -ftest-coverage @DEBUG_CFLAGS@ @DEFS@ @EMU_THR_DEFS@ -else # gcov -ifeq ($(TYPE),debug) -CFLAGS = @DEBUG_CFLAGS@ @DEFS@ @EMU_THR_DEFS@ -endif # debug -endif # gcov - -# On windows we *need* a separate zlib during debug build -OBJDIR= $(ERL_TOP)/erts/emulator/zlib/obj/$(TARGET)/$(TYPE) - -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -ifeq ($(TARGET), win32) -LIBRARY=$(OBJDIR)/z.lib -else -LIBRARY=$(OBJDIR)/libz.a -endif - -all: $(LIBRARY) - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: opt - -tests release_tests: - -docs release_docs release_docs_spec: - -clean: - rm -f $(OBJS) $(OBJDIR)/libz.a - -#### end OTP targets - -ifeq ($(TARGET), win32) -$(LIBRARY): $(OBJS) - $(AR) -out:$@ $(OBJS) -else -$(LIBRARY): $(OBJS) - $(AR) $(ARFLAGS) $@ $(OBJS) - -@ ($(RANLIB) $@ || true) 2>/dev/null -endif - -$(OBJDIR)/%.o: %.c - $(CC) -c $(CFLAGS) -o $@ $< - -# DO NOT DELETE THIS LINE -- make depend depends on it. - -adler32.o: zlib.h zconf.h -compress.o: zlib.h zconf.h -crc32.o: zlib.h zconf.h -deflate.o: deflate.h zutil.h zlib.h zconf.h -example.o: zlib.h zconf.h -gzio.o: zutil.h zlib.h zconf.h -infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h -infcodes.o: zutil.h zlib.h zconf.h -infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h -inffast.o: zutil.h zlib.h zconf.h inftrees.h -inffast.o: infblock.h infcodes.h infutil.h inffast.h -inflate.o: zutil.h zlib.h zconf.h infblock.h -inftrees.o: zutil.h zlib.h zconf.h inftrees.h -infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h -minigzip.o: zlib.h zconf.h -trees.o: deflate.h zutil.h zlib.h zconf.h -uncompr.o: zlib.h zconf.h -zutil.o: zutil.h zlib.h zconf.h diff --git a/erts/emulator/zlib/zlib.mk b/erts/emulator/zlib/zlib.mk new file mode 100644 index 0000000000..fa1f159fae --- /dev/null +++ b/erts/emulator/zlib/zlib.mk @@ -0,0 +1,74 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode +# ---------------------------------------------------- +# Make include file for zlib +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2011-2012. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# ---------------------------------------------------- +# Copyright for zlib itself see copyright notice in zlib.h + +ZLIB_FILES = \ + adler32 \ + compress \ + crc32 \ + uncompr \ + deflate \ + trees \ + zutil \ + inflate \ + inftrees \ + inffast + +# On windows we *need* a separate zlib during debug build +ZLIB_OBJDIR = $(ERL_TOP)/erts/emulator/zlib/obj/$(TARGET)/$(TYPE) + +ZLIB_OBJS = $(ZLIB_FILES:%=$(ZLIB_OBJDIR)/%.o) +ZLIB_SRC = $(ZLIB_FILES:%=zlib/%.c) + +ifeq ($(TARGET), win32) +ZLIB_LIBRARY = $(ZLIB_OBJDIR)/z.lib +else +ZLIB_LIBRARY = $(ZLIB_OBJDIR)/libz.a +endif + + +ifeq ($(TYPE),gcov) +ZLIB_CFLAGS = -O0 -fprofile-arcs -ftest-coverage $(DEBUG_CFLAGS) $(DEFS) $(THR_DEFS) +else # gcov +ifeq ($(TYPE),debug) +ZLIB_CFLAGS = $(DEBUG_CFLAGS) $(DEFS) $(THR_DEFS) +else # debug +ZLIB_CFLAGS = $(subst -O2, -O3, $(CONFIGURE_CFLAGS) $(DEFS) $(THR_DEFS)) +#ZLIB_CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#ZLIB_CFLAGS=-g -DDEBUG +#ZLIB_CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes +endif # debug +endif # gcov + +ifeq ($(TARGET), win32) +$(ZLIB_LIBRARY): $(ZLIB_OBJS) + $(AR) -out:$@ $(ZLIB_OBJS) +else +$(ZLIB_LIBRARY): $(ZLIB_OBJS) + $(AR) $(ARFLAGS) $@ $(ZLIB_OBJS) + -@ ($(RANLIB) $@ || true) 2>/dev/null +endif + +$(ZLIB_OBJDIR)/%.o: zlib/%.c + $(CC) -c $(ZLIB_CFLAGS) -o $@ $< diff --git a/erts/epmd/src/Makefile.in b/erts/epmd/src/Makefile.in index 2f5296a5e8..5767edc346 100644 --- a/erts/epmd/src/Makefile.in +++ b/erts/epmd/src/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1998-2010. All Rights Reserved. +# Copyright Ericsson AB 1998-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -24,6 +24,7 @@ PURIFY = TYPEMARKER = .debug TYPE_FLAGS = -DDEBUG @DEBUG_FLAGS@ else + ifeq ($(TYPE),purify) PURIFY = purify TYPEMARKER = @@ -33,6 +34,8 @@ else TYPE_FLAGS = -O2 -DPURIFY endif else + +override TYPE = opt PURIFY = TYPEMARKER = ifeq ($(findstring ose,$(TARGET)),ose) @@ -65,6 +68,8 @@ ERTS_INTERNAL_LIBS=-L../../lib/internal/$(TARGET) -lerts_internal$(ERTS_LIB_TYPE endif endif +ERTS_LIB = $(ERL_TOP)/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE + CC = @CC@ WFLAGS = @WFLAGS@ CFLAGS = @CFLAGS@ @DEFS@ $(TYPE_FLAGS) $(WFLAGS) $(ERTS_INCL) @@ -106,7 +111,7 @@ EPMD_OBJS = $(OBJDIR)/epmd.o \ #--------------------------------- -all: erts_lib $(BINDIR)/$(EPMD) +all: $(BINDIR)/$(EPMD) docs: @@ -122,13 +127,13 @@ clean: # Objects & executables # -$(BINDIR)/$(EPMD): $(EPMD_OBJS) +$(BINDIR)/$(EPMD): $(EPMD_OBJS) $(ERTS_LIB) $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(EPMD_OBJS) $(LIBS) $(OBJDIR)/%.o: %.c epmd.h epmd_int.h $(CC) $(CFLAGS) $(EPMD_FLAGS) -o $@ -c $< -erts_lib: +$(ERTS_LIB): cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE) include $(ERL_TOP)/make/otp_release_targets.mk @@ -139,4 +144,3 @@ release_spec: all release_docs_spec: - diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in index 4754328c0b..28c5e5ccad 100644 --- a/erts/etc/common/Makefile.in +++ b/erts/etc/common/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2010. All Rights Reserved. +# Copyright Ericsson AB 1996-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -22,13 +22,14 @@ include $(ERL_TOP)/make/target.mk ERTS_LIB_TYPEMARKER=.$(TYPE) USING_MINGW=@MIXED_CYGWIN_MINGW@ -USING_VC=@MIXED_CYGWIN_VC@ +USING_VC=@MIXED_VC@ ifeq ($(TYPE),debug) PURIFY = TYPEMARKER = .debug TYPE_FLAGS = -DDEBUG @DEBUG_FLAGS@ else + ifeq ($(TYPE),purify) PURIFY = purify TYPEMARKER = @@ -38,6 +39,8 @@ else TYPE_FLAGS = -g -O2 -DPURIFY endif else + +override TYPE=opt PURIFY = TYPEMARKER = ERTS_LIB_TYPEMARKER= @@ -101,6 +104,8 @@ else ERTS_INTERNAL_LIBS=-L../../lib/internal/$(TARGET) -lerts_internal$(ERTS_LIB_TYPEMARKER) @ERTS_INTERNAL_X_LIBS@ -lm endif +ERTS_LIB = $(ERL_TOP)/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE + # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -161,9 +166,8 @@ ERLSRV_OBJECTS= \ $(OBJDIR)/erlsrv_main.o \ $(OBJDIR)/erlsrv_util.o \ $(OBJDIR)/erlsrv_logmess.res -MC_OUTPUTS= \ - $(OBJDIR)/erlsrv_logmess.h $(OBJDIR)/erlsrv_logmess.rc - MT_FLAG="-MT" +MC_OUTPUTS=$(OBJDIR)/erlsrv_logmess.h $(OBJDIR)/erlsrv_logmess.rc +MT_FLAG="-MT" else ERLRES_OBJ=erl_res.o ERLSRV_OBJECTS= \ @@ -173,9 +177,8 @@ ERLSRV_OBJECTS= \ $(OBJDIR)/erlsrv_main.o \ $(OBJDIR)/erlsrv_util.o \ $(OBJDIR)/erlsrv_logmess.o -MC_OUTPUTS= \ - $(OBJDIR)/erlsrv_logmess.h $(OBJDIR)/erlsrv_logmess.res - MT_FLAG="-MD" +MC_OUTPUTS=$(OBJDIR)/erlsrv_logmess.h $(OBJDIR)/erlsrv_logmess.res +MT_FLAG="-MD" endif INET_GETHOST = $(BINDIR)/inet_gethost.exe INSTALL_EMBEDDED_PROGS += $(BINDIR)/typer.exe $(BINDIR)/dialyzer.exe $(BINDIR)/erlc.exe $(BINDIR)/start_erl.exe $(BINDIR)/escript.exe $(BINDIR)/ct_run.exe @@ -232,14 +235,17 @@ endif endif endif -etc: erts_lib $(ENTRY_OBJ) $(INSTALL_PROGS) $(INSTALL_LIBS) $(TEXTFILES) $(INSTALL_TOP_BIN) +.PHONY: etc +etc: $(ENTRY_OBJ) $(INSTALL_PROGS) $(INSTALL_LIBS) $(TEXTFILES) $(INSTALL_TOP_BIN) # erlexec needs the erts_internal library... -erts_lib: +$(ERTS_LIB): cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE) +.PHONY: docs docs: +.PHONY: clean clean: ifneq ($(INSTALL_PROGS),) rm -f $(INSTALL_PROGS) @@ -278,85 +284,9 @@ endif rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/vxcall.o rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/erl.o rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/werl.o + rm -f $(TEXTFILES) rm -f *~ core -# -# Objects & executables -# -#$(OBJDIR)/%.o: %.c -# $(CC) $(CFLAGS) -o $@ -c $< -# -#$(OBJDIR)/%.o: ../unix/%.c -# $(CC) $(CFLAGS) -o $@ -c $< -# -#$(BINDIR)/%: $(OBJDIR)/%.o -# $(PURIFY) $(LD) $(LDFLAGS) -o $@ $< $(LIBS) - -$(OBJDIR)/inet_gethost.o: inet_gethost.c - $(CC) $(CFLAGS) -o $@ -c inet_gethost.c - -$(BINDIR)/inet_gethost@EXEEXT@: $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) - $(PURIFY) $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(LIBS) $(ERTS_INTERNAL_LIBS) - -$(BINDIR)/run_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o - $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(LIBS) - -$(OBJDIR)/run_erl.o: ../unix/run_erl.c - $(CC) $(CFLAGS) -o $@ -c ../unix/run_erl.c - -$(BINDIR)/to_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o - $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o - -$(OBJDIR)/to_erl.o: ../unix/to_erl.c - $(CC) $(CFLAGS) -o $@ -c ../unix/to_erl.c - -$(BINDIR)/dyn_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o - $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o - -$(OBJDIR)/dyn_erl.o: ../unix/dyn_erl.c - $(CC) $(CFLAGS) -o $@ -c ../unix/dyn_erl.c - -$(OBJDIR)/safe_string.o: ../unix/safe_string.c - $(CC) $(CFLAGS) -o $@ -c ../unix/safe_string.c - -ifneq ($(TARGET),win32) -$(BINDIR)/$(ERLEXEC): $(OBJDIR)/$(ERLEXEC).o - $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/$(ERLEXEC).o $(ERTS_INTERNAL_LIBS) - -$(OBJDIR)/$(ERLEXEC).o: $(ERLEXECDIR)/$(ERLEXEC).c - $(CC) -I$(EMUDIR) $(CFLAGS) -o $@ -c $(ERLEXECDIR)/$(ERLEXEC).c -endif -$(BINDIR)/erlc@EXEEXT@: $(OBJDIR)/erlc.o - $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/erlc.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) - -$(OBJDIR)/erlc.o: erlc.c - $(CC) $(CFLAGS) -o $@ -c erlc.c - -$(BINDIR)/dialyzer@EXEEXT@: $(OBJDIR)/dialyzer.o - $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/dialyzer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) - -$(OBJDIR)/dialyzer.o: dialyzer.c - $(CC) $(CFLAGS) -o $@ -c dialyzer.c - -$(BINDIR)/typer@EXEEXT@: $(OBJDIR)/typer.o - $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/typer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) - -$(OBJDIR)/typer.o: typer.c - $(CC) $(CFLAGS) -o $@ -c typer.c - -$(BINDIR)/escript@EXEEXT@: $(OBJDIR)/escript.o - $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/escript.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) - -$(OBJDIR)/escript.o: escript.c - $(CC) $(CFLAGS) -o $@ -c escript.c - -$(BINDIR)/ct_run@EXEEXT@: $(OBJDIR)/ct_run.o - $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/ct_run.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) - -$(OBJDIR)/ct_run.o: ct_run.c - $(CC) $(CFLAGS) -o $@ -c ct_run.c - - #------------------------------------------------------------------------ # Windows specific targets # The windows platform is quite different from the others. erl/werl are small C programs @@ -367,7 +297,7 @@ $(OBJDIR)/ct_run.o: ct_run.c ifeq ($(TARGET),win32) -$(BINDIR)/$(ERLEXEC): $(OBJDIR)/erlexec.o $(OBJDIR)/win_erlexec.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) +$(BINDIR)/$(ERLEXEC): $(OBJDIR)/erlexec.o $(OBJDIR)/win_erlexec.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) $(ERTS_LIB) $(LD) -dll $(LDFLAGS) -o $@ $(OBJDIR)/erlexec.o $(OBJDIR)/win_erlexec.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) $(ERTS_INTERNAL_LIBS) $(BINDIR)/erl@EXEEXT@: $(OBJDIR)/erl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) @@ -382,58 +312,75 @@ $(BINDIR)/start_erl@EXEEXT@: $(OBJDIR)/start_erl.o $(BINDIR)/Install@EXEEXT@: $(OBJDIR)/Install.o $(OBJDIR)/init_file.o $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/Install.o $(OBJDIR)/init_file.o +# The service expects to be compiled with $(MT_FLAG) flag. $(BINDIR)/erlsrv@EXEEXT@: $(ERLSRV_OBJECTS) $(LD) $(LDFLAGS) $(MT_FLAG) -o $@ $(ERLSRV_OBJECTS) -# The service expects to be compiled with $(MT_FLAG) flag. - -$(OBJDIR)/%.o: $(WINETC)/erlsrv/%.c $(ERLSRV_HEADERS) - $(CC) $(CFLAGS) $(MT_FLAG) -o $@ -c $< - -$(OBJDIR)/erlsrv_util.o: $(WINETC)/erlsrv/erlsrv_util.c $(ERLSRV_HEADERS) \ -$(OBJDIR)/erlsrv_logmess.h - $(CC) $(CFLAGS) -I$(OBJDIR) $(MT_FLAG) -o $@ -c $< +# To fix a spooky parallel make build problem on Windows there are some +# false dependencies on the $(MC), $(RC) and .o rules. The theory behind +# is that the $(MC) and/or $(RC) compilers seems to temporarily create and +# destroy a toplevel file vc100.pdb that simultaneous ordinary compilations +# (that have been by flags explicitly ordered to not use .pdb files) +# gets upset when that file vanishes from under their feet. +# +# The false dependencies are targeted to make make (pun intended) run +# the $(MC) and $(RC) compilations to completion before all others. + +LOGMESS_GENERATED = $(OBJDIR)/LOGMESS-GENERATED +$(MC_OUTPUTS): $(LOGMESS_GENERATED) +$(LOGMESS_GENERATED): $(WINETC)/erlsrv/erlsrv_logmess.mc + $(MC) -o $(OBJDIR) $(WINETC)/erlsrv/erlsrv_logmess.mc && \ + echo $? >$(LOGMESS_GENERATED) + +$(OBJDIR)/$(ERLRES_OBJ): $(WINETC)/erl.rc $(WINETC)/erlang.ico \ + $(WINETC)/erl_icon.ico $(WINETC)/hrl_icon.ico \ + $(WINETC)/beam_icon.ico $(LOGMESS_GENERATED) + $(RC) -o $@ -I$(WINETC) $(WINETC)/erl.rc ifeq ($(USING_VC), yes) -$(OBJDIR)/erlsrv_logmess.res: $(OBJDIR)/erlsrv_logmess.rc +RC_GENERATED = $(OBJDIR)/erlsrv_logmess.res +$(RC_GENERATED): $(OBJDIR)/erlsrv_logmess.rc $(OBJDIR)/$(ERLRES_OBJ) $(RC) -o $(OBJDIR)/erlsrv_logmess.res -I$(OBJDIR) $(OBJDIR)/erlsrv_logmess.rc else -$(OBJDIR)/erlsrv_logmess.o: $(OBJDIR)/erlsrv_logmess.res +RC_GENERATED = $(OBJDIR)/erlsrv_logmess.o +$(RC_GENERATED): $(OBJDIR)/erlsrv_logmess.res $(OBJDIR)/$(ERLRES_OBJ) $(RC) -o $(OBJDIR)/erlsrv_logmess.o -I$(OBJDIR) $(OBJDIR)/erlsrv_logmess.res endif -$(MC_OUTPUTS): $(WINETC)/erlsrv/erlsrv_logmess.mc - $(MC) -o $(OBJDIR) $(WINETC)/erlsrv/erlsrv_logmess.mc +# The service expects to be compiled with $(MT_FLAG) flag. +$(OBJDIR)/%.o: $(WINETC)/erlsrv/%.c $(ERLSRV_HEADERS) $(RC_GENERATED) + $(CC) $(CFLAGS) $(MT_FLAG) -o $@ -c $< -$(OBJDIR)/werl.o: $(WINETC)/erl.c +$(OBJDIR)/erlsrv_util.o: $(WINETC)/erlsrv/erlsrv_util.c $(ERLSRV_HEADERS) \ + $(OBJDIR)/erlsrv_logmess.h $(RC_GENERATED) + $(CC) $(CFLAGS) -I$(OBJDIR) $(MT_FLAG) -o $@ -c $< + +$(OBJDIR)/werl.o: $(WINETC)/erl.c $(WINETC)/init_file.h $(RC_GENERATED) $(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \ -DWIN32_WERL -o $@ -c $(WINETC)/erl.c -$(OBJDIR)/erl.o: $(WINETC)/erl.c +$(OBJDIR)/erl.o: $(WINETC)/erl.c $(WINETC)/init_file.h $(RC_GENERATED) $(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \ -o $@ -c $(WINETC)/erl.c -$(OBJDIR)/erlexec.o: $(ERLEXECDIR)/erlexec.c +$(OBJDIR)/erlexec.o: $(ERLEXECDIR)/erlexec.c $(RC_GENERATED) $(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \ -o $@ -c $(ERLEXECDIR)/erlexec.c -$(OBJDIR)/win_erlexec.o: $(WINETC)/win_erlexec.c +$(OBJDIR)/win_erlexec.o: $(WINETC)/win_erlexec.c $(RC_GENERATED) $(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \ -o $@ -c $(WINETC)/win_erlexec.c -$(OBJDIR)/init_file.o: $(WINETC)/init_file.c $(WINETC)/init_file.h +$(OBJDIR)/init_file.o: $(WINETC)/init_file.c $(WINETC)/init_file.h $(RC_GENERATED) $(CC) $(CFLAGS) -o $@ -c $(WINETC)/init_file.c -$(OBJDIR)/Install.o: $(WINETC)/Install.c $(WINETC)/init_file.h +$(OBJDIR)/Install.o: $(WINETC)/Install.c $(WINETC)/init_file.h $(RC_GENERATED) $(CC) $(CFLAGS) -o $@ -c $(WINETC)/Install.c -$(OBJDIR)/$(ERLRES_OBJ): $(WINETC)/erl.rc $(WINETC)/erlang.ico $(WINETC)/erl_icon.ico $(WINETC)/hrl_icon.ico $(WINETC)/beam_icon.ico - $(RC) -o $@ -I$(WINETC) $(WINETC)/erl.rc - -$(OBJDIR)/start_erl.o: $(WINETC)/start_erl.c +$(OBJDIR)/start_erl.o: $(WINETC)/start_erl.c $(RC_GENERATED) $(CC) $(CFLAGS) -o $@ -c $(WINETC)/start_erl.c -$(ENTRY_OBJ): $(ENTRY_SRC) +$(ENTRY_OBJ): $(ENTRY_SRC) $(RC_GENERATED) $(CC) $(CFLAGS) -o $@ -c $(ENTRY_SRC) Install.ini: ../$(TARGET)/Install.src ../../vsn.mk $(TARGET)/Makefile @@ -442,6 +389,8 @@ Install.ini: ../$(TARGET)/Install.src ../../vsn.mk $(TARGET)/Makefile ../$(TARGET)/Install.src > Install.ini +else +RC_GENERATED = endif #--------------------------------------------------------- # End of windows specific targets. @@ -469,7 +418,7 @@ $(BINDIR)/heart@EXEEXT@: $(OBJDIR)/heart.o $(ENTRY_OBJ) $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/heart.o \ $(ENTRY_OBJ) $(WINDSOCK) -$(OBJDIR)/heart.o: heart.c +$(OBJDIR)/heart.o: heart.c $(RC_GENERATED) $(CC) $(CFLAGS) -o $@ -c heart.c endif @@ -497,6 +446,84 @@ $(OBJDIR)/vxcall.o: $(VXETC)/vxcall.c +# +# Objects & executables +# +#$(OBJDIR)/%.o: %.c +# $(CC) $(CFLAGS) -o $@ -c $< +# +#$(OBJDIR)/%.o: ../unix/%.c +# $(CC) $(CFLAGS) -o $@ -c $< +# +#$(BINDIR)/%: $(OBJDIR)/%.o +# $(PURIFY) $(LD) $(LDFLAGS) -o $@ $< $(LIBS) + +$(OBJDIR)/inet_gethost.o: inet_gethost.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c inet_gethost.c + +$(BINDIR)/inet_gethost@EXEEXT@: $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(LIBS) $(ERTS_INTERNAL_LIBS) + +$(BINDIR)/run_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o + $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(LIBS) + +$(OBJDIR)/run_erl.o: ../unix/run_erl.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c ../unix/run_erl.c + +$(BINDIR)/to_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o + $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o + +$(OBJDIR)/to_erl.o: ../unix/to_erl.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c ../unix/to_erl.c + +$(BINDIR)/dyn_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o + $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o + +$(OBJDIR)/dyn_erl.o: ../unix/dyn_erl.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c ../unix/dyn_erl.c + +$(OBJDIR)/safe_string.o: ../unix/safe_string.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c ../unix/safe_string.c + +ifneq ($(TARGET),win32) +$(BINDIR)/$(ERLEXEC): $(OBJDIR)/$(ERLEXEC).o $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/$(ERLEXEC).o $(ERTS_INTERNAL_LIBS) + +$(OBJDIR)/$(ERLEXEC).o: $(ERLEXECDIR)/$(ERLEXEC).c $(RC_GENERATED) + $(CC) -I$(EMUDIR) $(CFLAGS) -o $@ -c $(ERLEXECDIR)/$(ERLEXEC).c +endif +$(BINDIR)/erlc@EXEEXT@: $(OBJDIR)/erlc.o $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/erlc.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) + +$(OBJDIR)/erlc.o: erlc.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c erlc.c + +$(BINDIR)/dialyzer@EXEEXT@: $(OBJDIR)/dialyzer.o $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/dialyzer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) + +$(OBJDIR)/dialyzer.o: dialyzer.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c dialyzer.c + +$(BINDIR)/typer@EXEEXT@: $(OBJDIR)/typer.o $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/typer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) + +$(OBJDIR)/typer.o: typer.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c typer.c + +$(BINDIR)/escript@EXEEXT@: $(OBJDIR)/escript.o $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/escript.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) + +$(OBJDIR)/escript.o: escript.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c escript.c + +$(BINDIR)/ct_run@EXEEXT@: $(OBJDIR)/ct_run.o $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/ct_run.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) + +$(OBJDIR)/ct_run.o: ct_run.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c ct_run.c + + + Install: ../unix/Install.src ../../vsn.mk $(TARGET)/Makefile sed -e 's;%I_VSN%;$(VSN);' \ -e 's;%EMULATOR%;$(EMULATOR);' \ @@ -515,6 +542,7 @@ erl.src: ../unix/erl.src.src ../../vsn.mk $(TARGET)/Makefile # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk +.PHONY: release_spec release_spec: etc ifneq ($(INSTALL_OBJS),) $(INSTALL_DIR) $(RELEASE_PATH)/erts-$(VSN)/obj @@ -561,9 +589,5 @@ ifneq ($(INSTALL_INCLUDES),) $(INSTALL_DATA) $(INSTALL_INCLUDES) $(RELEASE_PATH)/erts-$(VSN)/include endif +.PHONY: release_docs_spec release_docs_spec: - - - - - diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c index 7a5746e630..fae4d870cc 100644 --- a/erts/etc/common/heart.c +++ b/erts/etc/common/heart.c @@ -685,14 +685,16 @@ do_terminate(reason) print_error("Would reboot. Terminating."); else { kill_old_erlang(); - system(command); + /* suppress gcc warning with 'if' */ + if(system(command)); print_error("Executed \"%s\". Terminating.",command); } free_env_val(command); } else { kill_old_erlang(); - system((char*)&cmd[0]); + /* suppress gcc warning with 'if' */ + if(system((char*)&cmd[0])); print_error("Executed \"%s\". Terminating.",cmd); } } diff --git a/erts/etc/common/inet_gethost.c b/erts/etc/common/inet_gethost.c index 77bfd5e2bc..d25d2910b4 100644 --- a/erts/etc/common/inet_gethost.c +++ b/erts/etc/common/inet_gethost.c @@ -1141,14 +1141,12 @@ static Worker *pick_worker(void) static Worker *pick_worker_greedy(AddrByte *domainbuff) { int i; - int ql = 0; int found = -1; for (i=0; i < num_busy_workers; ++i) { if (domaineq(busy_workers[i].domain, domainbuff)) { if ((found < 0) || (busy_workers[i].que_size < busy_workers[found].que_size)) { found = i; - ql = busy_workers[i].que_size; } } } @@ -1945,12 +1943,14 @@ static int worker_loop(void) } m = NULL; #else - write(1, reply, data_size); /* No signals expected */ + /* expect no signals */ + if (write(1, reply, data_size) < 0) + goto fail; #endif } /* for (;;) */ -#ifdef WIN32 fail: +#ifdef WIN32 if (m != NULL) { FREE(m); } @@ -1959,8 +1959,8 @@ static int worker_loop(void) if (reply) { FREE(reply); } - return 1; #endif + return 1; } static int map_netdb_error(int netdb_code) @@ -2561,7 +2561,8 @@ static void debugf(char *format, ...) WriteFile(debug_console_allocated,buff,strlen(buff),&res,NULL); } #else - write(2,buff,strlen(buff)); + /* suppress warning with 'if' */ + if(write(2,buff,strlen(buff))); #endif va_end(ap); } @@ -2583,7 +2584,8 @@ static void warning(char *format, ...) WriteFile(GetStdHandle(STD_ERROR_HANDLE),buff,strlen(buff),&res,NULL); } #else - write(2,buff,strlen(buff)); + /* suppress warning with 'if' */ + if(write(2,buff,strlen(buff))); #endif va_end(ap); } @@ -2605,7 +2607,8 @@ static void fatal(char *format, ...) WriteFile(GetStdHandle(STD_ERROR_HANDLE),buff,strlen(buff),&res,NULL); } #else - write(2,buff,strlen(buff)); + /* suppress warning with 'if' */ + if(write(2,buff,strlen(buff))); #endif va_end(ap); #ifndef WIN32 diff --git a/erts/etc/unix/etp-commands b/erts/etc/unix/etp-commands index 6a01e0b7e0..79e5d6b1d8 100644 --- a/erts/etc/unix/etp-commands +++ b/erts/etc/unix/etp-commands @@ -1883,6 +1883,28 @@ document etp-ets-tables %--------------------------------------------------------------------------- end +define etp-ets-obj +# Args: DbTerm* +# + set $etp_ets_obj_i = 1 + while $etp_ets_obj_i <= (($arg0)->tpl[0] >> 6) + if $etp_ets_obj_i == 1 + printf "{" + else + printf ", " + end + set $etp_ets_elem = ($arg0)->tpl[$etp_ets_obj_i] + if ($etp_ets_elem & 3) == 0 + printf "<compressed>" + else + etp-1 $etp_ets_elem 0 + end + set $etp_ets_obj_i++ + end + printf "}" +end + + define etp-ets-tabledump # Args: int tableindex # @@ -1896,10 +1918,10 @@ define etp-ets-tabledump if $etp_ets_tabledump_t->common.status & 0x130 # Hash table set $etp_ets_tabledump_h = $etp_ets_tabledump_t->hash - printf "%% nitems=%d\n", $etp_ets_tabledump_t->common.nitems - while $etp_ets_tabledump_i < $etp_ets_tabledump_h->nactive - set $etp_ets_tabledump_l = $etp_ets_tabledump_h->seg \ - [$etp_ets_tabledump_i>>8][$etp_ets_tabledump_i&0xFF] + printf "%% nitems=%d\n", (long) $etp_ets_tabledump_t->common.nitems + while $etp_ets_tabledump_i < (long) $etp_ets_tabledump_h->nactive + set $etp_ets_tabledump_seg = ((struct segment**)$etp_ets_tabledump_h->segtab)[$etp_ets_tabledump_i>>8] + set $etp_ets_tabledump_l = $etp_ets_tabledump_seg->buckets[$etp_ets_tabledump_i&0xFF] if $etp_ets_tabledump_l printf "%% Slot %d:\n", $etp_ets_tabledump_i while $etp_ets_tabledump_l @@ -1909,7 +1931,7 @@ define etp-ets-tabledump printf "[" end set $etp_ets_tabledump_n++ - etp-1 ((Eterm)($etp_ets_tabledump_l->dbterm.tpl)|0x2) 0 + etp-ets-obj &($etp_ets_tabledump_l->dbterm) if $etp_ets_tabledump_l->hvalue == ((unsigned long)-1) printf "% *\n" else diff --git a/erts/etc/unix/to_erl.c b/erts/etc/unix/to_erl.c index 11fa3ff4cc..67274e67ed 100644 --- a/erts/etc/unix/to_erl.c +++ b/erts/etc/unix/to_erl.c @@ -352,7 +352,10 @@ int main(int argc, char **argv) * to trigger the version handshaking between to_erl and run_erl * at the start of every new to_erl-session. */ - write(wfd, "\022", 1); + + if (write(wfd, "\022", 1) < 0) { + fprintf(stderr, "Error in writing ^R to FIFO.\n"); + } /* * read and write @@ -412,7 +415,7 @@ int main(int argc, char **argv) if (len) { #ifdef DEBUG - write(1, buf, len); + if(write(1, buf, len)); #endif if (write_all(wfd, buf, len) != len) { fprintf(stderr, "Error in writing to FIFO.\n"); diff --git a/erts/etc/win32/cygwin_tools/vc/emu_cc.sh b/erts/etc/win32/cygwin_tools/vc/emu_cc.sh index c74c35111b..6c179aed00 100755 --- a/erts/etc/win32/cygwin_tools/vc/emu_cc.sh +++ b/erts/etc/win32/cygwin_tools/vc/emu_cc.sh @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2002-2009. All Rights Reserved. +# Copyright Ericsson AB 2002-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -17,6 +17,11 @@ # # %CopyrightEnd% # +if [ X"$CONFIG_SUBTYPE" = X"win64" ]; then + GCC="x86_64-w64-mingw32-gcc.exe" +else + GCC="gcc" +fi TOOLDIR=$ERL_TOP/erts/etc/win32/cygwin_tools/vc COFFIX=$TOOLDIR/coffix WTOOLDIR=`(cygpath -d $TOOLDIR 2>/dev/null || cygpath -w $TOOLDIR)` @@ -71,7 +76,7 @@ if [ $SKIP_COFFIX = false ]; then if [ "X$EMU_CC_SH_DEBUG_LOG" != "X" ]; then echo "gcc -o $TEMPFILE -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer $CMD" >> $EMU_CC_SH_DEBUG_LOG 2>&1 fi - eval gcc -o $TEMPFILE -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer $CMD + eval $GCC -o $TEMPFILE -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer $CMD RES=$? if [ $RES = 0 ]; then $COFFIX.exe -e `(cygpath -d $TEMPFILE 2>/dev/null || cygpath -w $TEMPFILE)` @@ -85,6 +90,6 @@ if [ $SKIP_COFFIX = false ]; then rm -f $TEMPFILE exit $RES else - eval gcc -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer -fno-tree-copyrename $CMD 2>/dev/null + eval $GCC -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer -fno-tree-copyrename $CMD 2>/dev/null exit $? fi diff --git a/erts/etc/win32/msys_tools/erl b/erts/etc/win32/msys_tools/erl new file mode 100644 index 0000000000..525253fd84 --- /dev/null +++ b/erts/etc/win32/msys_tools/erl @@ -0,0 +1,42 @@ +#! /bin/sh +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Note! This shellscript expects to be run in a cygwin environment, +# it converts erlc command lines to native windows erlc commands, which +# basically means running the command cygpath on whatever is a path... + +CMD="" +for x in "$@"; do + case "$x" in + -I/*|-o/*) + y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`; + z=`echo $x | sed 's,^-\([Io]\)\(/.*\),\1,g'`; + MPATH=`msys2win_path.sh -m $y`; + CMD="$CMD -$z\"$MPATH\"";; + /*) + MPATH=`msys2win_path.sh -m $x`; + CMD="$CMD \"$MPATH\"";; + *) + y=`echo $x | sed 's,",\\\",g'`; + CMD="$CMD \"$y\"";; + esac +done +ERL_TOP=`msys2win_path.sh -m $ERL_TOP` +export ERL_TOP +eval erl.exe $CMD diff --git a/erts/etc/win32/msys_tools/erlc b/erts/etc/win32/msys_tools/erlc new file mode 100644 index 0000000000..3f53ef7f4f --- /dev/null +++ b/erts/etc/win32/msys_tools/erlc @@ -0,0 +1,59 @@ +#! /bin/sh +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + + +CMD="" +ECHO_ONLY=false +for x in "$@"; do + case "$x" in + --echo_only) + ECHO_ONLY=true;; + -I/*|-o/*) + y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`; + z=`echo $x | sed 's,^-\([Io]\)\(/.*\),\1,g'`; + MPATH=`msys2win_path.sh -m $y`; + CMD="$CMD -$z$MPATH";; + -pa/*) + y=`echo $x | sed 's,^-pa\(/.*\),\1,g'`; + MPATH=`msys2win_path.sh -m $y`; + CMD="$CMD -pa $MPATH";; + /*) + MPATH=`msys2win_path.sh -m $x`; + CMD="$CMD \"$MPATH\"";; +# Needed for +'{preproc_flags,whatever}' + +{preproc_flags,*}) + y=`echo $x | sed 's,^+{preproc_flags\,"\(.*\)"},\1,g'`; + z=`eval $0 --echo_only $y`; + case "$z" in # Dont "doubledoublequote" + \"*\") + CMD="$CMD +'{preproc_flags,$z}'";; + *) + CMD="$CMD +'{preproc_flags,\"$z\"}'";; + esac;; + *) + y=`echo $x | sed 's,",\\\",g'`; + CMD="$CMD \"$y\"";; + esac +done +if [ $ECHO_ONLY = true ]; then + echo $CMD +else + eval erlc.exe $CMD +fi diff --git a/erts/etc/win32/msys_tools/javac.sh b/erts/etc/win32/msys_tools/javac.sh new file mode 100644 index 0000000000..2d884bc2c8 --- /dev/null +++ b/erts/etc/win32/msys_tools/javac.sh @@ -0,0 +1,65 @@ +#! /bin/sh +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Note! This shellscript expects to be run in a cygwin environment, +# it converts erlc command lines to native windows erlc commands, which +# basically means running the command cygpath on whatever is a path... + +CMD="" +save_IFS=$IFS +IFS=":" +NEWCLASSPATH="" +for x in $CLASSPATH; do + TMP=`msys2win_path.sh -m $x` + if [ -z "$NEWCLASSPATH" ]; then + NEWCLASSPATH="$TMP" + else + NEWCLASSPATH="$NEWCLASSPATH;$TMP" + fi +done +IFS=$save_IFS +CLASSPATH="$NEWCLASSPATH" +export CLASSPATH +#echo "CLASSPATH=$CLASSPATH" +SAVE="$@" +while test -n "$1" ; do + x="$1" + case "$x" in + -I/*|-o/*|-d/*) + y=`echo $x | sed 's,^-[Iod]\(/.*\),\1,g'`; + z=`echo $x | sed 's,^-\([Iod]\)\(/.*\),\1,g'`; + #echo "Foooo:$z" + MPATH=`msys2win_path.sh -m $y`; + CMD="$CMD -$z\"$MPATH\"";; + -d|-I|-o) + shift; + MPATH=`msys2win_path.sh -m $1`; + CMD="$CMD $x $MPATH";; + /*) + #echo "absolute:"$x; + MPATH=`msys2win_path.sh -m $x`; + CMD="$CMD \"$MPATH\"";; + *) + y=`echo $x | sed 's,",\\\",g'`; + CMD="$CMD \"$y\"";; + esac + shift +done +#echo javac.exe "$CMD" +eval javac.exe "$CMD" diff --git a/erts/etc/win32/msys_tools/make_bootstrap_ini.sh b/erts/etc/win32/msys_tools/make_bootstrap_ini.sh new file mode 100644 index 0000000000..b61965f546 --- /dev/null +++ b/erts/etc/win32/msys_tools/make_bootstrap_ini.sh @@ -0,0 +1,44 @@ +#! /bin/bash +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Create a local init-file for erlang in the build environment. +if [ -z "$1" ]; then + echo "error: $0: No rootdir given" + exit 1 +else + RDIR=$1 +fi +if [ -z "$2" ]; then + echo "error: $0: No bindir given" + exit 1 +else + BDIR=$2 +fi + +DRDIR=`msys2win_path.sh $RDIR | sed 's,\\\,\\\\\\\\,g'` +DBDIR=`msys2win_path.sh $BDIR | sed 's,\\\,\\\\\\\\,g'` + + +cat > $RDIR/bin/erl.ini <<EOF +[erlang] +Bindir=$DBDIR +Progname=erl +Rootdir=$DRDIR +EOF + diff --git a/erts/emulator/zlib/Makefile b/erts/etc/win32/msys_tools/make_local_ini.sh index def8e1aa47..6c5d84c4f5 100644 --- a/erts/emulator/zlib/Makefile +++ b/erts/etc/win32/msys_tools/make_local_ini.sh @@ -1,7 +1,8 @@ +#! /bin/bash # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# Copyright Ericsson AB 2003-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -16,8 +17,25 @@ # # %CopyrightEnd% # -# -# Invoke with GNU make or clearmake -C gnu. -# +# Create a local init-file for erlang in the build environment. +if [ -z "$1" ]; then + if [ -z $ERL_TOP ]; then + echo "error: $0: No rootdir available" + exit 1 + else + RDIR=$ERL_TOP + fi +else + RDIR=$1 +fi + +DDIR=`msys2win_path.sh $RDIR | sed 's,\\\,\\\\\\\\,g'` + + +cat > $RDIR/bin/erl.ini <<EOF +[erlang] +Bindir=$DDIR\\\\bin\\\\win32 +Progname=erl +Rootdir=$DDIR +EOF -include $(ERL_TOP)/make/run_make.mk diff --git a/erts/etc/win32/msys_tools/msys2win_path.sh b/erts/etc/win32/msys_tools/msys2win_path.sh new file mode 100644 index 0000000000..679a9d6a8f --- /dev/null +++ b/erts/etc/win32/msys_tools/msys2win_path.sh @@ -0,0 +1,44 @@ +#! /bin/bash
+MIXED=false
+ABSOLUTE=false
+done=false
+while [ $done = false ]; do
+ case "$1" in
+ -m)
+ MIXED=true;
+ shift;;
+ -a)
+ ABSOLUTE=true;
+ shift;;
+ *)
+ done=true;;
+ esac
+done
+if [ -z "$1" ]; then
+ echo "Usage: $0 <path>" >&2
+ exit 1;
+fi
+MSYS_PATH=`win2msys_path.sh "$1"` # Clean up spaces
+if [ $ABSOLUTE = true ]; then
+ MSYS_DIR=`dirname "$MSYS_PATH"`
+ MSYS_FILE=`basename "$MSYS_PATH"`
+ if [ X"$MSYS_FILE" = X".." ]; then
+ MSYS_DIR="$MSYS_DIR/$MSYS_FILE"
+ WIN_ADD=""
+ else
+ WIN_ADD="/$MSYS_FILE"
+ fi
+ SAVEDIR=`pwd`
+ cd $MSYS_DIR
+ CURRENT=`pwd`
+ cd $SAVEDIR
+ WINPATH=`cmd //C echo $CURRENT`
+ WINPATH="$WINPATH$WIN_ADD"
+else
+ WINPATH=`cmd //c echo $MSYS_PATH`
+fi
+if [ $MIXED = true ]; then
+ echo $WINPATH
+else
+ echo $WINPATH | sed 's,/,\\,g'
+fi
\ No newline at end of file diff --git a/erts/etc/win32/msys_tools/reg_query.sh b/erts/etc/win32/msys_tools/reg_query.sh new file mode 100644 index 0000000000..ae6d5c3218 --- /dev/null +++ b/erts/etc/win32/msys_tools/reg_query.sh @@ -0,0 +1,24 @@ +#! /bin/sh
+BAT_FILE=/tmp/w$$.bat
+if [ -z "$1" -o -z "$2" ]; then
+ echo "Usage:" "$0" '<key> <valuename>'
+ exit 1
+fi
+BACKED=`echo "$1" | sed 's,/,\\\\,g'`
+# We need to get the 64bit part of the registry, hence we need to execute
+# a 64bit reg.exe, but c:\windows\system32 is redirected to 32bit versions
+# if we ate in the 32bit virtual environment, why we need to use the
+# sysnative trick to get to the 64bit executable of reg.exe (ouch!)
+if [ -d $WINDIR/sysnative ]; then
+ REG_CMD="$WINDIR\\sysnative\\reg.exe"
+else
+ REG_CMD="reg"
+fi
+cat > $BAT_FILE <<EOF
+@echo off
+$REG_CMD query "$BACKED" /v "$2"
+EOF
+#echo $BAT_FILE
+#cat $BAT_FILE
+RESULT=`cmd //C $BAT_FILE`
+echo $RESULT | sed "s,.*$2 REG_[^ ]* ,,"
diff --git a/erts/etc/win32/msys_tools/vc/ar.sh b/erts/etc/win32/msys_tools/vc/ar.sh new file mode 100644 index 0000000000..f4c61e1d92 --- /dev/null +++ b/erts/etc/win32/msys_tools/vc/ar.sh @@ -0,0 +1,47 @@ +#! /bin/sh +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +CMD="" +while test -n "$1" ; do + x="$1" + case "$x" in + -out:) + shift + case "$1" in + /*) + MPATH=`msys2win_path.sh -m $1`;; + *) + MPATH=$1;; + esac + CMD="$CMD -out:\"$MPATH\"";; + -out:/*) + y=`echo $x | sed 's,^-out:\(/.*\),\1,g'`; + MPATH=`msys2win_path.sh -m $y`; + CMD="$CMD -out:\"$MPATH\"";; + /*) + MPATH=`msys2win_path.sh -m $x`; + CMD="$CMD \"$MPATH\"";; + *) + y=`echo $x | sed 's,",\\\",g'`; + CMD="$CMD \"$y\"";; + esac + shift +done + +eval lib.exe $CMD diff --git a/erts/etc/win32/msys_tools/vc/cc.sh b/erts/etc/win32/msys_tools/vc/cc.sh new file mode 100644 index 0000000000..38b3d2ee81 --- /dev/null +++ b/erts/etc/win32/msys_tools/vc/cc.sh @@ -0,0 +1,320 @@ +#! /bin/sh +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Icky cl wrapper that does it's best to behave like a Unixish cc. +# Made to work for Erlang builds and to make configure happy, not really +# general I suspect. +# set -x +# Save the command line for debug outputs + +SAVE="$@" + +# Constants +COMMON_CFLAGS="-nologo -D__WIN32__ -DWIN32 -DWINDOWS -D_WIN32 -DNT -D_CRT_SECURE_NO_DEPRECATE" + +# Variables +# The stdout and stderr for the compiler +MSG_FILE=/tmp/cl.exe.$$.1 +ERR_FILE=/tmp/cl.exe.$$.2 + +# "Booleans" determined during "command line parsing" +# If the stdlib option is explicitly passed to this program +MD_FORCED=false +# If we're preprocession (only) i.e. -E +PREPROCESSING=false +# If we're generating dependencies (implies preprocesing) +DEPENDENCIES=false +# If this is supposed to be a debug build +DEBUG_BUILD=false +# If this is supposed to be an optimized build (there can only be one...) +OPTIMIZED_BUILD=false +# If we're linking or only compiling +LINKING=true + +# This data is accumulated during command line "parsing" +# The stdlibrary option, default multithreaded dynamic +MD=-MD +# Flags for debug compilation +DEBUG_FLAGS="" +# Flags for optimization +OPTIMIZE_FLAGS="" +# The specified output filename (if any), may be either object or exe. +OUTFILE="" +# Unspecified command line options for the compiler +CMD="" +# All the c source files, in unix style +SOURCES="" +# All the options to pass to the linker, kept in Unix style +LINKCMD="" + + +# Loop through the parameters and set the above variables accordingly +# Also convert some cygwin filenames to "mixed style" dito (understood by the +# compiler very well), except for anything passed to the linker, that script +# handles those and the sources, which are also kept unixish for now + +while test -n "$1" ; do + x="$1" + case "$x" in + -Wall) + ;; + -c) + LINKING=false;; + #CMD="$CMD -c";; + -MM) + PREPROCESSING=true; + LINKING=false; + DEPENDENCIES=true;; + -E) + PREPROCESSING=true; + LINKING=false;; # Obviously... + #CMD="$CMD -E";; + -Owx) + # Optimization hardcoded of wxErlang, needs to disable debugging too + OPTIMIZE_FLAGS="-Ob2ity -Gs -Zi"; + DEBUG_FLAGS=""; + DEBUG_BUILD=false; + if [ $MD_FORCED = false ]; then + MD=-MD; + fi + OPTIMIZED_BUILD=true;; + -O*) + # Optimization hardcoded, needs to disable debugging too + OPTIMIZE_FLAGS="-Ox -Zi"; + DEBUG_FLAGS=""; + DEBUG_BUILD=false; + if [ $MD_FORCED = false ]; then + MD=-MD; + fi + OPTIMIZED_BUILD=true;; + -g|-ggdb) + if [ $OPTIMIZED_BUILD = false ];then + # Hardcoded windows debug flags + DEBUG_FLAGS="-Z7"; + if [ $MD_FORCED = false ]; then + MD=-MDd; + fi + LINKCMD="$LINKCMD -g"; + DEBUG_BUILD=true; + fi;; + # Allow forcing of stdlib + -mt|-MT) + MD="-MT"; + MD_FORCED=true;; + -md|-MD) + MD="-MD"; + MD_FORCED=true;; + -ml|-ML) + MD="-ML"; + MD_FORCED=true;; + -mdd|-MDD|-MDd) + MD="-MDd"; + MD_FORCED=true;; + -mtd|-MTD|-MTd) + MD="-MTd"; + MD_FORCED=true;; + -mld|-MLD|-MLd) + MD="-MLd"; + MD_FORCED=true;; + -o) + shift; + OUTFILE="$1";; + -o*) + y=`echo $x | sed 's,^-[Io]\(.*\),\1,g'`; + OUTFILE="$y";; + -I/*) + y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`; + z=`echo $x | sed 's,^-\([Io]\)\(/.*\),\1,g'`; + MPATH=`echo $y`; + CMD="$CMD -$z\"$MPATH\"";; + -I*) + y=`echo $x | sed 's,",\\\",g'`; + CMD="$CMD $y";; + -D*) + y=`echo $x | sed 's,",\\\",g'`; + CMD="$CMD $y";; + -EH*) + y=`echo $x | sed 's,",\\\",g'`; + CMD="$CMD $y";; + -TP|-Tp) + y=`echo $x | sed 's,",\\\",g'`; + CMD="$CMD $y";; + -l*) + y=`echo $x | sed 's,^-l\(.*\),\1,g'`; + LINKCMD="$LINKCMD $x";; + /*.c) + SOURCES="$SOURCES $x";; + *.c) + SOURCES="$SOURCES $x";; + /*.cc) + SOURCES="$SOURCES $x";; + *.cc) + SOURCES="$SOURCES $x";; + /*.cpp) + SOURCES="$SOURCES $x";; + *.cpp) + SOURCES="$SOURCES $x";; + /*.o) + LINKCMD="$LINKCMD $x";; + *.o) + LINKCMD="$LINKCMD $x";; + *) + # Try to quote uninterpreted options + y=`echo $x | sed 's,",\\\",g'`; + LINKCMD="$LINKCMD $y";; + esac + shift +done + +#Return code from compiler, linker.sh and finally this script... +RES=0 + +# Accumulated object names +ACCUM_OBJECTS="" + +# A temporary object file location +TMPOBJDIR=/tmp/tmpobj$$ +mkdir $TMPOBJDIR + +# Compile +for x in $SOURCES; do + start_time=`date '+%s'` + # Compile each source + if [ $LINKING = false ]; then + # We should have an output defined, which is a directory + # or an object file + case $OUTFILE in + /*.o) + # Simple output, SOURCES should be one single + n=`echo $SOURCES | wc -w`; + if [ $n -gt 1 ]; then + echo "cc.sh:Error, multiple sources, one object output."; + exit 1; + else + output_filename=`echo $OUTFILE`; + fi;; + *.o) + # Relative path needs no translation + n=`echo $SOURCES | wc -w` + if [ $n -gt 1 ]; then + echo "cc.sh:Error, multiple sources, one object output." + exit 1 + else + output_filename=$OUTFILE + fi;; + /*) + # Absolute directory + o=`echo $x | sed 's,.*/,,' | sed 's,\.c$,.o,'` + output_filename=`echo $OUTFILE` + output_filename="$output_filename/${o}";; + *) + # Relative_directory or empty string (.//x.o is valid) + o=`echo $x | sed 's,.*/,,' | sed 's,\.cp*$,.o,'` + output_filename="./${OUTFILE}/${o}";; + esac + else + # We are linking, which means we build objects in a temporary + # directory and link from there. We should retain the basename + # of each source to make examining the exe easier... + o=`echo $x | sed 's,.*/,,' | sed 's,\.c$,.o,'` + output_filename=$TMPOBJDIR/$o + ACCUM_OBJECTS="$ACCUM_OBJECTS $output_filename" + fi + # Now we know enough, lets try a compilation... + MPATH=`echo $x` + if [ $PREPROCESSING = true ]; then + output_flag="-E" + else + output_flag="-c -Fo`cmd //C echo ${output_filename}`" + fi + params="$COMMON_CFLAGS $MD $DEBUG_FLAGS $OPTIMIZE_FLAGS \ + $CMD ${output_flag} $MPATH" + if [ "X$CC_SH_DEBUG_LOG" != "X" ]; then + echo cc.sh "$SAVE" >>$CC_SH_DEBUG_LOG + echo cl.exe $params >>$CC_SH_DEBUG_LOG + fi + eval cl.exe $params >$MSG_FILE 2>$ERR_FILE + RES=$? + if test $PREPROCESSING = false; then + cat $ERR_FILE >&2 + tail -n +2 $MSG_FILE + else + tail -n +2 $ERR_FILE >&2 + if test $DEPENDENCIES = true; then + if test `grep -v $x $MSG_FILE | grep -c '#line'` != "0"; then + o=`echo $x | sed 's,.*/,,' | sed 's,\.cp*$,.o,'` + echo -n $o':' +# cat $MSG_FILE | grep '#line' | grep -v $x | awk -F\" '{printf("%s\n",$2)}' | sort -u | grep -v " " | xargs -n 1 win2msys_path.sh | awk '{printf("\\\n %s ",$0)}' + cat $MSG_FILE | grep '#line' | grep -v $x | awk -F\" '{printf("%s\n",$2)}' | sort -u | grep -v " " | sed 's,^\([A-Za-z]\):[\\/]*,/\1/,;s,\\\\*,/,g'| awk '{printf("\\\n %s ",$0)}' + echo + echo + after_sed=`date '+%s'` + echo Made dependencises for $x':' `expr $after_sed '-' $start_time` 's' >&2 + fi + else + cat $MSG_FILE + fi + fi + rm -f $ERR_FILE $MSG_FILE + if [ $RES != 0 ]; then + rm -rf $TMPOBJDIR + exit $RES + fi +done + +# If we got here, we succeeded in compiling (if there were anything to compile) +# The output filename should name an executable if we're linking +if [ $LINKING = true ]; then + case $OUTFILE in + "") + # Use the first source name to name the executable + first_source="" + for x in $SOURCES; do first_source=$x; break; done; + if [ -n "$first_source" ]; then + e=`echo $x | sed 's,.*/,,' | sed 's,\.c$,.exe,'`; + out_spec="-o $e"; + else + out_spec=""; + fi;; + *) + out_spec="-o $OUTFILE";; + esac + # Descide which standard library to link against + case $MD in + -ML) + stdlib="-lLIBC";; + -MLd) + stdlib="-lLIBCD";; + -MD) + stdlib="-lMSVCRT";; + -MDd) + stdlib="-lMSVCRTD";; + -MT) + stdlib="-lLIBCMT";; + -MTd) + stdlib="-lLIBMTD";; + esac + # And finally call the next script to do the linking... + params="$out_spec $LINKCMD $stdlib" + eval ld.sh $ACCUM_OBJECTS $params + RES=$? +fi +rm -rf $TMPOBJDIR + +exit $RES diff --git a/erts/etc/win32/msys_tools/vc/coffix.c b/erts/etc/win32/msys_tools/vc/coffix.c new file mode 100644 index 0000000000..1773b222fe --- /dev/null +++ b/erts/etc/win32/msys_tools/vc/coffix.c @@ -0,0 +1,161 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 1999-2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* +** This mini tool fixes an incompatibility between +** Microsoft's tools, who dont like the virtual size being put in +** the physical address field, but rely on the raw size field for +** sizing the ".bss" section. +** This fixes some of the problems with linking gcc compiled objects +** together with MSVC dito. +** +** Courtesy DJ Delorie for describing the COFF file format on +** http://www.delorie.com/djgpp/doc/coff/ +** The coff structures are fetched from Microsofts headers though. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include <windows.h> +#include <winnt.h> /* Structure definitions for PE (COFF) */ + +static int dump_edit(char *filename, int edit); +static int v_printf(char *format, ...); + + +char *progname; +int verbouse = 0; + +int main(int argc, char **argv) +{ + int findex = 1; + int edit = 0; + int ret; + + progname = argv[0]; + if (argc == 1) { + fprintf(stderr,"Format : %s [-e] [-v] <filename>\n", progname); + return 1; + } + for (findex = 1; + findex < argc && (*argv[findex] == '-' || *argv[findex] == '/'); + ++findex) + switch (argv[findex][1]) { + case 'e': + case 'E': + edit = 1; + break; + case 'v': + case 'V': + verbouse = 1; + default: + fprintf(stderr, "%s: unknown option %s\n", progname, argv[findex]); + break; + } + if (findex == argc) { + fprintf(stderr,"%s: No filenames given.\n", progname); + return 1; + } + for(; findex < argc; ++findex) + if ((ret = dump_edit(argv[findex],edit)) != 0) + return ret; + return 0; +} + +int dump_edit(char *filename, int edit) +{ + FILE *f = fopen(filename, (edit) ? "r+b" : "rb"); + IMAGE_FILE_HEADER filhdr; + IMAGE_SECTION_HEADER scnhdr; + int i; + + if (f == NULL) { + fprintf(stderr, "%s: cannot open %s.\n", progname, filename); + return 1; + } + + if (fread(&filhdr, sizeof(filhdr), 1, f) == 0) { + fprintf(stderr,"%s: Could not read COFF header from %s," + " is this a PE (COFF) file?\n", progname, filename); + fclose(f); + return 1; + } + v_printf("File: %s\n", filename); + v_printf("Magic number: 0x%08x\n", filhdr.Machine); + v_printf("Number of sections: %d\n",filhdr.NumberOfSections); + + if (fseek(f, (long) filhdr.SizeOfOptionalHeader, SEEK_CUR) != 0) { + fprintf(stderr,"%s: Could not read COFF optional header from %s," + " is this a PE (COFF) file?\n", progname, filename); + fclose(f); + return 1; + } + + for (i = 0; i < filhdr.NumberOfSections; ++i) { + if (fread(&scnhdr, sizeof(scnhdr), 1, f) == 0) { + fprintf(stderr,"%s: Could not read section header from %s," + " is this a PE (COFF) file?\n", progname, filename); + fclose(f); + return 1; + } + v_printf("Section %s:\n", scnhdr.Name); + v_printf("Physical address: 0x%08x\n", scnhdr.Misc.PhysicalAddress); + v_printf("Size: 0x%08x\n", scnhdr.SizeOfRawData); + if (scnhdr.Misc.PhysicalAddress != 0 && + scnhdr.SizeOfRawData == 0) { + printf("Section header %s in file %s will confuse MSC linker, " + "virtual size is 0x%08x and raw size is 0\n", + scnhdr.Name, filename, scnhdr.Misc.PhysicalAddress, + scnhdr.SizeOfRawData); + if (edit) { + scnhdr.SizeOfRawData = scnhdr.Misc.PhysicalAddress; + scnhdr.Misc.PhysicalAddress = 0; + if (fseek(f, (long) -((long)sizeof(scnhdr)), SEEK_CUR) != 0 || + fwrite(&scnhdr, sizeof(scnhdr), 1, f) == 0) { + fprintf(stderr,"%s: could not edit file %s.\n", + progname, filename); + fclose(f); + return 1; + } + printf("Edited object, virtual size is now 0, and " + "raw size is 0x%08x.\n", scnhdr.SizeOfRawData); + } else { + printf("Specify option '-e' to correct the problem.\n"); + } + } + } + fclose(f); + return 0; +} + + +static int v_printf(char *format, ...) +{ + va_list ap; + int ret = 0; + if (verbouse) { + va_start(ap, format); + ret = vfprintf(stdout, format, ap); + va_end(ap); + } + return ret; +} + diff --git a/erts/etc/win32/msys_tools/vc/emu_cc.sh b/erts/etc/win32/msys_tools/vc/emu_cc.sh new file mode 100644 index 0000000000..68ce4e359f --- /dev/null +++ b/erts/etc/win32/msys_tools/vc/emu_cc.sh @@ -0,0 +1,95 @@ +#! /bin/sh +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +if [ X"$CONFIG_SUBTYPE" = X"win64" ]; then + GCC="x86_64-w64-mingw32-gcc.exe" +else + GCC="gcc" +fi +TOOLDIR=$ERL_TOP/erts/etc/win32/msys_tools/vc +COFFIX=$TOOLDIR/coffix +WTOOLDIR0=`win2msys_path.sh "$TOOLDIR"` +WTOOLDIR=`cmd //C echo $WTOOLDIR0` +# Do primitive 'make' +newer_exe=`find $TOOLDIR -newer $COFFIX.c -name coffix.exe -print` +if [ -z $newer_exe ]; then + echo recompiling $COFFIX.exe + cl.exe -Fe${WTOOLDIR}/coffix.exe ${WTOOLDIR}/coffix.c + rm -f $COFFIX.obj coffix.obj $COFFIX.pdb coffix.pdb +fi + +# Try to find out the output filename and remove it from command line +CMD="" +OUTFILE="" +INFILE="" +SKIP_COFFIX=false +while test -n "$1" ; do + x="$1" + case "$x" in + -o/*) + OUTFILE=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`;; + -o) + shift + OUTFILE=$1;; + -MM) + SKIP_COFFIX=true + CMD="$CMD \"$x\"";; + *.c) + INFILE="$INFILE $x"; + CMD="$CMD \"$x\"";; + *) + CMD="$CMD \"$x\"";; + esac + shift +done +if [ -z "$INFILE" ]; then + echo 'emu_cc.sh: please give an input filename for the compiler' >&2 + exit 1 +fi +if [ -z "$OUTFILE" ]; then + OUTFILE=`echo $INFILE | sed 's,\.c$,.o,'` +fi + +if [ $SKIP_COFFIX = false ]; then + n=`echo $INFILE | wc -w`; + if [ $n -gt 1 ]; then + echo "emu_cc.sh:Error, multiple sources, one object output."; + exit 1; + fi + TEMPFILE=/tmp/tmp_emu_cc$$.o + if [ "X$EMU_CC_SH_DEBUG_LOG" != "X" ]; then + echo "$GCC -o $TEMPFILE -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer $CMD" >> $EMU_CC_SH_DEBUG_LOG 2>&1 + fi + eval $GCC -o $TEMPFILE -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer $CMD + RES=$? + if [ $RES = 0 ]; then + $COFFIX.exe -e `win2msys_path.sh $TEMPFILE` + RES=$? + if [ $RES = 0 ]; then + cp $TEMPFILE $OUTFILE + else + echo "emu_cc.sh: fatal: coffix failed!" >&2 + fi + fi + rm -f $TEMPFILE + exit $RES +else + eval $GCC -D__WIN32__ -DWIN32 -DWINDOWS -fomit-frame-pointer -fno-tree-copyrename $CMD 2>/dev/null + exit $? +fi diff --git a/erts/etc/win32/msys_tools/vc/ld.sh b/erts/etc/win32/msys_tools/vc/ld.sh new file mode 100644 index 0000000000..0fcbf6f7d9 --- /dev/null +++ b/erts/etc/win32/msys_tools/vc/ld.sh @@ -0,0 +1,198 @@ +#! /bin/sh +# set -x +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Save the command line for debug outputs + +SAVE="$@" +kernel_libs="kernel32.lib advapi32.lib" +gdi_libs="gdi32.lib user32.lib comctl32.lib comdlg32.lib shell32.lib" +DEFAULT_LIBRARIES="$kernel_libs $gdi_libs" + +CMD="" +STDLIB=MSVCRT.LIB +DEBUG_BUILD=false +STDLIB_FORCED=false +BUILD_DLL=false +OUTPUT_FILENAME="" + +while test -n "$1" ; do + x="$1" + case "$x" in + -dll| -DLL) + BUILD_DLL=true;; + -L/*|-L.*) + y=`echo $x | sed 's,^-L\(.*\),\1,g'`; + MPATH=`msys2win_path.sh -m $y`; + CMD="$CMD -libpath:\"$MPATH\"";; + -lMSVCRT|-lmsvcrt) + STDLIB_FORCED=true; + STDLIB=MSVCRT.LIB;; + -lMSVCRTD|-lmsvcrtd) + STDLIB_FORCED=true; + STDLIB=MSVCRTD.LIB;; + -lLIBCMT|-llibcmt) + STDLIB_FORCED=true; + STDLIB=LIBCMT.LIB;; + -lLIBCMTD|-llibcmtd) + STDLIB_FORCED=true; + STDLIB=LIBCMTD.LIB;; + -lsocket) + DEFAULT_LIBRARIES="$DEFAULT_LIBRARIES WS2_32.LIB IPHLPAPI.LIB";; + -l*) + y=`echo $x | sed 's,^-l\(.*\),\1,g'`; + MPATH=`msys2win_path.sh -m $y`; + CMD="$CMD \"${MPATH}.lib\"";; + -g) + DEBUG_BUILD=true;; + -pdb:none|-incremental:no) + ;; + -implib:*) + y=`echo $x | sed 's,^-implib:\(.*\),\1,g'`; + MPATH=`msys2win_path.sh -m $y`; + CMD="$CMD -implib:\"${MPATH}\"";; + -def:*) + y=`echo $x | sed 's,^-def:\(.*\),\1,g'`; + MPATH=`msys2win_path.sh -m $y`; + CMD="$CMD -def:\"${MPATH}\"";; + -o) + shift + MPATH=`msys2win_path.sh -m $1`; + OUTPUT_FILENAME="$MPATH";; + -o/*) + y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`; + MPATH=`msys2win_path.sh -m $y`; + OUTPUT_FILENAME="$MPATH";; + /*) + MPATH=`msys2win_path.sh -m $x`; + CMD="$CMD \"$MPATH\"";; + *) + y=`echo $x | sed 's,",\\\",g'`; + CMD="$CMD \"$y\"";; + esac + shift +done +if [ $DEBUG_BUILD = true ]; then + linktype="-debug -pdb:none" + if [ $STDLIB_FORCED = false ]; then + STDLIB=MSVCRTD.LIB + fi +fi +# Generate a PDB +linkadd_pdb="" +case "$OUTPUT_FILENAME" in + *.exe|*.EXE) + fn=`echo "$OUTPUT_FILENAME" | sed 's,[eE][xX][eE]$,,g'`; + linkadd_pdb="-pdb:\"${fn}pdb\"";; + *.dll|*.DLL) + fn=`echo "$OUTPUT_FILENAME" | sed 's,[dD][lL][lL]$,,g'`; + linkadd_pdb="-pdb:\"${fn}pdb\"";; + "") + linkadd_pdb="-pdb:\"a.pdb\"";; + *) + linkadd_pdb="-pdb:\"${OUTPUT_FILENAME}.pdb\"";; +esac + + linktype="-debug $linkadd_pdb" + +CHMOD_FILE="" + +if [ $BUILD_DLL = true ];then + case "$OUTPUT_FILENAME" in + *.exe|*.EXE) + echo "Warning, output set to .exe when building DLL" >&2 + CHMOD_FILE="$OUTPUT_FILENAME"; + CMD="-dll -out:\"$OUTPUT_FILENAME\" $CMD"; + OUTPUTRES="${OUTPUT_FILENAME}\;2"; + MANIFEST="${OUTPUT_FILENAME}.manifest";; + *.dll|*.DLL) + CMD="-dll -out:\"$OUTPUT_FILENAME\" $CMD"; + OUTPUTRES="${OUTPUT_FILENAME}\;2"; + MANIFEST="${OUTPUT_FILENAME}.manifest";; + "") + CMD="-dll -out:\"a.dll\" $CMD"; + OUTPUTRES="a.dll\;2"; + MANIFEST="a.dll.manifest";; + *) + CMD="-dll -out:\"${OUTPUT_FILENAME}.dll\" $CMD"; + OUTPUTRES="${OUTPUT_FILENAME}.dll\;2"; + MANIFEST="${OUTPUT_FILENAME}.dll.manifest";; + esac +else + case "$OUTPUT_FILENAME" in + *.exe|*.EXE) + CHMOD_FILE="$OUTPUT_FILENAME"; + CMD="-out:\"$OUTPUT_FILENAME\" $CMD"; + OUTPUTRES="${OUTPUT_FILENAME}\;1" + MANIFEST="${OUTPUT_FILENAME}.manifest";; + *.dll|*.DLL) + echo "Warning, output set to .dll when building EXE" >&2 + CMD="-out:\"$OUTPUT_FILENAME\" $CMD"; + OUTPUTRES="${OUTPUT_FILENAME}\;1"; + MANIFEST="${OUTPUT_FILENAME}.manifest";; + "") + CHMOD_FILE="a.exe"; + CMD="-out:\"a.exe\" $CMD"; + OUTPUTRES="a.exe\;1"; + MANIFEST="a.exe.manifest";; + *) + CMD="-out:\"${OUTPUT_FILENAME}.exe\" $CMD"; + OUTPUTRES="${OUTPUT_FILENAME}.exe\;1"; + MANIFEST="${OUTPUT_FILENAME}.exe.manifest";; + esac +fi + +p=$$ +CMD="$linktype -nologo -incremental:no $CMD $STDLIB $DEFAULT_LIBRARIES" +if [ "X$LD_SH_DEBUG_LOG" != "X" ]; then + echo ld.sh "$SAVE" >>$LD_SH_DEBUG_LOG + echo link.exe $CMD >>$LD_SH_DEBUG_LOG +fi +eval link.exe "$CMD" >/tmp/link.exe.${p}.1 2>/tmp/link.exe.${p}.2 +RES=$? + +CMANIFEST=`win2msys_path.sh $MANIFEST` +if [ "$RES" = "0" -a -f "$CMANIFEST" ]; then + # Add stuff to manifest to turn off "virtualization" + sed -n -i '1h;1!H;${;g;s,<trustInfo.*</trustInfo>.,,g;p;}' $CMANIFEST 2>/dev/null + sed -i "s/<\/assembly>/ <ms_asmv2:trustInfo xmlns:ms_asmv2=\"urn:schemas-microsoft-com:asm.v2\">\n <ms_asmv2:security>\n <ms_asmv2:requestedPrivileges>\n <ms_asmv2:requestedExecutionLevel level=\"AsInvoker\" uiAccess=\"false\"\/>\n <\/ms_asmv2:requestedPrivileges>\n <\/ms_asmv2:security>\n <\/ms_asmv2:trustInfo>\n<\/assembly>/" $CMANIFEST 2>/dev/null + + eval mt.exe -nologo -manifest "$MANIFEST" -outputresource:"$OUTPUTRES" >>/tmp/link.exe.${p}.1 2>>/tmp/link.exe.${p}.2 + RES=$? + if [ "$RES" != "0" ]; then + REMOVE=`echo "$OUTPUTRES" | sed 's,\\\;[12]$,,g'` + CREMOVE=`cygpath $REMOVE` + rm -f "$CREMOVE" + fi + rm -f "$CMANIFEST" +fi + +# This works around some strange behaviour +# in cygwin 1.7 Beta on Windows 7 with samba drive. +# Configure will think the compiler failed if test -x fails, +# which it might do as we might not be the owner of the +# file. +if [ '!' -z "$CHMOD_FILE" -a -s "$CHMOD_FILE" -a '!' -x "$CHMOD_FILE" ]; then + chmod +x $CHMOD_FILE +fi + +tail -n +2 /tmp/link.exe.${p}.2 >&2 +cat /tmp/link.exe.${p}.1 +rm -f /tmp/link.exe.${p}.2 /tmp/link.exe.${p}.1 +exit $RES diff --git a/erts/etc/win32/msys_tools/vc/mc.sh b/erts/etc/win32/msys_tools/vc/mc.sh new file mode 100644 index 0000000000..27d985f73e --- /dev/null +++ b/erts/etc/win32/msys_tools/vc/mc.sh @@ -0,0 +1,87 @@ +#! /bin/sh +# set -x +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Save the command line for debug outputs +SAVE="$@" +CMD="" +OUTPUT_DIRNAME="" + +# Find the correct mc.exe. This could be done by the configure script, +# But as we seldom use the message compiler, it might as well be done here... +MCC="" +save_ifs=$IFS +IFS=: +for p in $PATH; do + if [ -f $p/mc.exe ]; then + if [ -n "`$p/mc.exe -? 2>&1 >/dev/null </dev/null \ + | grep -i \"message compiler\"`" ]; then + MCC=`echo "$p/mc.exe" | sed 's/ /\\\\ /g'` + fi + fi +done +IFS=$save_ifs + +if [ -z "$MCC" ]; then + echo 'mc.exe not found!' >&2 + exit 1 +fi + +while test -n "$1" ; do + x="$1" + case "$x" in + -o) + shift + OUTPUT_DIRNAME="$1";; + -o/*) + y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`; + OUTPUT_DIRNAME="$y";; + -I) + shift + MPATH=`msys2win_path.sh -m $1`; + CMD="$CMD -I\"$MPATH\"";; + -I/*) + y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`; + MPATH=`msys2win_path.sh -m $y`; + CMD="$CMD -I\"$MPATH\"";; + *) + MPATH=`msys2win_path.sh -m -a $x`; + CMD="$CMD \"$MPATH\"";; + esac + shift +done +p=$$ +if [ "X$MC_SH_DEBUG_LOG" != "X" ]; then + echo mc.sh "$SAVE" >>$MC_SH_DEBUG_LOG + echo mc.exe $CMD >>$MC_SH_DEBUG_LOG +fi +if [ -n "$OUTPUT_DIRNAME" ]; then + cd $OUTPUT_DIRNAME + RES=$? + if [ "$RES" != "0" ]; then + echo "mc.sh: Error: could not cd to $OUTPUT_DIRNAME">&2 + exit $RES + fi +fi +eval $MCC "$CMD" >/tmp/mc.exe.${p}.1 2>/tmp/mc.exe.${p}.2 +RES=$? +tail +2 /tmp/mc.exe.${p}.2 >&2 +cat /tmp/mc.exe.${p}.1 +rm -f /tmp/mc.exe.${p}.2 /tmp/mc.exe.${p}.1 +exit $RES diff --git a/erts/etc/win32/msys_tools/vc/rc.sh b/erts/etc/win32/msys_tools/vc/rc.sh new file mode 100644 index 0000000000..dfa9e324db --- /dev/null +++ b/erts/etc/win32/msys_tools/vc/rc.sh @@ -0,0 +1,86 @@ +#! /bin/sh +# set -x +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Save the command line for debug outputs +SAVE="$@" +CMD="" +OUTPUT_FILENAME="" + +# Find the correct rc.exe. This could be done by the configure script, +# But as we seldom use the resource compiler, it might as well be done here... +RCC="" +save_ifs=$IFS +IFS=: +for p in $PATH; do + if [ -f $p/rc.exe ]; then + if [ -n "`$p/rc.exe -? 2>&1 | grep -i "resource compiler"`" ]; then + RCC=`echo "$p/rc.exe" | sed 's/ /\\\\ /g'` + fi + fi +done +IFS=$save_ifs + +if [ -z "$RCC" ]; then + echo 'rc.exe not found!' >&2 + exit 1 +fi + +while test -n "$1" ; do + x="$1" + case "$x" in + -o) + shift + MPATH=`msys2win_path.sh -m $1`; + OUTPUT_FILENAME="$MPATH";; + -o/*) + y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`; + MPATH=`msys2win_path.sh -m $y`; + OUTPUT_FILENAME="$MPATH";; + -I) + shift + MPATH=`msys2win_path.sh -m $1`; + CMD="$CMD -I\"$MPATH\"";; + -I/*) + y=`echo $x | sed 's,^-[Io]\(/.*\),\1,g'`; + MPATH=`msys2win_path.sh -m $y`; + CMD="$CMD -I\"$MPATH\"";; + /*) + MPATH=`msys2win_path.sh -m $x`; + CMD="$CMD \"$MPATH\"";; + *) + y=`echo $x | sed 's,",\\\",g'`; + CMD="$CMD \"$y\"";; + esac + shift +done +p=$$ +if [ -n "$OUTPUT_FILENAME" ]; then + CMD="-Fo$OUTPUT_FILENAME $CMD" +fi +if [ "X$RC_SH_DEBUG_LOG" != "X" ]; then + echo rc.sh "$SAVE" >>$RC_SH_DEBUG_LOG + echo rc.exe $CMD >>$RC_SH_DEBUG_LOG +fi +eval $RCC "$CMD" >/tmp/rc.exe.${p}.1 2>/tmp/rc.exe.${p}.2 +RES=$? +tail +2 /tmp/rc.exe.${p}.2 >&2 +cat /tmp/rc.exe.${p}.1 +rm -f /tmp/rc.exe.${p}.2 /tmp/rc.exe.${p}.1 +exit $RES diff --git a/erts/etc/win32/msys_tools/win2msys_path.sh b/erts/etc/win32/msys_tools/win2msys_path.sh new file mode 100644 index 0000000000..6558a15ecd --- /dev/null +++ b/erts/etc/win32/msys_tools/win2msys_path.sh @@ -0,0 +1,38 @@ +#! /bin/bash
+if [ -z "$1" ]; then
+ echo "Usage: $0 <path>" >&2
+ exit 1;
+fi
+
+MSYS_PATH=`echo "$1" | sed 's,^\([a-zA-Z]\):\\\\,/\L\1/,;s,\\\\,/,g'`
+if [ -z "$MSYS_PATH" ]; then
+ echo "$0: Could not translate $1 to msys format" >&2
+ exit 2;
+fi
+
+DELBLANK=`echo "$MSYS_PATH" | sed 's, ,,g'`
+
+if [ "X$DELBLANK" != "X$MSYS_PATH" ]; then
+ if [ -d "$MSYS_PATH" ]; then
+ C1=`(cd "$MSYS_PATH" && cmd //C "for %i in (".") do @echo %~fsi")`
+ MSYS_PATH=`echo "$C1" | sed 's,^\([a-zA-Z]\):\\\\,/\L\1/,;s,\\\\,/,g'`
+ else
+ MSYS_DIR=`dirname "$MSYS_PATH"`
+ MSYS_FILE=`basename "$MSYS_PATH"`
+ if [ -d "$MSYS_DIR" ]; then
+ C1=`(cd "$MSYS_DIR" && cmd //C "for %i in (".") do @echo %~fsi")`
+ BAT_FILE=/tmp/w$$.bat
+ # I simply cannot get the quoting right for this,
+ # need an intermediate bat file
+ cat > $BAT_FILE <<EOF
+@echo off
+for %%i in ("$MSYS_FILE") do @echo %%~snxi
+EOF
+ C2=`(cd "$MSYS_DIR" && cmd //C $BAT_FILE)`
+ rm -f $BAT_FILE
+ MSYS_PATH=`echo "$C1/$C2" | sed 's,^\([a-zA-Z]\):\\\\,/\L\1/,;s,\\\\,/,g;s," ", ,g'`
+ fi
+ fi
+fi
+echo $MSYS_PATH
+exit 0
\ No newline at end of file diff --git a/erts/etc/win32/nsis/Makefile b/erts/etc/win32/nsis/Makefile index ae2343b420..6a93c5153d 100644 --- a/erts/etc/win32/nsis/Makefile +++ b/erts/etc/win32/nsis/Makefile @@ -40,10 +40,29 @@ clean: include $(ERL_TOP)/make/otp_release_targets.mk TARGET_DIR = $(RELEASE_PATH) -WTESTROOT=$(shell (cygpath -d $(RELEASE_PATH) 2>/dev/null || cygpath -w $(RELEASE_PATH))) -WTARGET_DIR=$(shell (cygpath -d $(TARGET_DIR) 2>/dev/null || cygpath -d $(TARGET_DIR))) + +ifeq ($(MSYSTEM),MINGW32) + + MAKENSISFLAGS = //V2 + WTESTROOT=$(shell (msys2win_path.sh $(RELEASE_PATH))) + WTARGET_DIR=$(shell (msys2win_path.sh $(TARGET_DIR))) + +else + + MAKENSISFLAGS = /V2 + WTESTROOT=$(shell (cygpath -d $(RELEASE_PATH) 2>/dev/null || cygpath -w $(RELEASE_PATH))) + WTARGET_DIR=$(shell (cygpath -d $(TARGET_DIR) 2>/dev/null || cygpath -d $(TARGET_DIR))) + +endif + +ifeq ($(CONFIG_SUBTYPE),win64) + WINTYPE=win64 +else + WINTYPE=win32 +endif REDIST_FILE=$(shell (sh ./find_redist.sh || echo "")) +REDIST_TARGET=$(shell (sh ./find_redist.sh -n || echo "")) REDIST_DLL_VERSION=$(shell (sh ./dll_version_helper.sh || echo "")) REDIST_DLL_NAME=$(shell (sh ./dll_version_helper.sh -n || echo "")) @@ -65,16 +84,18 @@ release_spec: echo '!define ERTS_VERSION "$(VSN)"' >> $(VERSION_HEADER);\ echo '!define TESTROOT "$(WTESTROOT)"' >> $(VERSION_HEADER);\ echo '!define OUTFILEDIR "$(WTARGET_DIR)"' >> $(VERSION_HEADER);\ + echo '!define WINTYPE "$(WINTYPE)"' >> $(VERSION_HEADER);\ if [ -f $(CUSTOM_MODERN) ];\ then \ echo '!define HAVE_CUSTOM_MODERN 1' >> $(VERSION_HEADER); \ fi;\ if [ '!' -z "$(REDIST_FILE)" -a '!' -z "$(REDIST_DLL_VERSION)" ];\ then \ - cp $(REDIST_FILE) $(RELEASE_PATH)/vcredist_x86.exe;\ + cp $(REDIST_FILE) $(RELEASE_PATH)/$(REDIST_TARGET);\ echo '!define HAVE_REDIST_FILE 1' >> $(VERSION_HEADER); \ echo '!define REDIST_DLL_VERSION "$(REDIST_DLL_VERSION)"' >> $(VERSION_HEADER);\ echo '!define REDIST_DLL_NAME "$(REDIST_DLL_NAME)"' >> $(VERSION_HEADER);\ + echo '!define REDIST_EXECUTABLE "$(REDIST_TARGET)"' >> $(VERSION_HEADER);\ fi;\ if [ -f $(RELEASE_PATH)/docs/doc/index.html ];\ then \ diff --git a/erts/etc/win32/nsis/dll_version_helper.sh b/erts/etc/win32/nsis/dll_version_helper.sh index eecd4a72b5..96e4532b7a 100755 --- a/erts/etc/win32/nsis/dll_version_helper.sh +++ b/erts/etc/win32/nsis/dll_version_helper.sh @@ -36,11 +36,11 @@ int main(void) } EOF -cl /MD hello.c > /dev/null 2>&1 +cl -MD hello.c > /dev/null 2>&1 if [ '!' -f hello.exe.manifest ]; then # Gah - VC 2010 changes the way it handles DLL's and manifests... Again... # need another way of getting the version - DLLNAME=`dumpbin.exe /imports hello.exe | egrep MSVCR.*dll` + DLLNAME=`dumpbin.exe -imports hello.exe | egrep MSVCR.*dll` DLLNAME=`echo $DLLNAME` cat > helper.c <<EOF #include <windows.h> @@ -59,11 +59,7 @@ int main(void) char *vs_verinfo; unsigned int vs_ver_size; - struct LANGANDCODEPAGE { - WORD language; - WORD codepage; - } *translate; - + WORD *translate; unsigned int tr_size; if (!(versize = GetFileVersionInfoSize(REQ_MODULE,&dummy))) { @@ -79,10 +75,10 @@ int main(void) fprintf(stderr,"No translation info in %s!\n",REQ_MODULE); exit(3); } - n = tr_size/sizeof(translate); + n = tr_size/(2*sizeof(*translate)); for(i=0; i < n; ++i) { sprintf(buff,"\\\\StringFileInfo\\\\%04x%04x\\\\FileVersion", - translate[i].language,translate[i].codepage); + translate[i*2],translate[i*2+1]); if (VerQueryValue(versinfo,buff,&vs_verinfo,&vs_ver_size)) { printf("%s\n",(char *) vs_verinfo); return 0; @@ -92,7 +88,7 @@ int main(void) return 0; } EOF - cl /MD helper.c version.lib > /dev/null 2>&1 + cl -MD helper.c version.lib > /dev/null 2>&1 if [ '!' -f helper.exe ]; then echo "Failed to build helper program." >&2 exit 1 diff --git a/erts/etc/win32/nsis/erlang20.nsi b/erts/etc/win32/nsis/erlang20.nsi index 941e8e6f5d..fb0eff3867 100644 --- a/erts/etc/win32/nsis/erlang20.nsi +++ b/erts/etc/win32/nsis/erlang20.nsi @@ -31,17 +31,24 @@ Var STARTMENU_FOLDER !define MY_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
;General
- OutFile "${OUTFILEDIR}\otp_win32_${OTP_VERSION}.exe"
+ OutFile "${OUTFILEDIR}\otp_${WINTYPE}_${OTP_VERSION}.exe"
;Folder selection page
+!if ${WINTYPE} == "win64"
+ InstallDir "$PROGRAMFILES64\erl${ERTS_VERSION}"
+!else
InstallDir "$PROGRAMFILES\erl${ERTS_VERSION}"
-
+!endif
;Remember install folder
InstallDirRegKey HKLM "SOFTWARE\Ericsson\Erlang\${ERTS_VERSION}" ""
; Set the default start menu folder
+!if ${WINTYPE} == "win64"
+ !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION} (x64)"
+!else
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION}"
+!endif
;--------------------------------
;Modern UI Configuration
@@ -98,12 +105,12 @@ Var STARTMENU_FOLDER Section "Microsoft redistributable libraries." SecMSRedist
SetOutPath "$INSTDIR"
- File "${TESTROOT}\vcredist_x86.exe"
+ File "${TESTROOT}\${REDIST_EXECUTABLE}"
; Set back verbosity...
!verbose 1
; Run the setup program
- ExecWait '"$INSTDIR\vcredist_x86.exe"'
+ ExecWait '"$INSTDIR\${REDIST_EXECUTABLE}"'
!verbose 1
SectionEnd ; MSRedist
diff --git a/erts/etc/win32/nsis/find_redist.sh b/erts/etc/win32/nsis/find_redist.sh index bc4260ecba..7c449c9e4e 100755 --- a/erts/etc/win32/nsis/find_redist.sh +++ b/erts/etc/win32/nsis/find_redist.sh @@ -65,7 +65,6 @@ remove_path_element() else echo "${ACC}/$1" fi - #echo "ACC=$ACC" >&2 #echo "1=$1" >&2 } @@ -89,20 +88,39 @@ add_path_element() echo "$PA" } + CLPATH=`lookup_prog_in_path cl` if [ -z "$CLPATH" ]; then - echo "Can not locate cl.exe and vcredist_x86.exe - OK if using mingw" >&2 + echo "Can not locate cl.exe and vcredist_x86/x64.exe - OK if using mingw" >&2 exit 1 fi -#echo $CLPATH +# Look to see if it's 64bit +XX=`remove_path_element cl "$CLPATH"` +YY=`remove_path_element amd64 "$XX"` +if [ "$YY" != "$XX" ]; then + AMD64DIR=true + VCREDIST=vcredist_x64 + COMPONENTS="cl amd64 bin vc" +else + AMD64DIR=false + VCREDIST=vcredist_x86 + COMPONENTS="cl bin vc" +fi + +if [ X"$1" = X"-n" ]; then + echo $VCREDIST.exe + exit 0 +fi + +# echo $CLPATH BPATH=$CLPATH -for x in cl bin vc; do - #echo $x +for x in $COMPONENTS; do + # echo $x NBPATH=`remove_path_element $x "$BPATH"` if [ "$NBPATH" = "$BPATH" ]; then - echo "Failed to locate vcredist_x86.exe because cl.exe was in an unexpected location" >&2 + echo "Failed to locate $VCREDIST.exe because cl.exe was in an unexpected location" >&2 exit 2 fi BPATH="$NBPATH" @@ -115,7 +133,12 @@ fail=false if [ '!' -z "$RCPATH" ]; then BPATH=$RCPATH allow_fail=false - for x in rc bin @ANY v6.0A v7.0A v7.1; do + if [ $AMD64DIR = true ]; then + COMPONENTS="rc x64 bin @ANY v6.0A v7.0A v7.1" + else + COMPONENTS="rc bin @ANY v6.0A v7.0A v7.1" + fi + for x in $COMPONENTS; do if [ $x = @ANY ]; then allow_fail=true else @@ -131,6 +154,7 @@ if [ '!' -z "$RCPATH" ]; then BPATH_LIST="$BPATH_LIST $BPATH" fi fi +# echo "BPATH_LIST=$BPATH_LIST" # Frantic search through two roots with different # version directories. We want to be very specific about the @@ -143,7 +167,7 @@ for BP in $BPATH_LIST; do BPATH=$BP fail=false allow_fail=false - for x in $verdir @ANY bootstrapper packages vcredist_x86 Redist VC @ALL vcredist_x86.exe; do + for x in $verdir @ANY bootstrapper packages $VCREDIST Redist VC @ALL $VCREDIST.exe; do #echo "x=$x" #echo "BPATH=$BPATH" #echo "allow_fail=$allow_fail" @@ -170,18 +194,18 @@ for BP in $BPATH_LIST; do fi done -# shortcut for locating vcredist_x86.exe is to put it into $ERL_TOP -if [ -f $ERL_TOP/vcredist_x86.exe ]; then - echo $ERL_TOP/vcredist_x86.exe +# shortcut for locating $VCREDIST.exe is to put it into $ERL_TOP +if [ -f $ERL_TOP/$VCREDIST.exe ]; then + echo $ERL_TOP/$VCREDIST.exe exit 0 fi # or $ERL_TOP/.. to share across multiple builds -if [ -f $ERL_TOP/../vcredist_x86.exe ]; then - echo $ERL_TOP/../vcredist_x86.exe +if [ -f $ERL_TOP/../$VCREDIST.exe ]; then + echo $ERL_TOP/../$VCREDIST.exe exit 0 fi -echo "Failed to locate vcredist_x86.exe because directory structure was unexpected" >&2 +echo "Failed to locate $VCREDIST.exe because directory structure was unexpected" >&2 exit 3 diff --git a/erts/etc/win32/win_erlexec.c b/erts/etc/win32/win_erlexec.c index 0eed8e28b9..11cc6a30f7 100644 --- a/erts/etc/win32/win_erlexec.c +++ b/erts/etc/win32/win_erlexec.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2009. All Rights Reserved. + * Copyright Ericsson AB 1997-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -30,6 +30,9 @@ #include <winuser.h> #include <wincon.h> #include <process.h> +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif #include "sys.h" #include "erl_driver.h" diff --git a/erts/include/erl_int_sizes_config.h.in b/erts/include/erl_int_sizes_config.h.in index 4b8a8e1b98..14d7c6a702 100644 --- a/erts/include/erl_int_sizes_config.h.in +++ b/erts/include/erl_int_sizes_config.h.in @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * Copyright Ericsson AB 2004-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -32,5 +32,8 @@ /* The number of bytes in a long long. */ #undef SIZEOF_LONG_LONG +/* The size of a pointer. */ +#undef SIZEOF_VOID_P + /* Define if building a halfword-heap 64bit emulator (needed for NIF's) */ #undef HALFWORD_HEAP_EMULATOR diff --git a/erts/include/internal/ethr_atomics.h b/erts/include/internal/ethr_atomics.h index 0f3c26f1df..612894b8c1 100644 --- a/erts/include/internal/ethr_atomics.h +++ b/erts/include/internal/ethr_atomics.h @@ -10,7 +10,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011. All Rights Reserved. + * Copyright Ericsson AB 2011-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -64,12 +64,31 @@ * Appart from a function implementing the atomic operation * with unspecified memory barrier semantics, there are * functions implementing each operation with the following - * memory barrier semantics: - * - rb (read barrier) - * - wb (write barrier) - * - acqb (acquire barrier) - * - relb (release barrier) - * - mb (full memory barrier) + * implied memory barrier semantics: + * - mb - Full memory barrier. Orders both loads, and + * stores before, and after the atomic operation. + * No load or store is allowed to be reordered + * over the atomic operation. + * - relb - Release barrier. Orders both loads, and + * stores appearing *before* the atomic + * operation. These are not allowed to be + * reordered over the atomic operation. + * - acqb - Acquire barrier. Orders both loads, and stores + * appearing *after* the atomic operation. These + * are not allowed to be reordered over the + * atomic operation. + * - wb - Write barrier. Orders *only* stores. These are + * not allowed to be reordered over the barrier. + * Store in atomic operation is ordered *after* + * the barrier. + * - rb - Read barrier. Orders *only* loads. These are + * not allowed to be reordered over the barrier. + * Load in atomic operation is ordered *before* + * the barrier. + * - ddrb - Data dependency read barrier. Orders *only* + * loads according to data dependency across the + * barrier. Load in atomic operation is ordered + * before the barrier. * * We implement all of these operation/barrier * combinations, regardless of whether they are useful @@ -535,24 +554,28 @@ char **ethr_native_su_dw_atomic_ops(void); #ifdef ETHR_NEED_DW_ATMC_PROTOTYPES__ ethr_sint_t *ethr_dw_atomic_addr(ethr_dw_atomic_t *var); int ethr_dw_atomic_cmpxchg(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); +int ethr_dw_atomic_cmpxchg_ddrb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); int ethr_dw_atomic_cmpxchg_rb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); int ethr_dw_atomic_cmpxchg_wb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); int ethr_dw_atomic_cmpxchg_acqb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); int ethr_dw_atomic_cmpxchg_relb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); int ethr_dw_atomic_cmpxchg_mb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); void ethr_dw_atomic_set(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); +void ethr_dw_atomic_set_ddrb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_set_rb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_set_wb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_set_acqb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_set_relb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_set_mb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_read(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); +void ethr_dw_atomic_read_ddrb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_read_rb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_read_wb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_read_acqb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_read_relb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_read_mb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_init(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); +void ethr_dw_atomic_init_ddrb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_init_rb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_init_wb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ethr_dw_atomic_init_acqb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); @@ -561,24 +584,28 @@ void ethr_dw_atomic_init_mb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); #if defined(ETHR_RTCHK_USE_NATIVE_DW_ATOMIC_IMPL__) ethr_sint_t *ETHR_DW_ATOMIC_FUNC__(addr)(ethr_dw_atomic_t *var); int ETHR_DW_ATOMIC_FUNC__(cmpxchg)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); +int ETHR_DW_ATOMIC_FUNC__(cmpxchg_ddrb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); int ETHR_DW_ATOMIC_FUNC__(cmpxchg_rb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); int ETHR_DW_ATOMIC_FUNC__(cmpxchg_wb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); int ETHR_DW_ATOMIC_FUNC__(cmpxchg_acqb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); int ETHR_DW_ATOMIC_FUNC__(cmpxchg_relb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); int ETHR_DW_ATOMIC_FUNC__(cmpxchg_mb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val); void ETHR_DW_ATOMIC_FUNC__(set)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); +void ETHR_DW_ATOMIC_FUNC__(set_ddrb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(set_rb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(set_wb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(set_acqb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(set_relb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(set_mb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(read)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); +void ETHR_DW_ATOMIC_FUNC__(read_ddrb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(read_rb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(read_wb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(read_acqb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(read_relb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(read_mb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(init)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); +void ETHR_DW_ATOMIC_FUNC__(init_ddrb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(init_rb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(init_wb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); void ETHR_DW_ATOMIC_FUNC__(init_acqb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val); @@ -1491,6 +1518,15 @@ static ETHR_INLINE int ETHR_DW_ATMC_FUNC__(cmpxchg_mb)(ethr_dw_atomic_t *var, et return res; } +static ETHR_INLINE int ETHR_DW_ATMC_FUNC__(cmpxchg_ddrb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_DW_ATMC_FUNC__(cmpxchg)(var, val, old_val); +#else + return ETHR_DW_ATMC_FUNC__(cmpxchg_rb)(var, val, old_val); +#endif +} + /* --- set() --- */ @@ -1981,6 +2017,15 @@ static ETHR_INLINE void ETHR_DW_ATMC_FUNC__(set_mb)(ethr_dw_atomic_t *var, ethr_ } +static ETHR_INLINE void ETHR_DW_ATMC_FUNC__(set_ddrb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + ETHR_DW_ATMC_FUNC__(set)(var, val); +#else + ETHR_DW_ATMC_FUNC__(set_rb)(var, val); +#endif +} + /* --- read() --- */ @@ -2309,6 +2354,15 @@ static ETHR_INLINE void ETHR_DW_ATMC_FUNC__(read_mb)(ethr_dw_atomic_t *var, ethr } +static ETHR_INLINE void ETHR_DW_ATMC_FUNC__(read_ddrb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + ETHR_DW_ATMC_FUNC__(read)(var, val); +#else + ETHR_DW_ATMC_FUNC__(read_rb)(var, val); +#endif +} + /* --- init() --- */ @@ -2607,6 +2661,15 @@ static ETHR_INLINE void ETHR_DW_ATMC_FUNC__(init_mb)(ethr_dw_atomic_t *var, ethr } +static ETHR_INLINE void ETHR_DW_ATMC_FUNC__(init_ddrb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + ETHR_DW_ATMC_FUNC__(init)(var, val); +#else + ETHR_DW_ATMC_FUNC__(init_rb)(var, val); +#endif +} + #endif /* ETHR_DW_ATMC_INLINE__ */ @@ -2616,78 +2679,91 @@ static ETHR_INLINE void ETHR_DW_ATMC_FUNC__(init_mb)(ethr_dw_atomic_t *var, ethr #ifdef ETHR_NEED_ATMC_PROTOTYPES__ ethr_sint_t *ethr_atomic_addr(ethr_atomic_t *var); ethr_sint_t ethr_atomic_cmpxchg(ethr_atomic_t *var, ethr_sint_t val, ethr_sint_t old_val); +ethr_sint_t ethr_atomic_cmpxchg_ddrb(ethr_atomic_t *var, ethr_sint_t val, ethr_sint_t old_val); ethr_sint_t ethr_atomic_cmpxchg_rb(ethr_atomic_t *var, ethr_sint_t val, ethr_sint_t old_val); ethr_sint_t ethr_atomic_cmpxchg_wb(ethr_atomic_t *var, ethr_sint_t val, ethr_sint_t old_val); ethr_sint_t ethr_atomic_cmpxchg_acqb(ethr_atomic_t *var, ethr_sint_t val, ethr_sint_t old_val); ethr_sint_t ethr_atomic_cmpxchg_relb(ethr_atomic_t *var, ethr_sint_t val, ethr_sint_t old_val); ethr_sint_t ethr_atomic_cmpxchg_mb(ethr_atomic_t *var, ethr_sint_t val, ethr_sint_t old_val); ethr_sint_t ethr_atomic_xchg(ethr_atomic_t *var, ethr_sint_t val); +ethr_sint_t ethr_atomic_xchg_ddrb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_xchg_rb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_xchg_wb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_xchg_acqb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_xchg_relb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_xchg_mb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_set(ethr_atomic_t *var, ethr_sint_t val); +void ethr_atomic_set_ddrb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_set_rb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_set_wb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_set_acqb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_set_relb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_set_mb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_init(ethr_atomic_t *var, ethr_sint_t val); +void ethr_atomic_init_ddrb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_init_rb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_init_wb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_init_acqb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_init_relb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_init_mb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_add_read(ethr_atomic_t *var, ethr_sint_t val); +ethr_sint_t ethr_atomic_add_read_ddrb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_add_read_rb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_add_read_wb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_add_read_acqb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_add_read_relb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_add_read_mb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_read(ethr_atomic_t *var); +ethr_sint_t ethr_atomic_read_ddrb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_read_rb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_read_wb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_read_acqb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_read_relb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_read_mb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_inc_read(ethr_atomic_t *var); +ethr_sint_t ethr_atomic_inc_read_ddrb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_inc_read_rb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_inc_read_wb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_inc_read_acqb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_inc_read_relb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_inc_read_mb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_dec_read(ethr_atomic_t *var); +ethr_sint_t ethr_atomic_dec_read_ddrb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_dec_read_rb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_dec_read_wb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_dec_read_acqb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_dec_read_relb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_dec_read_mb(ethr_atomic_t *var); void ethr_atomic_add(ethr_atomic_t *var, ethr_sint_t val); +void ethr_atomic_add_ddrb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_add_rb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_add_wb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_add_acqb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_add_relb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_add_mb(ethr_atomic_t *var, ethr_sint_t val); void ethr_atomic_inc(ethr_atomic_t *var); +void ethr_atomic_inc_ddrb(ethr_atomic_t *var); void ethr_atomic_inc_rb(ethr_atomic_t *var); void ethr_atomic_inc_wb(ethr_atomic_t *var); void ethr_atomic_inc_acqb(ethr_atomic_t *var); void ethr_atomic_inc_relb(ethr_atomic_t *var); void ethr_atomic_inc_mb(ethr_atomic_t *var); void ethr_atomic_dec(ethr_atomic_t *var); +void ethr_atomic_dec_ddrb(ethr_atomic_t *var); void ethr_atomic_dec_rb(ethr_atomic_t *var); void ethr_atomic_dec_wb(ethr_atomic_t *var); void ethr_atomic_dec_acqb(ethr_atomic_t *var); void ethr_atomic_dec_relb(ethr_atomic_t *var); void ethr_atomic_dec_mb(ethr_atomic_t *var); ethr_sint_t ethr_atomic_read_band(ethr_atomic_t *var, ethr_sint_t val); +ethr_sint_t ethr_atomic_read_band_ddrb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_read_band_rb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_read_band_wb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_read_band_acqb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_read_band_relb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_read_band_mb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_read_bor(ethr_atomic_t *var, ethr_sint_t val); +ethr_sint_t ethr_atomic_read_bor_ddrb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_read_bor_rb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_read_bor_wb(ethr_atomic_t *var, ethr_sint_t val); ethr_sint_t ethr_atomic_read_bor_acqb(ethr_atomic_t *var, ethr_sint_t val); @@ -3551,6 +3627,15 @@ static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(cmpxchg_mb)(ethr_atomic_t *var, return res; } +static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(cmpxchg_ddrb)(ethr_atomic_t *var, ethr_sint_t val, ethr_sint_t old_val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC_FUNC__(cmpxchg)(var, val, old_val); +#else + return ETHR_ATMC_FUNC__(cmpxchg_rb)(var, val, old_val); +#endif +} + /* --- xchg() --- */ @@ -3801,6 +3886,15 @@ static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(xchg_mb)(ethr_atomic_t *var, eth return res; } +static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(xchg_ddrb)(ethr_atomic_t *var, ethr_sint_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC_FUNC__(xchg)(var, val); +#else + return ETHR_ATMC_FUNC__(xchg_rb)(var, val); +#endif +} + /* --- set() --- */ @@ -3943,6 +4037,15 @@ static ETHR_INLINE void ETHR_ATMC_FUNC__(set_mb)(ethr_atomic_t *var, ethr_sint_t #endif } +static ETHR_INLINE void ETHR_ATMC_FUNC__(set_ddrb)(ethr_atomic_t *var, ethr_sint_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + ETHR_ATMC_FUNC__(set)(var, val); +#else + ETHR_ATMC_FUNC__(set_rb)(var, val); +#endif +} + /* --- init() --- */ @@ -4085,6 +4188,15 @@ static ETHR_INLINE void ETHR_ATMC_FUNC__(init_mb)(ethr_atomic_t *var, ethr_sint_ #endif } +static ETHR_INLINE void ETHR_ATMC_FUNC__(init_ddrb)(ethr_atomic_t *var, ethr_sint_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + ETHR_ATMC_FUNC__(init)(var, val); +#else + ETHR_ATMC_FUNC__(init_rb)(var, val); +#endif +} + /* --- add_read() --- */ @@ -4335,6 +4447,15 @@ static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(add_read_mb)(ethr_atomic_t *var, return res; } +static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(add_read_ddrb)(ethr_atomic_t *var, ethr_sint_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC_FUNC__(add_read)(var, val); +#else + return ETHR_ATMC_FUNC__(add_read_rb)(var, val); +#endif +} + /* --- read() --- */ @@ -4489,6 +4610,15 @@ static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(read_mb)(ethr_atomic_t *var) return res; } +static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(read_ddrb)(ethr_atomic_t *var) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC_FUNC__(read)(var); +#else + return ETHR_ATMC_FUNC__(read_rb)(var); +#endif +} + /* --- inc_read() --- */ @@ -4643,6 +4773,15 @@ static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(inc_read_mb)(ethr_atomic_t *var) return res; } +static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(inc_read_ddrb)(ethr_atomic_t *var) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC_FUNC__(inc_read)(var); +#else + return ETHR_ATMC_FUNC__(inc_read_rb)(var); +#endif +} + /* --- dec_read() --- */ @@ -4797,6 +4936,15 @@ static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(dec_read_mb)(ethr_atomic_t *var) return res; } +static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(dec_read_ddrb)(ethr_atomic_t *var) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC_FUNC__(dec_read)(var); +#else + return ETHR_ATMC_FUNC__(dec_read_rb)(var); +#endif +} + /* --- add() --- */ @@ -4939,6 +5087,15 @@ static ETHR_INLINE void ETHR_ATMC_FUNC__(add_mb)(ethr_atomic_t *var, ethr_sint_t #endif } +static ETHR_INLINE void ETHR_ATMC_FUNC__(add_ddrb)(ethr_atomic_t *var, ethr_sint_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + ETHR_ATMC_FUNC__(add)(var, val); +#else + ETHR_ATMC_FUNC__(add_rb)(var, val); +#endif +} + /* --- inc() --- */ @@ -5081,6 +5238,15 @@ static ETHR_INLINE void ETHR_ATMC_FUNC__(inc_mb)(ethr_atomic_t *var) #endif } +static ETHR_INLINE void ETHR_ATMC_FUNC__(inc_ddrb)(ethr_atomic_t *var) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + ETHR_ATMC_FUNC__(inc)(var); +#else + ETHR_ATMC_FUNC__(inc_rb)(var); +#endif +} + /* --- dec() --- */ @@ -5223,6 +5389,15 @@ static ETHR_INLINE void ETHR_ATMC_FUNC__(dec_mb)(ethr_atomic_t *var) #endif } +static ETHR_INLINE void ETHR_ATMC_FUNC__(dec_ddrb)(ethr_atomic_t *var) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + ETHR_ATMC_FUNC__(dec)(var); +#else + ETHR_ATMC_FUNC__(dec_rb)(var); +#endif +} + /* --- read_band() --- */ @@ -5473,6 +5648,15 @@ static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(read_band_mb)(ethr_atomic_t *var return res; } +static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(read_band_ddrb)(ethr_atomic_t *var, ethr_sint_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC_FUNC__(read_band)(var, val); +#else + return ETHR_ATMC_FUNC__(read_band_rb)(var, val); +#endif +} + /* --- read_bor() --- */ @@ -5723,6 +5907,15 @@ static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(read_bor_mb)(ethr_atomic_t *var, return res; } +static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(read_bor_ddrb)(ethr_atomic_t *var, ethr_sint_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC_FUNC__(read_bor)(var, val); +#else + return ETHR_ATMC_FUNC__(read_bor_rb)(var, val); +#endif +} + #endif /* ETHR_ATMC_INLINE__ */ @@ -5732,78 +5925,91 @@ static ETHR_INLINE ethr_sint_t ETHR_ATMC_FUNC__(read_bor_mb)(ethr_atomic_t *var, #ifdef ETHR_NEED_ATMC32_PROTOTYPES__ ethr_sint32_t *ethr_atomic32_addr(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_cmpxchg(ethr_atomic32_t *var, ethr_sint32_t val, ethr_sint32_t old_val); +ethr_sint32_t ethr_atomic32_cmpxchg_ddrb(ethr_atomic32_t *var, ethr_sint32_t val, ethr_sint32_t old_val); ethr_sint32_t ethr_atomic32_cmpxchg_rb(ethr_atomic32_t *var, ethr_sint32_t val, ethr_sint32_t old_val); ethr_sint32_t ethr_atomic32_cmpxchg_wb(ethr_atomic32_t *var, ethr_sint32_t val, ethr_sint32_t old_val); ethr_sint32_t ethr_atomic32_cmpxchg_acqb(ethr_atomic32_t *var, ethr_sint32_t val, ethr_sint32_t old_val); ethr_sint32_t ethr_atomic32_cmpxchg_relb(ethr_atomic32_t *var, ethr_sint32_t val, ethr_sint32_t old_val); ethr_sint32_t ethr_atomic32_cmpxchg_mb(ethr_atomic32_t *var, ethr_sint32_t val, ethr_sint32_t old_val); ethr_sint32_t ethr_atomic32_xchg(ethr_atomic32_t *var, ethr_sint32_t val); +ethr_sint32_t ethr_atomic32_xchg_ddrb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_xchg_rb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_xchg_wb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_xchg_acqb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_xchg_relb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_xchg_mb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_set(ethr_atomic32_t *var, ethr_sint32_t val); +void ethr_atomic32_set_ddrb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_set_rb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_set_wb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_set_acqb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_set_relb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_set_mb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_init(ethr_atomic32_t *var, ethr_sint32_t val); +void ethr_atomic32_init_ddrb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_init_rb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_init_wb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_init_acqb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_init_relb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_init_mb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_add_read(ethr_atomic32_t *var, ethr_sint32_t val); +ethr_sint32_t ethr_atomic32_add_read_ddrb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_add_read_rb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_add_read_wb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_add_read_acqb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_add_read_relb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_add_read_mb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_read(ethr_atomic32_t *var); +ethr_sint32_t ethr_atomic32_read_ddrb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_read_rb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_read_wb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_read_acqb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_read_relb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_read_mb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_inc_read(ethr_atomic32_t *var); +ethr_sint32_t ethr_atomic32_inc_read_ddrb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_inc_read_rb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_inc_read_wb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_inc_read_acqb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_inc_read_relb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_inc_read_mb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_dec_read(ethr_atomic32_t *var); +ethr_sint32_t ethr_atomic32_dec_read_ddrb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_dec_read_rb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_dec_read_wb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_dec_read_acqb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_dec_read_relb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_dec_read_mb(ethr_atomic32_t *var); void ethr_atomic32_add(ethr_atomic32_t *var, ethr_sint32_t val); +void ethr_atomic32_add_ddrb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_add_rb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_add_wb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_add_acqb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_add_relb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_add_mb(ethr_atomic32_t *var, ethr_sint32_t val); void ethr_atomic32_inc(ethr_atomic32_t *var); +void ethr_atomic32_inc_ddrb(ethr_atomic32_t *var); void ethr_atomic32_inc_rb(ethr_atomic32_t *var); void ethr_atomic32_inc_wb(ethr_atomic32_t *var); void ethr_atomic32_inc_acqb(ethr_atomic32_t *var); void ethr_atomic32_inc_relb(ethr_atomic32_t *var); void ethr_atomic32_inc_mb(ethr_atomic32_t *var); void ethr_atomic32_dec(ethr_atomic32_t *var); +void ethr_atomic32_dec_ddrb(ethr_atomic32_t *var); void ethr_atomic32_dec_rb(ethr_atomic32_t *var); void ethr_atomic32_dec_wb(ethr_atomic32_t *var); void ethr_atomic32_dec_acqb(ethr_atomic32_t *var); void ethr_atomic32_dec_relb(ethr_atomic32_t *var); void ethr_atomic32_dec_mb(ethr_atomic32_t *var); ethr_sint32_t ethr_atomic32_read_band(ethr_atomic32_t *var, ethr_sint32_t val); +ethr_sint32_t ethr_atomic32_read_band_ddrb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_read_band_rb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_read_band_wb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_read_band_acqb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_read_band_relb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_read_band_mb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_read_bor(ethr_atomic32_t *var, ethr_sint32_t val); +ethr_sint32_t ethr_atomic32_read_bor_ddrb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_read_bor_rb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_read_bor_wb(ethr_atomic32_t *var, ethr_sint32_t val); ethr_sint32_t ethr_atomic32_read_bor_acqb(ethr_atomic32_t *var, ethr_sint32_t val); @@ -6667,6 +6873,15 @@ static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(cmpxchg_mb)(ethr_atomic32_t return res; } +static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(cmpxchg_ddrb)(ethr_atomic32_t *var, ethr_sint32_t val, ethr_sint32_t old_val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC32_FUNC__(cmpxchg)(var, val, old_val); +#else + return ETHR_ATMC32_FUNC__(cmpxchg_rb)(var, val, old_val); +#endif +} + /* --- xchg() --- */ @@ -6917,6 +7132,15 @@ static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(xchg_mb)(ethr_atomic32_t *va return res; } +static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(xchg_ddrb)(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC32_FUNC__(xchg)(var, val); +#else + return ETHR_ATMC32_FUNC__(xchg_rb)(var, val); +#endif +} + /* --- set() --- */ @@ -7059,6 +7283,15 @@ static ETHR_INLINE void ETHR_ATMC32_FUNC__(set_mb)(ethr_atomic32_t *var, ethr_si #endif } +static ETHR_INLINE void ETHR_ATMC32_FUNC__(set_ddrb)(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + ETHR_ATMC32_FUNC__(set)(var, val); +#else + ETHR_ATMC32_FUNC__(set_rb)(var, val); +#endif +} + /* --- init() --- */ @@ -7201,6 +7434,15 @@ static ETHR_INLINE void ETHR_ATMC32_FUNC__(init_mb)(ethr_atomic32_t *var, ethr_s #endif } +static ETHR_INLINE void ETHR_ATMC32_FUNC__(init_ddrb)(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + ETHR_ATMC32_FUNC__(init)(var, val); +#else + ETHR_ATMC32_FUNC__(init_rb)(var, val); +#endif +} + /* --- add_read() --- */ @@ -7451,6 +7693,15 @@ static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(add_read_mb)(ethr_atomic32_t return res; } +static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(add_read_ddrb)(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC32_FUNC__(add_read)(var, val); +#else + return ETHR_ATMC32_FUNC__(add_read_rb)(var, val); +#endif +} + /* --- read() --- */ @@ -7605,6 +7856,15 @@ static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(read_mb)(ethr_atomic32_t *va return res; } +static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(read_ddrb)(ethr_atomic32_t *var) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC32_FUNC__(read)(var); +#else + return ETHR_ATMC32_FUNC__(read_rb)(var); +#endif +} + /* --- inc_read() --- */ @@ -7759,6 +8019,15 @@ static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(inc_read_mb)(ethr_atomic32_t return res; } +static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(inc_read_ddrb)(ethr_atomic32_t *var) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC32_FUNC__(inc_read)(var); +#else + return ETHR_ATMC32_FUNC__(inc_read_rb)(var); +#endif +} + /* --- dec_read() --- */ @@ -7913,6 +8182,15 @@ static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(dec_read_mb)(ethr_atomic32_t return res; } +static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(dec_read_ddrb)(ethr_atomic32_t *var) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC32_FUNC__(dec_read)(var); +#else + return ETHR_ATMC32_FUNC__(dec_read_rb)(var); +#endif +} + /* --- add() --- */ @@ -8055,6 +8333,15 @@ static ETHR_INLINE void ETHR_ATMC32_FUNC__(add_mb)(ethr_atomic32_t *var, ethr_si #endif } +static ETHR_INLINE void ETHR_ATMC32_FUNC__(add_ddrb)(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + ETHR_ATMC32_FUNC__(add)(var, val); +#else + ETHR_ATMC32_FUNC__(add_rb)(var, val); +#endif +} + /* --- inc() --- */ @@ -8197,6 +8484,15 @@ static ETHR_INLINE void ETHR_ATMC32_FUNC__(inc_mb)(ethr_atomic32_t *var) #endif } +static ETHR_INLINE void ETHR_ATMC32_FUNC__(inc_ddrb)(ethr_atomic32_t *var) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + ETHR_ATMC32_FUNC__(inc)(var); +#else + ETHR_ATMC32_FUNC__(inc_rb)(var); +#endif +} + /* --- dec() --- */ @@ -8339,6 +8635,15 @@ static ETHR_INLINE void ETHR_ATMC32_FUNC__(dec_mb)(ethr_atomic32_t *var) #endif } +static ETHR_INLINE void ETHR_ATMC32_FUNC__(dec_ddrb)(ethr_atomic32_t *var) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + ETHR_ATMC32_FUNC__(dec)(var); +#else + ETHR_ATMC32_FUNC__(dec_rb)(var); +#endif +} + /* --- read_band() --- */ @@ -8589,6 +8894,15 @@ static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(read_band_mb)(ethr_atomic32_ return res; } +static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(read_band_ddrb)(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC32_FUNC__(read_band)(var, val); +#else + return ETHR_ATMC32_FUNC__(read_band_rb)(var, val); +#endif +} + /* --- read_bor() --- */ @@ -8839,6 +9153,15 @@ static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(read_bor_mb)(ethr_atomic32_t return res; } +static ETHR_INLINE ethr_sint32_t ETHR_ATMC32_FUNC__(read_bor_ddrb)(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#ifdef ETHR_ORDERED_READ_DEPEND + return ETHR_ATMC32_FUNC__(read_bor)(var, val); +#else + return ETHR_ATMC32_FUNC__(read_bor_rb)(var, val); +#endif +} + #endif /* ETHR_ATMC32_INLINE__ */ #endif /* ETHR_ATOMICS_H__ */ diff --git a/erts/lib_src/Makefile.in b/erts/lib_src/Makefile.in index 12b8732735..ea80e74100 100644 --- a/erts/lib_src/Makefile.in +++ b/erts/lib_src/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2004-2011. All Rights Reserved. +# Copyright Ericsson AB 2004-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -138,7 +138,7 @@ INCLUDES=-I$(ERTS_INCL) -I$(ERTS_INCL)/$(TARGET) -I$(ERTS_INCL_INT) -I$(ERTS_INC INCLUDES += -I../emulator/beam -I../emulator/sys/$(ERLANG_OSTYPE) USING_MINGW=@MIXED_CYGWIN_MINGW@ -USING_VC=@MIXED_CYGWIN_VC@ +USING_VC=@MIXED_VC@ ifeq ($(USING_VC),yes) LIB_SUFFIX=.lib @@ -318,10 +318,14 @@ ETHREAD_LIB= endif +_create_dirs := $(shell mkdir -p $(CREATE_DIRS)) # # Everything to build # -all: $(CREATE_DIRS) $(ETHREAD_LIB) $(ERTS_LIBS) $(ERTS_INTERNAL_LIBS) +.PHONY: all +all: $(OBJ_DIR)/MADE + +$(OBJ_DIR)/MADE: $(ETHREAD_LIB) $(ERTS_LIBS) $(ERTS_INTERNAL_LIBS) ifeq ($(OMIT_OMIT_FP),yes) @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' @@ -331,6 +335,8 @@ ifeq ($(OMIT_OMIT_FP),yes) @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' endif + echo $? > $(OBJ_DIR)/MADE + # # The libs ... # @@ -428,13 +434,6 @@ $(MTd_OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c $(CC) $(THR_DEFS) $(CFLAGS) -MTd $(INCLUDES) -c $< -o $@ # -# Create directories -# - -$(CREATE_DIRS): - $(MKDIR) -p $@ - -# # Install # @@ -471,6 +470,7 @@ INTERNAL_RELEASE_LIBS= \ $(ETHREAD_LIB) \ $(ERTS_INTERNAL_LIBS) +.PHONY: release_spec release_spec: all ifneq ($(strip $(RELEASE_INCLUDES)),) $(INSTALL_DIR) $(RELSYSDIR)/include @@ -500,19 +500,20 @@ ifneq ($(strip $(INTERNAL_RELEASE_LIBS)),) $(INSTALL_DATA) $(INTERNAL_RELEASE_LIBS) $(RELSYSDIR)/lib/internal endif +.PHONY: docs docs: +.PHONY: release_docs_spec release_docs_spec: - # # Cleanup # +.PHONY: clean clean: $(RM) -rf ../lib/internal/$(TARGET)/* $(RM) -rf ../lib/$(TARGET)/* $(RM) -rf obj/$(TARGET)/* - $(RM) -f $(TARGET)/depend.mk # # Make dependencies @@ -554,9 +555,11 @@ SED_MDd_DEPEND=sed '$(SED_PREFIX)$(SED_REPL_MDd_O);$(SED_REPL_TT_DIR);$(SED_REPL SED_MT_DEPEND=sed '$(SED_PREFIX)$(SED_REPL_MT_O);$(SED_REPL_TT_DIR);$(SED_REPL_TARGET)' SED_MTd_DEPEND=sed '$(SED_PREFIX)$(SED_REPL_MTd_O);$(SED_REPL_TT_DIR);$(SED_REPL_TARGET)' -DEPEND_MK=$(TARGET)/depend.mk +DEPEND_MK=$(OBJ_DIR)/depend.mk -depend: +.PHONY: depend +depend: $(DEPEND_MK) +$(DEPEND_MK): @echo "Generating dependency file $(DEPEND_MK)..." @echo "# Generated dependency rules" > $(DEPEND_MK); @echo "# " >> $(DEPEND_MK); @@ -629,6 +632,8 @@ endif endif @echo "# EOF" >> $(DEPEND_MK); +ifneq ($(MAKECMDGOALS),clean) -include $(DEPEND_MK) +endif # eof diff --git a/erts/lib_src/common/erl_memory_trace_parser.c b/erts/lib_src/common/erl_memory_trace_parser.c index ebf7182913..625c140cf9 100644 --- a/erts/lib_src/common/erl_memory_trace_parser.c +++ b/erts/lib_src/common/erl_memory_trace_parser.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2004-2009. All Rights Reserved. + * Copyright Ericsson AB 2004-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in diff --git a/erts/lib_src/common/erl_misc_utils.c b/erts/lib_src/common/erl_misc_utils.c index 5e94ff19db..4806311dfe 100644 --- a/erts/lib_src/common/erl_misc_utils.c +++ b/erts/lib_src/common/erl_misc_utils.c @@ -834,8 +834,8 @@ read_topology(erts_cpu_info_t *cpuinfo) ix = -1; if (realpath(ERTS_SYS_NODE_PATH, npath)) { - got_nodes = 1; ndir = opendir(npath); + got_nodes = (ndir != NULL); } do { diff --git a/erts/lib_src/common/ethr_atomics.c b/erts/lib_src/common/ethr_atomics.c index 5796bdc22e..c52166a7ec 100644 --- a/erts/lib_src/common/ethr_atomics.c +++ b/erts/lib_src/common/ethr_atomics.c @@ -10,7 +10,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011. All Rights Reserved. + * Copyright Ericsson AB 2011-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -64,12 +64,31 @@ * Appart from a function implementing the atomic operation * with unspecified memory barrier semantics, there are * functions implementing each operation with the following - * memory barrier semantics: - * - rb (read barrier) - * - wb (write barrier) - * - acqb (acquire barrier) - * - relb (release barrier) - * - mb (full memory barrier) + * implied memory barrier semantics: + * - mb - Full memory barrier. Orders both loads, and + * stores before, and after the atomic operation. + * No load or store is allowed to be reordered + * over the atomic operation. + * - relb - Release barrier. Orders both loads, and + * stores appearing *before* the atomic + * operation. These are not allowed to be + * reordered over the atomic operation. + * - acqb - Acquire barrier. Orders both loads, and stores + * appearing *after* the atomic operation. These + * are not allowed to be reordered over the + * atomic operation. + * - wb - Write barrier. Orders *only* stores. These are + * not allowed to be reordered over the barrier. + * Store in atomic operation is ordered *after* + * the barrier. + * - rb - Read barrier. Orders *only* loads. These are + * not allowed to be reordered over the barrier. + * Load in atomic operation is ordered *before* + * the barrier. + * - ddrb - Data dependency read barrier. Orders *only* + * loads according to data dependency across the + * barrier. Load in atomic operation is ordered + * before the barrier. * * We implement all of these operation/barrier * combinations, regardless of whether they are useful @@ -542,6 +561,17 @@ int ethr_dw_atomic_cmpxchg(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_s } #endif +int ethr_dw_atomic_cmpxchg_ddrb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val) +{ +#if defined(ETHR_HAVE_DOUBLE_WORD_SZ_NATIVE_ATOMIC_OPS) + return ethr_dw_atomic_cmpxchg_ddrb__(var, val, old_val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_dw_atomic_cmpxchg(var, val, old_val); +#else + return ethr_dw_atomic_cmpxchg_rb(var, val, old_val); +#endif +} + int ETHR_DW_ATOMIC_FUNC__(cmpxchg_rb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val) { int res; @@ -756,6 +786,17 @@ void ethr_dw_atomic_set(ethr_dw_atomic_t *var, ethr_dw_sint_t *val) } #endif +void ethr_dw_atomic_set_ddrb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val) +{ +#if defined(ETHR_HAVE_DOUBLE_WORD_SZ_NATIVE_ATOMIC_OPS) + ethr_dw_atomic_set_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + ethr_dw_atomic_set(var, val); +#else + ethr_dw_atomic_set_rb(var, val); +#endif +} + void ETHR_DW_ATOMIC_FUNC__(set_rb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val) { ETHR_ASSERT(!ethr_not_inited__); @@ -910,6 +951,17 @@ void ethr_dw_atomic_read(ethr_dw_atomic_t *var, ethr_dw_sint_t *val) } #endif +void ethr_dw_atomic_read_ddrb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val) +{ +#if defined(ETHR_HAVE_DOUBLE_WORD_SZ_NATIVE_ATOMIC_OPS) + ethr_dw_atomic_read_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + ethr_dw_atomic_read(var, val); +#else + ethr_dw_atomic_read_rb(var, val); +#endif +} + void ETHR_DW_ATOMIC_FUNC__(read_rb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val) { ETHR_ASSERT(!ethr_not_inited__); @@ -1061,6 +1113,17 @@ void ethr_dw_atomic_init(ethr_dw_atomic_t *var, ethr_dw_sint_t *val) } #endif +void ethr_dw_atomic_init_ddrb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val) +{ +#if defined(ETHR_HAVE_DOUBLE_WORD_SZ_NATIVE_ATOMIC_OPS) + ethr_dw_atomic_init_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + ethr_dw_atomic_init(var, val); +#else + ethr_dw_atomic_init_rb(var, val); +#endif +} + void ETHR_DW_ATOMIC_FUNC__(init_rb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val) { ETHR_ASSERT(var); @@ -1221,6 +1284,17 @@ ethr_sint_t ethr_atomic_cmpxchg(ethr_atomic_t *var, ethr_sint_t val, ethr_sint_t return res; } +ethr_sint_t ethr_atomic_cmpxchg_ddrb(ethr_atomic_t *var, ethr_sint_t val, ethr_sint_t old_val) +{ +#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS) + return ethr_atomic_cmpxchg_ddrb__(var, val, old_val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic_cmpxchg(var, val, old_val); +#else + return ethr_atomic_cmpxchg_rb(var, val, old_val); +#endif +} + ethr_sint_t ethr_atomic_cmpxchg_rb(ethr_atomic_t *var, ethr_sint_t val, ethr_sint_t old_val) { ethr_sint_t res; @@ -1332,6 +1406,17 @@ ethr_sint_t ethr_atomic_xchg(ethr_atomic_t *var, ethr_sint_t val) return res; } +ethr_sint_t ethr_atomic_xchg_ddrb(ethr_atomic_t *var, ethr_sint_t val) +{ +#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS) + return ethr_atomic_xchg_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic_xchg(var, val); +#else + return ethr_atomic_xchg_rb(var, val); +#endif +} + ethr_sint_t ethr_atomic_xchg_rb(ethr_atomic_t *var, ethr_sint_t val) { ethr_sint_t res; @@ -1437,6 +1522,17 @@ void ethr_atomic_set(ethr_atomic_t *var, ethr_sint_t val) } +void ethr_atomic_set_ddrb(ethr_atomic_t *var, ethr_sint_t val) +{ +#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS) + ethr_atomic_set_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + ethr_atomic_set(var, val); +#else + ethr_atomic_set_rb(var, val); +#endif +} + void ethr_atomic_set_rb(ethr_atomic_t *var, ethr_sint_t val) { ETHR_ASSERT(!ethr_not_inited__); @@ -1536,6 +1632,17 @@ void ethr_atomic_init(ethr_atomic_t *var, ethr_sint_t val) } +void ethr_atomic_init_ddrb(ethr_atomic_t *var, ethr_sint_t val) +{ +#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS) + ethr_atomic_init_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + ethr_atomic_init(var, val); +#else + ethr_atomic_init_rb(var, val); +#endif +} + void ethr_atomic_init_rb(ethr_atomic_t *var, ethr_sint_t val) { ETHR_ASSERT(var); @@ -1632,6 +1739,17 @@ ethr_sint_t ethr_atomic_add_read(ethr_atomic_t *var, ethr_sint_t val) return res; } +ethr_sint_t ethr_atomic_add_read_ddrb(ethr_atomic_t *var, ethr_sint_t val) +{ +#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS) + return ethr_atomic_add_read_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic_add_read(var, val); +#else + return ethr_atomic_add_read_rb(var, val); +#endif +} + ethr_sint_t ethr_atomic_add_read_rb(ethr_atomic_t *var, ethr_sint_t val) { ethr_sint_t res; @@ -1738,6 +1856,17 @@ ethr_sint_t ethr_atomic_read(ethr_atomic_t *var) return res; } +ethr_sint_t ethr_atomic_read_ddrb(ethr_atomic_t *var) +{ +#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS) + return ethr_atomic_read_ddrb__(var); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic_read(var); +#else + return ethr_atomic_read_rb(var); +#endif +} + ethr_sint_t ethr_atomic_read_rb(ethr_atomic_t *var) { ethr_sint_t res; @@ -1843,6 +1972,17 @@ ethr_sint_t ethr_atomic_inc_read(ethr_atomic_t *var) return res; } +ethr_sint_t ethr_atomic_inc_read_ddrb(ethr_atomic_t *var) +{ +#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS) + return ethr_atomic_inc_read_ddrb__(var); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic_inc_read(var); +#else + return ethr_atomic_inc_read_rb(var); +#endif +} + ethr_sint_t ethr_atomic_inc_read_rb(ethr_atomic_t *var) { ethr_sint_t res; @@ -1949,6 +2089,17 @@ ethr_sint_t ethr_atomic_dec_read(ethr_atomic_t *var) return res; } +ethr_sint_t ethr_atomic_dec_read_ddrb(ethr_atomic_t *var) +{ +#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS) + return ethr_atomic_dec_read_ddrb__(var); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic_dec_read(var); +#else + return ethr_atomic_dec_read_rb(var); +#endif +} + ethr_sint_t ethr_atomic_dec_read_rb(ethr_atomic_t *var) { ethr_sint_t res; @@ -2054,6 +2205,17 @@ void ethr_atomic_add(ethr_atomic_t *var, ethr_sint_t val) } +void ethr_atomic_add_ddrb(ethr_atomic_t *var, ethr_sint_t val) +{ +#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS) + ethr_atomic_add_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + ethr_atomic_add(var, val); +#else + ethr_atomic_add_rb(var, val); +#endif +} + void ethr_atomic_add_rb(ethr_atomic_t *var, ethr_sint_t val) { ETHR_ASSERT(!ethr_not_inited__); @@ -2154,6 +2316,17 @@ void ethr_atomic_inc(ethr_atomic_t *var) } +void ethr_atomic_inc_ddrb(ethr_atomic_t *var) +{ +#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS) + ethr_atomic_inc_ddrb__(var); +#elif defined(ETHR_ORDERED_READ_DEPEND) + ethr_atomic_inc(var); +#else + ethr_atomic_inc_rb(var); +#endif +} + void ethr_atomic_inc_rb(ethr_atomic_t *var) { ETHR_ASSERT(!ethr_not_inited__); @@ -2254,6 +2427,17 @@ void ethr_atomic_dec(ethr_atomic_t *var) } +void ethr_atomic_dec_ddrb(ethr_atomic_t *var) +{ +#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS) + ethr_atomic_dec_ddrb__(var); +#elif defined(ETHR_ORDERED_READ_DEPEND) + ethr_atomic_dec(var); +#else + ethr_atomic_dec_rb(var); +#endif +} + void ethr_atomic_dec_rb(ethr_atomic_t *var) { ETHR_ASSERT(!ethr_not_inited__); @@ -2355,6 +2539,17 @@ ethr_sint_t ethr_atomic_read_band(ethr_atomic_t *var, ethr_sint_t val) return res; } +ethr_sint_t ethr_atomic_read_band_ddrb(ethr_atomic_t *var, ethr_sint_t val) +{ +#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS) + return ethr_atomic_read_band_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic_read_band(var, val); +#else + return ethr_atomic_read_band_rb(var, val); +#endif +} + ethr_sint_t ethr_atomic_read_band_rb(ethr_atomic_t *var, ethr_sint_t val) { ethr_sint_t res; @@ -2461,6 +2656,17 @@ ethr_sint_t ethr_atomic_read_bor(ethr_atomic_t *var, ethr_sint_t val) return res; } +ethr_sint_t ethr_atomic_read_bor_ddrb(ethr_atomic_t *var, ethr_sint_t val) +{ +#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS) + return ethr_atomic_read_bor_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic_read_bor(var, val); +#else + return ethr_atomic_read_bor_rb(var, val); +#endif +} + ethr_sint_t ethr_atomic_read_bor_rb(ethr_atomic_t *var, ethr_sint_t val) { ethr_sint_t res; @@ -2587,6 +2793,17 @@ ethr_sint32_t ethr_atomic32_cmpxchg(ethr_atomic32_t *var, ethr_sint32_t val, eth return res; } +ethr_sint32_t ethr_atomic32_cmpxchg_ddrb(ethr_atomic32_t *var, ethr_sint32_t val, ethr_sint32_t old_val) +{ +#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) + return ethr_atomic32_cmpxchg_ddrb__(var, val, old_val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic32_cmpxchg(var, val, old_val); +#else + return ethr_atomic32_cmpxchg_rb(var, val, old_val); +#endif +} + ethr_sint32_t ethr_atomic32_cmpxchg_rb(ethr_atomic32_t *var, ethr_sint32_t val, ethr_sint32_t old_val) { ethr_sint32_t res; @@ -2675,6 +2892,17 @@ ethr_sint32_t ethr_atomic32_xchg(ethr_atomic32_t *var, ethr_sint32_t val) return res; } +ethr_sint32_t ethr_atomic32_xchg_ddrb(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) + return ethr_atomic32_xchg_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic32_xchg(var, val); +#else + return ethr_atomic32_xchg_rb(var, val); +#endif +} + ethr_sint32_t ethr_atomic32_xchg_rb(ethr_atomic32_t *var, ethr_sint32_t val) { ethr_sint32_t res; @@ -2762,6 +2990,17 @@ void ethr_atomic32_set(ethr_atomic32_t *var, ethr_sint32_t val) } +void ethr_atomic32_set_ddrb(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) + ethr_atomic32_set_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + ethr_atomic32_set(var, val); +#else + ethr_atomic32_set_rb(var, val); +#endif +} + void ethr_atomic32_set_rb(ethr_atomic32_t *var, ethr_sint32_t val) { ETHR_ASSERT(!ethr_not_inited__); @@ -2843,6 +3082,17 @@ void ethr_atomic32_init(ethr_atomic32_t *var, ethr_sint32_t val) } +void ethr_atomic32_init_ddrb(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) + ethr_atomic32_init_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + ethr_atomic32_init(var, val); +#else + ethr_atomic32_init_rb(var, val); +#endif +} + void ethr_atomic32_init_rb(ethr_atomic32_t *var, ethr_sint32_t val) { ETHR_ASSERT(var); @@ -2921,6 +3171,17 @@ ethr_sint32_t ethr_atomic32_add_read(ethr_atomic32_t *var, ethr_sint32_t val) return res; } +ethr_sint32_t ethr_atomic32_add_read_ddrb(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) + return ethr_atomic32_add_read_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic32_add_read(var, val); +#else + return ethr_atomic32_add_read_rb(var, val); +#endif +} + ethr_sint32_t ethr_atomic32_add_read_rb(ethr_atomic32_t *var, ethr_sint32_t val) { ethr_sint32_t res; @@ -3009,6 +3270,17 @@ ethr_sint32_t ethr_atomic32_read(ethr_atomic32_t *var) return res; } +ethr_sint32_t ethr_atomic32_read_ddrb(ethr_atomic32_t *var) +{ +#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) + return ethr_atomic32_read_ddrb__(var); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic32_read(var); +#else + return ethr_atomic32_read_rb(var); +#endif +} + ethr_sint32_t ethr_atomic32_read_rb(ethr_atomic32_t *var) { ethr_sint32_t res; @@ -3097,6 +3369,17 @@ ethr_sint32_t ethr_atomic32_inc_read(ethr_atomic32_t *var) return res; } +ethr_sint32_t ethr_atomic32_inc_read_ddrb(ethr_atomic32_t *var) +{ +#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) + return ethr_atomic32_inc_read_ddrb__(var); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic32_inc_read(var); +#else + return ethr_atomic32_inc_read_rb(var); +#endif +} + ethr_sint32_t ethr_atomic32_inc_read_rb(ethr_atomic32_t *var) { ethr_sint32_t res; @@ -3185,6 +3468,17 @@ ethr_sint32_t ethr_atomic32_dec_read(ethr_atomic32_t *var) return res; } +ethr_sint32_t ethr_atomic32_dec_read_ddrb(ethr_atomic32_t *var) +{ +#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) + return ethr_atomic32_dec_read_ddrb__(var); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic32_dec_read(var); +#else + return ethr_atomic32_dec_read_rb(var); +#endif +} + ethr_sint32_t ethr_atomic32_dec_read_rb(ethr_atomic32_t *var) { ethr_sint32_t res; @@ -3272,6 +3566,17 @@ void ethr_atomic32_add(ethr_atomic32_t *var, ethr_sint32_t val) } +void ethr_atomic32_add_ddrb(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) + ethr_atomic32_add_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + ethr_atomic32_add(var, val); +#else + ethr_atomic32_add_rb(var, val); +#endif +} + void ethr_atomic32_add_rb(ethr_atomic32_t *var, ethr_sint32_t val) { ETHR_ASSERT(!ethr_not_inited__); @@ -3354,6 +3659,17 @@ void ethr_atomic32_inc(ethr_atomic32_t *var) } +void ethr_atomic32_inc_ddrb(ethr_atomic32_t *var) +{ +#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) + ethr_atomic32_inc_ddrb__(var); +#elif defined(ETHR_ORDERED_READ_DEPEND) + ethr_atomic32_inc(var); +#else + ethr_atomic32_inc_rb(var); +#endif +} + void ethr_atomic32_inc_rb(ethr_atomic32_t *var) { ETHR_ASSERT(!ethr_not_inited__); @@ -3436,6 +3752,17 @@ void ethr_atomic32_dec(ethr_atomic32_t *var) } +void ethr_atomic32_dec_ddrb(ethr_atomic32_t *var) +{ +#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) + ethr_atomic32_dec_ddrb__(var); +#elif defined(ETHR_ORDERED_READ_DEPEND) + ethr_atomic32_dec(var); +#else + ethr_atomic32_dec_rb(var); +#endif +} + void ethr_atomic32_dec_rb(ethr_atomic32_t *var) { ETHR_ASSERT(!ethr_not_inited__); @@ -3519,6 +3846,17 @@ ethr_sint32_t ethr_atomic32_read_band(ethr_atomic32_t *var, ethr_sint32_t val) return res; } +ethr_sint32_t ethr_atomic32_read_band_ddrb(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) + return ethr_atomic32_read_band_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic32_read_band(var, val); +#else + return ethr_atomic32_read_band_rb(var, val); +#endif +} + ethr_sint32_t ethr_atomic32_read_band_rb(ethr_atomic32_t *var, ethr_sint32_t val) { ethr_sint32_t res; @@ -3607,6 +3945,17 @@ ethr_sint32_t ethr_atomic32_read_bor(ethr_atomic32_t *var, ethr_sint32_t val) return res; } +ethr_sint32_t ethr_atomic32_read_bor_ddrb(ethr_atomic32_t *var, ethr_sint32_t val) +{ +#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS) + return ethr_atomic32_read_bor_ddrb__(var, val); +#elif defined(ETHR_ORDERED_READ_DEPEND) + return ethr_atomic32_read_bor(var, val); +#else + return ethr_atomic32_read_bor_rb(var, val); +#endif +} + ethr_sint32_t ethr_atomic32_read_bor_rb(ethr_atomic32_t *var, ethr_sint32_t val) { ethr_sint32_t res; diff --git a/erts/lib_src/pthread/ethread.c b/erts/lib_src/pthread/ethread.c index ad29249bac..fb7d135418 100644 --- a/erts/lib_src/pthread/ethread.c +++ b/erts/lib_src/pthread/ethread.c @@ -123,34 +123,53 @@ ethr_ts_event *ethr_get_tse__(void) #if defined(ETHR_PPC_RUNTIME_CONF__) -static volatile int lwsync_caused_sigill; +#include <sys/wait.h> static void handle_lwsync_sigill(int signum) { - lwsync_caused_sigill = 1; + _exit(1); } static int ppc_init__(void) { - struct sigaction act, oact; - lwsync_caused_sigill = 0; + int pid; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = handle_lwsync_sigill; - if (sigaction(SIGILL, &act, &oact) != 0) - return errno; + /* If anything what so ever failes we assume no lwsync for safety */ + ethr_runtime__.conf.have_lwsync = 0; + + /* + * We perform the lwsync test (which might cause an illegal + * instruction signal) in a separate process in order to be + * completely certain that we do not mess up our own state. + */ + pid = fork(); + if (pid == 0) { + struct sigaction act, oact; - __asm__ __volatile__ ("lwsync\n\t" : : : "memory"); + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESETHAND; + act.sa_handler = handle_lwsync_sigill; + if (sigaction(SIGILL, &act, &oact) != 0) + _exit(2); - act.sa_flags = 0; - act.sa_handler = SIG_DFL; - if (sigaction(SIGILL, &act, &oact) != 0) - return errno; + __asm__ __volatile__ ("lwsync\n\t" : : : "memory"); + + _exit(0); + } - ethr_runtime__.conf.have_lwsync = (int) !lwsync_caused_sigill; + if (pid != -1) { + while (1) { + int status, res; + res = waitpid(pid, &status, 0); + if (res == pid) { + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + ethr_runtime__.conf.have_lwsync = 1; + break; + } + } + } return 0; } diff --git a/erts/lib_src/utils/make_atomics_api b/erts/lib_src/utils/make_atomics_api index f4e71c7618..74736c5a2d 100755 --- a/erts/lib_src/utils/make_atomics_api +++ b/erts/lib_src/utils/make_atomics_api @@ -4,7 +4,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% Copyright Ericsson AB 2011-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -50,7 +50,9 @@ -define(DW_RTCHK_MACRO, "ETHR_RTCHK_USE_NATIVE_DW_ATOMIC_IMPL__"). %% Barrier versions we implement --define(BARRIERS, [none, rb, wb, acqb, relb, mb]). +-define(BARRIERS, [none, ddrb, rb, wb, acqb, relb, mb]). +-define(NON_NATIVE_BARRIERS, [ddrb]). +-define(NATIVE_BARRIERS, (?BARRIERS -- ?NON_NATIVE_BARRIERS)). -define(ATOMIC_SIZES, ["dword", "word", "32"]). @@ -381,7 +383,6 @@ do_func_header(#atomic_context{dw = true, cmpxchg, Inline, Func) -> [Inline, "int ", Func, "(", AtomicT, " *", Arg1, ", ", AintT, " *", Arg2, ", ", AintT, " *", Arg3, ")"]. - xbarriers(_Op, none, _NB) -> {"", ""}; @@ -455,7 +456,7 @@ try_barrier_order_first(mb) -> try_barrier_order(B) -> First = try_barrier_order_first(B), - First ++ (?BARRIERS -- First). + First ++ (?NATIVE_BARRIERS -- First). native_barrier_op(#atomic_context{'NATMC' = NATMC} = AC, If, ExtraDecl, Op, B, NB, TypeCasts) -> NOpStr = opstr(native(Op)), @@ -571,12 +572,12 @@ do_cmpxchg_fallback_define(#atomic_context{'NATMC' = NATMC, NoneTryBarrierOrder = try_barrier_order(none), %% First a sanity check [" -#if (", NotDefCMPXCHG(hd(?BARRIERS)) , +#if (", NotDefCMPXCHG(hd(?NATIVE_BARRIERS)) , lists:map(fun (B) -> [" \\ && ", NotDefCMPXCHG(B)] end, - tl(?BARRIERS)), ") + tl(?NATIVE_BARRIERS)), ") # error \"No native cmpxchg() op available\" #endif @@ -744,7 +745,7 @@ translate_have_defs(#atomic_context{dw = DW, 'NATMC' = NATMC}) -> ] end] end, - ?BARRIERS) + ?NATIVE_BARRIERS) end, case DW of true -> ?DW_ATOMIC_OPS; @@ -801,6 +802,69 @@ rtchk_fallback_call(Return, #atomic_context{dw = DW, false -> [RetVar, " ="] end, [?DW_FUNC_MACRO, "(", opstr(Op), op_barrier_ext(B), ")"], Arg1, Arg2, Arg3, ""). +non_native_barrier(B) -> + lists:member(B, ?NON_NATIVE_BARRIERS). + +non_native_barrier_impl(AC, inline_implementation = Type, Op, B) -> + [" +", func_header(AC, Type, false, Op, B), " +{", + case B of + ddrb -> + [" +#ifdef ETHR_ORDERED_READ_DEPEND + ", func_call(AC, Type, Op, none, true), " +#else + ", func_call(AC, Type, Op, rb, true), " +#endif +" + ] + end, + "} +" + ]; +non_native_barrier_impl(#atomic_context{have_native_atomic_ops = HaveNative} = AC, + implementation = Type, + Op, + B) -> + [" +", func_header(AC, Type, false, Op, B), " +{", + case B of + ddrb -> + [" +#if defined(", HaveNative, ") + ", func_call(AC, Type, Op, B, true), " +#elif defined(ETHR_ORDERED_READ_DEPEND) + ", func_call(AC, symbol_implementation, Op, none, true), " +#else + ", func_call(AC, symbol_implementation, Op, rb, true), " +#endif +" + ] + end, + "} +" + ]. + +func_call(#atomic_context{'ATMC' = ATMC} = AC, inline_implementation, Op, B, RetStatement) -> + func_call(AC, Op, ["ETHR_", ATMC, "_FUNC__(", opstr(Op), op_barrier_ext(B), ")"], RetStatement); +func_call(#atomic_context{atomic = Atomic} = AC, implementation, Op, B, RetStatement) -> + func_call(AC, Op, [Atomic, "_", opstr(Op), op_barrier_ext(B), "__"], RetStatement); +func_call(#atomic_context{atomic = Atomic} = AC, symbol_implementation, Op, B, RetStatement) -> + func_call(AC, Op, [Atomic, "_", opstr(Op), op_barrier_ext(B)], RetStatement). + +func_call(#atomic_context{dw = DW, arg1 = Arg1, arg2 = Arg2, arg3 = Arg3} = AC, Op, Func, true) -> + op_call(Op, DW, case is_return_op(AC, Op) of + true -> "return"; + false -> "" + end, Func, Arg1, Arg2, Arg3, ""); +func_call(#atomic_context{dw = DW, arg1 = Arg1, arg2 = Arg2, arg3 = Arg3, ret_var = RetVar} = AC, Op, Func, false) -> + op_call(Op, DW, case is_return_op(AC, Op) of + true -> [RetVar, " = "]; + false -> "" + end, Func, Arg1, Arg2, Arg3, ""). + make_implementations(#atomic_context{dw = DW, ret_type = RetType, ret_var = RetVar, @@ -858,73 +922,78 @@ make_implementations(#atomic_context{dw = DW, ", lists:map(fun (B) -> - TryBarriers = try_barrier_order(B), - [" + case non_native_barrier(B) of + true -> + non_native_barrier_impl(AC, inline_implementation, Op, B); + false -> + TryBarriers = try_barrier_order(B), + [" ", func_header(AC, inline_implementation, false, Op, B), " { ", - case is_return_op(AC, Op) of - true -> - [" ", RetType, " ", RetVar, ";\n"]; - _ -> "" - end, - case DW of - true -> - [RtchkBegin, - "\n", - su_dw_native_barrier_op(AC, "#if", Op, B, hd(TryBarriers)), - lists:map(fun (NB) -> - su_dw_native_barrier_op(AC, "#elif", Op, B, NB) - end, - tl(TryBarriers)), - lists:map(fun (NB) -> - dw_native_barrier_op(AC, "#elif", "", Op, B, NB) - end, - TryBarriers), - case simple_fallback(AC, Op, B) of - "" -> - %% No simple fallback available; - %% use cmpxchg() fallbacks... - [cmpxchg_fallbacks(AC#atomic_context{'NATMC' = ["SU_", NATMC]}, true, Op, B), - cmpxchg_fallbacks(AC, false, Op, B), - "#else + case is_return_op(AC, Op) of + true -> + [" ", RetType, " ", RetVar, ";\n"]; + _ -> "" + end, + case DW of + true -> + [RtchkBegin, + "\n", + su_dw_native_barrier_op(AC, "#if", Op, B, hd(TryBarriers)), + lists:map(fun (NB) -> + su_dw_native_barrier_op(AC, "#elif", Op, B, NB) + end, + tl(TryBarriers)), + lists:map(fun (NB) -> + dw_native_barrier_op(AC, "#elif", "", Op, B, NB) + end, + TryBarriers), + case simple_fallback(AC, Op, B) of + "" -> + %% No simple fallback available; + %% use cmpxchg() fallbacks... + [cmpxchg_fallbacks(AC#atomic_context{'NATMC' = ["SU_", NATMC]}, true, Op, B), + cmpxchg_fallbacks(AC, false, Op, B), + "#else #error \"Missing implementation of ", Atomic, "_", opstr(Op), op_barrier_ext(B), "()!\" #endif " - ]; - SimpleFallback -> - ["#else\n", SimpleFallback, "#endif\n"] - end, - RtchkEnd(false, Op, B), "\n"]; - false -> - [native_barrier_op(AC, "#if", "", Op, B, hd(TryBarriers), true), - lists:map(fun (NB) -> - native_barrier_op(AC, "#elif", "", Op, B, NB, true) - end, - tl(TryBarriers)), - case simple_fallback(AC, Op, B) of - "" -> - %% No simple fallback available; - %% use cmpxchg() fallbacks... - [cmpxchg_fallbacks(AC, false, Op, B), - "#else + ]; + SimpleFallback -> + ["#else\n", SimpleFallback, "#endif\n"] + end, + RtchkEnd(false, Op, B), "\n"]; + false -> + [native_barrier_op(AC, "#if", "", Op, B, hd(TryBarriers), true), + lists:map(fun (NB) -> + native_barrier_op(AC, "#elif", "", Op, B, NB, true) + end, + tl(TryBarriers)), + case simple_fallback(AC, Op, B) of + "" -> + %% No simple fallback available; + %% use cmpxchg() fallbacks... + [cmpxchg_fallbacks(AC, false, Op, B), + "#else #error \"Missing implementation of ", Atomic, "_", opstr(Op), op_barrier_ext(B), "()!\" #endif " - ]; - SimpleFallback -> - ["#else\n", SimpleFallback, "#endif\n"] - end] - end, - case is_return_op(AC, Op) of - true -> - [" return ", RetVar, ";\n"]; - false -> - "" - end, - "}\n"] + ]; + SimpleFallback -> + ["#else\n", SimpleFallback, "#endif\n"] + end] + end, + case is_return_op(AC, Op) of + true -> + [" return ", RetVar, ";\n"]; + false -> + "" + end, + "}\n"] + end end, - ?BARRIERS)] + ?NATIVE_BARRIERS ++ ?NON_NATIVE_BARRIERS)] %% non-native needs to be after native... end, case DW of true -> ?DW_ATOMIC_OPS; @@ -1159,33 +1228,38 @@ int ethr_have_native_dw_atomic(void) ", lists:map(fun (B) -> - ["\n", - func_header(AC, implementation, - case DW of - true -> ?DW_FUNC_MACRO; - false -> false - end, Op, B), - "\n{\n", - case is_return_op(AC, Op) of - true -> [" ", RetType, " ", RetVar, ";\n"]; - false -> "" - end, - case Op of - init -> ""; - _ -> [" ETHR_ASSERT(!ethr_not_inited__);\n"] - end, - [" ETHR_ASSERT(", Arg1, ");\n"], - make_native_impl_op(AC, Op, B), - make_amc_fallback_op(AC#atomic_context{arg1 = FallbackVar}, Op, B), - make_locked_fallback_op(AC#atomic_context{arg1 = FallbackVar}, Op, B), - case is_return_op(AC, Op) of - true -> [" return ", RetVar, ";" - ]; - false -> - "" - end, - "\n}\n", - make_symbol_to_fallback_impl(AC, Op, B)] + Macro = case DW of + true -> ?DW_FUNC_MACRO; + false -> false + end, + case non_native_barrier(B) of + true -> + non_native_barrier_impl(AC, implementation, Op, B); + false -> + ["\n", + func_header(AC, implementation, Macro, Op, B), + "\n{\n", + case is_return_op(AC, Op) of + true -> [" ", RetType, " ", RetVar, ";\n"]; + false -> "" + end, + case Op of + init -> ""; + _ -> [" ETHR_ASSERT(!ethr_not_inited__);\n"] + end, + [" ETHR_ASSERT(", Arg1, ");\n"], + make_native_impl_op(AC, Op, B), + make_amc_fallback_op(AC#atomic_context{arg1 = FallbackVar}, Op, B), + make_locked_fallback_op(AC#atomic_context{arg1 = FallbackVar}, Op, B), + case is_return_op(AC, Op) of + true -> [" return ", RetVar, ";" + ]; + false -> + "" + end, + "\n}\n", + make_symbol_to_fallback_impl(AC, Op, B)] + end end, ?BARRIERS)] end, @@ -1233,7 +1307,7 @@ static char *native_", DW, "atomic", Bits, "_ops[] = {", #endif" ] end, - ?BARRIERS) + ?NATIVE_BARRIERS) end, case NBits of "dw" -> ?DW_ATOMIC_OPS; @@ -1390,25 +1464,51 @@ comments() -> * Appart from a function implementing the atomic operation * with unspecified memory barrier semantics, there are * functions implementing each operation with the following - * memory barrier semantics: -", + * implied memory barrier semantics:", lists:map(fun (none) -> ""; - (rb) -> - [" * - rb (read barrier)\n"]; - (wb) -> - [" * - wb (write barrier)\n"]; + (mb) -> + [" + * - mb - Full memory barrier. Orders both loads, and + * stores before, and after the atomic operation. + * No load or store is allowed to be reordered + * over the atomic operation."]; (acqb) -> - [" * - acqb (acquire barrier)\n"]; + [" + * - acqb - Acquire barrier. Orders both loads, and stores + * appearing *after* the atomic operation. These + * are not allowed to be reordered over the + * atomic operation."]; (relb) -> - [" * - relb (release barrier)\n"]; - (mb) -> - [" * - mb (full memory barrier)\n"]; + [" + * - relb - Release barrier. Orders both loads, and + * stores appearing *before* the atomic + * operation. These are not allowed to be + * reordered over the atomic operation."]; + (rb) -> + [" + * - rb - Read barrier. Orders *only* loads. These are + * not allowed to be reordered over the barrier. + * Load in atomic operation is ordered *before* + * the barrier. "]; + (ddrb) -> + [" + * - ddrb - Data dependency read barrier. Orders *only* + * loads according to data dependency across the + * barrier. Load in atomic operation is ordered + * before the barrier."]; + (wb) -> + [" + * - wb - Write barrier. Orders *only* stores. These are + * not allowed to be reordered over the barrier. + * Store in atomic operation is ordered *after* + * the barrier."]; (B) -> [" * - ", a2l(B), "\n"] end, - ?BARRIERS), - " * + lists:reverse(?BARRIERS)), + " + * * We implement all of these operation/barrier * combinations, regardless of whether they are useful * or not (some of them are useless). diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam Binary files differindex fe91a604b5..df1831f340 100644 --- a/erts/preloaded/ebin/erl_prim_loader.beam +++ b/erts/preloaded/ebin/erl_prim_loader.beam diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex dda24d4405..b78747bc84 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam Binary files differindex 37fd8bb832..cc170b86b2 100644 --- a/erts/preloaded/ebin/init.beam +++ b/erts/preloaded/ebin/init.beam diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam Binary files differindex e255cc803f..45a409738c 100644 --- a/erts/preloaded/ebin/otp_ring0.beam +++ b/erts/preloaded/ebin/otp_ring0.beam diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex 6227b562a1..87e80aae9b 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam Binary files differindex d44bbbbd27..b2f3ab6c5b 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam Binary files differindex 7e1a5d1fdb..411fc8d524 100644 --- a/erts/preloaded/ebin/prim_zip.beam +++ b/erts/preloaded/ebin/prim_zip.beam diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam Binary files differindex ebf9f8e6d6..7a1f896d36 100644 --- a/erts/preloaded/ebin/zlib.beam +++ b/erts/preloaded/ebin/zlib.beam diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 35defde692..14a7a2bf20 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -129,7 +129,7 @@ start(Id, Pgm0, Hosts) -> {error,Reason} end. -%% Hosts must be a list on form ['1.2.3.4' ...] +%% Hosts must be a list of form ['1.2.3.4' ...] start_it("inet", Id, Pid, Hosts) -> process_flag(trap_exit, true), ?dbg(inet, {Id,Pid,Hosts}), diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index e9a59a7aaf..4cbff3f36e 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -43,6 +43,9 @@ -export([memory/0, memory/1]). -export([alloc_info/1, alloc_sizes/1]). +-export([gather_sched_wall_time_result/1, + await_sched_wall_time_modifications/2]). + -deprecated([hash/2]). % Get rid of autoimports of spawn to avoid clashes with ourselves. @@ -1091,8 +1094,6 @@ receive_emd(Ref, EMD, N) -> receive_emd(Ref) -> receive_emd(Ref, #memory{}, erlang:system_info(schedulers)). -aa_mem_data(notsup, _) -> - notsup; aa_mem_data(#memory{} = Mem, [{maximum, Max} | Rest]) -> aa_mem_data(Mem#memory{maximum = Max}, @@ -1204,3 +1205,34 @@ receive_allocator(Ref, N, Acc) -> {Ref, _, InfoList} -> receive_allocator(Ref, N-1, insert_info(InfoList, Acc)) end. + +-spec await_sched_wall_time_modifications(Ref, Result) -> boolean() when + Ref :: reference(), + Result :: boolean(). + +await_sched_wall_time_modifications(Ref, Result) -> + sched_wall_time(Ref, erlang:system_info(schedulers)), + Result. + +-spec gather_sched_wall_time_result(Ref) -> [{pos_integer(), + non_neg_integer(), + non_neg_integer()}] when + Ref :: reference(). + +gather_sched_wall_time_result(Ref) when is_reference(Ref) -> + sched_wall_time(Ref, erlang:system_info(schedulers), []). + +sched_wall_time(_Ref, 0) -> + ok; +sched_wall_time(Ref, N) -> + receive Ref -> sched_wall_time(Ref, N-1) end. + +sched_wall_time(_Ref, 0, Acc) -> + Acc; +sched_wall_time(Ref, N, undefined) -> + receive {Ref, _} -> sched_wall_time(Ref, N-1, undefined) end; +sched_wall_time(Ref, N, Acc) -> + receive + {Ref, undefined} -> sched_wall_time(Ref, N-1, undefined); + {Ref, SWT} -> sched_wall_time(Ref, N-1, [SWT|Acc]) + end. diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 30b7a5246a..36cbe329e8 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -26,7 +26,8 @@ %% Generic file contents operations -export([open/2, close/1, datasync/1, sync/1, advise/4, position/2, truncate/1, - write/2, pwrite/2, pwrite/3, read/2, read_line/1, pread/2, pread/3, copy/3]). + write/2, pwrite/2, pwrite/3, read/2, read_line/1, pread/2, pread/3, + copy/3, sendfile/10]). %% Specialized file operations -export([open/1, open/3]). @@ -44,13 +45,13 @@ rename/2, rename/3, make_dir/1, make_dir/2, del_dir/1, del_dir/2, - read_file_info/1, read_file_info/2, + read_file_info/1, read_file_info/2, read_file_info/3, altname/1, altname/2, - write_file_info/2, write_file_info/3, + write_file_info/2, write_file_info/3, write_file_info/4, make_link/2, make_link/3, make_symlink/2, make_symlink/3, read_link/1, read_link/2, - read_link_info/1, read_link_info/2, + read_link_info/1, read_link_info/2, read_link_info/3, list_dir/1, list_dir/2]). %% How to start and stop the ?DRV port. -export([start/0, stop/1]). @@ -98,6 +99,7 @@ -define(FILE_READ_LINE, 29). -define(FILE_FDATASYNC, 30). -define(FILE_ADVISE, 31). +-define(FILE_SENDFILE, 32). %% Driver responses -define(FILE_RESP_OK, 0). @@ -537,7 +539,31 @@ write_file(File, Bin) when (is_list(File) orelse is_binary(File)) -> end; write_file(_, _) -> {error, badarg}. - + + +%% Returns {error, Reason} | {ok, BytesCopied} +%sendfile(_,_,_,_,_,_,_,_,_,_) -> +% {error, enotsup}; +sendfile(#file_descriptor{module = ?MODULE, data = {Port, _}}, + Dest, Offset, Bytes, _ChunkSize, Headers, Trailers, + _Nodiskio, _MNowait, _Sync) -> + case erlang:port_get_data(Dest) of + Data when Data == inet_tcp; Data == inet6_tcp -> + ok = inet:lock_socket(Dest,true), + {ok, DestFD} = prim_inet:getfd(Dest), + try drv_command(Port, [<<?FILE_SENDFILE, DestFD:32, + 0:8, + Offset:64/unsigned, + Bytes:64/unsigned, + (iolist_size(Headers)):32/unsigned, + (iolist_size(Trailers)):32/unsigned>>, + Headers,Trailers]) + after + ok = inet:lock_socket(Dest,false) + end; + _Else -> + {error,badarg} + end. %%%----------------------------------------------------------------- @@ -699,16 +725,33 @@ del_dir_int(Port, Dir) -> -%% read_file_info/{1,2} +%% read_file_info/{1,2,3} read_file_info(File) -> - read_file_info_int({?DRV, [binary]}, File). + read_file_info_int({?DRV, [binary]}, File, local). read_file_info(Port, File) when is_port(Port) -> - read_file_info_int(Port, File). + read_file_info_int(Port, File, local); +read_file_info(File, Opts) -> + read_file_info_int({?DRV, [binary]}, File, plgv(time, Opts, local)). + +read_file_info(Port, File, Opts) when is_port(Port) -> + read_file_info_int(Port, File, plgv(time, Opts, local)). + +read_file_info_int(Port, File, TimeType) -> + try + case drv_command(Port, [?FILE_FSTAT, pathname(File)]) of + {ok, FI} -> {ok, FI#file_info{ + ctime = from_seconds(FI#file_info.ctime, TimeType), + mtime = from_seconds(FI#file_info.mtime, TimeType), + atime = from_seconds(FI#file_info.atime, TimeType) + }}; + Error -> Error + end + catch + error:_ -> {error, badarg} + end. -read_file_info_int(Port, File) -> - drv_command(Port, [?FILE_FSTAT, pathname(File)]). %% altname/{1,2} @@ -721,38 +764,61 @@ altname(Port, File) when is_port(Port) -> altname_int(Port, File) -> drv_command(Port, [?FILE_ALTNAME, pathname(File)]). -%% write_file_info/{2,3} +%% write_file_info/{2,3,4} write_file_info(File, Info) -> - write_file_info_int({?DRV, [binary]}, File, Info). + write_file_info_int({?DRV, [binary]}, File, Info, local). write_file_info(Port, File, Info) when is_port(Port) -> - write_file_info_int(Port, File, Info). + write_file_info_int(Port, File, Info, local); +write_file_info(File, Info, Opts) -> + write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts, local)). + +write_file_info(Port, File, Info, Opts) when is_port(Port) -> + write_file_info_int(Port, File, Info, plgv(time, Opts, local)). -write_file_info_int(Port, - File, +write_file_info_int(Port, File, #file_info{mode=Mode, uid=Uid, gid=Gid, atime=Atime0, mtime=Mtime0, - ctime=Ctime}) -> - {Atime, Mtime} = - case {Atime0, Mtime0} of - {undefined, Mtime0} -> {erlang:localtime(), Mtime0}; - {Atime0, undefined} -> {Atime0, Atime0}; - Complete -> Complete - end, - drv_command(Port, [?FILE_WRITE_INFO, - int_to_bytes(Mode), - int_to_bytes(Uid), - int_to_bytes(Gid), - date_to_bytes(Atime), - date_to_bytes(Mtime), - date_to_bytes(Ctime), - pathname(File)]). + ctime=Ctime0}, + TimeType) -> + + % Atime and/or Mtime might be undefined + % - use localtime() for atime, if atime is undefined + % - use atime as mtime if mtime is undefined + % - use mtime as ctime if ctime is undefined + + try + Atime = file_info_validate_atime(Atime0, TimeType), + Mtime = file_info_validate_mtime(Mtime0, Atime), + Ctime = file_info_validate_ctime(Ctime0, Mtime), + + drv_command(Port, [?FILE_WRITE_INFO, + int_to_int32bytes(Mode), + int_to_int32bytes(Uid), + int_to_int32bytes(Gid), + int_to_int64bytes(to_seconds(Atime, TimeType)), + int_to_int64bytes(to_seconds(Mtime, TimeType)), + int_to_int64bytes(to_seconds(Ctime, TimeType)), + pathname(File)]) + catch + error:_ -> {error, badarg} + end. + +file_info_validate_atime(Atime, _) when Atime =/= undefined -> Atime; +file_info_validate_atime(undefined, local) -> erlang:localtime(); +file_info_validate_atime(undefined, universal) -> erlang:universaltime(); +file_info_validate_atime(undefined, posix) -> erlang:universaltime_to_posixtime(erlang:universaltime()). +file_info_validate_mtime(undefined, Atime) -> Atime; +file_info_validate_mtime(Mtime, _) -> Mtime. + +file_info_validate_ctime(undefined, Mtime) -> Mtime; +file_info_validate_ctime(Ctime, _) -> Ctime. %% make_link/{2,3} @@ -796,15 +862,31 @@ read_link_int(Port, Link) -> %% read_link_info/{2,3} read_link_info(Link) -> - read_link_info_int({?DRV, [binary]}, Link). + read_link_info_int({?DRV, [binary]}, Link, local). read_link_info(Port, Link) when is_port(Port) -> - read_link_info_int(Port, Link). + read_link_info_int(Port, Link, local); + +read_link_info(Link, Opts) -> + read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts, local)). -read_link_info_int(Port, Link) -> - drv_command(Port, [?FILE_LSTAT, pathname(Link)]). +read_link_info(Port, Link, Opts) when is_port(Port) -> + read_link_info_int(Port, Link, plgv(time, Opts, local)). +read_link_info_int(Port, Link, TimeType) -> + try + case drv_command(Port, [?FILE_LSTAT, pathname(Link)]) of + {ok, FI} -> {ok, FI#file_info{ + ctime = from_seconds(FI#file_info.ctime, TimeType), + mtime = from_seconds(FI#file_info.mtime, TimeType), + atime = from_seconds(FI#file_info.atime, TimeType) + }}; + Error -> Error + end + catch + error:_ -> {error, badarg} + end. %% list_dir/{1,2} @@ -1049,7 +1131,7 @@ translate_response(?FILE_RESP_DATA, List) -> {_N, _Data} = ND = get_uint64(List), {ok, ND}; translate_response(?FILE_RESP_INFO, List) when is_list(List) -> - {ok, transform_info_ints(get_uint32s(List))}; + {ok, transform_info(List)}; translate_response(?FILE_RESP_NUMERR, L0) -> {N, L1} = get_uint64(L0), {error, {N, list_to_atom(L1)}}; @@ -1103,27 +1185,37 @@ translate_response(?FILE_RESP_ALL_DATA, Data) -> translate_response(X, Data) -> {error, {bad_response_from_port, [X | Data]}}. -transform_info_ints(Ints) -> - [HighSize, LowSize, Type|Tail0] = Ints, - Size = HighSize * 16#100000000 + LowSize, - [Ay, Am, Ad, Ah, Ami, As|Tail1] = Tail0, - [My, Mm, Md, Mh, Mmi, Ms|Tail2] = Tail1, - [Cy, Cm, Cd, Ch, Cmi, Cs|Tail3] = Tail2, - [Mode, Links, Major, Minor, Inode, Uid, Gid, Access] = Tail3, +transform_info([ + Hsize1, Hsize2, Hsize3, Hsize4, + Lsize1, Lsize2, Lsize3, Lsize4, + Type1, Type2, Type3, Type4, + Atime1, Atime2, Atime3, Atime4, Atime5, Atime6, Atime7, Atime8, + Mtime1, Mtime2, Mtime3, Mtime4, Mtime5, Mtime6, Mtime7, Mtime8, + Ctime1, Ctime2, Ctime3, Ctime4, Ctime5, Ctime6, Ctime7, Ctime8, + Mode1, Mode2, Mode3, Mode4, + Links1, Links2, Links3, Links4, + Major1, Major2, Major3, Major4, + Minor1, Minor2, Minor3, Minor4, + Inode1, Inode2, Inode3, Inode4, + Uid1, Uid2, Uid3, Uid4, + Gid1, Gid2, Gid3, Gid4, + Access1,Access2,Access3,Access4]) -> #file_info { - size = Size, - type = file_type(Type), - access = file_access(Access), - atime = {{Ay, Am, Ad}, {Ah, Ami, As}}, - mtime = {{My, Mm, Md}, {Mh, Mmi, Ms}}, - ctime = {{Cy, Cm, Cd}, {Ch, Cmi, Cs}}, - mode = Mode, - links = Links, - major_device = Major, - minor_device = Minor, - inode = Inode, - uid = Uid, - gid = Gid}. + size = uint32(Hsize1,Hsize2,Hsize3,Hsize4)*16#100000000 + uint32(Lsize1,Lsize2,Lsize3,Lsize4), + type = file_type(uint32(Type1,Type2,Type3,Type4)), + access = file_access(uint32(Access1,Access2,Access3,Access4)), + atime = sint64(Atime1, Atime2, Atime3, Atime4, Atime5, Atime6, Atime7, Atime8), + mtime = sint64(Mtime1, Mtime2, Mtime3, Mtime4, Mtime5, Mtime6, Mtime7, Mtime8), + ctime = sint64(Ctime1, Ctime2, Ctime3, Ctime4, Ctime5, Ctime6, Ctime7, Ctime8), + mode = uint32(Mode1,Mode2,Mode3,Mode4), + links = uint32(Links1,Links2,Links3,Links4), + major_device = uint32(Major1,Major2,Major3,Major4), + minor_device = uint32(Minor1,Minor2,Minor3,Minor4), + inode = uint32(Inode1,Inode2,Inode3,Inode4), + uid = uint32(Uid1,Uid2,Uid3,Uid4), + gid = uint32(Gid1,Gid2,Gid3,Gid4) + }. + file_type(1) -> device; file_type(2) -> directory; @@ -1136,24 +1228,22 @@ file_access(1) -> write; file_access(2) -> read; file_access(3) -> read_write. -int_to_bytes(Int) when is_integer(Int) -> +int_to_int32bytes(Int) when is_integer(Int) -> <<Int:32>>; -int_to_bytes(undefined) -> +int_to_int32bytes(undefined) -> <<-1:32>>. -date_to_bytes(undefined) -> - <<-1:32, -1:32, -1:32, -1:32, -1:32, -1:32>>; -date_to_bytes({{Y, Mon, D}, {H, Min, S}}) -> - <<Y:32, Mon:32, D:32, H:32, Min:32, S:32>>. +int_to_int64bytes(Int) when is_integer(Int) -> + <<Int:64/signed>>. -%% uint64([[X1, X2, X3, X4] = Y1 | [X5, X6, X7, X8] = Y2]) -> -%% (uint32(Y1) bsl 32) bor uint32(Y2). -%% uint64(X1, X2, X3, X4, X5, X6, X7, X8) -> -%% (uint32(X1, X2, X3, X4) bsl 32) bor uint32(X5, X6, X7, X8). +sint64(I1,I2,I3,I4,I5,I6,I7,I8) when I1 > 127 -> + ((I1 bsl 56) bor (I2 bsl 48) bor (I3 bsl 40) bor (I4 bsl 32) bor + (I5 bsl 24) bor (I6 bsl 16) bor (I7 bsl 8) bor I8) - (1 bsl 64); +sint64(I1,I2,I3,I4,I5,I6,I7,I8) -> + ((I1 bsl 56) bor (I2 bsl 48) bor (I3 bsl 40) bor (I4 bsl 32) bor + (I5 bsl 24) bor (I6 bsl 16) bor (I7 bsl 8) bor I8). -%% uint32([X1,X2,X3,X4]) -> -%% (X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4. uint32(X1,X2,X3,X4) -> (X1 bsl 24) bor (X2 bsl 16) bor (X3 bsl 8) bor X4. @@ -1166,11 +1256,6 @@ get_uint64(L0) -> get_uint32([X1,X2,X3,X4|List]) -> {(((((X1 bsl 8) bor X2) bsl 8) bor X3) bsl 8) bor X4, List}. -get_uint32s([X1,X2,X3,X4|Tail]) -> - [uint32(X1,X2,X3,X4) | get_uint32s(Tail)]; -get_uint32s([]) -> []. - - %% Binary mode transform_ldata(<<0:32, 0:32>>) -> @@ -1249,3 +1334,28 @@ reverse(L, T) -> lists:reverse(L, T). % in list_to_binary, which is caught and generates the {error,badarg} return pathname(File) -> (catch prim_file:internal_name2native(File)). + + +%% proplist:get_value/3 +plgv(K, [{K, V}|_], _) -> V; +plgv(K, [_|KVs], D) -> plgv(K, KVs, D); +plgv(_, [], D) -> D. + +%% +%% We don't actually want this here +%% We want to use posix time in all prim but erl_prim_loader makes that tricky +%% It is probably needed to redo the whole erl_prim_loader + +from_seconds(Seconds, posix) when is_integer(Seconds) -> + Seconds; +from_seconds(Seconds, universal) when is_integer(Seconds) -> + erlang:posixtime_to_universaltime(Seconds); +from_seconds(Seconds, local) when is_integer(Seconds) -> + erlang:universaltime_to_localtime(erlang:posixtime_to_universaltime(Seconds)). + +to_seconds(Seconds, posix) when is_integer(Seconds) -> + Seconds; +to_seconds({_,_} = Datetime, universal) -> + erlang:universaltime_to_posixtime(Datetime); +to_seconds({_,_} = Datetime, local) -> + erlang:universaltime_to_posixtime(erlang:localtime_to_universaltime(Datetime)). diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index f144f73d68..14bf3b6c69 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -36,7 +36,8 @@ -export([recvfrom/2, recvfrom/3]). -export([setopt/3, setopts/2, getopt/2, getopts/2, is_sockopt_val/2]). -export([chgopt/3, chgopts/2]). --export([getstat/2, getfd/1, getindex/1, getstatus/1, gettype/1, +-export([getstat/2, getfd/1, ignorefd/2, + getindex/1, getstatus/1, gettype/1, getifaddrs/1, getiflist/1, ifget/3, ifset/3, gethostname/1]). -export([getservbyname/3, getservbyport/3]). @@ -82,8 +83,10 @@ open(Protocol, Family, Type, Req, Data) -> end catch %% The only (?) way to get here is to try to open - %% the sctp driver when it does not exist - error:badarg -> {error,eprotonosupport} + %% the sctp driver when it does not exist (badarg) + error:badarg -> {error, eprotonosupport}; + %% system_limit if out of port slots + error:system_limit -> {error, system_limit} end. enc_family(inet) -> ?INET_AF_INET; @@ -842,6 +845,21 @@ getfd(S) when is_port(S) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% +%% IGNOREFD(insock(),boolean()) -> {ok,integer()} | {error, Reason} +%% +%% steal internal file descriptor +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +ignorefd(S,Bool) when is_port(S) -> + Val = if Bool -> 1; true -> 0 end, + case ctl_cmd(S, ?INET_REQ_IGNOREFD, [Val]) of + {ok, _} -> ok; + Error -> Error + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% %% GETIX(insock()) -> {ok,integer()} | {error, Reason} %% %% get internal socket index diff --git a/erts/preloaded/src/prim_zip.erl b/erts/preloaded/src/prim_zip.erl index 392a9feb45..d29f17ae56 100644 --- a/erts/preloaded/src/prim_zip.erl +++ b/erts/preloaded/src/prim_zip.erl @@ -432,7 +432,7 @@ binary_io({file_info, B}, _) -> is_binary(B) -> {regular, byte_size(B)}; B =:= directory -> {directory, 0} end, - Now = calendar:local_time(), + Now = erlang:localtime(), #file_info{size = Size, type = Type, access = read_write, atime = Now, mtime = Now, ctime = Now, mode = 0, links = 1, major_device = 0, diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl index 210532edac..71b730016d 100644 --- a/erts/preloaded/src/zlib.erl +++ b/erts/preloaded/src/zlib.erl @@ -349,10 +349,14 @@ getQSize(Z) -> Compressed :: binary(). compress(Data) -> Z = open(), - deflateInit(Z, default), - Bs = deflate(Z, Data, finish), - deflateEnd(Z), - close(Z), + Bs = try + deflateInit(Z, default), + B = deflate(Z, Data, finish), + deflateEnd(Z), + B + after + close(Z) + end, iolist_to_binary(Bs). -spec uncompress(Data) -> Decompressed when @@ -364,10 +368,14 @@ uncompress(Data) -> if Size >= 8 -> Z = open(), - inflateInit(Z), - Bs = inflate(Z, Data), - inflateEnd(Z), - close(Z), + Bs = try + inflateInit(Z), + B = inflate(Z, Data), + inflateEnd(Z), + B + after + close(Z) + end, iolist_to_binary(Bs); true -> erlang:error(data_error) @@ -383,10 +391,14 @@ uncompress(Data) -> Compressed :: binary(). zip(Data) -> Z = open(), - deflateInit(Z, default, deflated, -?MAX_WBITS, 8, default), - Bs = deflate(Z, Data, finish), - deflateEnd(Z), - close(Z), + Bs = try + deflateInit(Z, default, deflated, -?MAX_WBITS, 8, default), + B = deflate(Z, Data, finish), + deflateEnd(Z), + B + after + close(Z) + end, iolist_to_binary(Bs). -spec unzip(Data) -> Decompressed when @@ -394,10 +406,14 @@ zip(Data) -> Decompressed :: binary(). unzip(Data) -> Z = open(), - inflateInit(Z, -?MAX_WBITS), - Bs = inflate(Z, Data), - inflateEnd(Z), - close(Z), + Bs = try + inflateInit(Z, -?MAX_WBITS), + B = inflate(Z, Data), + inflateEnd(Z), + B + after + close(Z) + end, iolist_to_binary(Bs). -spec gzip(Data) -> Compressed when @@ -405,10 +421,14 @@ unzip(Data) -> Compressed :: binary(). gzip(Data) -> Z = open(), - deflateInit(Z, default, deflated, 16+?MAX_WBITS, 8, default), - Bs = deflate(Z, Data, finish), - deflateEnd(Z), - close(Z), + Bs = try + deflateInit(Z, default, deflated, 16+?MAX_WBITS, 8, default), + B = deflate(Z, Data, finish), + deflateEnd(Z), + B + after + close(Z) + end, iolist_to_binary(Bs). -spec gunzip(Data) -> Decompressed when @@ -416,10 +436,14 @@ gzip(Data) -> Decompressed :: binary(). gunzip(Data) -> Z = open(), - inflateInit(Z, 16+?MAX_WBITS), - Bs = inflate(Z, Data), - inflateEnd(Z), - close(Z), + Bs = try + inflateInit(Z, 16+?MAX_WBITS), + B = inflate(Z, Data), + inflateEnd(Z), + B + after + close(Z) + end, iolist_to_binary(Bs). -spec collect(zstream()) -> iolist(). diff --git a/erts/start_scripts/Makefile b/erts/start_scripts/Makefile index 4df7568484..d8e39062e3 100644 --- a/erts/start_scripts/Makefile +++ b/erts/start_scripts/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2010. All Rights Reserved. +# Copyright Ericsson AB 1997-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -74,7 +74,7 @@ $(SS_ROOT)/start_clean.script \ $(SS_ROOT)/start_clean.boot: $(SS_ROOT)/start_clean.rel $(INSTALL_DIR) $(SS_TMP) ( cd $(SS_TMP) && \ - $(ERLC) $(SASL_FLAGS) $(SCRIPT_PATH) -o $(SS_ROOT) $< ) + $(ERLC) $(SASL_FLAGS) $(SCRIPT_PATH) +no_warn_sasl -o $(SS_ROOT) $< ) $(SS_ROOT)/start_sasl.script \ $(SS_ROOT)/start_sasl.boot: $(SS_ROOT)/start_sasl.rel @@ -128,7 +128,7 @@ $(SS_ROOT)/start_all_example.rel: $(SS_ROOT)/start_all_example.rel.src \ $(ERL_TOP)/bin/start.script: $(INSTALL_DIR) $(SS_TMP) ( cd $(SS_TMP) && \ - $(ERLC) $(SCRIPT_PATH) +otp_build -o $@ $(SS_ROOT)/start_clean.rel ) + $(ERLC) $(SCRIPT_PATH) +no_warn_sasl +otp_build -o $@ $(SS_ROOT)/start_clean.rel ) $(ERL_TOP)/bin/start_sasl.script: $(INSTALL_DIR) $(SS_TMP) @@ -138,7 +138,7 @@ $(ERL_TOP)/bin/start_sasl.script: $(ERL_TOP)/bin/start_clean.script: $(INSTALL_DIR) $(SS_TMP) ( cd $(SS_TMP) && \ - $(ERLC) $(SCRIPT_PATH) +otp_build -o $@ $(SS_ROOT)/start_clean.rel ) + $(ERLC) $(SCRIPT_PATH) +no_warn_sasl +otp_build -o $@ $(SS_ROOT)/start_clean.rel ) ## Special target used from system/build/Makefile for source code release bootstrap. bootstrap_scripts: $(SS_ROOT)/start_clean.rel diff --git a/erts/test/erl_print_SUITE.erl b/erts/test/erl_print_SUITE.erl index ee1a200530..adc353bd51 100644 --- a/erts/test/erl_print_SUITE.erl +++ b/erts/test/erl_print_SUITE.erl @@ -303,7 +303,7 @@ read_case_data(Port, TestCase) -> {Port, {data, {eol, [?PID_MARKER | PidStr]}}} -> ?line ?t:format("Port program pid: ~s~n", [PidStr]), ?line CaseProc = self(), - ?line list_to_integer(PidStr), % Sanity check + ?line _ = list_to_integer(PidStr), % Sanity check spawn_opt(fun () -> port_prog_killer(CaseProc, PidStr) end, diff --git a/erts/test/erl_print_SUITE_data/Makefile.src b/erts/test/erl_print_SUITE_data/Makefile.src index 109d55e572..dec5650416 100644 --- a/erts/test/erl_print_SUITE_data/Makefile.src +++ b/erts/test/erl_print_SUITE_data/Makefile.src @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2005-2009. All Rights Reserved. +# Copyright Ericsson AB 2005-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -27,7 +27,7 @@ EPTF_CFLAGS = -Wall $(CFLAGS) @DEFS@ -I@erts_lib_include_internal@ -I@erts_lib_i EPTF_LIBS = $(LIBS) -L@erts_lib_internal_path@ -lerts_internal@type_marker@ EPTT_CFLAGS = -DTHREAD_SAFE $(ETHR_DEFS) $(EPTF_CFLAGS) -EPTT_LIBS = $(LIBS) -L@erts_lib_internal_path@ -lerts_internal_r@type_marker@ $(ETHR_LIBS) +EPTT_LIBS = -L@erts_lib_internal_path@ -lerts_internal_r@type_marker@ $(ETHR_LIBS) $(LIBS) GCC = .@DS@gccifier -CC"$(CC)" diff --git a/erts/test/erlc_SUITE.erl b/erts/test/erlc_SUITE.erl index a9e28672e3..6c0d662126 100644 --- a/erts/test/erlc_SUITE.erl +++ b/erts/test/erlc_SUITE.erl @@ -154,7 +154,8 @@ compile_mib(Config) when is_list(Config) -> ?line BadFile = filename:join(SrcDir, "BAD-MIB.mib"), ?line run(Config, Cmd, BadFile, "", - ["Error: syntax error before: mibs\$", "compilation_failed_ERROR_"]), + ["BAD-MIB.mib: 1: syntax error before: mibs\$", + "compilation_failed_ERROR_"]), %% Make sure that no -I option works. @@ -237,6 +238,12 @@ num_d_options() -> %% of arguments is 16383. %% See: http://www.in-ulm.de/~mascheck/various/argmax/ 5440; + {{unix,darwin},{Major,_,_}} when Major >= 11 -> + %% "getconf ARG_MAX" still reports 262144 (as in previous + %% version of MacOS X), but the useful space seem to have + %% shrunk significantly (or possibly the number of arguments). + %% 7673 + 7500; {_,_} -> 12000 end. diff --git a/erts/test/ethread_SUITE.erl b/erts/test/ethread_SUITE.erl index 4206bebfe7..5bb5aed3ed 100644 --- a/erts/test/ethread_SUITE.erl +++ b/erts/test/ethread_SUITE.erl @@ -68,9 +68,6 @@ tests() -> atomic, dw_atomic_massage]. -all(doc) -> []; -all(suite) -> tests(). - suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> @@ -125,35 +122,37 @@ try_lock_mutex(suite) -> try_lock_mutex(Config) -> run_case(Config, "try_lock_mutex", ""). -wd_dispatch(P) -> - receive - bye -> - ?line true = port_command(P, "-1 "), - ?line bye; - L when is_list(L) -> - ?line true = port_command(P, L), - ?line wd_dispatch(P) - end. - -watchdog(Port) -> - ?line process_flag(priority, max), - ?line receive after 500 -> ok end, - - ?line random:seed(), - ?line true = port_command(Port, "0 "), - ?line lists:foreach(fun (T) -> - erlang:send_after(T, - self(), - integer_to_list(T) - ++ " ") - end, - lists:usort(lists:map(fun (_) -> - random:uniform(4500)+500 - end, - lists:duplicate(50,0)))), - ?line erlang:send_after(5100, self(), bye), - - wd_dispatch(Port). +%% Remove dead code? + +% wd_dispatch(P) -> +% receive +% bye -> +% ?line true = port_command(P, "-1 "), +% ?line bye; +% L when is_list(L) -> +% ?line true = port_command(P, L), +% ?line wd_dispatch(P) +% end. +% +% watchdog(Port) -> +% ?line process_flag(priority, max), +% ?line receive after 500 -> ok end, +% +% ?line random:seed(), +% ?line true = port_command(Port, "0 "), +% ?line lists:foreach(fun (T) -> +% erlang:send_after(T, +% self(), +% integer_to_list(T) +% ++ " ") +% end, +% lists:usort(lists:map(fun (_) -> +% random:uniform(4500)+500 +% end, +% lists:duplicate(50,0)))), +% ?line erlang:send_after(5100, self(), bye), +% +% wd_dispatch(Port). cond_wait(doc) -> ["Tests ethr_cond_wait with ethr_cond_signal and ethr_cond_broadcast."]; @@ -174,7 +173,15 @@ detached_thread(doc) -> detached_thread(suite) -> []; detached_thread(Config) -> - run_case(Config, "detached_thread", ""). + case {os:type(), os:version()} of + {{unix,darwin}, {9, _, _}} -> + %% For some reason pthread_create() crashes when more + %% threads cannot be created, instead of returning an + %% error code on our MacOS X Leopard machine... + {skipped, "MacOS X Leopard cannot cope with this test..."}; + _ -> + run_case(Config, "detached_thread", "") + end. max_threads(doc) -> ["Tests maximum number of threads."]; @@ -299,7 +306,7 @@ read_case_data(Port, TestCase) -> {Port, {data, {eol, [?PID_MARKER | PidStr]}}} -> ?line ?t:format("Port program pid: ~s~n", [PidStr]), ?line CaseProc = self(), - ?line list_to_integer(PidStr), % Sanity check + ?line _ = list_to_integer(PidStr), % Sanity check spawn_opt(fun () -> port_prog_killer(CaseProc, PidStr) end, diff --git a/erts/test/ethread_SUITE_data/ethread_tests.c b/erts/test/ethread_SUITE_data/ethread_tests.c index 7e7e133d6c..ed96ecdbd2 100644 --- a/erts/test/ethread_SUITE_data/ethread_tests.c +++ b/erts/test/ethread_SUITE_data/ethread_tests.c @@ -82,6 +82,7 @@ static void print_eol(void) { fprintf(stderr, EOL); + fflush(stderr); } static void print_line(char *frmt,...) @@ -826,6 +827,7 @@ detached_thread_test(void) * Tests */ #define MTT_TIMES 10 +#define MTT_HARD_LIMIT (80000) static int mtt_terminate; static ethr_mutex mtt_mutex; @@ -866,14 +868,20 @@ mtt_create_join_threads(void) while (1) { if (ix >= no_tids) { no_tids += 100; + if (no_tids > MTT_HARD_LIMIT) { + print_line("Hit the hard limit on number of threads (%d)!", + MTT_HARD_LIMIT); + break; + } tids = (ethr_tid *) realloc((void *)tids, sizeof(ethr_tid)*no_tids); ASSERT(tids); } res = ethr_thr_create(&tids[ix], mtt_thread, NULL, NULL); - if (res != 0) + if (res != 0) { break; + } ix++; - } while (res == 0); + } no_threads = ix; diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl index d61fbbddcf..b34d9a5422 100644 --- a/erts/test/otp_SUITE.erl +++ b/erts/test/otp_SUITE.erl @@ -94,15 +94,16 @@ undefined_functions(Config) when is_list(Config) -> case Undef of [] -> ok; _ -> + Fd = open_log(Config, "undefined_functions"), foreach(fun ({MFA1,MFA2}) -> io:format("~s calls undefined ~s", + [format_mfa(MFA1),format_mfa(MFA2)]), + io:format(Fd, "~s ~s\n", [format_mfa(MFA1),format_mfa(MFA2)]) end, Undef), + close_log(Fd), ?line ?t:fail({length(Undef),undefined_functions_in_otp}) - - end, - - ok. + end. hipe_filter(Undef) -> case erlang:system_info(hipe_architecture) of @@ -150,6 +151,9 @@ ssl_crypto_filter(Undef) -> {{error,bad_name},{error,bad_name}} -> filter(fun({_,{ssl,_,_}}) -> false; ({_,{crypto,_,_}}) -> false; + ({_,{ssh,_,_}}) -> false; + ({_,{ssh_connection,_,_}}) -> false; + ({_,{ssh_sftp,_,_}}) -> false; (_) -> true end, Undef); {_,_} -> Undef @@ -211,7 +215,10 @@ deprecated_not_in_obsolete(Config) when is_list(Config) -> _ -> io:put_chars("The following functions have -deprecated() attributes,\n" "but are not listed in otp_internal:obsolete/3.\n"), - ?line print_mfas(L), + ?line print_mfas(group_leader(), L), + Fd = open_log(Config, "deprecated_not_obsolete"), + print_mfas(Fd, L), + close_log(Fd), ?line ?t:fail({length(L),deprecated_but_not_obsolete}) end. @@ -232,11 +239,13 @@ obsolete_but_not_deprecated(Config) when is_list(Config) -> io:put_chars("The following functions are listed " "in otp_internal:obsolete/3,\n" "but don't have -deprecated() attributes.\n"), - ?line print_mfas(L), + ?line print_mfas(group_leader(), L), + Fd = open_log(Config, "obsolete_not_deprecated"), + print_mfas(Fd, L), + close_log(Fd), ?line ?t:fail({length(L),obsolete_but_not_deprecated}) end. - call_to_deprecated(Config) when is_list(Config) -> Server = ?config(xref_server, Config), ?line {ok,DeprecatedCalls} = xref:q(Server, "strict(E || DF)"), @@ -302,10 +311,20 @@ strong_components(Config) when is_list(Config) -> %%% -print_mfas([MFA|T]) -> - io:format("~s\n", [format_mfa(MFA)]), - print_mfas(T); -print_mfas([]) -> ok. +print_mfas(Fd, [MFA|T]) -> + io:format(Fd, "~s\n", [format_mfa(MFA)]), + print_mfas(Fd, T); +print_mfas(_, []) -> ok. format_mfa({M,F,A}) -> lists:flatten(io_lib:format("~s:~s/~p", [M,F,A])). + +open_log(Config, Name) -> + PrivDir = ?config(priv_dir, Config), + RunDir = filename:dirname(filename:dirname(PrivDir)), + Path = filename:join(RunDir, "system_"++Name++".log"), + {ok,Fd} = file:open(Path, [write]), + Fd. + +close_log(Fd) -> + ok = file:close(Fd). diff --git a/erts/test/z_SUITE.erl b/erts/test/z_SUITE.erl index 482ecb8fba..28da923497 100644 --- a/erts/test/z_SUITE.erl +++ b/erts/test/z_SUITE.erl @@ -236,8 +236,8 @@ format_core(#core_search_conf{file = false}, Core, Ignore) -> [Ignore, Core] ++ mod_time_list(Core)); format_core(#core_search_conf{file = File}, Core, Ignore) -> FRes = str_strip(os:cmd(File ++ " " ++ Core)), - case catch regexp:match(FRes, Core) of - {match, _, _} -> + case catch re:run(FRes, Core, [caseless,{capture,none}]) of + match -> io:format(" ~s~s " ++ time_fstr() ++ "~n", [Ignore, FRes] ++ mod_time_list(Core)); _ -> diff --git a/erts/vsn.mk b/erts/vsn.mk index 1b3cd67947..bbf77b1a68 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2011. All Rights Reserved. +# Copyright Ericsson AB 1997-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -17,8 +17,8 @@ # %CopyrightEnd% # -VSN = 5.9 -SYSTEM_VSN = R15B +VSN = 5.9.1 +SYSTEM_VSN = R15B01 # Port number 4365 in 4.2 # Port number 4366 in 4.3 |