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
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
-# 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
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)
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) \
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 ----
$(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)
# -----------------------------------------------------
#------------------------------------------------------
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
##############################################################
+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:
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")
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.")
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
#
#
+CPLUS ?= clang++
+CONLY ?= clang
COMPILE_ONLY = -c -MMD
PREPROC_ONLY = -E -x c++
INCLUDE_KEY = -I
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
#
#
+CPLUS ?= g++
+CONLY ?= gcc
COMPILE_ONLY = -c -MMD
PREPROC_ONLY = -E -x c++
INCLUDE_KEY = -I
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
# 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
#
#
+CPLUS ?= icpc
+CONLY ?= icc
COMPILE_ONLY = -c -MMD
PREPROC_ONLY = -E -x c++
INCLUDE_KEY = -I
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
#
#
+CPLUS ?= pathCC
+CONLY ?= pathcc
COMPILE_ONLY = -c -MMD
PREPROC_ONLY = -E -x c++
INCLUDE_KEY = -I
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
####### Detections and Commands ###############################################
+CPLUS ?= xlc++_r
+CONLY ?= xlc_r
COMPILE_ONLY = -c
PREPROC_ONLY = -E -qsourcetype=c
INCLUDE_KEY = -I
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)
#
#
-CPLUS = clang++
-CONLY = clang
+CPLUS ?= clang++
+CONLY ?= clang
COMPILE_ONLY = -c -MMD
PREPROC_ONLY = -E -x c++
INCLUDE_KEY = -I
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
#
#
-CPLUS = g++
-CONLY = gcc
+CPLUS ?= g++
+CONLY ?= gcc
COMPILE_ONLY = -c -MMD
PREPROC_ONLY = -E -x c++
INCLUDE_KEY = -I
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
#
#
-CPLUS = icpc
-CONLY = icc
+CPLUS ?= icpc
+CONLY ?= icc
COMPILE_ONLY = -c -MMD
PREPROC_ONLY = -E -x c++
INCLUDE_KEY = -I
#
#
+CPLUS ?= icpc
+CONLY ?= icc
COMPILE_ONLY = -c -MMD
PREPROC_ONLY = -E -x c++
INCLUDE_KEY = -I
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
#------------------------------------------------------------------------------
# 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
# Compiler-specific variables
#------------------------------------------------------------------------------
-CPLUS = g++
+CPLUS ?= g++
COMPILE_ONLY = -c -MMD
PREPROC_ONLY = -E -x c++
INCLUDE_KEY = -I
#------------------------------------------------------------------------------
# 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
--- /dev/null
+<hr>
+<p></p>
+Copyright © 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.
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);
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" );
#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);
}
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;
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:
#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);
}
__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
#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
#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.");
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
}}}
#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 )) \
#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)
__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 ) { \
#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
#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)
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
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>
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>
//! 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 */
//! 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);
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.
//! 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();
//! 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
//! 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();
};
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;
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
~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() )
/**
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.
#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"
#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"
#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 **/
#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
#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)
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; };
#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
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")
#define RECORD_EVENTS 0
-using namespace std;
-
namespace tbb {
namespace internal {
__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;
}
#include <dlfcn.h>
#endif /* _WIN32||_WIN64 */
-using namespace std;
-
#if __TBB_WEAK_SYMBOLS_PRESENT
#pragma weak scalable_malloc
// 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;
}
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);
// 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);
}
}
}
__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
#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)
__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;
#pragma warning (disable: 4267)
#endif
-using namespace std;
-
namespace tbb {
namespace internal {
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
}
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
}
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 ) {
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 );
namespace tbb {
-using namespace std;
-
namespace internal {
//------------------------------------------------------------------------
#define __TBB_EXPORTED_FUNC
#endif
-using namespace std;
-
#if __TBBMALLOC_BUILD
namespace rml { namespace internal {
#else
_CrtDbgBreak();
#else
fflush(stderr);
- abort();
+ std::abort();
#endif
}
}
#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"; }
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 */
// 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 */
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 */
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;
}
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;
}
}
#endif
__TBB_machine_end_transaction();
- s.my_scoped_lock.internal_set_mutex(NULL);
+ s.my_scoped_lock.mutex = NULL;
}
break;
case RTM_real_reader:
}
#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;
}
#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
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))
} 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.
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 ) {
#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;
}
}
#else
bool isCurrentThreadId() const { return GetCurrentThreadId() == tid; }
#endif
- static void init() {}
+ static bool init() { return true; }
static void destroy() {}
};
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()
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;
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) {
}
#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);
num += 1;
STAT_increment(getThreadId(), ThreadCommonCounters, cacheLargeObj);
- } while (( curr = curr->next ));
+ } while ((curr = curr->next) != NULL);
LargeMemoryBlock *tail = prev;
addToPutList(head, tail, num);
CacheBinOperation *opNext = opClean->next;
prep.commitOperation( opClean );
- while (( opClean = opNext )) {
+ while ((opClean = opNext) != NULL) {
opNext = opClean->next;
prep.commitOperation(opClean);
}
*/
+#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) {
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);
}
"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
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()
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
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);
#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;
}
}
#endif /* !__TBB_USE_DLOPEN_REENTRANCY_WORKAROUND */
~RegisterProcessShutdownNotification() {
- __TBB_mallocProcessShutdownNotification();
+ __TBB_mallocProcessShutdownNotification(false);
}
};
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; }
} AllocationModeInternalParam;
void MallocInitializeITT();
-void __TBB_mallocProcessShutdownNotification();
+void __TBB_mallocProcessShutdownNotification(bool);
#if _WIN32||_WIN64
void __TBB_mallocThreadShutdownNotification();
#endif
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;
}
};
// 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& ) {}
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>());
}
};
}
#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;
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());
}
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() {
*/
+#define NOMINMAX
+
#include "harness_defs.h"
#if __TBB_TEST_SKIP_LAMBDA
#else /*__TBB_TEST_SKIP_LAMBDA*/
-#define NOMINMAX
#include "tbb/tbb.h"
#include "tbb/combinable.h"
#include <cstdio>
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
void *p = scalable_malloc(32);
assert(p);
scalable_free(p);
- __TBB_mallocProcessShutdownNotification();
+ __TBB_mallocProcessShutdownNotification(false);
}
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;
}
--- /dev/null
+/*
+ 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;
+}
+
#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) {
//! 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 ) ;
}
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);
// 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
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 {
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.
{
// 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 */
//--------------------------------------------------//
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;
#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
#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 {
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 {
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 {}
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
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
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> );
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 );
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();
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));