Committing TBB 2019 Update 1 source code
authortbbdev <inteltbbdevelopers@intel.com>
Thu, 4 Oct 2018 09:38:29 +0000 (12:38 +0300)
committertbbdev <inteltbbdevelopers@intel.com>
Thu, 4 Oct 2018 09:38:29 +0000 (12:38 +0300)
73 files changed:
CHANGES
Doxyfile [changed mode: 0755->0644]
Makefile
README.md
build/Makefile.tbbmalloc
build/android.clang.inc
build/build.py
build/common.inc
build/common_rules.inc
build/linux.clang.inc
build/linux.gcc.inc
build/linux.icc.inc
build/linux.pathcc.inc
build/linux.xl.inc
build/macos.clang.inc
build/macos.gcc.inc
build/macos.icc.inc
build/mic.icc.inc
build/windows.cl.inc
build/windows.gcc.inc
build/windows.icl.inc
doc/copyright_brand_disclaimer_doxygen.txt [new file with mode: 0644]
include/tbb/concurrent_hash_map.h
include/tbb/internal/_concurrent_unordered_impl.h
include/tbb/internal/_x86_rtm_rw_mutex_impl.h
include/tbb/machine/gcc_generic.h
include/tbb/machine/gcc_ia32_common.h
include/tbb/machine/msvc_ia32_common.h
include/tbb/machine/windows_ia32.h
include/tbb/machine/windows_intel64.h
include/tbb/parallel_sort.h
include/tbb/queuing_mutex.h
include/tbb/queuing_rw_mutex.h
include/tbb/spin_rw_mutex.h
include/tbb/task_group.h
include/tbb/tbb.h
include/tbb/tbb_config.h
include/tbb/tbb_machine.h
include/tbb/tbb_stddef.h
python/tbb/__init__.py
src/old/concurrent_queue_v2.cpp
src/tbb/cache_aligned_allocator.cpp
src/tbb/concurrent_queue.cpp
src/tbb/concurrent_vector.cpp
src/tbb/custom_scheduler.h
src/tbb/dynamic_link.cpp
src/tbb/observer_proxy.cpp
src/tbb/task.cpp
src/tbb/tbb_assert_impl.h
src/tbb/tbb_misc.cpp
src/tbb/x86_rtm_rw_mutex.cpp
src/tbbmalloc/backend.cpp
src/tbbmalloc/frontend.cpp
src/tbbmalloc/large_objects.cpp
src/tbbmalloc/proxy.cpp
src/tbbmalloc/tbb_function_replacement.cpp
src/tbbmalloc/tbbmalloc.cpp
src/tbbmalloc/tbbmalloc_internal.h
src/tbbmalloc/tbbmalloc_internal_api.h
src/test/harness_allocator.h
src/test/harness_defs.h
src/test/test_atomic.cpp
src/test/test_continue_node.cpp
src/test/test_lambda.cpp
src/test/test_malloc_pure_c.c
src/test/test_malloc_shutdown_hang.cpp [new file with mode: 0644]
src/test/test_multifunction_node.cpp
src/test/test_parallel_for.cpp
src/test/test_parallel_sort.cpp
src/test/test_task_arena.cpp
src/test/test_task_group.cpp
src/test/test_tbb_header.cpp
src/test/test_tbb_version.cpp

diff --git a/CHANGES b/CHANGES
index 54d00e7..3cc1f5f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,33 @@
 The list of most significant changes made over time in
 Intel(R) Threading Building Blocks (Intel(R) TBB).
 
+Intel TBB 2019 Update 1
+TBB_INTERFACE_VERSION == 11001
+
+Changes (w.r.t. Intel TBB 2019):
+
+- Doxygen documentation could be built with 'make doxygen' command now.
+
+Changes affecting backward compatibility:
+
+- Enforced 8 byte alignment for tbb::atomic<long long> and
+    tbb::atomic<double>. On IA-32 architecture it may cause layout
+    changes in structures that use these types.
+
+Bugs fixed:
+
+- Fixed an issue with dynamic memory allocation replacement on Windows*
+    occurred for some versions of ucrtbase.dll.
+- Fixed possible deadlock in tbbmalloc cleanup procedure during process
+    shutdown.
+- Fixed usage of std::uncaught_exception() deprecated in C++17
+   (https://github.com/01org/tbb/issues/67).
+- Fixed a crash when a local observer is activated after an arena
+    observer.
+- Fixed compilation of task_group.h by Visual C++* 15.7 with
+    /permissive- option (https://github.com/01org/tbb/issues/53).
+
+------------------------------------------------------------------------
 Intel TBB 2019
 TBB_INTERFACE_VERSION == 11000
 
old mode 100755 (executable)
new mode 100644 (file)
index 22486be..0f7d30d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -56,6 +56,9 @@ examples: tbb tbbmalloc
 python: tbb
        $(MAKE) -C "$(work_dir)_release" -rf $(tbb_root)/python/Makefile install
 
+doxygen:
+       doxygen Doxyfile
+
 .PHONY: clean clean_examples mkdir info
 
 clean: clean_examples
index c7c2bf3..a502785 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
-# Intel(R) Threading Building Blocks 2019
-[![Stable release](https://img.shields.io/badge/version-2019-green.svg)](https://github.com/01org/tbb/releases/tag/2019)
+# Threading Building Blocks 2019 Update 1
+[![Stable release](https://img.shields.io/badge/version-2019_U1-green.svg)](https://github.com/01org/tbb/releases/tag/2019_U1)
 [![Apache License Version 2.0](https://img.shields.io/badge/license-Apache_2.0-green.svg)](LICENSE)
 
-Intel(R) Threading Building Blocks (Intel(R) TBB) lets you easily write parallel C++ programs that take
+Threading Building Blocks (TBB) lets you easily write parallel C++ programs that take
 full advantage of multicore performance, that are portable, composable and have future-proof scalability.
 
 ## Release Information
@@ -11,17 +11,17 @@ Here are the latest [Changes](CHANGES) and [Release Notes](doc/Release_Notes.txt
 Since [2018 U5](https://github.com/01org/tbb/releases/tag/2018_U5) TBB binary packages include [Parallel STL](https://github.com/intel/parallelstl) as a high-level component.
 
 ## Documentation
-* Intel(R) TBB [tutorial](https://software.intel.com/en-us/tbb-tutorial)
-* Intel(R) TBB general documentation: [stable](https://software.intel.com/en-us/tbb-documentation)
+* TBB [tutorial](https://software.intel.com/en-us/tbb-tutorial)
+* TBB general documentation: [stable](https://software.intel.com/en-us/tbb-documentation)
 and [latest](https://www.threadingbuildingblocks.org/docs/help/index.htm)
 
 ## Support
 Please report issues and suggestions via
 [GitHub issues](https://github.com/01org/tbb/issues) or start a topic on the
-[Intel(R) TBB forum](http://software.intel.com/en-us/forums/intel-threading-building-blocks/).
+[TBB forum](http://software.intel.com/en-us/forums/intel-threading-building-blocks/).
 
 ## How to Contribute
-Please, read the instructions on the official [Intel(R) TBB open source site](https://www.threadingbuildingblocks.org/submit-contribution).
+Please, read the instructions on the official [TBB open source site](https://www.threadingbuildingblocks.org/submit-contribution).
 
 ## Engineering team contacts
 * [E-mail us.](mailto:inteltbbdevelopers@intel.com)
index 999e52b..01214fd 100644 (file)
@@ -138,7 +138,8 @@ MALLOC_TESTS = test_ScalableAllocator.$(TEST_EXT) \
                test_malloc_pure_c.$(TEST_EXT) \
                test_malloc_whitebox.$(TEST_EXT) \
                test_malloc_used_by_lib.$(TEST_EXT) \
-               test_malloc_lib_unload.$(TEST_EXT)
+               test_malloc_lib_unload.$(TEST_EXT) \
+               test_malloc_shutdown_hang.$(TEST_EXT)
 ifneq (,$(MALLOCPROXY.DLL))
 MALLOC_TESTS += test_malloc_overload.$(TEST_EXT) \
                 test_malloc_overload_proxy.$(TEST_EXT) \
@@ -212,6 +213,17 @@ test_malloc_lib_unload_dll.$(DLL): INCLUDES=$(ORIG_INCLUDES) $(INCLUDE_TEST_HEAD
 test_malloc_used_by_lib_dll.$(DLL): CPLUS_FLAGS:=$(subst /MT,/LD,$(M_CPLUS_FLAGS))
 test_malloc_used_by_lib_dll.$(DLL): LINK_FILES+=$(ORIG_LINK_MALLOC.LIB)
 test_malloc_used_by_lib_dll.$(DLL): LIBDL=
+
+# The test needs both tbb and tbbmalloc.
+# For static build LINK_TBB.LIB is resolved in tbb.a static lib name (Linux), which cannot be found (dynamic tbb is used only).
+# In order to link properly, have to define LINK_TBB.LIB ourselves except for Windows where linkage with *.lib file expected.
+ifdef extra_inc
+ifneq ($(tbb_os),windows)
+DYNAMIC_TBB_LIB=$(LIBPREF)tbb$(CPF_SUFFIX)$(DEBUG_SUFFIX).$(DLL)
+endif
+endif
+test_malloc_shutdown_hang.$(TEST_EXT): LINK_FILES += $(if $(DYNAMIC_TBB_LIB), $(DYNAMIC_TBB_LIB), $(LINK_TBB.LIB))
+
 # -----------------------------------------------------
 
 # ---- The list of TBBMalloc test running commands ----
@@ -235,6 +247,7 @@ endif
        $(run_cmd) ./test_malloc_regression.$(TEST_EXT) $(args)
        $(run_cmd) ./test_malloc_init_shutdown.$(TEST_EXT) $(args)
        $(run_cmd) ./test_malloc_pure_c.$(TEST_EXT) $(args)
+       $(run_cmd) ./test_malloc_shutdown_hang.$(TEST_EXT)
 # -----------------------------------------------------
 
 #------------------------------------------------------
index 8807a43..4f9ef31 100644 (file)
@@ -68,9 +68,9 @@ ifeq (0, $(dynamic_load))
 endif
 
 # Paths to the NDK prebuilt tools and libraries
-ifneq (,$(findstring $(ndk_version),r16 r16b))
+ifeq (,$(findstring $(ndk_version), $(foreach v, 7 8 9 10 11 12 13 14 15,r$(v) r$(v)b r$(v)c r$(v)d r$(v)e)))
     # Since Android* NDK r16 another sysroot and isystem paths have to be specified
-    CPLUS_FLAGS += --sysroot=$(NDK_ROOT)/sysroot -isystem $(NDK_ROOT)/sysroot/usr/include/$(TRIPLE) 
+    CPLUS_FLAGS += --sysroot=$(NDK_ROOT)/sysroot -isystem $(NDK_ROOT)/sysroot/usr/include/$(TRIPLE)
     # Android* version flag required since r16
     CPLUS_FLAGS += -D__ANDROID_API__=$(API_LEVEL)
 else
index 458d680..53796a9 100644 (file)
@@ -93,10 +93,14 @@ tbb_names = ["tbb", "tbbmalloc", "tbbmalloc_proxy"]
 
 ##############################################################
 
+def system(arg):
+    print('$ ', arg)
+    return os.system(arg)
+
 def run_make(arg):
-    if os.system('%s -j %s'% (args.make_tool, arg)) != 0:
+    if system('%s -j %s'% (args.make_tool, arg)) != 0:
        print("\nBummer. Running serial build in order to recover the log and have a chance to fix the build")
-       assert os.system('%s %s'% (args.make_tool, arg)) == 0
+       assert system('%s %s'% (args.make_tool, arg)) == 0
 
 os.chdir(args.tbbroot)
 if args.prebuilt:
@@ -180,10 +184,10 @@ for f, dest in filemap.items():
     install_cp(f, dest)
 
 if args.install_python: # Python part
-    paths = [os.path.abspath(d) for d in (args.prefix, irml_dir, lib_dir, inc_dir)]
+    paths = [os.path.abspath(d) for d in [args.prefix, inc_dir, irml_dir, lib_dir]+release_dirs]
     os.environ["TBBROOT"] = paths[0]
     # all the paths must be relative to python/ directory or be absolute
-    assert os.system('python python/setup.py build -b%s build_ext -L%s:%s -I%s install -f'% \
-        (paths[1], paths[2], paths[1], paths[3])) == 0 # add install location? windows needs pythnon/Library location separation
+    assert system('python python/setup.py build -b%s build_ext -I%s -L%s install -f'% \
+        (paths[2], paths[1], ':'.join(paths[2:]))) == 0
 
 print("done")
index fd29320..cef75df 100644 (file)
@@ -54,6 +54,14 @@ ifdef cpp0x
     override cpp0x=
 endif
 
+# Define C & C++ compilers according to platform defaults or CXX & CC environment variables
+ifneq (,$(findstring environment, $(origin CXX)))
+    CPLUS = $(CXX)
+endif
+ifneq (,$(findstring environment, $(origin CC)))
+    CONLY = $(CC)
+endif
+
 ifneq (,$(stdver))
     ifeq (,$(findstring ++, $(stdver)))
         $(warning "Warning: unexpected stdver=$(stdver) is used.")
index e923afc..6bb2e7a 100644 (file)
@@ -63,14 +63,8 @@ ifeq ($(origin LIB_LINK_LIBS), undefined)
     LIB_LINK_LIBS = $(LIBDL) $(LIBS)
 endif
 
-# Define C & C++ compilers according to platform defaults or CXX & CC environment variables
-ifneq (,$(findstring environment, $(origin CXX)))
-CPLUS = $(CXX)
-endif
+# some platforms do not provide separate C-only compiler
 CONLY ?= $(CPLUS)
-ifneq (,$(findstring environment, $(origin CC)))
-CONLY = $(CC)
-endif
 
 # The most generic rules
 #$(1) - is the target pattern
index 3988951..065f1d3 100644 (file)
@@ -16,6 +16,8 @@
 #
 #
 
+CPLUS ?= clang++
+CONLY ?= clang
 COMPILE_ONLY = -c -MMD
 PREPROC_ONLY = -E -x c++
 INCLUDE_KEY = -I
@@ -31,8 +33,6 @@ DYLIB_KEY = -shared
 EXPORT_KEY = -Wl,--version-script,
 LIBDL = -ldl
 
-CPLUS = clang++
-CONLY = clang
 LIB_LINK_FLAGS = $(DYLIB_KEY) -Wl,-soname=$(BUILDING_LIBRARY)
 LIBS += -lpthread -lrt
 LINK_FLAGS = -Wl,-rpath-link=. -rdynamic
index 6cb89d1..3693676 100644 (file)
@@ -16,6 +16,8 @@
 #
 #
 
+CPLUS ?= g++
+CONLY ?= gcc
 COMPILE_ONLY = -c -MMD
 PREPROC_ONLY = -E -x c++
 INCLUDE_KEY = -I
@@ -32,30 +34,28 @@ DYLIB_KEY = -shared
 EXPORT_KEY = -Wl,--version-script,
 LIBDL = -ldl
 
-CPLUS = g++
-CONLY = gcc
 LIB_LINK_FLAGS = $(DYLIB_KEY) -Wl,-soname=$(BUILDING_LIBRARY)
 LIBS += -lpthread -lrt
 LINK_FLAGS = -Wl,-rpath-link=. -rdynamic
 C_FLAGS = $(CPLUS_FLAGS)
 
 # gcc 4.2 and higher support OpenMP
-ifneq (,$(shell gcc -dumpversion | egrep  "^(4\.[2-9]|[5-9])"))
+ifneq (,$(shell $(CONLY) -dumpversion | egrep  "^(4\.[2-9]|[5-9])"))
     OPENMP_FLAG = -fopenmp
 endif
 
 # gcc 4.8 and later support RTM intrinsics, but require command line switch to enable them
-ifneq (,$(shell gcc -dumpversion | egrep  "^(4\.[8-9]|[5-9])"))
+ifneq (,$(shell $(CONLY) -dumpversion | egrep  "^(4\.[8-9]|[5-9])"))
     RTM_KEY = -mrtm
 endif
 
 # gcc 4.0 and later have -Wextra that is used by some our customers.
-ifneq (,$(shell gcc -dumpversion | egrep  "^([4-9])"))
+ifneq (,$(shell $(CONLY) -dumpversion | egrep  "^([4-9])"))
     WARNING_KEY += -Wextra
 endif
 
 # gcc 5.0 and later have -Wsuggest-override and -Wno-sized-deallocation options
-ifneq (,$(shell gcc -dumpversion | egrep  "^([5-9])"))
+ifneq (,$(shell $(CONLY) -dumpversion | egrep  "^([5-9])"))
     # enable -Wsuggest-override via a pre-included header in order to limit to C++11 and above
     INCLUDE_TEST_HEADERS = -include $(tbb_root)/src/test/harness_preload.h
     WARNING_SUPPRESS += -Wno-sized-deallocation
@@ -63,7 +63,7 @@ endif
 
 # gcc 6.0 and later have -flifetime-dse option that controls
 # elimination of stores done outside the object lifetime
-ifneq (,$(shell gcc -dumpversion | egrep  "^([6-9])"))
+ifneq (,$(shell $(CONLY) -dumpversion | egrep  "^([6-9])"))
     # keep pre-contruction stores for zero initialization
     DSE_KEY = -flifetime-dse=1
 endif
index a22290a..4731f96 100644 (file)
@@ -16,6 +16,8 @@
 #
 #
 
+CPLUS ?= icpc
+CONLY ?= icc
 COMPILE_ONLY = -c -MMD
 PREPROC_ONLY = -E -x c++
 INCLUDE_KEY = -I
@@ -33,9 +35,6 @@ ifneq (,$(shell icc -dumpversion | egrep "1[2-9]\."))
 SDL_FLAGS = -fstack-protector -Wformat -Wformat-security
 endif
 
-CPLUS = icpc
-CONLY = icc
-
 ITT_NOTIFY = -DDO_ITT_NOTIFY
 ifeq (release,$(cfg))
 SDL_FLAGS += -D_FORTIFY_SOURCE=2
index dbad197..d2693c1 100644 (file)
@@ -16,6 +16,8 @@
 #
 #
 
+CPLUS ?= pathCC
+CONLY ?= pathcc
 COMPILE_ONLY = -c -MMD
 PREPROC_ONLY = -E -x c++
 INCLUDE_KEY = -I
@@ -32,8 +34,6 @@ DYLIB_KEY = -shared
 EXPORT_KEY = -Wl,--version-script,
 LIBDL = -ldl
 
-CPLUS = pathCC
-CONLY = pathcc
 LIB_LINK_FLAGS = $(DYLIB_KEY) -Wl,-soname=$(BUILDING_LIBRARY)
 LIBS += -lstl -lpthread -lrt
 LINK_FLAGS = -Wl,-rpath-link=. -rdynamic
index 3005aae..dcec5a6 100644 (file)
@@ -18,6 +18,8 @@
 
 ####### Detections and Commands ###############################################
 
+CPLUS ?= xlc++_r
+CONLY ?= xlc_r
 COMPILE_ONLY = -c
 PREPROC_ONLY = -E -qsourcetype=c
 INCLUDE_KEY = -I
@@ -34,8 +36,6 @@ DYLIB_KEY = -qmkshrobj
 EXPORT_KEY = -Wl,--version-script,
 LIBDL = -ldl
 
-CPLUS = xlc++_r
-CONLY = xlc_r
 LIB_LINK_FLAGS = $(DYLIB_KEY) -Wl,-soname=$(BUILDING_LIBRARY)
 LIBS = -lpthread -lrt
 C_FLAGS = $(CPLUS_FLAGS)
index 7a95725..23a4288 100644 (file)
@@ -16,8 +16,8 @@
 #
 #
 
-CPLUS = clang++
-CONLY = clang
+CPLUS ?= clang++
+CONLY ?= clang
 COMPILE_ONLY = -c -MMD
 PREPROC_ONLY = -E -x c++
 INCLUDE_KEY = -I
@@ -47,7 +47,7 @@ endif
 CPLUS_FLAGS += -DUSE_PTHREAD $(ITT_NOTIFY)
 
 # For Clang, we add the option to support RTM intrinsics *iff* xtest is found in <immintrin.h>
-ifneq (,$(shell grep xtest `echo "\#include<immintrin.h>" | clang -E -M - 2>&1 | grep immintrin.h` 2>/dev/null))
+ifneq (,$(shell grep xtest `echo "\#include<immintrin.h>" | $(CONLY) -E -M - 2>&1 | grep immintrin.h` 2>/dev/null))
     RTM_KEY = -mrtm
 endif
 
index 10fe1cf..5df569d 100644 (file)
@@ -16,8 +16,8 @@
 #
 #
 
-CPLUS = g++
-CONLY = gcc
+CPLUS ?= g++
+CONLY ?= gcc
 COMPILE_ONLY = -c -MMD
 PREPROC_ONLY = -E -x c++
 INCLUDE_KEY = -I
@@ -39,19 +39,19 @@ LIB_LINK_FLAGS = -dynamiclib -install_name @rpath/$(BUILDING_LIBRARY)
 C_FLAGS = $(CPLUS_FLAGS)
 
 # gcc 4.8 and later support RTM intrinsics, but require command line switch to enable them
-ifneq (,$(shell gcc -dumpversion | egrep  "^(4\.[8-9]|[5-9])"))
+ifneq (,$(shell $(CONLY) -dumpversion | egrep  "^(4\.[8-9]|[5-9])"))
     RTM_KEY = -mrtm
 endif
 
 # gcc 5.0 and later have -Wsuggest-override option
 # enable it via a pre-included header in order to limit to C++11 and above
-ifneq (,$(shell gcc -dumpversion | egrep  "^([5-9])"))
+ifneq (,$(shell $(CONLY) -dumpversion | egrep  "^([5-9])"))
     INCLUDE_TEST_HEADERS = -include $(tbb_root)/src/test/harness_preload.h
 endif
 
 # gcc 6.0 and later have -flifetime-dse option that controls
 # elimination of stores done outside the object lifetime
-ifneq (,$(shell gcc -dumpversion | egrep  "^([6-9])"))
+ifneq (,$(shell $(CONLY) -dumpversion | egrep  "^([6-9])"))
     # keep pre-contruction stores for zero initialization
     DSE_KEY = -flifetime-dse=1
 endif
index bc19ffd..aa7d332 100644 (file)
@@ -16,8 +16,8 @@
 #
 #
 
-CPLUS = icpc
-CONLY = icc
+CPLUS ?= icpc
+CONLY ?= icc
 COMPILE_ONLY = -c -MMD
 PREPROC_ONLY = -E -x c++
 INCLUDE_KEY = -I
index 0fe4a93..f91519a 100644 (file)
@@ -16,6 +16,8 @@
 #
 #
 
+CPLUS ?= icpc
+CONLY ?= icc
 COMPILE_ONLY = -c -MMD
 PREPROC_ONLY = -E -x c++
 INCLUDE_KEY = -I
@@ -30,8 +32,6 @@ EXPORT_KEY = -Wl,--version-script,
 NOINTRINSIC_KEY = -fno-builtin
 LIBDL = -ldl
 SDL_FLAGS = -fstack-protector -Wformat -Wformat-security
-CPLUS = icpc
-CONLY = icc
 
 ifeq (release,$(cfg))
     SDL_FLAGS += -D_FORTIFY_SOURCE=2
index 86e32dc..97909cf 100644 (file)
@@ -24,7 +24,7 @@
 #------------------------------------------------------------------------------
 # Setting compiler flags.
 #------------------------------------------------------------------------------
-CPLUS = cl /nologo
+CPLUS ?= cl /nologo
 LINK_FLAGS = /link /nologo
 LIB_LINK_FLAGS=/link /nologo /DLL /MAP /DEBUG /fixed:no /INCREMENTAL:NO /DYNAMICBASE /NXCOMPAT
 
index 4f2fcf9..90a956a 100644 (file)
@@ -49,7 +49,7 @@ PROXY.LIB =
 # Compiler-specific variables
 #------------------------------------------------------------------------------
 
-CPLUS = g++
+CPLUS ?= g++
 COMPILE_ONLY = -c -MMD
 PREPROC_ONLY = -E -x c++
 INCLUDE_KEY = -I
index 0f191c8..8fc8cdf 100644 (file)
@@ -33,7 +33,7 @@ cfg ?= release
 #------------------------------------------------------------------------------
 # Setting compiler flags.
 #------------------------------------------------------------------------------
-CPLUS = icl /nologo $(VCCOMPAT_FLAG)
+CPLUS ?= icl /nologo $(VCCOMPAT_FLAG)
 LINK_FLAGS = /link /nologo
 LIB_LINK_FLAGS= /link /nologo /DLL /MAP /DEBUG /fixed:no /INCREMENTAL:NO /DYNAMICBASE /NXCOMPAT
 
diff --git a/doc/copyright_brand_disclaimer_doxygen.txt b/doc/copyright_brand_disclaimer_doxygen.txt
new file mode 100644 (file)
index 0000000..7ba446b
--- /dev/null
@@ -0,0 +1,9 @@
+<hr>
+<p></p>
+Copyright &copy; 2005-2018 Intel Corporation.  All Rights Reserved.
+<p></p>
+Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are
+registered trademarks or trademarks of Intel Corporation or its
+subsidiaries in the United States and other countries.
+<p></p>
+* Other names and brands may be claimed as the property of others.
index 35128e1..f84dfd3 100644 (file)
@@ -604,8 +604,8 @@ protected:
     static node* allocate_node_emplace_construct(node_allocator_type& allocator, Args&&... args){
         return  new( allocator ) node(std::forward<Args>(args)...);
     }
-#endif //#if __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT
-#endif
+#endif //__TBB_CPP11_VARIADIC_TEMPLATES_PRESENT
+#endif //__TBB_CPP11_RVALUE_REF_PRESENT
 
     static node* allocate_node_default_construct(node_allocator_type& allocator, const Key &key, const T * ){
         return  new( allocator ) node(key);
@@ -1407,7 +1407,7 @@ void concurrent_hash_map<Key,T,HashCompare,A>::clear() {
         reported = true;
     }
 #endif
-#endif//TBB_USE_ASSERT || TBB_USE_PERFORMANCE_WARNINGS || __TBB_STATISTICS
+#endif // TBB_USE_ASSERT || TBB_USE_PERFORMANCE_WARNINGS || __TBB_STATISTICS
     my_size = 0;
     segment_index_t s = segment_index_of( m );
     __TBB_ASSERT( s+1 == pointers_per_table || !my_table[s+1], "wrong mask or concurrent grow" );
index 3520f6c..2e68e2f 100644 (file)
@@ -727,8 +727,10 @@ protected:
 
 #if __TBB_CPP11_RVALUE_REF_PRESENT
     concurrent_unordered_base(concurrent_unordered_base&& right)
-        : Traits(right.my_hash_compare), my_solist(right.get_allocator()), my_allocator(right.get_allocator())
+        : Traits(right.my_hash_compare), my_solist(right.get_allocator()), my_allocator(right.get_allocator()),
+          my_maximum_bucket_size(float(initial_bucket_load))
     {
+        my_number_of_buckets = initial_bucket_number;
         internal_init();
         swap(right);
     }
@@ -740,6 +742,8 @@ protected:
 
         internal_init();
         if (a == right.get_allocator()){
+            my_number_of_buckets = initial_bucket_number;
+            my_maximum_bucket_size = float(initial_bucket_load);
             this->swap(right);
         }else{
             my_maximum_bucket_size = right.my_maximum_bucket_size;
index 8c7ef76..c268b93 100644 (file)
@@ -88,11 +88,11 @@ private:
 
     static x86_rtm_rw_mutex* internal_get_mutex( const spin_rw_mutex::scoped_lock& lock )
     {
-        return static_cast<x86_rtm_rw_mutex*>( lock.internal_get_mutex() );
+        return static_cast<x86_rtm_rw_mutex*>( lock.mutex );
     }
     static void internal_set_mutex( spin_rw_mutex::scoped_lock& lock, spin_rw_mutex* mtx )
     {
-        lock.internal_set_mutex( mtx );
+        lock.mutex = mtx;
     }
     //! @endcond
 public:
index 6ccc75c..390c1c2 100644 (file)
@@ -106,23 +106,17 @@ __TBB_MACHINE_DEFINE_ATOMICS(8,int64_t)
 
 #undef __TBB_MACHINE_DEFINE_ATOMICS
 
-namespace tbb{ namespace internal { namespace gcc_builtins {
-    inline int clz(unsigned int x){ return __builtin_clz(x);};
-    inline int clz(unsigned long int x){ return __builtin_clzl(x);};
-    inline int clz(unsigned long long int x){ return __builtin_clzll(x);};
-}}}
-//gcc __builtin_clz builtin count _number_ of leading zeroes
-static inline intptr_t __TBB_machine_lg( uintptr_t x ) {
-    return sizeof(x)*8 - tbb::internal::gcc_builtins::clz(x) -1 ;
-}
-
-
 typedef unsigned char __TBB_Flag;
 typedef __TBB_atomic __TBB_Flag __TBB_atomic_flag;
 
 #if __TBB_GCC_VERSION < 40700
 // Use __sync_* builtins
 
+// Use generic machine_load_store functions if there are no builtin atomics
+#define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE            1
+#define __TBB_USE_GENERIC_RELAXED_LOAD_STORE                1
+#define __TBB_USE_GENERIC_SEQUENTIAL_CONSISTENCY_LOAD_STORE 1
+
 static inline void __TBB_machine_or( volatile void *ptr, uintptr_t addend ) {
     __sync_fetch_and_or(reinterpret_cast<volatile uintptr_t *>(ptr),addend);
 }
@@ -158,6 +152,59 @@ inline void __TBB_machine_unlock_byte( __TBB_atomic_flag &flag ) {
     __atomic_clear(&flag,__ATOMIC_RELEASE);
 }
 
+namespace tbb { namespace internal {
+
+/** GCC atomic operation intrinsics might miss compiler fence.
+    Adding it after load-with-acquire, before store-with-release, and
+    on both sides of sequentially consistent operations is sufficient for correctness. **/
+
+template <typename T, int MemOrder>
+inline T __TBB_machine_atomic_load( const volatile T& location) {
+    if (MemOrder == __ATOMIC_SEQ_CST) __TBB_compiler_fence();
+    T value = __atomic_load_n(&location, MemOrder);
+    if (MemOrder != __ATOMIC_RELAXED) __TBB_compiler_fence();
+    return value;
+}
+
+template <typename T, int MemOrder>
+inline void __TBB_machine_atomic_store( volatile T& location, T value) {
+    if (MemOrder != __ATOMIC_RELAXED) __TBB_compiler_fence();
+    __atomic_store_n(&location, value, MemOrder);
+    if (MemOrder == __ATOMIC_SEQ_CST) __TBB_compiler_fence();
+}
+
+template <typename T, size_t S>
+struct machine_load_store {
+    static T load_with_acquire ( const volatile T& location ) {
+        return __TBB_machine_atomic_load<T, __ATOMIC_ACQUIRE>(location);
+    }
+    static void store_with_release ( volatile T &location, T value ) {
+        __TBB_machine_atomic_store<T, __ATOMIC_RELEASE>(location, value);
+    }
+};
+
+template <typename T, size_t S>
+struct machine_load_store_relaxed {
+    static inline T load ( const volatile T& location ) {
+        return __TBB_machine_atomic_load<T, __ATOMIC_RELAXED>(location);
+    }
+    static inline void store ( volatile T& location, T value ) {
+        __TBB_machine_atomic_store<T, __ATOMIC_RELAXED>(location, value);
+    }
+};
+
+template <typename T, size_t S>
+struct machine_load_store_seq_cst {
+    static T load ( const volatile T& location ) {
+        return __TBB_machine_atomic_load<T, __ATOMIC_SEQ_CST>(location);
+    }
+    static void store ( volatile T &location, T value ) {
+        __TBB_machine_atomic_store<T, __ATOMIC_SEQ_CST>(location, value);
+    }
+};
+
+}} // namespace tbb::internal
+
 #endif // __TBB_GCC_VERSION < 40700
 
 // Machine specific atomic operations
@@ -167,18 +214,24 @@ inline void __TBB_machine_unlock_byte( __TBB_atomic_flag &flag ) {
 #define __TBB_TryLockByte   __TBB_machine_try_lock_byte
 #define __TBB_UnlockByte    __TBB_machine_unlock_byte
 
-// Definition of other functions
-#define __TBB_Log2(V)           __TBB_machine_lg(V)
+// __builtin_clz counts the number of leading zeroes
+namespace tbb{ namespace internal { namespace gcc_builtins {
+    inline int clz(unsigned int x){ return __builtin_clz(x); };
+    inline int clz(unsigned long int x){ return __builtin_clzl(x); };
+    inline int clz(unsigned long long int x){ return __builtin_clzll(x); };
+}}}
+// logarithm is the index of the most significant non-zero bit
+static inline intptr_t __TBB_machine_lg( uintptr_t x ) {
+    // If P is a power of 2 and x<P, then (P-1)-x == (P-1) XOR x
+    return (sizeof(x)*8 - 1) ^ tbb::internal::gcc_builtins::clz(x);
+}
 
-// TODO: implement with __atomic_* builtins where available
-#define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE            1
-#define __TBB_USE_GENERIC_RELAXED_LOAD_STORE                1
-#define __TBB_USE_GENERIC_SEQUENTIAL_CONSISTENCY_LOAD_STORE 1
+#define __TBB_Log2(V)  __TBB_machine_lg(V)
 
 #if __TBB_WORDSIZE==4
     #define __TBB_USE_GENERIC_DWORD_LOAD_STORE              1
 #endif
 
 #if __TBB_x86_32 || __TBB_x86_64
-#include "gcc_itsx.h"
+#include "gcc_ia32_common.h"
 #endif
index 10a1229..7ace018 100644 (file)
 #ifndef __TBB_machine_gcc_ia32_common_H
 #define __TBB_machine_gcc_ia32_common_H
 
+#ifndef __TBB_Log2
 //TODO: Add a higher-level function, e.g. tbb::internal::log2(), into tbb_stddef.h, which
 //uses __TBB_Log2 and contains the assert and remove the assert from here and all other
 //platform-specific headers.
-//TODO: Check if use of gcc intrinsic gives a better chance for cross call optimizations
 template <typename T>
 static inline intptr_t __TBB_machine_lg( T x ) {
     __TBB_ASSERT(x>0, "The logarithm of a non-positive value is undefined.");
@@ -33,6 +33,7 @@ static inline intptr_t __TBB_machine_lg( T x ) {
     return j;
 }
 #define __TBB_Log2(V)  __TBB_machine_lg(V)
+#endif /* !__TBB_Log2 */
 
 #ifndef __TBB_Pause
 //TODO: check if raising a ratio of pause instructions to loop control instructions
index 637505d..613acaf 100644 (file)
@@ -49,7 +49,7 @@
     }}}
 #endif
 
-#if _MSC_VER>=1600 && (!__INTEL_COMPILER || __INTEL_COMPILER>=1310)
+#if __TBB_MSVC_PART_WORD_INTERLOCKED_INTRINSICS_PRESENT
     // S is the operand size in bytes, B is the suffix for intrinsics for that size
     #define __TBB_MACHINE_DEFINE_ATOMICS(S,B,T,U)                                           \
     __pragma(intrinsic( _InterlockedCompareExchange##B ))                                   \
@@ -75,8 +75,7 @@
     #endif
 
     #undef __TBB_MACHINE_DEFINE_ATOMICS
-    #define __TBB_ATOMIC_PRIMITIVES_DEFINED
-#endif /*_MSC_VER>=1600*/
+#endif /* __TBB_MSVC_PART_WORD_INTERLOCKED_INTRINSICS_PRESENT */
 
 #if _MSC_VER>=1300 || __INTEL_COMPILER>=1100
     #pragma intrinsic(_ReadWriteBarrier)
index 0d8164d..169d14f 100644 (file)
@@ -43,7 +43,7 @@ extern "C" {
     __int64 __TBB_EXPORTED_FUNC __TBB_machine_load8 (const volatile void *ptr);
 }
 
-#ifndef __TBB_ATOMIC_PRIMITIVES_DEFINED
+#if !__TBB_MSVC_PART_WORD_INTERLOCKED_INTRINSICS_PRESENT
 
 #define __TBB_MACHINE_DEFINE_ATOMICS(S,T,U,A,C) \
 static inline T __TBB_machine_cmpswp##S ( volatile void * ptr, U value, U comparand ) { \
@@ -93,7 +93,7 @@ __TBB_MACHINE_DEFINE_ATOMICS(4, ptrdiff_t, ptrdiff_t, eax, ecx)
 
 #undef __TBB_MACHINE_DEFINE_ATOMICS
 
-#endif /*__TBB_ATOMIC_PRIMITIVES_DEFINED*/
+#endif /* __TBB_MSVC_PART_WORD_INTERLOCKED_INTRINSICS_PRESENT */
 
 //TODO: Check if it possible and profitable for IA-32 architecture on (Linux and Windows)
 //to use of 64-bit load/store via floating point registers together with full fence
index 0d24faa..2103c90 100644 (file)
@@ -29,7 +29,7 @@
 
 #include "msvc_ia32_common.h"
 
-#ifndef __TBB_ATOMIC_PRIMITIVES_DEFINED
+#if !__TBB_MSVC_PART_WORD_INTERLOCKED_INTRINSICS_PRESENT
 
 #include <intrin.h>
 #pragma intrinsic(_InterlockedCompareExchange,_InterlockedExchangeAdd,_InterlockedExchange)
@@ -66,7 +66,7 @@ inline __int64 __TBB_machine_fetchstore8 (volatile void *ptr, __int64 value ) {
     return _InterlockedExchange64( (__int64*)ptr, value );
 }
 
-#endif /*__TBB_ATOMIC_PRIMITIVES_DEFINED*/
+#endif /* __TBB_MSVC_PART_WORD_INTERLOCKED_INTRINSICS_PRESENT */
 
 #define __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE           1
 #define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE            1
index 12ee540..753bf3c 100644 (file)
@@ -233,13 +233,6 @@ void parallel_sort(Range& rng, const Compare& comp) {
     parallel_sort(tbb::internal::first(rng), tbb::internal::last(rng), comp);
 }
 
-//! Sorts the data in const rng using the given comparator
-/** @ingroup algorithms **/
-template<typename Range, typename Compare>
-void parallel_sort(const Range& rng, const Compare& comp) {
-    parallel_sort(tbb::internal::first(rng), tbb::internal::last(rng), comp);
-}
-
 //! Sorts the data in rng with a default comparator \c std::less<RandomAccessIterator>
 /** @ingroup algorithms **/
 template<typename Range>
@@ -247,13 +240,6 @@ void parallel_sort(Range& rng) {
     parallel_sort(tbb::internal::first(rng), tbb::internal::last(rng));
 }
 
-//! Sorts the data in const rng with a default comparator \c std::less<RandomAccessIterator>
-/** @ingroup algorithms **/
-template<typename Range>
-void parallel_sort(const Range& rng) {
-    parallel_sort(tbb::internal::first(rng), tbb::internal::last(rng));
-}
-
 //! Sorts the data in the range \c [begin,end) with a default comparator \c std::less<T>
 /** @ingroup algorithms **/
 template<typename T>
index b23181e..7092499 100644 (file)
@@ -46,6 +46,7 @@ public:
         //! Initialize fields to mean "no lock held".
         void initialize() {
             mutex = NULL;
+            going = 0;
 #if TBB_USE_ASSERT
             internal::poison_pointer(next);
 #endif /* TBB_USE_ASSERT */
index 1de31e6..9dd8444 100644 (file)
@@ -55,6 +55,8 @@ public:
         //! Initialize fields to mean "no lock held".
         void initialize() {
             my_mutex = NULL;
+            my_internal_lock = 0;
+            my_going = 0;
 #if TBB_USE_ASSERT
             my_state = 0xFF; // Set to invalid state
             internal::poison_pointer(my_next);
index 7ed3aaa..835ca6c 100644 (file)
@@ -90,9 +90,6 @@ public:
     class scoped_lock : internal::no_copy {
 #if __TBB_TSX_AVAILABLE
         friend class tbb::interface8::internal::x86_rtm_rw_mutex;
-        // helper methods for x86_rtm_rw_mutex
-        spin_rw_mutex *internal_get_mutex() const { return mutex; }
-        void internal_set_mutex(spin_rw_mutex* m) { mutex = m; }
 #endif
     public:
         //! Construct lock that has not acquired a mutex.
@@ -121,7 +118,7 @@ public:
         //! Upgrade reader to become a writer.
         /** Returns whether the upgrade happened without releasing and re-acquiring the lock */
         bool upgrade_to_writer() {
-            __TBB_ASSERT( mutex, "lock is not acquired" );
+            __TBB_ASSERT( mutex, "mutex is not acquired" );
             __TBB_ASSERT( !is_writer, "not a reader" );
             is_writer = true;
             return mutex->internal_upgrade();
@@ -129,7 +126,7 @@ public:
 
         //! Release lock.
         void release() {
-            __TBB_ASSERT( mutex, "lock is not acquired" );
+            __TBB_ASSERT( mutex, "mutex is not acquired" );
             spin_rw_mutex *m = mutex;
             mutex = NULL;
 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
@@ -143,7 +140,7 @@ public:
 
         //! Downgrade writer to become a reader.
         bool downgrade_to_reader() {
-            __TBB_ASSERT( mutex, "lock is not acquired" );
+            __TBB_ASSERT( mutex, "mutex is not acquired" );
             __TBB_ASSERT( is_writer, "not a writer" );
 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
             mutex->internal_downgrade();
index 3d57b0b..42fd724 100644 (file)
@@ -82,6 +82,16 @@ public:
 };
 
 class task_group_base : internal::no_copy {
+    class ref_count_guard : internal::no_copy {
+        task& my_task;
+    public:
+        ref_count_guard(task& t) : my_task(t) {
+            my_task.increment_ref_count();
+        }
+        ~ref_count_guard() {
+            my_task.decrement_ref_count();
+        }
+    };
 protected:
     empty_task* my_root;
     task_group_context my_context;
@@ -90,16 +100,6 @@ protected:
 
     template<typename F>
     task_group_status internal_run_and_wait( F& f ) {
-        class ref_count_guard : internal::no_copy {
-            task& my_task;
-        public:
-            ref_count_guard( task& t ) : my_task(t) {
-                my_task.increment_ref_count();
-            }
-            ~ref_count_guard() {
-                my_task.decrement_ref_count();
-            }
-        };
         __TBB_TRY {
             if ( !my_context.is_group_execution_cancelled() ) {
                 // We need to increase the reference count of the root task to notify waiters that
@@ -128,7 +128,11 @@ public:
 
     ~task_group_base() __TBB_NOEXCEPT(false) {
         if( my_root->ref_count() > 1 ) {
+#if __TBB_CPP17_UNCAUGHT_EXCEPTIONS_PRESENT
+            bool stack_unwinding_in_progress = std::uncaught_exceptions() > 0;
+#else
             bool stack_unwinding_in_progress = std::uncaught_exception();
+#endif
             // Always attempt to do proper cleanup to avoid inevitable memory corruption
             // in case of missing wait (for the sake of better testability & debuggability)
             if ( !is_canceling() )
index 9dc18ff..8908b86 100644 (file)
@@ -23,7 +23,7 @@
 
 /**
     This header bulk-includes declarations or definitions of all the functionality
-    provided by TBB (save for malloc dependent headers).
+    provided by TBB (save for tbbmalloc and 3rd party dependent headers).
 
     If you use only a few TBB constructs, consider including specific headers only.
     Any header listed below can be included independently of others.
@@ -37,6 +37,9 @@
 #include "blocked_range.h"
 #include "blocked_range2d.h"
 #include "blocked_range3d.h"
+#if TBB_PREVIEW_BLOCKED_RANGE_ND
+#include "blocked_rangeNd.h"
+#endif
 #include "cache_aligned_allocator.h"
 #include "combinable.h"
 #include "concurrent_hash_map.h"
@@ -54,6 +57,7 @@
 #if TBB_PREVIEW_GLOBAL_CONTROL
 #include "global_control.h"
 #endif
+#include "iterators.h"
 #include "mutex.h"
 #include "null_mutex.h"
 #include "null_rw_mutex.h"
index feaf778..74f59c1 100644 (file)
 #ifndef __TBB_CPP11_VARIADIC_FIXED_LENGTH_EXP_PRESENT
 #define __TBB_CPP11_VARIADIC_FIXED_LENGTH_EXP_PRESENT       __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT
 #endif
-#define __TBB_CPP11_VARIADIC_TUPLE_PRESENT                  (!_MSC_VER || _MSC_VER >=1800)
+#define __TBB_CPP11_VARIADIC_TUPLE_PRESENT                  (!_MSC_VER || _MSC_VER >= 1800)
 
 #define __TBB_CPP11_TYPE_PROPERTIES_PRESENT                 (_LIBCPP_VERSION || _MSC_VER >= 1700 || (__TBB_GLIBCXX_VERSION >= 50000 && __GXX_EXPERIMENTAL_CXX0X__))
 #define __TBB_TR1_TYPE_PROPERTIES_IN_STD_PRESENT            (__GXX_EXPERIMENTAL_CXX0X__ && __TBB_GLIBCXX_VERSION >= 40300 || _MSC_VER >= 1600)
 // Due to libc++ limitations in C++03 mode, do not pass rvalues to std::make_shared()
 #define __TBB_CPP11_SMART_POINTERS_PRESENT                  ( _MSC_VER >= 1600 || _LIBCPP_VERSION   \
                                                             || ((__cplusplus >= 201103L || __GXX_EXPERIMENTAL_CXX0X__)  \
-                                                            && (__TBB_GLIBCXX_VERSION>=40500 || __TBB_GLIBCXX_VERSION>=40400 && __TBB_USE_OPTIONAL_RTTI)) )
+                                                            && (__TBB_GLIBCXX_VERSION >= 40500 || __TBB_GLIBCXX_VERSION >= 40400 && __TBB_USE_OPTIONAL_RTTI)) )
 
-#define __TBB_CPP11_FUTURE_PRESENT                          (_MSC_VER >= 1700 || __TBB_GLIBCXX_VERSION >= 40600 && _GXX_EXPERIMENTAL_CXX0X__ || _LIBCPP_VERSION)
+#define __TBB_CPP11_FUTURE_PRESENT                          (_MSC_VER >= 1700 || __TBB_GLIBCXX_VERSION >= 40600 && __GXX_EXPERIMENTAL_CXX0X__ || _LIBCPP_VERSION)
 
-#define __TBB_CPP11_GET_NEW_HANDLER_PRESENT                 (_LIBCPP_VERSION || _MSC_VER >= 1900 || (__TBB_GLIBCXX_VERSION >= 40900 && __GXX_EXPERIMENTAL_CXX0X__))
+#define __TBB_CPP11_GET_NEW_HANDLER_PRESENT                 (_MSC_VER >= 1900 || __TBB_GLIBCXX_VERSION >= 40900 && __GXX_EXPERIMENTAL_CXX0X__ || _LIBCPP_VERSION)
+
+#define __TBB_CPP17_UNCAUGHT_EXCEPTIONS_PRESENT             (_MSC_VER >= 1900 || __GLIBCXX__ && __cpp_lib_uncaught_exceptions || _LIBCPP_VERSION >= 3700)
 
 // std::swap is in <utility> only since C++11, though MSVC had it at least since VS2005
 #if _MSC_VER>=1400 || _LIBCPP_VERSION || __GXX_EXPERIMENTAL_CXX0X__
     #define __TBB_GCC_BUILTIN_ATOMICS_PRESENT 1
 #endif
 
+#if __TBB_GCC_VERSION >= 70000 && !__INTEL_COMPILER && !__clang__
+    // After GCC7 there was possible reordering problem in generic atomic load/store operations.
+    // So always using builtins.
+    #define TBB_USE_GCC_BUILTINS 1
+#endif
+
 #if __INTEL_COMPILER >= 1200
     /** built-in C++11 style atomics available in ICC since 12.0 **/
     #define __TBB_ICC_BUILTIN_ATOMICS_PRESENT 1
 #endif
 
+#if _MSC_VER>=1600 && (!__INTEL_COMPILER || __INTEL_COMPILER>=1310)
+    #define __TBB_MSVC_PART_WORD_INTERLOCKED_INTRINSICS_PRESENT 1
+#endif
+
 #define __TBB_TSX_INTRINSICS_PRESENT ((__RTM__ || _MSC_VER>=1700 || __INTEL_COMPILER>=1300) && !__TBB_DEFINE_MIC && !__ANDROID__)
 
 /** Macro helpers **/
@@ -668,7 +680,7 @@ There are four cases that are supported:
     #define __TBB_ICC_ASM_VOLATILE_BROKEN 1
 #endif
 
-#if !__INTEL_COMPILER && (_MSC_VER || __GNUC__==3 && __GNUC_MINOR__<=2)
+#if !__INTEL_COMPILER && (_MSC_VER && _MSC_VER < 1700 || __GNUC__==3 && __GNUC_MINOR__<=2)
     /** Bug in GCC 3.2 and MSVC compilers that sometimes return 0 for __alignof(T)
         when T has not yet been instantiated. **/
     #define __TBB_ALIGNOF_NOT_INSTANTIATED_TYPES_BROKEN 1
index c9e1be0..e79d82e 100644 (file)
@@ -788,7 +788,7 @@ struct __TBB_machine_type_with_alignment_##PowerOf2 { \
 #endif
 
 /* Now declare types aligned to useful powers of two */
-// TODO: Is __TBB_DefineTypeWithAlignment(8) needed on 32 bit platforms?
+__TBB_DefineTypeWithAlignment(8) // i386 ABI says that uint64_t is aligned on 4 bytes  
 __TBB_DefineTypeWithAlignment(16)
 __TBB_DefineTypeWithAlignment(32)
 __TBB_DefineTypeWithAlignment(64)
@@ -802,7 +802,7 @@ template<size_t N> struct type_with_alignment;
 template<> struct type_with_alignment<1> { char member; };
 template<> struct type_with_alignment<2> { uint16_t member; };
 template<> struct type_with_alignment<4> { uint32_t member; };
-template<> struct type_with_alignment<8> { uint64_t member; };
+template<> struct type_with_alignment<8> { __TBB_machine_type_with_alignment_8 member; };
 template<> struct type_with_alignment<16> {__TBB_machine_type_with_alignment_16 member; };
 template<> struct type_with_alignment<32> {__TBB_machine_type_with_alignment_32 member; };
 template<> struct type_with_alignment<64> {__TBB_machine_type_with_alignment_64 member; };
index d782c88..37961df 100644 (file)
@@ -26,7 +26,7 @@
 #define TBB_VERSION_MINOR 0
 
 // Engineering-focused interface version
-#define TBB_INTERFACE_VERSION 11000
+#define TBB_INTERFACE_VERSION 11001
 #define TBB_INTERFACE_VERSION_MAJOR TBB_INTERFACE_VERSION/1000
 
 // The oldest major interface version still supported
index a1827ee..1e1d7d5 100644 (file)
@@ -57,6 +57,7 @@ def _test(arg=None):
     import platform
     if platform.system() == "Linux":
         ctypes.CDLL(libirml)
+        assert 256 == os.system("ldd "+_api.__file__+"| grep -E 'libimf|libsvml|libintlc'")
     from .test import test
     test(arg)
     print("done")
index a68d650..4f6cf1f 100644 (file)
@@ -32,8 +32,6 @@
 
 #define RECORD_EVENTS 0
 
-using namespace std;
-
 namespace tbb {
 
 namespace internal {
@@ -210,7 +208,7 @@ concurrent_queue_base::concurrent_queue_base( size_t item_sz ) {
     __TBB_ASSERT( (size_t)&my_rep->head_counter % NFS_GetLineSize()==0, "alignment error" );
     __TBB_ASSERT( (size_t)&my_rep->tail_counter % NFS_GetLineSize()==0, "alignment error" );
     __TBB_ASSERT( (size_t)&my_rep->array % NFS_GetLineSize()==0, "alignment error" );
-    memset(static_cast<void*>(my_rep),0,sizeof(concurrent_queue_rep));
+    std::memset(static_cast<void*>(my_rep),0,sizeof(concurrent_queue_rep));
     this->item_size = item_sz;
 }
 
index d78d3f4..6525308 100644 (file)
@@ -32,8 +32,6 @@
 #include <dlfcn.h>
 #endif /* _WIN32||_WIN64 */
 
-using namespace std;
-
 #if __TBB_WEAK_SYMBOLS_PRESENT
 
 #pragma weak scalable_malloc
@@ -124,8 +122,8 @@ void initialize_handler_pointers() {
         // This must be done now, and not before FillDynamicLinks runs, because if other
         // threads call the handlers, we want them to go through the DoOneTimeInitializations logic,
         // which forces them to wait.
-        FreeHandler = &free;
-        MallocHandler = &malloc;
+        FreeHandler = &std::free;
+        MallocHandler = &std::malloc;
         padded_allocate_handler = &padded_allocate;
         padded_free_handler = &padded_free;
     }
@@ -207,7 +205,7 @@ void NFS_Free( void* p ) {
 
 static void* padded_allocate( size_t bytes, size_t alignment ) {
     unsigned char* result = NULL;
-    unsigned char* base = (unsigned char*)malloc(alignment+bytes);
+    unsigned char* base = (unsigned char*)std::malloc(alignment+bytes);
     if( base ) {
         // Round up to the next line
         result = (unsigned char*)((uintptr_t)(base+alignment)&-alignment);
@@ -223,7 +221,7 @@ static void padded_free( void* p ) {
         // Recover where block actually starts
         unsigned char* base = ((unsigned char**)p)[-1];
         __TBB_ASSERT( (void*)((uintptr_t)(base+NFS_LineSize)&-NFS_LineSize)==p, "not allocated by NFS_Allocate?" );
-        free(base);
+        std::free(base);
     }
 }
 
@@ -248,9 +246,9 @@ bool __TBB_EXPORTED_FUNC is_malloc_used_v3() {
     }
     __TBB_ASSERT( MallocHandler!=&DummyMalloc && FreeHandler!=&DummyFree, NULL );
     // Cast to void avoids type mismatch errors on some compilers (e.g. __IBMCPP__)
-    __TBB_ASSERT( !(((void*)MallocHandler==(void*)&malloc) ^ ((void*)FreeHandler==(void*)&free)),
+    __TBB_ASSERT( !(((void*)MallocHandler==(void*)&std::malloc) ^ ((void*)FreeHandler==(void*)&std::free)),
                   "Both shim pointers must refer to routines from the same package (either TBB or CRT)" );
-    return (void*)MallocHandler == (void*)&malloc;
+    return (void*)MallocHandler == (void*)&std::malloc;
 }
 
 } // namespace internal
index e663841..5401e23 100644 (file)
@@ -29,8 +29,6 @@
 #include <new>
 #include <cstring>   // for memset()
 
-using namespace std;
-
 #if defined(_MSC_VER) && defined(_Wp64)
     // Workaround for overzealous compiler warnings in /Wp64 mode
     #pragma warning (disable: 4267)
@@ -353,7 +351,7 @@ concurrent_queue_base_v3::concurrent_queue_base_v3( size_t item_sz ) {
     __TBB_ASSERT( is_aligned(&my_rep->head_counter, NFS_GetLineSize()), "alignment error" );
     __TBB_ASSERT( is_aligned(&my_rep->tail_counter, NFS_GetLineSize()), "alignment error" );
     __TBB_ASSERT( is_aligned(&my_rep->array, NFS_GetLineSize()), "alignment error" );
-    memset(static_cast<void*>(my_rep),0,sizeof(concurrent_queue_rep));
+    std::memset(static_cast<void*>(my_rep),0,sizeof(concurrent_queue_rep));
     new ( &my_rep->items_avail ) concurrent_monitor();
     new ( &my_rep->slots_avail ) concurrent_monitor();
     this->item_size = item_sz;
index 1ecc2ac..d9a2596 100644 (file)
@@ -38,8 +38,6 @@
     #pragma warning (disable: 4267)
 #endif
 
-using namespace std;
-
 namespace tbb {
 
 namespace internal {
index e12bf70..2e6f874 100644 (file)
@@ -216,9 +216,9 @@ task* custom_scheduler<SchedulerTraits>::receive_or_steal_task( __TBB_ISOLATION_
             GATHER_STATISTIC( ++my_counters.mails_received );
         }
         // Check if there are tasks in starvation-resistant stream.
-        // Only allowed at the outermost dispatch level.
-        else if ( outermost_dispatch_level && !my_arena->my_task_stream.empty(p)
-                  && (t = my_arena->my_task_stream.pop( p, my_arena_slot->hint_for_pop)) ) {
+        // Only allowed at the outermost dispatch level without isolation.
+        else if (__TBB_ISOLATION_EXPR(isolation == no_isolation &&) outermost_dispatch_level &&
+            !my_arena->my_task_stream.empty(p) && (t = my_arena->my_task_stream.pop( p, my_arena_slot->hint_for_pop)) ) {
             ITT_NOTIFY(sync_acquired, &my_arena->my_task_stream);
             // just proceed with the obtained task
         }
index 37bf266..ed046f3 100644 (file)
@@ -362,21 +362,20 @@ OPEN_INTERNAL_NAMESPACE
         in  len  -- Size of buffer.
         ret      -- 0         -- Error occurred.
                     > len     -- Buffer too short, required size returned.
-                    otherwise -- Ok, number of characters (not counting terminating null) written to
-                    buffer.
+                    otherwise -- Ok, number of characters (incl. terminating null) written to buffer.
     */
     static size_t abs_path( char const * name, char * path, size_t len ) {
-        if ( !ap_data._len )
+        if ( ap_data._len == 0 )
             return 0;
 
         size_t name_len = strlen( name );
         size_t full_len = name_len+ap_data._len;
         if ( full_len < len ) {
-            strncpy( path, ap_data._path, ap_data._len );
-            strncpy( path+ap_data._len, name, name_len );
-            path[full_len] = 0;
+            __TBB_ASSERT(ap_data._path[ap_data._len] == 0, NULL);
+            strcpy( path, ap_data._path );
+            strcat( path, name );
         }
-        return full_len;
+        return full_len+1; // +1 for null character
     }
 #endif  // __TBB_DYNAMIC_LOAD_ENABLED
 
@@ -512,37 +511,37 @@ OPEN_INTERNAL_NAMESPACE
     }
 
     dynamic_link_handle dynamic_load( const char* library, const dynamic_link_descriptor descriptors[], size_t required ) {
-    ::tbb::internal::suppress_unused_warning( library, descriptors, required );
-    #if __TBB_DYNAMIC_LOAD_ENABLED
+        ::tbb::internal::suppress_unused_warning( library, descriptors, required );
+#if __TBB_DYNAMIC_LOAD_ENABLED
 
-    size_t const len = PATH_MAX + 1;
-    char path[ len ];
-    size_t rc = abs_path( library, path, len );
-    if ( 0 < rc && rc < len ) {
+        size_t const len = PATH_MAX + 1;
+        char path[ len ];
+        size_t rc = abs_path( library, path, len );
+        if ( 0 < rc && rc <= len ) {
 #if _WIN32
-        // Prevent Windows from displaying silly message boxes if it fails to load library
-        // (e.g. because of MS runtime problems - one of those crazy manifest related ones)
-        UINT prev_mode = SetErrorMode (SEM_FAILCRITICALERRORS);
+            // Prevent Windows from displaying silly message boxes if it fails to load library
+            // (e.g. because of MS runtime problems - one of those crazy manifest related ones)
+            UINT prev_mode = SetErrorMode (SEM_FAILCRITICALERRORS);
 #endif /* _WIN32 */
-        dynamic_link_handle library_handle = dlopen( path, RTLD_LAZY );
+            dynamic_link_handle library_handle = dlopen( path, RTLD_LAZY );
 #if _WIN32
-        SetErrorMode (prev_mode);
+            SetErrorMode (prev_mode);
 #endif /* _WIN32 */
-        if( library_handle ) {
-            if( !resolve_symbols( library_handle, descriptors, required ) ) {
-                // The loaded library does not contain all the expected entry points
-                dynamic_unlink( library_handle );
-                library_handle = NULL;
-            }
-        } else
-            DYNAMIC_LINK_WARNING( dl_lib_not_found, path, dlerror() );
-        return library_handle;
-    } else if ( rc>=len )
-            DYNAMIC_LINK_WARNING( dl_buff_too_small );
-            // rc == 0 means failing of init_ap_data so the warning has already been issued.
+            if( library_handle ) {
+                if( !resolve_symbols( library_handle, descriptors, required ) ) {
+                    // The loaded library does not contain all the expected entry points
+                    dynamic_unlink( library_handle );
+                    library_handle = NULL;
+                }
+            } else
+                DYNAMIC_LINK_WARNING( dl_lib_not_found, path, dlerror() );
+            return library_handle;
+        } else if ( rc>len )
+                DYNAMIC_LINK_WARNING( dl_buff_too_small );
+                // rc == 0 means failing of init_ap_data so the warning has already been issued.
 
-    #endif /* __TBB_DYNAMIC_LOAD_ENABLED */
-        return 0;
+#endif /* __TBB_DYNAMIC_LOAD_ENABLED */
+            return 0;
     }
 
     bool dynamic_link( const char* library, const dynamic_link_descriptor descriptors[], size_t required, dynamic_link_handle *handle, int flags ) {
index f5b86f1..1a5b39a 100644 (file)
@@ -369,7 +369,7 @@ void task_scheduler_observer_v3::observe( bool enable ) {
                     a->initialize();
                     my_proxy->my_list = &a->my_arena->my_observers;
                 } else {
-                    if( !s )
+                    if( !(s && s->my_arena) )
                         s = governor::init_scheduler( task_scheduler_init::automatic, 0, true );
                     __TBB_ASSERT( __TBB_InitOnce::initialization_done(), NULL );
                     __TBB_ASSERT( s && s->my_arena, NULL );
index ebcef07..e8e7e46 100644 (file)
@@ -31,8 +31,6 @@
 
 namespace tbb {
 
-using namespace std;
-
 namespace internal {
 
 //------------------------------------------------------------------------
index 01d742f..9032adb 100644 (file)
@@ -38,8 +38,6 @@
 #define __TBB_EXPORTED_FUNC
 #endif
 
-using namespace std;
-
 #if __TBBMALLOC_BUILD
 namespace rml { namespace internal {
 #else
@@ -72,7 +70,7 @@ namespace tbb {
                         _CrtDbgBreak();
 #else
                 fflush(stderr);
-                abort();
+                std::abort();
 #endif
             }
         }
index 36d9bcb..3a1468f 100644 (file)
@@ -46,8 +46,6 @@
 #include <cxxabi.h>
 #endif
 
-using namespace std;
-
 namespace tbb {
 
 const char* bad_last_alloc::what() const throw() { return "bad allocation in previous or concurrent attempt"; }
@@ -65,7 +63,7 @@ namespace internal {
         fprintf (stderr, "Exception %s with message %s would've been thrown, "  \
             "if exception handling were not disabled. Aborting.\n", exc_name, msg); \
         fflush(stderr); \
-        abort();
+        std::abort();
     #define DO_THROW(exc, init_args) PRINT_ERROR_AND_ABORT(#exc, #init_args)
 #endif /* !TBB_USE_EXCEPTIONS */
 
@@ -88,7 +86,7 @@ void handle_perror( int error_code, const char* what ) {
     // Ensure that buffer ends in terminator.
     buf[sizeof(buf)-1] = 0;
 #if TBB_USE_EXCEPTIONS
-    throw runtime_error(buf);
+    throw std::runtime_error(buf);
 #else
     PRINT_ERROR_AND_ABORT( "runtime_error", buf);
 #endif /* !TBB_USE_EXCEPTIONS */
@@ -105,7 +103,7 @@ void handle_win_error( int error_code ) {
     sprintf_s((char*)&buf, 512, "error code %d", error_code);
 #endif
 #if TBB_USE_EXCEPTIONS
-    throw runtime_error(buf);
+    throw std::runtime_error(buf);
 #else
     PRINT_ERROR_AND_ABORT( "runtime_error", buf);
 #endif /* !TBB_USE_EXCEPTIONS */
@@ -119,27 +117,27 @@ void throw_bad_last_alloc_exception_v4() {
 void throw_exception_v4 ( exception_id eid ) {
     __TBB_ASSERT ( eid > 0 && eid < eid_max, "Unknown exception ID" );
     switch ( eid ) {
-    case eid_bad_alloc: DO_THROW( bad_alloc, () );
+    case eid_bad_alloc: DO_THROW(std::bad_alloc, () );
     case eid_bad_last_alloc: DO_THROW( bad_last_alloc, () );
-    case eid_nonpositive_step: DO_THROW( invalid_argument, ("Step must be positive") );
-    case eid_out_of_range: DO_THROW( out_of_range, ("Index out of requested size range") );
-    case eid_segment_range_error: DO_THROW( range_error, ("Index out of allocated segment slots") );
-    case eid_index_range_error: DO_THROW( range_error, ("Index is not allocated") );
+    case eid_nonpositive_step: DO_THROW(std::invalid_argument, ("Step must be positive") );
+    case eid_out_of_range: DO_THROW(std::out_of_range, ("Index out of requested size range") );
+    case eid_segment_range_error: DO_THROW(std::range_error, ("Index out of allocated segment slots") );
+    case eid_index_range_error: DO_THROW(std::range_error, ("Index is not allocated") );
     case eid_missing_wait: DO_THROW( missing_wait, () );
     case eid_invalid_multiple_scheduling: DO_THROW( invalid_multiple_scheduling, () );
     case eid_improper_lock: DO_THROW( improper_lock, () );
-    case eid_possible_deadlock: DO_THROW( runtime_error, ("Resource deadlock would occur") );
-    case eid_operation_not_permitted: DO_THROW( runtime_error, ("Operation not permitted") );
-    case eid_condvar_wait_failed: DO_THROW( runtime_error, ("Wait on condition variable failed") );
-    case eid_invalid_load_factor: DO_THROW( out_of_range, ("Invalid hash load factor") );
-    case eid_reserved: DO_THROW( out_of_range, ("[backward compatibility] Invalid number of buckets") );
-    case eid_invalid_swap: DO_THROW( invalid_argument, ("swap() is invalid on non-equal allocators") );
-    case eid_reservation_length_error: DO_THROW( length_error, ("reservation size exceeds permitted max size") );
-    case eid_invalid_key: DO_THROW( out_of_range, ("invalid key") );
+    case eid_possible_deadlock: DO_THROW(std::runtime_error, ("Resource deadlock would occur") );
+    case eid_operation_not_permitted: DO_THROW(std::runtime_error, ("Operation not permitted") );
+    case eid_condvar_wait_failed: DO_THROW(std::runtime_error, ("Wait on condition variable failed") );
+    case eid_invalid_load_factor: DO_THROW(std::out_of_range, ("Invalid hash load factor") );
+    case eid_reserved: DO_THROW(std::out_of_range, ("[backward compatibility] Invalid number of buckets") );
+    case eid_invalid_swap: DO_THROW(std::invalid_argument, ("swap() is invalid on non-equal allocators") );
+    case eid_reservation_length_error: DO_THROW(std::length_error, ("reservation size exceeds permitted max size") );
+    case eid_invalid_key: DO_THROW(std::out_of_range, ("invalid key") );
     case eid_user_abort: DO_THROW( user_abort, () );
-    case eid_bad_tagged_msg_cast: DO_THROW( runtime_error, ("Illegal tagged_msg cast") );
+    case eid_bad_tagged_msg_cast: DO_THROW(std::runtime_error, ("Illegal tagged_msg cast") );
 #if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE
-    case eid_blocking_thread_join_impossible: DO_THROW( runtime_error, ("Blocking terminate failed") );
+    case eid_blocking_thread_join_impossible: DO_THROW(std::runtime_error, ("Blocking terminate failed") );
 #endif
     default: break;
     }
@@ -195,7 +193,7 @@ bool gcc_rethrow_exception_broken() { return false; }
 bool GetBoolEnvironmentVariable( const char * ) { return false;}
 #else  /* __TBB_WIN8UI_SUPPORT */
 bool GetBoolEnvironmentVariable( const char * name ) {
-    if( const char* s = getenv(name) )
+    if( const char* s = std::getenv(name) )
         return strcmp(s,"0") != 0;
     return false;
 }
index e60dc55..ebf9d0c 100644 (file)
@@ -80,7 +80,7 @@ void x86_rtm_rw_mutex::internal_release(x86_rtm_rw_mutex::scoped_lock& s) {
             }
 #endif
             __TBB_machine_end_transaction();
-            s.my_scoped_lock.internal_set_mutex(NULL);
+            s.my_scoped_lock.mutex = NULL;
         }
         break;
     case RTM_real_reader:
@@ -127,7 +127,9 @@ void x86_rtm_rw_mutex::internal_acquire_writer(x86_rtm_rw_mutex::scoped_lock& s,
                 }
 #endif
                 s.transaction_state = RTM_transacting_writer;
-                s.my_scoped_lock.internal_set_mutex(this);  // need mutex for release()
+                // Don not wrap the following assignment to a function,
+                // because it can abort the transaction in debug. Need mutex for release().
+                s.my_scoped_lock.mutex = this;
                 return;  // successfully started speculation
             }
             ++num_retries;
@@ -170,7 +172,9 @@ void x86_rtm_rw_mutex::internal_acquire_reader(x86_rtm_rw_mutex::scoped_lock& s,
                 }
 #endif
                 s.transaction_state = RTM_transacting_reader;
-                s.my_scoped_lock.internal_set_mutex(this);  // need mutex for release()
+                // Don not wrap the following assignment to a function,
+                // because it can abort the transaction in debug. Need mutex for release().
+                s.my_scoped_lock.mutex = this;
                 return;  // successfully started speculation
             }
             // fallback path
index 2807931..cd57b38 100644 (file)
@@ -87,7 +87,7 @@ extern HugePagesStatus hugePages;
 void *Backend::allocRawMem(size_t &size)
 {
     void *res = NULL;
-    size_t allocSize;
+    size_t allocSize = 0;
 
     if (extMemPool->userPool()) {
         if (extMemPool->fixedPool && bootsrapMemDone == FencedLoad(bootsrapMemStatus))
@@ -101,6 +101,7 @@ void *Backend::allocRawMem(size_t &size)
     } else {
         // Align allocation on page size
         size_t pageSize = hugePages.isEnabled ? hugePages.getGranularity() : extMemPool->granularity;
+        MALLOC_ASSERT(pageSize, "Page size cannot be zero.");
         allocSize = alignUpGeneric(size, pageSize);
 
         // If user requested huge pages and they are available, try to use preallocated ones firstly.
index 6a78a09..c854a04 100644 (file)
@@ -139,16 +139,19 @@ class ThreadId {
         return result;
     }
 public:
-    static void init() {
+    static bool init() {
 #if USE_WINTHREAD
         Tid_key = TlsAlloc();
+        if (Tid_key == TLS_ALLOC_FAILURE)
+            return false;
 #else
         int status = pthread_key_create( &Tid_key, NULL );
         if ( status ) {
-            fprintf (stderr, "The memory manager cannot create tls key during initialization; exiting \n");
-            exit(1);
+            fprintf (stderr, "The memory manager cannot create tls key during initialization\n");
+            return false;
         }
 #endif /* USE_WINTHREAD */
+        return true;
     }
     static void destroy() {
         if( Tid_key ) {
@@ -157,10 +160,8 @@ public:
 #else
             int status = pthread_key_delete( Tid_key );
 #endif /* USE_WINTHREAD */
-            if ( status ) {
-                fprintf (stderr, "The memory manager cannot delete tls key; exiting \n");
-                exit(1);
-            }
+            if ( status )
+                fprintf (stderr, "The memory manager cannot delete tls key\n");
             Tid_key = 0;
         }
     }
@@ -203,7 +204,7 @@ public:
 #else
     bool isCurrentThreadId() const { return GetCurrentThreadId() == tid; }
 #endif
-    static void init() {}
+    static bool init() { return true; }
     static void destroy() {}
 };
 
@@ -1993,9 +1994,8 @@ static bool initMemoryManager()
         extMemPool.init(0, NULL, NULL, granularity,
                         /*keepAllMemory=*/false, /*fixedPool=*/false);
 // TODO: extMemPool.init() to not allocate memory
-    if (!initOk || !initBackRefMaster(&defaultMemPool->extMemPool.backend))
+    if (!initOk || !initBackRefMaster(&defaultMemPool->extMemPool.backend) || !ThreadId::init())
         return false;
-    ThreadId::init();      // Create keys for thread id
     MemoryPool::initDefaultPool();
     // init() is required iff initMemoryManager() is called
     // after mallocProcessShutdownNotification()
@@ -2184,7 +2184,7 @@ LargeMemoryBlock *LocalLOCImpl<LOW_MARK, HIGH_MARK>::get(size_t size)
     if (size > MAX_TOTAL_SIZE)
         return NULL;
 
-    if (!head || !(localHead = (LargeMemoryBlock*)AtomicFetchStore(&head, 0))) {
+    if (!head || (localHead = (LargeMemoryBlock*)AtomicFetchStore(&head, 0)) == NULL) {
         // do not restore totalSize, numOfBlocks and tail at this point,
         // as they are used only in put(), where they must be restored
         return NULL;
@@ -2645,8 +2645,10 @@ rml::MemPoolError pool_create_v1(intptr_t pool_id, const MemPoolPolicy *policy,
         return UNSUPPORTED_POLICY;
     }
     if (!isMallocInitialized())
-        if (!doInitialization())
+        if (!doInitialization()) {
+            *pool = NULL;
             return NO_MEMORY;
+        }
     rml::internal::MemoryPool *memPool =
         (rml::internal::MemoryPool*)internalMalloc((sizeof(rml::internal::MemoryPool)));
     if (!memPool) {
@@ -2813,11 +2815,14 @@ extern "C" void __TBB_mallocThreadShutdownNotification()
 }
 #endif
 
-extern "C" void __TBB_mallocProcessShutdownNotification()
+extern "C" void __TBB_mallocProcessShutdownNotification(bool windows_process_dying)
 {
     if (!isMallocInitialized()) return;
 
-    doThreadShutdownNotification(NULL, /*main_thread=*/true);
+    // Don't clean allocator internals if the entire process is exiting
+    if (!windows_process_dying) {
+        doThreadShutdownNotification(NULL, /*main_thread=*/true);
+    }
 #if  __TBB_MALLOC_LOCACHE_STAT
     printf("cache hit ratio %f, size hit %f\n",
            1.*cacheHits/mallocCalls, 1.*memHitKB/memAllocKB);
index 34215ef..07d1294 100644 (file)
@@ -292,7 +292,7 @@ template<typename Props> void CacheBinFunctor<Props>::
                     num += 1;
 
                     STAT_increment(getThreadId(), ThreadCommonCounters, cacheLargeObj);
-                } while (( curr = curr->next ));
+                } while ((curr = curr->next) != NULL);
 
                 LargeMemoryBlock *tail = prev;
                 addToPutList(head, tail, num);
@@ -401,7 +401,7 @@ template<typename Props> void CacheBinFunctor<Props>::operator()(CacheBinOperati
         CacheBinOperation *opNext = opClean->next;
         prep.commitOperation( opClean );
 
-        while (( opClean = opNext )) {
+        while ((opClean = opNext) != NULL) {
             opNext = opClean->next;
             prep.commitOperation(opClean);
         }
index 423b839..73b041d 100644 (file)
 
 */
 
+#if __linux__ && !__ANDROID__
+// include <bits/c++config.h> indirectly so that <cstdlib> is not included
+#include <cstddef>
+// include <features.h> indirectly so that <stdlib.h> is not included
+#include <unistd.h>
+// Working around compiler issue with Anaconda's gcc 7.3 compiler package.
+// New gcc ported for old libc may provide their inline implementation
+// of aligned_alloc as required by new C++ standard, this makes it hard to
+// redefine aligned_alloc here. However, running on systems with new libc
+// version, it still needs it to be redefined, thus tricking system headers
+#if defined(__GLIBC_PREREQ) && !__GLIBC_PREREQ(2, 16) && _GLIBCXX_HAVE_ALIGNED_ALLOC
+// tell <cstdlib> that there is no aligned_alloc
+#undef _GLIBCXX_HAVE_ALIGNED_ALLOC
+// trick <stdlib.h> to define another symbol instead
+#define aligned_alloc __hidden_redefined_aligned_alloc
+// Fix the state and undefine the trick
+#include <cstdlib>
+#undef aligned_alloc
+#endif // defined(__GLIBC_PREREQ)&&!__GLIBC_PREREQ(2, 16)&&_GLIBCXX_HAVE_ALIGNED_ALLOC
+#endif // __linux__ && !__ANDROID__
+
 #include "proxy.h"
 #include "tbb/tbb_config.h"
 
 #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED || _WIN32 && !__TBB_WIN8UI_SUPPORT
 /*** internal global operator new implementation (Linux, Windows) ***/
 #include <new>
+
+// Synchronization primitives to protect original library pointers and new_handler 
 #include "Synchronize.h"
 
+#if __TBB_MSVC_PART_WORD_INTERLOCKED_INTRINSICS_PRESENT
+// Use MallocMutex implementation
+typedef MallocMutex ProxyMutex;
+#else
+// One byte atomic intrinsics are not available,
+// so use simple pointer based spin mutex
+class SimpleSpinMutex : tbb::internal::no_copy {
+    intptr_t flag;
+public:
+    class scoped_lock : tbb::internal::no_copy {
+        SimpleSpinMutex& mutex;
+    public:
+        scoped_lock( SimpleSpinMutex& m ) : mutex(m) {
+            while( !(AtomicFetchStore( &(m.flag), 1 ) == 0) );
+        }
+        ~scoped_lock() {
+            FencedStore(mutex.flag, 0);
+        }
+    };
+    friend class scoped_lock;
+};
+typedef SimpleSpinMutex ProxyMutex;
+#endif /* __TBB_MSVC_PART_WORD_INTERLOCKED_INTRINSICS_PRESENT */
+
 // In case there is no std::get_new_handler function
+// which provides synchronized access to std::new_handler
 #if !__TBB_CPP11_GET_NEW_HANDLER_PRESENT
-static MallocMutex new_lock;
+static ProxyMutex new_lock;
 #endif
 
 static inline void* InternalOperatorNew(size_t sz) {
@@ -58,7 +106,7 @@ static inline void* InternalOperatorNew(size_t sz) {
         handler = std::get_new_handler();
 #else
         {
-            MallocMutex::scoped_lock lock(new_lock);
+            ProxyMutex::scoped_lock lock(new_lock);
             handler = std::set_new_handler(0);
             std::set_new_handler(handler);
         }
@@ -397,6 +445,7 @@ const char* known_bytecodes[] = {
     "C7442410000000008B",     // release free() ucrtbase.dll 10.0.14393.33
     "E90B000000CCCC",         // release _msize() ucrtbase.dll 10.0.14393.33
     "48895C24085748",         // release _aligned_msize() ucrtbase.dll 10.0.14393.33
+    "E903000000CCCC",         // release _aligned_msize() ucrtbase.dll 10.0.16299.522
     "48894C24084883EC28BA",   // debug prologue
     "4C894424184889542410",   // debug _aligned_msize() 10.0
     "48894C24084883EC2848",   // debug _aligned_free 10.0
@@ -659,7 +708,11 @@ void ReplaceFunctionWithStore( const unicode_char_t *dllName, const char *funcNa
 
     fprintf(stderr, "Failed to %s function %s in module %s\n",
             res==FRR_NOFUNC? "find" : "replace", funcName, dllName);
-    exit(1);
+
+    // Unable to replace a required function
+    // Aborting because incomplete replacement of memory management functions
+    // may leave the program in an invalid state
+    abort();
 }
 
 void doMallocReplacement()
index 08191b7..93a519e 100644 (file)
@@ -378,7 +378,7 @@ static bool InsertTrampoline(void *inpAddr, void *targetAddr, const char ** opco
     if (!VirtualProtect(inpAddr, MAX_PROBE_SIZE, PAGE_EXECUTE_WRITECOPY, &origProt))
         return FALSE;
 
-    UINT opcodeIdx = 0;
+    const char* pattern = NULL;
     if ( origFunc ){ // Need to store original function code
         UCHAR * const codePtr = (UCHAR *)inpAddr;
         if ( *codePtr == 0xE9 ){ // JMP relative instruction
@@ -389,12 +389,12 @@ static bool InsertTrampoline(void *inpAddr, void *targetAddr, const char ** opco
             origFunc = NULL; // now it must be ignored by InsertTrampoline32/64
         } else {
             // find the right opcode pattern
-            opcodeIdx = CheckOpcodes( opcodes, inpAddr, /*abortOnError=*/true );
+            UINT opcodeIdx = CheckOpcodes( opcodes, inpAddr, /*abortOnError=*/true );
             __TBB_ASSERT( opcodeIdx > 0, "abortOnError ignored in CheckOpcodes?" );
+            pattern = opcodes[opcodeIdx-1];  // -1 compensates for +1 in CheckOpcodes
         }
     }
 
-    const char* pattern = opcodeIdx>0? opcodes[opcodeIdx-1]: NULL; // -1 compensates for +1 in CheckOpcodes
     probeSize = InsertTrampoline32(inpAddr, targetAddr, pattern, origFunc);
     if (!probeSize)
         probeSize = InsertTrampoline64(inpAddr, targetAddr, pattern, origFunc);
index ba70a77..bab6e79 100644 (file)
@@ -75,16 +75,15 @@ void init_tbbmalloc() {
 
 #if !__TBB_SOURCE_DIRECTLY_INCLUDED
 #if USE_WINTHREAD
-extern "C" BOOL WINAPI DllMain( HINSTANCE /*hInst*/, DWORD callReason, LPVOID )
+extern "C" BOOL WINAPI DllMain( HINSTANCE /*hInst*/, DWORD callReason, LPVOID lpvReserved)
 {
-
     if (callReason==DLL_THREAD_DETACH)
     {
         __TBB_mallocThreadShutdownNotification();
     }
     else if (callReason==DLL_PROCESS_DETACH)
     {
-        __TBB_mallocProcessShutdownNotification();
+        __TBB_mallocProcessShutdownNotification(lpvReserved != NULL);
     }
     return TRUE;
 }
@@ -98,7 +97,7 @@ struct RegisterProcessShutdownNotification {
     }
 #endif /* !__TBB_USE_DLOPEN_REENTRANCY_WORKAROUND */
     ~RegisterProcessShutdownNotification() {
-        __TBB_mallocProcessShutdownNotification();
+        __TBB_mallocProcessShutdownNotification(false);
     }
 };
 
index 7f5d3d9..d31e757 100644 (file)
@@ -520,7 +520,7 @@ private:
     uint16_t largeObj:1;  // is this object "large"?
     uint16_t offset  :15; // offset from beginning of BackRefBlock
 public:
-    BackRefIdx() : master(invalid) {}
+    BackRefIdx() : master(invalid), largeObj(0), offset(0) {}
     bool isInvalid() const { return master == invalid; }
     bool isLargeObject() const { return largeObj; }
     master_t getMaster() const { return master; }
index 20427ca..f9efc38 100644 (file)
@@ -32,7 +32,7 @@ typedef enum {
 } AllocationModeInternalParam;
 
 void MallocInitializeITT();
-void __TBB_mallocProcessShutdownNotification();
+void __TBB_mallocProcessShutdownNotification(bool);
 #if _WIN32||_WIN64
 void __TBB_mallocThreadShutdownNotification();
 #endif
index 4c30629..d57bb96 100644 (file)
@@ -515,7 +515,7 @@ public:
 
     pointer allocate(const size_type n, const void *hint = 0 ) {
         pointer ptr = base_allocator_type::allocate( n, hint );
-        std::memset( ptr, 0xE3E3E3E3, n * sizeof(value_type) );
+        std::memset( (void*)ptr, 0xE3E3E3E3, n * sizeof(value_type) );
         return ptr;
     }
 };
index 407ef5d..f7727d2 100644 (file)
 
 // Unable to use constexpr member functions to initialize compile time constants
 #define __TBB_CONSTEXPR_MEMBER_FUNCTION_BROKEN (__INTEL_COMPILER == 1500)
-// MSVC 2015 does not do compile-time initialization of static variables with constexpr constructors in debug mode
-#define __TBB_STATIC_CONSTEXPR_INIT_BROKEN (_MSC_VER==1900 && !__INTEL_COMPILER && _DEBUG)
+// Some versions of MSVC do not do compile-time initialization of static variables with constexpr constructors in debug mode
+#define __TBB_STATIC_CONSTEXPR_INIT_BROKEN (_MSC_VER >= 1900 && _MSC_VER <= 1914 && !__INTEL_COMPILER && _DEBUG)
 
 #if __GNUC__ && __ANDROID__
   #define __TBB_EXCEPTION_TYPE_INFO_BROKEN ( __TBB_GCC_VERSION < 40600 )
 
 // Intel C++ Compiler fails to generate non-throwing move members for a class inherited from template
 #define __TBB_NOTHROW_MOVE_MEMBERS_IMPLICIT_GENERATION_BROKEN \
-    (__INTEL_COMPILER>=1600 && __INTEL_COMPILER<=1800 || __INTEL_COMPILER==1500 && __INTEL_COMPILER_UPDATE>3)
+    (__INTEL_COMPILER>=1600 && __INTEL_COMPILER<=1900 || __INTEL_COMPILER==1500 && __INTEL_COMPILER_UPDATE>3)
+
+// std::is_copy_constructible<T>::value returns 'true' for non copyable type when MSVC compiler is used.
+#define __TBB_IS_COPY_CONSTRUCTIBLE_BROKEN ( _MSC_VER && (_MSC_VER <= 1700 || _MSC_VER <= 1800 && !__INTEL_COMPILER) )
+
+// GCC 4.7 and 4.8 might fail to take an address of overloaded template function (bug 57043)
+#if __GNUC__ && !__INTEL_COMPILER && !__clang__
+  #define __TBB_GCC_OVERLOADED_TEMPLATE_FUNCTION_ADDRESS_BROKEN \
+    (__TBB_GCC_VERSION>=40700 && __TBB_GCC_VERSION<40704 || __TBB_GCC_VERSION>=40800 && __TBB_GCC_VERSION<40803 )
+#endif
 
 // The tuple-based tests with more inputs take a long time to compile.  If changes
 // are made to the tuple implementation or any switch that controls it, or if testing
     #endif
 #endif
 
-// std::is_copy_constructible<T>::value returns 'true' for non copyable type when MSVC compiler is used.
-#define __TBB_IS_COPY_CONSTRUCTIBLE_BROKEN ( _MSC_VER && (_MSC_VER <= 1700 || _MSC_VER <= 1800 && !__INTEL_COMPILER) )
-
 namespace Harness {
     //! Utility template function to prevent "unused" warnings by various compilers.
     template<typename T> void suppress_unused_warning( const T& ) {}
index 76de68a..bea5425 100644 (file)
@@ -1132,8 +1132,7 @@ public:
         ASSERT( raw_space<=reinterpret_cast<char*>(y), "y starts before raw_space" );
         ASSERT( reinterpret_cast<char*>(y+1) <= raw_space+sizeof(raw_space), "y starts after raw_space" );
         ASSERT( !(aligned ^ tbb::internal::is_aligned(y,sizeof(T))), "y is not aligned as it required" );
-        new (y) tbb::atomic<T> ();
-        return *y;
+        return *(new (y) tbb::atomic<T>());
     }
 };
 
index ee84c8f..dcbeef9 100644 (file)
@@ -366,9 +366,9 @@ void test_extract() {
 }
 #endif
 
-struct lightweight_policy_body {
+struct lightweight_policy_body : NoAssign {
     const tbb::tbb_thread::id my_thread_id;
-    tbb::atomic<int> my_count;
+    tbb::atomic<size_t> my_count;
 
     lightweight_policy_body() : my_thread_id(tbb::this_tbb_thread::get_id()) {
         my_count = 0;
@@ -386,7 +386,7 @@ void test_lightweight_policy() {
     tbb::flow::continue_node<tbb::flow::continue_msg, tbb::flow::lightweight> node2(g, lightweight_policy_body());
 
     tbb::flow::make_edge(node1, node2);
-    const int n = 10;
+    const size_t n = 10;
     for(size_t i = 0; i < n; ++i) {
         node1.try_put(tbb::flow::continue_msg());
     }
@@ -394,8 +394,8 @@ void test_lightweight_policy() {
 
     lightweight_policy_body body1 = tbb::flow::copy_body<lightweight_policy_body>(node1);
     lightweight_policy_body body2 = tbb::flow::copy_body<lightweight_policy_body>(node2);
-    ASSERT(int(body1.my_count) == n, "Body of the first node needs to be executed N times");
-    ASSERT(int(body2.my_count) == n, "Body of the second node needs to be executed N times");
+    ASSERT(body1.my_count == n, "Body of the first node needs to be executed N times");
+    ASSERT(body2.my_count == n, "Body of the second node needs to be executed N times");
 }
 
 int TestMain() {
index 994ff41..50c4a73 100644 (file)
@@ -18,6 +18,8 @@
 
 */
 
+#define NOMINMAX
+
 #include "harness_defs.h"
 #if __TBB_TEST_SKIP_LAMBDA
 
@@ -29,7 +31,6 @@ int TestMain() {
 
 #else /*__TBB_TEST_SKIP_LAMBDA*/
 
-#define NOMINMAX
 #include "tbb/tbb.h"
 #include "tbb/combinable.h"
 #include <cstdio>
index 3bbddf8..3cf6e74 100644 (file)
@@ -39,10 +39,19 @@ const int ExpectedResultHugePages = TBBMALLOC_OK;
 const int ExpectedResultHugePages = TBBMALLOC_NO_EFFECT;
 #endif
 
+/* bool type definition for C */
+#if (defined(_MSC_VER) && _MSC_VER < 1800) || __sun || __SUNPRO_CC
+typedef int bool;
+#define false 0
+#define true 1
+#else
+#include <stdbool.h>
+#endif
+
 #if __TBB_SOURCE_DIRECTLY_INCLUDED
 #include "../tbbmalloc/tbbmalloc_internal_api.h"
 #else
-#define __TBB_mallocProcessShutdownNotification()
+#define __TBB_mallocProcessShutdownNotification(bool)
 #endif
 
 /* test that it's possible to call allocation function from atexit
@@ -51,7 +60,7 @@ static void MyExit(void) {
     void *p = scalable_malloc(32);
     assert(p);
     scalable_free(p);
-    __TBB_mallocProcessShutdownNotification();
+    __TBB_mallocProcessShutdownNotification(false);
 }
 
 int main(void) {
@@ -117,7 +126,7 @@ int main(void) {
     res = scalable_allocation_command(TBBMALLOC_CLEAN_THREAD_BUFFERS,
                                       (void*)(intptr_t)1);
     assert(res == TBBMALLOC_INVALID_PARAM);
-    __TBB_mallocProcessShutdownNotification();
+    __TBB_mallocProcessShutdownNotification(false);
     printf("done\n");
     return 0;
 }
diff --git a/src/test/test_malloc_shutdown_hang.cpp b/src/test/test_malloc_shutdown_hang.cpp
new file mode 100644 (file)
index 0000000..01a7424
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+    Copyright (c) 2005-2018 Intel Corporation
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+
+
+
+*/
+
+#define HARNESS_CUSTOM_MAIN 1
+#include "harness.h"
+
+#include <tbb/task.h>
+#include <tbb/scalable_allocator.h>
+#include <tbb/task_scheduler_init.h>
+
+// Lets slow down the main thread on exit
+const int MAX_DELAY = 5;
+struct GlobalObject {
+    ~GlobalObject() {
+        Harness::Sleep(rand( ) % MAX_DELAY);
+    }
+} go;
+
+void allocatorRandomThrashing() {
+    const int ARRAY_SIZE = 1000;
+    const int MAX_ITER = 10000;
+    const int MAX_ALLOC = 10 * 1024 * 1024;
+
+    void *arr[ARRAY_SIZE] = {0};
+    for (int i = 0; i < rand() % MAX_ITER; ++i) {
+        // Random allocation size for random arrays
+        for (int j = 0; j < rand() % ARRAY_SIZE; ++j) {
+            arr[j] = scalable_malloc(rand() % MAX_ALLOC);
+        }
+        // Deallocate everything
+        for (int j = 0; j < ARRAY_SIZE; ++j) {
+            scalable_free(arr[j]);
+            arr[j] = NULL;
+        }
+    }
+}
+
+struct AllocatorThrashTask : tbb::task {
+    tbb::task* execute() __TBB_override {
+        allocatorRandomThrashing();
+        return NULL;
+    }
+};
+
+void hangOnExitReproducer() {
+    const int P = tbb::task_scheduler_init::default_num_threads();
+    for (int i = 0; i < P-1; i++) {
+        // Enqueue tasks for workers
+        tbb::task::enqueue(*new (tbb::task::allocate_root()) AllocatorThrashTask());
+    }
+}
+
+#if (_WIN32 || _WIN64) && !__TBB_WIN8UI_SUPPORT
+#include <process.h> // _spawnl
+void processSpawn(const char* self) {
+    _spawnl(_P_WAIT, self, self, "1", NULL);
+}
+#elif __linux__ || __APPLE__
+#include <unistd.h> // fork/exec
+#include <sys/wait.h> // waitpid
+void processSpawn(const char* self) {
+    pid_t pid = fork();
+    if (pid == -1) {
+        REPORT("ERROR: fork failed.\n");
+    } else if (pid == 0) { // child
+        execl(self, self, "1", NULL);
+        REPORT("ERROR: exec never returns\n");
+        exit(1);
+    } else { // parent
+        int status;
+        waitpid(pid, &status, 0);
+    }
+}
+#else
+void processSpawn(const char* /*self*/) {
+    REPORT("Known issue: no support for process spawn on this platform.\n");
+    REPORT("done\n");
+    exit(0);
+}
+#endif
+
+#if _MSC_VER && !__INTEL_COMPILER
+#pragma warning (push)
+#pragma warning (disable: 4702)  /* Unreachable code */
+#endif
+
+HARNESS_EXPORT
+int main(int argc, char* argv[]) {
+    ParseCommandLine( argc, argv );
+
+    // Executed from child processes
+    if (argc == 2 && strcmp(argv[1],"1") == 0) {
+        hangOnExitReproducer();
+        return 0;
+    }
+
+    // The number of executions is a tradeoff
+    // between execution time and NBTS statistics
+    const int EXEC_TIMES = 100;
+    const char* self = argv[0];
+    for (int i = 0; i < EXEC_TIMES; i++) {
+        processSpawn(self);
+    }
+
+#if _MSC_VER && !__INTEL_COMPILER
+#pragma warning (pop)
+#endif
+
+    REPORT("done\n");
+    return 0;
+}
+
index 23e0675..17b1f10 100644 (file)
@@ -501,13 +501,13 @@ void test_ports_return_references() {
 #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION
 // the integer received indicates which output ports should succeed and which should fail
 // on try_put().
-typedef tbb::flow::multifunction_node<int, tbb::flow::tuple<int, int> > mf_node;
+typedef tbb::flow::multifunction_node<int, tbb::flow::tuple<int, int> > mf_node_type;
 
 struct add_to_counter {
     int my_invocations;
     int *counter;
     add_to_counter(int& var):counter(&var){ my_invocations = 0;}
-    void operator()(const int &i, mf_node::output_ports_type &outports) {
+    void operator()(const int &i, mf_node_type::output_ports_type &outports) {
         *counter+=1;
         ++my_invocations;
         if(i & 0x1) {
index ce3fb11..8a7857f 100644 (file)
@@ -394,14 +394,15 @@ struct SSE_Functor {
 //! Test that parallel_for works with stack-allocated __m128
 template<typename ClassWithVectorType>
 void TestVectorTypes() {
-    ClassWithVectorType Array1[N], Array2[N];
-    for( int i=0; i<N; ++i ) {
+       const int aSize = 300;
+    ClassWithVectorType Array1[aSize], Array2[aSize];
+    for( int i=0; i<aSize; ++i ) {
         // VC8 does not properly align a temporary value; to work around, use explicit variable
         ClassWithVectorType foo(i);
         Array1[i] = foo;
     }
-    tbb::parallel_for( tbb::blocked_range<int>(0,N), SSE_Functor<ClassWithVectorType>(Array1, Array2) );
-    for( int i=0; i<N; ++i ) {
+    tbb::parallel_for( tbb::blocked_range<int>(0,aSize), SSE_Functor<ClassWithVectorType>(Array1, Array2) );
+    for( int i=0; i<aSize; ++i ) {
         ClassWithVectorType foo(i);
         ASSERT( Array2[i]==foo, NULL ) ;
     }
index d3a8a02..1bf90ad 100644 (file)
@@ -529,17 +529,6 @@ void range_sort_test() {
     for(itor a=v.begin(); a<v.end()-1; ++a) ASSERT(*a >= *(a+1), "v not sorted");
     v.clear();
 
-    // const range checks
-    rand_vec(v);
-    tbb::parallel_sort(tbb::blocked_range<std::vector<int>::iterator>(v.begin(), v.end()));
-    for(itor a=v.begin(); a<v.end()-1; ++a) ASSERT(*a <= *(a+1), "v not sorted");
-    v.clear();
-
-    rand_vec(v);
-    tbb::parallel_sort(tbb::blocked_range<std::vector<int>::iterator>(v.begin(), v.end()), std::greater<int>());
-    for(itor a=v.begin(); a<v.end()-1; ++a) ASSERT(*a >= *(a+1), "v not sorted");
-    v.clear();
-
     // array tests
     int arr[elements];
     for(int i=0; i<elements; ++i) arr[i] = rand()%(elements*10);
index 92399b5..6425c2c 100644 (file)
@@ -185,11 +185,20 @@ struct AsynchronousWork : NoAssign {
 // Test that task_arenas might be created and used from multiple application threads.
 // Also tests arena observers. The parameter p is the index of an app thread running this test.
 void TestConcurrentArenasFunc(int idx) {
+    // A regression test for observer activation order:
+    // check that arena observer can be activated before local observer
+    struct LocalObserver : public tbb::task_scheduler_observer {
+        LocalObserver() : tbb::task_scheduler_observer(/*local=*/true) { observe(true); }
+    };
     tbb::task_arena a1;
     a1.initialize(1,0);
     ArenaObserver o1(a1, 1, 0, idx*2+1); // the last argument is a "unique" observer/arena id for the test
+    ASSERT(o1.is_observing(), "Arena observer has not been activated");
+    LocalObserver lo;
+    ASSERT(lo.is_observing(), "Local observer has not been activated");
     tbb::task_arena a2(2,1);
     ArenaObserver o2(a2, 2, 1, idx*2+2);
+    ASSERT(o2.is_observing(), "Arena observer has not been activated");
     Harness::SpinBarrier barrier(2);
     AsynchronousWork work(barrier);
     a1.enqueue(work); // put async work
@@ -879,9 +888,8 @@ namespace TestIsolatedExecuteNS {
         for ( int i = 0; i < 5; ++i ) {
             HeavyMixTestBody b( random, isolated_level, 1, false );
             b( 0 );
-            REMARK( "\rHeavyMixTest: %d of 10", i+1 );
+            REMARK( "." );
         }
-        REMARK( "\n" );
     }
     //--------------------------------------------------//
     struct ContinuationTestReduceBody : NoAssign {
@@ -976,9 +984,68 @@ namespace TestIsolatedExecuteNS {
         tbb::this_task_arena::isolate(body);
         ASSERT(body.state == 0x93682a12, "The wrong state");
     }
+
+    class TestEnqueueTask : public tbb::task {
+        bool enqueued;
+        tbb::enumerable_thread_specific<bool>& executed;
+        tbb::atomic<int>& completed;
+    public:
+        static const int N = 100;
+
+        TestEnqueueTask(bool enq, tbb::enumerable_thread_specific<bool>& exe, tbb::atomic<int>& c)
+            : enqueued(enq), executed(exe), completed(c) {}
+        tbb::task* execute() __TBB_override {
+            if (enqueued) {
+                executed.local() = true;
+                ++completed;
+                __TBB_Yield();
+            } else {
+                parent()->add_ref_count(N);
+                for (int i = 0; i < N; ++i)
+                    tbb::task::enqueue(*new (parent()->allocate_child()) TestEnqueueTask(true, executed, completed));
+            }
+            return NULL;
+        }
+    };
+
+    class TestEnqueueIsolateBody : NoCopy {
+        tbb::enumerable_thread_specific<bool>& executed;
+        tbb::atomic<int>& completed;
+    public:
+        TestEnqueueIsolateBody(tbb::enumerable_thread_specific<bool>& exe, tbb::atomic<int>& c)
+            : executed(exe), completed(c) {}
+        void operator()() {
+            tbb::task::spawn_root_and_wait(*new (tbb::task::allocate_root()) TestEnqueueTask(false, executed, completed));
+        }
+    };
+
+    void TestEnqueue() {
+        tbb::enumerable_thread_specific<bool> executed(false);
+        tbb::atomic<int> completed;
+
+        // Check that the main thread can process enqueued tasks.
+        completed = 0;
+        TestEnqueueIsolateBody b1(executed, completed);
+        b1();
+        if (!executed.local())
+            REPORT("Warning: No one enqueued task has executed by the main thread.\n");
+
+        executed.local() = false;
+        completed = 0;
+        const int N = 100;
+        // Create enqueued tasks out of isolation.
+        for (int i = 0; i < N; ++i)
+            tbb::task::enqueue(*new (tbb::task::allocate_root()) TestEnqueueTask(true, executed, completed));
+        TestEnqueueIsolateBody b2(executed, completed);
+        tbb::this_task_arena::isolate(b2);
+        ASSERT(executed.local() == false, "An enqueued task was executed within isolate.");
+
+        while (completed < TestEnqueueTask::N + N) __TBB_Yield();
+    }
 }
 
 void TestIsolatedExecute() {
+    REMARK("TestIsolatedExecute");
     // At least 3 threads (owner + 2 thieves) are required to reproduce a situation when the owner steals outer
     // level task on a nested level. If we have only one thief then it will execute outer level tasks first and
     // the owner will not have a possibility to steal outer level tasks.
@@ -986,15 +1053,17 @@ void TestIsolatedExecute() {
     {
         // Too many threads require too many work to reproduce the stealing from outer level.
         tbb::task_scheduler_init init( max(num_threads, 7) );
-        TestIsolatedExecuteNS::TwoLoopsTest();
-        TestIsolatedExecuteNS::HeavyMixTest();
-        TestIsolatedExecuteNS::ContinuationTest();
-        TestIsolatedExecuteNS::ExceptionTest();
+        REMARK("."); TestIsolatedExecuteNS::TwoLoopsTest();
+        REMARK("."); TestIsolatedExecuteNS::HeavyMixTest();
+        REMARK("."); TestIsolatedExecuteNS::ContinuationTest();
+        REMARK("."); TestIsolatedExecuteNS::ExceptionTest();
     }
     tbb::task_scheduler_init init(num_threads);
-    TestIsolatedExecuteNS::HeavyMixTest();
-    TestIsolatedExecuteNS::ContinuationTest();
-    TestIsolatedExecuteNS::TestNonConstBody();
+    REMARK("."); TestIsolatedExecuteNS::HeavyMixTest();
+    REMARK("."); TestIsolatedExecuteNS::ContinuationTest();
+    REMARK("."); TestIsolatedExecuteNS::TestNonConstBody();
+    REMARK("."); TestIsolatedExecuteNS::TestEnqueue();
+    REMARK("\rTestIsolatedExecute: done                                                  \n");
 }
 #endif /* __TBB_TASK_ISOLATION */
 //--------------------------------------------------//
index 9125bb9..1a88acc 100644 (file)
@@ -227,7 +227,7 @@ public:
     void operator() ( uint_t idx ) const { m_pImpl->Run(idx); }
 };
 
-class RunAndWaitSyncronizationTestBody {
+class RunAndWaitSyncronizationTestBody : NoAssign {
     Harness::SpinBarrier& m_barrier;
     tbb::atomic<bool>& m_completed;
     tbb::task_group& m_tg;
index 2e4b098..fe2500d 100644 (file)
@@ -31,6 +31,8 @@
 #define TBB_PREVIEW_VARIADIC_PARALLEL_INVOKE 1
 #define TBB_PREVIEW_FLOW_GRAPH_NODES 1
 #define TBB_PREVIEW_GLOBAL_CONTROL 1
+#define TBB_PREVIEW_BLOCKED_RANGE_ND 1
+#define TBB_PREVIEW_WAITING_FOR_WORKERS 1
 #endif
 
 #if __TBB_TEST_SECONDARY
@@ -86,6 +88,7 @@ static volatile size_t g_sink;
 
 #define TestTypeDefinitionPresence( Type ) g_sink = sizeof(tbb::Type);
 #define TestTypeDefinitionPresence2(TypeStart, TypeEnd) g_sink = sizeof(tbb::TypeStart,TypeEnd);
+#define TestTypeDefinitionPresence3(TypeStart, TypeMid, TypeEnd) g_sink = sizeof(tbb::TypeStart,TypeMid,TypeEnd);
 #define TestFuncDefinitionPresence(Fn, Args, ReturnType) { ReturnType (*pfn)Args = &tbb::Fn; (void)pfn; }
 
 struct Body {
@@ -94,10 +97,10 @@ struct Body {
 struct Body1 {
     void operator() ( int ) const {}
 };
-struct Body1a {
-    int operator() ( const tbb::blocked_range<int>&, const int ) const { return 0; }
+struct Body1a { // feeder body for parallel_do
+    void operator() ( int, tbb::parallel_do_feeder<int>& ) const {}
 };
-struct Body1b {
+struct Body1b { // binary operator for reduction and comparison
     int operator() ( const int, const int ) const { return 0; }
 };
 struct Body2 {
@@ -106,7 +109,10 @@ struct Body2 {
     void operator() ( const tbb::blocked_range<int>& ) const {}
     void join( const Body2& ) {}
 };
-struct Body3 {
+struct Body2a { // for lambda-friendly parallel_reduce
+    int operator() ( const tbb::blocked_range<int>&, const int ) const { return 0; }
+};
+struct Body3 { // for parallel_scan
     Body3 () {}
     Body3 ( const Body3&, tbb::split ) {}
     void operator() ( const tbb::blocked_range2d<int>&, tbb::pre_scan_tag ) const {}
@@ -114,6 +120,10 @@ struct Body3 {
     void reverse_join( Body3& ) {}
     void assign( const Body3& ) {}
 };
+struct Body3a { // for lambda-friednly parallel_scan
+    int operator() ( const tbb::blocked_range<int>&, const int, bool ) const { return 0; }
+};
+struct Msg {};
 
 #if !__TBB_TEST_SECONDARY
 
@@ -181,11 +191,14 @@ struct Handler {
 static void TestPreviewNames() {
     TestTypeDefinitionPresence( aggregator );
     TestTypeDefinitionPresence( aggregator_ext<Handler> );
+#if __TBB_CPP11_PRESENT
+    TestTypeDefinitionPresence2(blocked_rangeNd<int,4> );
+#endif
     TestTypeDefinitionPresence2(concurrent_lru_cache<int, int> );
-    #if __TBB_FLOW_GRAPH_CPP11_FEATURES
-    TestTypeDefinitionPresence2( flow::composite_node<tbb::flow::tuple<int>, tbb::flow::tuple<int> > );
-    #endif
-    TestTypeDefinitionPresence( static_partitioner );
+    TestTypeDefinitionPresence( global_control );
+#if !__TBB_TEST_SECONDARY
+    TestExceptionClassExports( std::runtime_error("test"), tbb::internal::eid_blocking_thread_join_impossible );
+#endif
 }
 #endif
 
@@ -216,18 +229,24 @@ int TestMain ()
     TestTypeDefinitionPresence( concurrent_queue<int> );
     TestTypeDefinitionPresence( strict_ppl::concurrent_queue<int> );
     TestTypeDefinitionPresence( concurrent_priority_queue<int> );
-    TestTypeDefinitionPresence( combinable<int> );
     TestTypeDefinitionPresence( concurrent_vector<int> );
+    TestTypeDefinitionPresence( combinable<int> );
     TestTypeDefinitionPresence( enumerable_thread_specific<int> );
     /* Flow graph names */
     TestTypeDefinitionPresence( flow::graph );
-    // TODO: add a check for make_edge and maybe other functions in tbb::flow
-    TestTypeDefinitionPresence( flow::source_node<int> );
-    TestTypeDefinitionPresence2(flow::function_node<int, int> );
+    TestTypeDefinitionPresence( flow::continue_msg );
+    TestTypeDefinitionPresence2(flow::tagged_msg<int, int> );
+    TestFuncDefinitionPresence( flow::make_edge, (tbb::flow::sender<Msg>&, tbb::flow::receiver<Msg>&), void );
+    TestFuncDefinitionPresence( flow::remove_edge, (tbb::flow::sender<Msg>&, tbb::flow::receiver<Msg>&), void );
     typedef tbb::flow::tuple<int, int> intpair;
-    TestTypeDefinitionPresence2(flow::multifunction_node<int, intpair> );
+    TestTypeDefinitionPresence( flow::source_node<int> );
+    TestTypeDefinitionPresence3(flow::function_node<int, int, tbb::flow::rejecting> );
+    TestTypeDefinitionPresence3(flow::multifunction_node<int, intpair, tbb::flow::queueing> );
+    TestTypeDefinitionPresence3(flow::async_node<int, int, tbb::flow::queueing_lightweight> );
+    TestTypeDefinitionPresence2(flow::continue_node<int, tbb::flow::lightweight> );
+    TestTypeDefinitionPresence2(flow::join_node<intpair, tbb::flow::reserving> );
+    TestTypeDefinitionPresence2(flow::join_node<intpair, tbb::flow::key_matching<int> > );
     TestTypeDefinitionPresence( flow::split_node<intpair> );
-    TestTypeDefinitionPresence( flow::continue_node<int> );
     TestTypeDefinitionPresence( flow::overwrite_node<int> );
     TestTypeDefinitionPresence( flow::write_once_node<int> );
     TestTypeDefinitionPresence( flow::broadcast_node<int> );
@@ -238,10 +257,8 @@ int TestMain ()
     TestTypeDefinitionPresence( flow::limiter_node<int> );
     TestTypeDefinitionPresence2(flow::indexer_node<int, int> );
 #if __TBB_FLOW_GRAPH_CPP11_FEATURES
-    TestTypeDefinitionPresence2( flow::composite_node<tbb::flow::tuple<int>, tbb::flow::tuple<int> > );
+    TestTypeDefinitionPresence2(flow::composite_node<tbb::flow::tuple<int>, tbb::flow::tuple<int> > );
 #endif
-    using tbb::flow::queueing;
-    TestTypeDefinitionPresence2( flow::join_node< intpair, queueing > );
     /* Mutex names */
     TestTypeDefinitionPresence( mutex );
     TestTypeDefinitionPresence( null_mutex );
@@ -267,35 +284,56 @@ int TestMain ()
     TestTypeDefinitionPresence( structured_task_group );
     TestTypeDefinitionPresence( task_handle<Body> );
 #endif /* __TBB_TASK_GROUP_CONTEXT */
+    /* Algorithm related names */
+    TestTypeDefinitionPresence( blocked_range<int> );
+    TestTypeDefinitionPresence( blocked_range2d<int> );
     TestTypeDefinitionPresence( blocked_range3d<int> );
-    TestFuncDefinitionPresence( parallel_invoke, (const Body&, const Body&), void );
+    TestFuncDefinitionPresence( parallel_invoke, (const Body&, const Body&, const Body&), void );
     TestFuncDefinitionPresence( parallel_do, (int*, int*, const Body1&), void );
     TestFuncDefinitionPresence( parallel_for_each, (int*, int*, const Body1&), void );
     TestFuncDefinitionPresence( parallel_for, (int, int, int, const Body1&), void );
     TestFuncDefinitionPresence( parallel_for, (const tbb::blocked_range<int>&, const Body2&, const tbb::simple_partitioner&), void );
-    TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, const int&, const Body1a&, const Body1b&, const tbb::auto_partitioner&), int );
+    TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, const int&, const Body2a&, const Body1b&), int );
     TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::affinity_partitioner&), void );
-    TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, const int&, const Body1a&, const Body1b&), int );
-    TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&), void );
+    TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, const int&, const Body2a&, const Body1b&), int );
+    TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::static_partitioner&), void );
     TestFuncDefinitionPresence( parallel_scan, (const tbb::blocked_range2d<int>&, Body3&, const tbb::auto_partitioner&), void );
+    TestFuncDefinitionPresence( parallel_scan, (const tbb::blocked_range<int>&, const int&, const Body3a&, const Body1b&), int );
+    typedef int intarray[10];
     TestFuncDefinitionPresence( parallel_sort, (int*, int*), void );
+    TestFuncDefinitionPresence( parallel_sort, (intarray&, const Body1b&), void );
     TestTypeDefinitionPresence( pipeline );
     TestFuncDefinitionPresence( parallel_pipeline, (size_t, const tbb::filter_t<void,void>&), void );
+#if __TBB_TASK_GROUP_CONTEXT
+    TestFuncDefinitionPresence( parallel_invoke, (const Body&, const Body&, tbb::task_group_context&), void );
+    TestFuncDefinitionPresence( parallel_do, (const intarray&, const Body1a&, tbb::task_group_context&), void );
+    TestFuncDefinitionPresence( parallel_for_each, (const intarray&, const Body1&, tbb::task_group_context&), void );
+    TestFuncDefinitionPresence( parallel_for, (int, int, const Body1&, const tbb::auto_partitioner&, tbb::task_group_context&), void );
+    TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::auto_partitioner&, tbb::task_group_context&), void );
+#endif /* __TBB_TASK_GROUP_CONTEXT */
+    TestTypeDefinitionPresence( proportional_split );
+
     TestTypeDefinitionPresence( task );
     TestTypeDefinitionPresence( empty_task );
     TestTypeDefinitionPresence( task_list );
     TestTypeDefinitionPresence( task_arena );
+    TestFuncDefinitionPresence( this_task_arena::current_thread_index, (), int );
+    TestFuncDefinitionPresence( this_task_arena::max_concurrency, (), int );
+#if !__TBB_GCC_OVERLOADED_TEMPLATE_FUNCTION_ADDRESS_BROKEN
+    TestFuncDefinitionPresence( this_task_arena::isolate, (const Body&), void );
+#endif
     TestTypeDefinitionPresence( task_scheduler_init );
     TestTypeDefinitionPresence( task_scheduler_observer );
     TestTypeDefinitionPresence( tbb_thread );
+    TestFuncDefinitionPresence( tbb_thread::hardware_concurrency, (), unsigned );
+    TestFuncDefinitionPresence( this_tbb_thread::yield, (), void );
     TestTypeDefinitionPresence( tbb_allocator<int> );
     TestTypeDefinitionPresence( zero_allocator<int> );
     TestTypeDefinitionPresence( tick_count );
-#if TBB_PREVIEW_GLOBAL_CONTROL
-    TestTypeDefinitionPresence( global_control );
+#if __TBB_CPP11_PRESENT
+    TestTypeDefinitionPresence( counting_iterator<int> );
+    TestTypeDefinitionPresence2(zip_iterator<int*,int*> );
 #endif
-    TestFuncDefinitionPresence( parallel_for, (int, int, int, const Body1&, const tbb::static_partitioner&), void );
-    TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::static_partitioner&), void );
 
 #if __TBB_CPF_BUILD
     TestPreviewNames();
index 205de38..3c595a7 100644 (file)
@@ -229,7 +229,7 @@ int main(int argc, char *argv[] ) {
 void initialize_strings_vector(std::vector <string_pair>* vector)
 {
     vector->push_back(string_pair("TBB: VERSION\t\t2019.0", required));       // check TBB_VERSION
-    vector->push_back(string_pair("TBB: INTERFACE VERSION\t11000", required)); // check TBB_INTERFACE_VERSION
+    vector->push_back(string_pair("TBB: INTERFACE VERSION\t11001", required)); // check TBB_INTERFACE_VERSION
     vector->push_back(string_pair("TBB: BUILD_DATE", required));
     vector->push_back(string_pair("TBB: BUILD_HOST", required));
     vector->push_back(string_pair("TBB: BUILD_OS", required));