From 60b7d0a78f8910976678ba63a19fdaee22c0ef65 Mon Sep 17 00:00:00 2001 From: tbbdev Date: Mon, 30 Mar 2020 14:38:06 +0300 Subject: [PATCH] Committing TBB 2020 Update 2 source code --- CHANGES | 20 + README.md | 2 +- build/Makefile.test | 1 + cmake/templates/TBBConfig.cmake.in | 4 +- examples/graph/binpack/binpack.cpp | 4 +- examples/graph/fgbzip2/fgbzip2.cpp | 3 +- examples/graph/logic_sim/basics.h | 8 +- include/serial/tbb/parallel_for.h | 30 +- include/tbb/aligned_space.h | 2 +- include/tbb/atomic.h | 14 +- include/tbb/compat/condition_variable | 20 +- include/tbb/compat/thread | 2 +- include/tbb/compat/tuple | 6 +- include/tbb/concurrent_vector.h | 4 +- include/tbb/critical_section.h | 2 +- include/tbb/flow_graph.h | 483 ++++++++++++++++-- include/tbb/flow_graph_opencl_node.h | 43 +- .../tbb/internal/_flow_graph_async_msg_impl.h | 2 +- .../internal/_flow_graph_item_buffer_impl.h | 3 +- include/tbb/internal/_flow_graph_node_impl.h | 2 +- .../internal/_flow_graph_nodes_deduction.h | 10 + .../tbb/internal/_flow_graph_streaming_node.h | 7 +- include/tbb/mutex.h | 2 +- include/tbb/reader_writer_lock.h | 2 +- include/tbb/recursive_mutex.h | 2 +- include/tbb/runtime_loader.h | 2 +- include/tbb/task.h | 25 +- include/tbb/task_scheduler_init.h | 2 +- include/tbb/tbb_config.h | 8 +- include/tbb/tbb_exception.h | 2 +- include/tbb/tbb_stddef.h | 4 +- include/tbb/tbb_thread.h | 8 +- src/tbb/arena.cpp | 8 +- src/tbb/custom_scheduler.h | 5 + src/tbb/mailbox.h | 15 +- src/tbb/scheduler.cpp | 8 +- src/tbb/tbb_bind.cpp | 94 ++-- src/tbbmalloc/proxy.cpp | 17 + src/test/harness_graph.h | 4 + src/test/test_arena_constraints_hwloc.cpp | 1 + src/test/test_async_node.cpp | 18 + src/test/test_buffer_node.cpp | 21 +- src/test/test_composite_node.cpp | 6 +- src/test/test_eh_flow_graph.cpp | 114 ++--- src/test/test_flow_graph.cpp | 2 +- src/test/test_flow_graph_priorities.cpp | 2 +- src/test/test_flow_graph_whitebox.cpp | 8 +- src/test/test_function_node.cpp | 25 +- src/test/test_indexer_node.cpp | 6 +- src/test/test_input_node.cpp | 357 +++++++++++++ src/test/test_join_node.cpp | 2 +- src/test/test_join_node.h | 6 +- src/test/test_multifunction_node.cpp | 28 +- src/test/test_priority_queue_node.cpp | 21 +- src/test/test_queue_node.cpp | 22 +- src/test/test_sequencer_node.cpp | 21 +- src/test/test_source_node.cpp | 58 ++- src/test/test_split_node.cpp | 15 +- src/test/test_task_leaks.cpp | 25 + src/test/test_tbb_header.cpp | 1 + src/test/test_tbb_version.cpp | 4 +- third-party-programs.txt | 172 +------ 62 files changed, 1352 insertions(+), 463 deletions(-) create mode 100644 src/test/test_input_node.cpp diff --git a/CHANGES b/CHANGES index eb40d4d7c7..de502b6856 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,26 @@ The list of most significant changes made over time in Intel(R) Threading Building Blocks (Intel(R) TBB). +Intel TBB 2020 Update 2 +TBB_INTERFACE_VERSION == 11102 + +Changes (w.r.t. Intel TBB 2020 Update 1): + +- Cross-allocator copying constructor and copy assignment operator for + concurrent_vector are deprecated. +- Added input_node to the flow graph API. It acts like a source_node + except for being inactive by default; source_node is deprecated. +- Allocator template parameter for flow graph nodes is deprecated. Set + TBB_DEPRECATED_FLOW_NODE_ALLOCATOR to 1 to avoid compilation errors. +- Flow graph preview hetero-features are deprecated. + +Bugs fixed: + +- Fixed the task affinity mechanism to prevent unlimited memory + consumption in case the number of threads is explicitly decreased. +- Fixed memory leak related NUMA support functionality in task_arena. + +------------------------------------------------------------------------ Intel TBB 2020 Update 1 TBB_INTERFACE_VERSION == 11101 diff --git a/README.md b/README.md index 909be027d9..8efcf6736f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Threading Building Blocks 2020 -[![Stable release](https://img.shields.io/badge/version-2020.1-green.svg)](https://github.com/intel/tbb/releases/tag/v2020.1) +[![Stable release](https://img.shields.io/badge/version-2020.2-green.svg)](https://github.com/intel/tbb/releases/tag/v2020.2) [![Apache License Version 2.0](https://img.shields.io/badge/license-Apache_2.0-green.svg)](LICENSE) Threading Building Blocks (TBB) lets you easily write parallel C++ programs that take diff --git a/build/Makefile.test b/build/Makefile.test index 9ae464c11f..eb2c705343 100644 --- a/build/Makefile.test +++ b/build/Makefile.test @@ -199,6 +199,7 @@ TEST_TBB_PLAIN.EXE = test_assembly.$(TEST_EXT) \ test_priority_queue_node.$(TEST_EXT) \ test_sequencer_node.$(TEST_EXT) \ test_source_node.$(TEST_EXT) \ + test_input_node.$(TEST_EXT) \ test_overwrite_node.$(TEST_EXT) \ test_write_once_node.$(TEST_EXT) \ test_indexer_node.$(TEST_EXT) \ diff --git a/cmake/templates/TBBConfig.cmake.in b/cmake/templates/TBBConfig.cmake.in index c9da1a28bd..744f121569 100644 --- a/cmake/templates/TBBConfig.cmake.in +++ b/cmake/templates/TBBConfig.cmake.in @@ -57,9 +57,11 @@ foreach (_tbb_component ${TBB_FIND_COMPONENTS}) if (NOT TARGET TBB::${_tbb_component}) add_library(TBB::${_tbb_component} SHARED IMPORTED) - get_filename_component(_tbb_include_dir "${CMAKE_CURRENT_LIST_DIR}/@TBB_INC_REL_PATH@" ABSOLUTE) + get_filename_component(_tbb_current_realpath "${CMAKE_CURRENT_LIST_DIR}" REALPATH) + get_filename_component(_tbb_include_dir "${_tbb_current_realpath}/@TBB_INC_REL_PATH@" ABSOLUTE) set_target_properties(TBB::${_tbb_component} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${_tbb_include_dir}") + unset(_tbb_current_realpath) unset(_tbb_include_dir) if (EXISTS "${_tbb_release_lib}") diff --git a/examples/graph/binpack/binpack.cpp b/examples/graph/binpack/binpack.cpp index c9bc17c6c3..67cc513ec9 100644 --- a/examples/graph/binpack/binpack.cpp +++ b/examples/graph/binpack/binpack.cpp @@ -46,7 +46,7 @@ typedef buffer_node bin_buffer; // Packed bins are taken from the_bin_buffer and processed by the_writer: typedef function_node bin_writer; // Items are injected into the graph when this node sends them to the_value_pool: -typedef source_node value_source; +typedef input_node value_source; // User-specified globals with default values size_type V = 42; // desired capacity for each bin @@ -259,7 +259,7 @@ int main(int argc, char *argv[]) { << optimality << ", " << num_bin_packers << " bins of capacity=" << V << " on " << p << " threads.\n"; graph g; - value_source the_source(g, item_generator(), false); + value_source the_source(g, item_generator()); value_pool the_value_pool(g); make_edge(the_source, the_value_pool); bin_buffer the_bin_buffer(g); diff --git a/examples/graph/fgbzip2/fgbzip2.cpp b/examples/graph/fgbzip2/fgbzip2.cpp index 6dca7e0246..6dfc31f4a0 100644 --- a/examples/graph/fgbzip2/fgbzip2.cpp +++ b/examples/graph/fgbzip2/fgbzip2.cpp @@ -378,7 +378,7 @@ void fgCompressionAsyncMsg(IOOperations& io, int blockSizeIn100KB, size_t memory void fgCompression(IOOperations& io, int blockSizeIn100KB) { tbb::flow::graph g; - tbb::flow::source_node< BufferMsg > file_reader(g, [&io](BufferMsg& bufferMsg)->bool { + tbb::flow::input_node< BufferMsg > file_reader(g, [&io](BufferMsg& bufferMsg)->bool { if (io.hasDataToRead()) { bufferMsg = BufferMsg::createBufferMsg(io.chunksRead(), io.chunkSize()); io.readChunk(bufferMsg.inputBuffer); @@ -402,6 +402,7 @@ void fgCompression(IOOperations& io, int blockSizeIn100KB) { make_edge(compressor, ordering); make_edge(ordering, output_writer); + file_reader.activate(); g.wait_for_all(); } diff --git a/examples/graph/logic_sim/basics.h b/examples/graph/logic_sim/basics.h index 7624d0bd2b..8ec39a276f 100644 --- a/examples/graph/logic_sim/basics.h +++ b/examples/graph/logic_sim/basics.h @@ -188,17 +188,17 @@ class pulse { graph& my_graph; size_t ms, init_ms; int reps, init_reps; - source_node clock_node; + input_node clock_node; public: pulse(graph& g, size_t _ms=1000, int _reps=-1) : my_graph(g), ms(_ms), init_ms(_ms), reps(_reps), init_reps(_reps), - clock_node(g, clock_body(ms, reps), false) + clock_node(g, clock_body(ms, reps)) {} pulse(const pulse& src) : my_graph(src.my_graph), ms(src.init_ms), init_ms(src.init_ms), reps(src.init_reps), init_reps(src.init_reps), - clock_node(src.my_graph, clock_body(ms, reps), false) + clock_node(src.my_graph, clock_body(ms, reps)) {} ~pulse() {} // Assignment changes the behavior of LHS to that of the RHS, but doesn't change owning graph @@ -206,7 +206,7 @@ class pulse { ms = src.ms; init_ms = src.init_ms; reps = src.reps; init_reps = src.init_reps; return *this; } - source_node& get_out() { return clock_node; } + input_node& get_out() { return clock_node; } void activate() { clock_node.activate(); } void reset() { reps = init_reps; } }; diff --git a/include/serial/tbb/parallel_for.h b/include/serial/tbb/parallel_for.h index 0a58453bfb..4e6111b77d 100644 --- a/include/serial/tbb/parallel_for.h +++ b/include/serial/tbb/parallel_for.h @@ -105,35 +105,35 @@ void start_for< Range, Body, Partitioner >::execute() { //! Parallel iteration over range with default partitioner. /** @ingroup algorithms **/ template -__TBB_DEPRECATED_VERBOSE void parallel_for( const Range& range, const Body& body ) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for( const Range& range, const Body& body ) { serial::interface9::start_for::run(range,body,__TBB_DEFAULT_PARTITIONER()); } //! Parallel iteration over range with simple partitioner. /** @ingroup algorithms **/ template -__TBB_DEPRECATED_VERBOSE void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner ) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for( const Range& range, const Body& body, const simple_partitioner& partitioner ) { serial::interface9::start_for::run(range,body,partitioner); } //! Parallel iteration over range with auto_partitioner. /** @ingroup algorithms **/ template -__TBB_DEPRECATED_VERBOSE void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner ) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for( const Range& range, const Body& body, const auto_partitioner& partitioner ) { serial::interface9::start_for::run(range,body,partitioner); } //! Parallel iteration over range with static_partitioner. /** @ingroup algorithms **/ template -__TBB_DEPRECATED_VERBOSE void parallel_for( const Range& range, const Body& body, const static_partitioner& partitioner ) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for( const Range& range, const Body& body, const static_partitioner& partitioner ) { serial::interface9::start_for::run(range,body,partitioner); } //! Parallel iteration over range with affinity_partitioner. /** @ingroup algorithms **/ template -__TBB_DEPRECATED_VERBOSE void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner ) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for( const Range& range, const Body& body, affinity_partitioner& partitioner ) { serial::interface9::start_for::run(range,body,partitioner); } @@ -161,53 +161,53 @@ void parallel_for_impl(Index first, Index last, Index step, const Function& f, P //! Parallel iteration over a range of integers with explicit step and default partitioner template -__TBB_DEPRECATED_VERBOSE void parallel_for(Index first, Index last, Index step, const Function& f) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for(Index first, Index last, Index step, const Function& f) { parallel_for_impl(first, last, step, f, auto_partitioner()); } //! Parallel iteration over a range of integers with explicit step and simple partitioner template -__TBB_DEPRECATED_VERBOSE void parallel_for(Index first, Index last, Index step, const Function& f, const simple_partitioner& p) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for(Index first, Index last, Index step, const Function& f, const simple_partitioner& p) { parallel_for_impl(first, last, step, f, p); } //! Parallel iteration over a range of integers with explicit step and auto partitioner template -__TBB_DEPRECATED_VERBOSE void parallel_for(Index first, Index last, Index step, const Function& f, const auto_partitioner& p) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for(Index first, Index last, Index step, const Function& f, const auto_partitioner& p) { parallel_for_impl(first, last, step, f, p); } //! Parallel iteration over a range of integers with explicit step and static partitioner template -__TBB_DEPRECATED_VERBOSE void parallel_for(Index first, Index last, Index step, const Function& f, const static_partitioner& p) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for(Index first, Index last, Index step, const Function& f, const static_partitioner& p) { parallel_for_impl(first, last, step, f, p); } //! Parallel iteration over a range of integers with explicit step and affinity partitioner template -__TBB_DEPRECATED_VERBOSE void parallel_for(Index first, Index last, Index step, const Function& f, affinity_partitioner& p) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for(Index first, Index last, Index step, const Function& f, affinity_partitioner& p) { parallel_for_impl(first, last, step, f, p); } //! Parallel iteration over a range of integers with default step and default partitioner template -__TBB_DEPRECATED_VERBOSE void parallel_for(Index first, Index last, const Function& f) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for(Index first, Index last, const Function& f) { parallel_for_impl(first, last, static_cast(1), f, auto_partitioner()); } //! Parallel iteration over a range of integers with default step and simple partitioner template -__TBB_DEPRECATED_VERBOSE void parallel_for(Index first, Index last, const Function& f, const simple_partitioner& p) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for(Index first, Index last, const Function& f, const simple_partitioner& p) { parallel_for_impl(first, last, static_cast(1), f, p); } //! Parallel iteration over a range of integers with default step and auto partitioner template -__TBB_DEPRECATED_VERBOSE void parallel_for(Index first, Index last, const Function& f, const auto_partitioner& p) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for(Index first, Index last, const Function& f, const auto_partitioner& p) { parallel_for_impl(first, last, static_cast(1), f, p); } //! Parallel iteration over a range of integers with default step and static partitioner template -__TBB_DEPRECATED_VERBOSE void parallel_for(Index first, Index last, const Function& f, const static_partitioner& p) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for(Index first, Index last, const Function& f, const static_partitioner& p) { parallel_for_impl(first, last, static_cast(1), f, p); } //! Parallel iteration over a range of integers with default step and affinity_partitioner template -__TBB_DEPRECATED_VERBOSE void parallel_for(Index first, Index last, const Function& f, affinity_partitioner& p) { +__TBB_DEPRECATED_IN_VERBOSE_MODE void parallel_for(Index first, Index last, const Function& f, affinity_partitioner& p) { parallel_for_impl(first, last, static_cast(1), f, p); } diff --git a/include/tbb/aligned_space.h b/include/tbb/aligned_space.h index ad8a3faf35..1b047f97aa 100644 --- a/include/tbb/aligned_space.h +++ b/include/tbb/aligned_space.h @@ -40,7 +40,7 @@ namespace tbb { /** The elements are not constructed or destroyed by this class. @ingroup memory_allocation */ template -class __TBB_DEPRECATED_VERBOSE_MSG("tbb::aligned_space is deprecated, use std::aligned_storage") aligned_space { +class __TBB_DEPRECATED_IN_VERBOSE_MODE_MSG("tbb::aligned_space is deprecated, use std::aligned_storage") aligned_space { private: typedef __TBB_TypeWithAlignmentAtLeastAsStrict(T) element_type; element_type array[(sizeof(T)*N+sizeof(element_type)-1)/sizeof(element_type)]; diff --git a/include/tbb/atomic.h b/include/tbb/atomic.h index 1557eb9506..e602306f27 100644 --- a/include/tbb/atomic.h +++ b/include/tbb/atomic.h @@ -414,7 +414,7 @@ struct atomic_impl_with_arithmetic: atomic_impl { /** See the Reference for details. @ingroup synchronization */ template -struct __TBB_DEPRECATED_VERBOSE_MSG("tbb::atomic is deprecated, use std::atomic") +struct __TBB_DEPRECATED_IN_VERBOSE_MODE_MSG("tbb::atomic is deprecated, use std::atomic") atomic: internal::atomic_impl { #if __TBB_ATOMIC_CTORS atomic() = default; @@ -430,7 +430,7 @@ atomic: internal::atomic_impl { #if __TBB_ATOMIC_CTORS #define __TBB_DECL_ATOMIC(T) \ - template<> struct __TBB_DEPRECATED_VERBOSE_MSG("tbb::atomic is deprecated, use std::atomic") \ + template<> struct __TBB_DEPRECATED_IN_VERBOSE_MODE_MSG("tbb::atomic is deprecated, use std::atomic") \ atomic: internal::atomic_impl_with_arithmetic { \ atomic() = default; \ constexpr atomic(T arg): internal::atomic_impl_with_arithmetic(arg) {} \ @@ -442,7 +442,7 @@ atomic: internal::atomic_impl { }; #else #define __TBB_DECL_ATOMIC(T) \ - template<> struct __TBB_DEPRECATED_VERBOSE_MSG("tbb::atomic is deprecated, use std::atomic") \ + template<> struct __TBB_DEPRECATED_IN_VERBOSE_MODE_MSG("tbb::atomic is deprecated, use std::atomic") \ atomic: internal::atomic_impl_with_arithmetic { \ T operator=( T rhs ) {return store_with_release(rhs);} \ atomic& operator=( const atomic& rhs ) {store_with_release(rhs); return *this;} \ @@ -467,7 +467,7 @@ __TBB_DECL_ATOMIC(unsigned long) type synonyms on the platform. Type U should be the wider variant of T from the perspective of /Wp64. */ #define __TBB_DECL_ATOMIC_ALT(T,U) \ - template<> struct __TBB_DEPRECATED_VERBOSE_MSG("tbb::atomic is deprecated, use std::atomic") \ + template<> struct __TBB_DEPRECATED_IN_VERBOSE_MODE_MSG("tbb::atomic is deprecated, use std::atomic") \ atomic: internal::atomic_impl_with_arithmetic { \ atomic() = default ; \ constexpr atomic(T arg): internal::atomic_impl_with_arithmetic(arg) {} \ @@ -479,7 +479,7 @@ __TBB_DECL_ATOMIC(unsigned long) }; #else #define __TBB_DECL_ATOMIC_ALT(T,U) \ - template<> struct __TBB_DEPRECATED_VERBOSE_MSG("tbb::atomic is deprecated, use std::atomic") \ + template<> struct __TBB_DEPRECATED_IN_VERBOSE_MODE_MSG("tbb::atomic is deprecated, use std::atomic") \ atomic: internal::atomic_impl_with_arithmetic { \ T operator=( U rhs ) {return store_with_release(T(rhs));} \ atomic& operator=( const atomic& rhs ) {store_with_release(rhs); return *this;} \ @@ -503,7 +503,7 @@ __TBB_DECL_ATOMIC(wchar_t) #endif /* _MSC_VER||!defined(_NATIVE_WCHAR_T_DEFINED) */ //! Specialization for atomic with arithmetic and operator->. -template struct __TBB_DEPRECATED_VERBOSE_MSG("tbb::atomic is deprecated, use std::atomic") +template struct __TBB_DEPRECATED_IN_VERBOSE_MODE_MSG("tbb::atomic is deprecated, use std::atomic") atomic: internal::atomic_impl_with_arithmetic { #if __TBB_ATOMIC_CTORS atomic() = default ; @@ -523,7 +523,7 @@ atomic: internal::atomic_impl_with_arithmetic { }; //! Specialization for atomic, for sake of not allowing arithmetic or operator->. -template<> struct __TBB_DEPRECATED_VERBOSE_MSG("tbb::atomic is deprecated, use std::atomic") +template<> struct __TBB_DEPRECATED_IN_VERBOSE_MODE_MSG("tbb::atomic is deprecated, use std::atomic") atomic: internal::atomic_impl { #if __TBB_ATOMIC_CTORS atomic() = default ; diff --git a/include/tbb/compat/condition_variable b/include/tbb/compat/condition_variable index e9545b8b7b..a696781779 100644 --- a/include/tbb/compat/condition_variable +++ b/include/tbb/compat/condition_variable @@ -79,17 +79,17 @@ namespace interface5 { // C++0x standard working draft 30.4.3 // Lock tag types -struct __TBB_DEPRECATED_VERBOSE defer_lock_t { }; //! do not acquire ownership of the mutex -struct __TBB_DEPRECATED_VERBOSE try_to_lock_t { }; //! try to acquire ownership of the mutex without blocking -struct __TBB_DEPRECATED_VERBOSE adopt_lock_t { }; //! assume the calling thread has already -__TBB_DEPRECATED_VERBOSE const defer_lock_t defer_lock = {}; -__TBB_DEPRECATED_VERBOSE const try_to_lock_t try_to_lock = {}; -__TBB_DEPRECATED_VERBOSE const adopt_lock_t adopt_lock = {}; +struct __TBB_DEPRECATED_IN_VERBOSE_MODE defer_lock_t { }; //! do not acquire ownership of the mutex +struct __TBB_DEPRECATED_IN_VERBOSE_MODE try_to_lock_t { }; //! try to acquire ownership of the mutex without blocking +struct __TBB_DEPRECATED_IN_VERBOSE_MODE adopt_lock_t { }; //! assume the calling thread has already +__TBB_DEPRECATED_IN_VERBOSE_MODE const defer_lock_t defer_lock = {}; +__TBB_DEPRECATED_IN_VERBOSE_MODE const try_to_lock_t try_to_lock = {}; +__TBB_DEPRECATED_IN_VERBOSE_MODE const adopt_lock_t adopt_lock = {}; // C++0x standard working draft 30.4.3.1 //! lock_guard template -class __TBB_DEPRECATED_VERBOSE lock_guard : tbb::internal::no_copy { +class __TBB_DEPRECATED_IN_VERBOSE_MODE lock_guard : tbb::internal::no_copy { public: //! mutex type typedef M mutex_type; @@ -112,7 +112,7 @@ private: // C++0x standard working draft 30.4.3.2 //! unique_lock template -class __TBB_DEPRECATED_VERBOSE unique_lock : tbb::internal::no_copy { +class __TBB_DEPRECATED_IN_VERBOSE_MODE unique_lock : tbb::internal::no_copy { friend class condition_variable; public: typedef M mutex_type; @@ -245,7 +245,7 @@ private: }; template -__TBB_DEPRECATED_VERBOSE bool unique_lock::try_lock_for( const tick_count::interval_t &i) +__TBB_DEPRECATED_IN_VERBOSE_MODE bool unique_lock::try_lock_for( const tick_count::interval_t &i) { const int unique_lock_tick = 100; /* microseconds; 0.1 milliseconds */ // the smallest wait-time is 0.1 milliseconds. @@ -292,7 +292,7 @@ enum cv_status { no_timeout, timeout }; //! condition variable /** C++0x standard working draft 30.5.1 @ingroup synchronization */ -class __TBB_DEPRECATED_VERBOSE condition_variable : tbb::internal::no_copy { +class __TBB_DEPRECATED_IN_VERBOSE_MODE condition_variable : tbb::internal::no_copy { public: //! Constructor condition_variable() { diff --git a/include/tbb/compat/thread b/include/tbb/compat/thread index 9e5e09d9c2..8b8a13d794 100644 --- a/include/tbb/compat/thread +++ b/include/tbb/compat/thread @@ -45,7 +45,7 @@ namespace this_thread { using tbb::this_tbb_thread::get_id; using tbb::this_tbb_thread::yield; - __TBB_DEPRECATED_VERBOSE inline void sleep_for(const tbb::tick_count::interval_t& rel_time) { + __TBB_DEPRECATED_IN_VERBOSE_MODE inline void sleep_for(const tbb::tick_count::interval_t& rel_time) { tbb::internal::thread_sleep_v3( rel_time ); } } diff --git a/include/tbb/compat/tuple b/include/tbb/compat/tuple index 59fb7ac0e5..c568ef3d20 100644 --- a/include/tbb/compat/tuple +++ b/include/tbb/compat/tuple @@ -360,7 +360,7 @@ inline const __T wrap_dcons(__T*) { return __T(); } // tuple definition template -class __TBB_DEPRECATED_VERBOSE tuple : public internal::tuple_traits<__T0, __T1, __T2, __T3, __T4 __TBB_T_PACK >::U { +class __TBB_DEPRECATED_IN_VERBOSE_MODE tuple : public internal::tuple_traits<__T0, __T1, __T2, __T3, __T4 __TBB_T_PACK >::U { // friends template friend class tuple_size; template friend struct tuple_element; @@ -376,7 +376,7 @@ class __TBB_DEPRECATED_VERBOSE tuple : public internal::tuple_traits<__T0, __T1, typedef typename internal::tuple_traits<__T0,__T1,__T2,__T3, __T4 __TBB_T_PACK >::U my_cons; public: - __TBB_DEPRECATED_VERBOSE tuple(const __T0& t0=internal::wrap_dcons((__T0*)NULL) + __TBB_DEPRECATED_IN_VERBOSE_MODE tuple(const __T0& t0=internal::wrap_dcons((__T0*)NULL) ,const __T1& t1=internal::wrap_dcons((__T1*)NULL) ,const __T2& t2=internal::wrap_dcons((__T2*)NULL) ,const __T3& t3=internal::wrap_dcons((__T3*)NULL) @@ -435,7 +435,7 @@ public: // empty tuple template<> -class __TBB_DEPRECATED_VERBOSE tuple : public null_type { +class __TBB_DEPRECATED_IN_VERBOSE_MODE tuple : public null_type { }; // helper classes diff --git a/include/tbb/concurrent_vector.h b/include/tbb/concurrent_vector.h index 4c53abbdbc..a4988aaa7b 100644 --- a/include/tbb/concurrent_vector.h +++ b/include/tbb/concurrent_vector.h @@ -677,7 +677,7 @@ class concurrent_vector: protected internal::allocator_base, //! Copying constructor for vector with different allocator type template - concurrent_vector( const concurrent_vector& vector, const allocator_type& a = allocator_type() ) + __TBB_DEPRECATED concurrent_vector( const concurrent_vector& vector, const allocator_type& a = allocator_type() ) : internal::allocator_base(a), internal::concurrent_vector_base() { vector_allocator_ptr = &internal_allocator; @@ -759,7 +759,7 @@ class concurrent_vector: protected internal::allocator_base, //! Assignment for vector with different allocator type template - concurrent_vector& operator=( const concurrent_vector& vector ) { + __TBB_DEPRECATED concurrent_vector& operator=( const concurrent_vector& vector ) { if( static_cast( this ) != static_cast( &vector ) ) internal_assign(vector.internal_vector_base(), sizeof(T), &destroy_array, &assign_array, ©_array); diff --git a/include/tbb/critical_section.h b/include/tbb/critical_section.h index 095f03bcc2..fb3332b2e6 100644 --- a/include/tbb/critical_section.h +++ b/include/tbb/critical_section.h @@ -136,7 +136,7 @@ class critical_section_v4 : internal::no_copy { static const bool is_fair_mutex = true; }; // critical_section_v4 } // namespace internal -__TBB_DEPRECATED_VERBOSE_MSG("tbb::critical_section is deprecated, use std::mutex") typedef internal::critical_section_v4 critical_section; +__TBB_DEPRECATED_IN_VERBOSE_MODE_MSG("tbb::critical_section is deprecated, use std::mutex") typedef internal::critical_section_v4 critical_section; __TBB_DEFINE_PROFILING_SET_NAME(critical_section) } // namespace tbb diff --git a/include/tbb/flow_graph.h b/include/tbb/flow_graph.h index 1a6d22b9a9..8c9702e181 100644 --- a/include/tbb/flow_graph.h +++ b/include/tbb/flow_graph.h @@ -31,6 +31,7 @@ #include "tbb_exception.h" #include "internal/_template_helpers.h" #include "internal/_aggregator_impl.h" +#include "tbb/internal/_allocator_traits.h" #include "tbb_profiling.h" #include "task_arena.h" @@ -63,6 +64,12 @@ #define FLOW_SPAWN(a) tbb::task::spawn((a)) #endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR +#define __TBB_DEFAULT_NODE_ALLOCATOR(T) cache_aligned_allocator +#else +#define __TBB_DEFAULT_NODE_ALLOCATOR(T) null_type +#endif + // use the VC10 or gcc version of tuple if it is available. #if __TBB_CPP11_TUPLE_PRESENT #include @@ -205,7 +212,7 @@ static inline tbb::task *combine_tasks(graph& g, tbb::task * left, tbb::task * r #if __TBB_PREVIEW_ASYNC_MSG -template < typename T > class async_msg; +template < typename T > class __TBB_DEPRECATED async_msg; namespace internal { @@ -893,7 +900,285 @@ using internal::node_set; //! An executable node that acts as a source, i.e. it has no predecessors template < typename Output > -class source_node : public graph_node, public sender< Output > { +class input_node : public graph_node, public sender< Output > { +public: + //! The type of the output message, which is complete + typedef Output output_type; + + //! The type of successors of this node + typedef typename sender::successor_type successor_type; + + //Source node has no input type + typedef null_type input_type; + +#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION + typedef typename sender::built_successors_type built_successors_type; + typedef typename sender::successor_list_type successor_list_type; +#endif + + //! Constructor for a node with a successor + template< typename Body > + __TBB_NOINLINE_SYM input_node( graph &g, Body body ) + : graph_node(g), my_active(false), + my_body( new internal::source_body_leaf< output_type, Body>(body) ), + my_init_body( new internal::source_body_leaf< output_type, Body>(body) ), + my_reserved(false), my_has_cached_item(false) + { + my_successors.set_owner(this); + tbb::internal::fgt_node_with_body( CODEPTR(), tbb::internal::FLOW_SOURCE_NODE, &this->my_graph, + static_cast *>(this), this->my_body ); + } + +#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET + template + input_node( const node_set& successors, Body body ) + : input_node(successors.graph_reference(), body) { + make_edges(*this, successors); + } +#endif + + //! Copy constructor + __TBB_NOINLINE_SYM input_node( const input_node& src ) : + graph_node(src.my_graph), sender(), + my_active(false), + my_body( src.my_init_body->clone() ), my_init_body(src.my_init_body->clone() ), + my_reserved(false), my_has_cached_item(false) + { + my_successors.set_owner(this); + tbb::internal::fgt_node_with_body(CODEPTR(), tbb::internal::FLOW_SOURCE_NODE, &this->my_graph, + static_cast *>(this), this->my_body ); + } + + //! The destructor + ~input_node() { delete my_body; delete my_init_body; } + +#if TBB_PREVIEW_FLOW_GRAPH_TRACE + void set_name( const char *name ) __TBB_override { + tbb::internal::fgt_node_desc( this, name ); + } +#endif + + //! Add a new successor to this node + bool register_successor( successor_type &r ) __TBB_override { + spin_mutex::scoped_lock lock(my_mutex); + my_successors.register_successor(r); + if ( my_active ) + spawn_put(); + return true; + } + + //! Removes a successor from this node + bool remove_successor( successor_type &r ) __TBB_override { + spin_mutex::scoped_lock lock(my_mutex); + my_successors.remove_successor(r); + return true; + } + +#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION + + built_successors_type &built_successors() __TBB_override { return my_successors.built_successors(); } + + void internal_add_built_successor( successor_type &r) __TBB_override { + spin_mutex::scoped_lock lock(my_mutex); + my_successors.internal_add_built_successor(r); + } + + void internal_delete_built_successor( successor_type &r) __TBB_override { + spin_mutex::scoped_lock lock(my_mutex); + my_successors.internal_delete_built_successor(r); + } + + size_t successor_count() __TBB_override { + spin_mutex::scoped_lock lock(my_mutex); + return my_successors.successor_count(); + } + + void copy_successors(successor_list_type &v) __TBB_override { + spin_mutex::scoped_lock l(my_mutex); + my_successors.copy_successors(v); + } +#endif /* TBB_DEPRECATED_FLOW_NODE_EXTRACTION */ + + //! Request an item from the node + bool try_get( output_type &v ) __TBB_override { + spin_mutex::scoped_lock lock(my_mutex); + if ( my_reserved ) + return false; + + if ( my_has_cached_item ) { + v = my_cached_item; + my_has_cached_item = false; + return true; + } + // we've been asked to provide an item, but we have none. enqueue a task to + // provide one. + if ( my_active ) + spawn_put(); + return false; + } + + //! Reserves an item. + bool try_reserve( output_type &v ) __TBB_override { + spin_mutex::scoped_lock lock(my_mutex); + if ( my_reserved ) { + return false; + } + + if ( my_has_cached_item ) { + v = my_cached_item; + my_reserved = true; + return true; + } else { + return false; + } + } + + //! Release a reserved item. + /** true = item has been released and so remains in sender, dest must request or reserve future items */ + bool try_release( ) __TBB_override { + spin_mutex::scoped_lock lock(my_mutex); + __TBB_ASSERT( my_reserved && my_has_cached_item, "releasing non-existent reservation" ); + my_reserved = false; + if(!my_successors.empty()) + spawn_put(); + return true; + } + + //! Consumes a reserved item + bool try_consume( ) __TBB_override { + spin_mutex::scoped_lock lock(my_mutex); + __TBB_ASSERT( my_reserved && my_has_cached_item, "consuming non-existent reservation" ); + my_reserved = false; + my_has_cached_item = false; + if ( !my_successors.empty() ) { + spawn_put(); + } + return true; + } + + //! Activates a node that was created in the inactive state + void activate() { + spin_mutex::scoped_lock lock(my_mutex); + my_active = true; + if (!my_successors.empty()) + spawn_put(); + } + + template + Body copy_function_object() { + internal::source_body &body_ref = *this->my_body; + return dynamic_cast< internal::source_body_leaf & >(body_ref).get_body(); + } + +#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION + void extract( ) __TBB_override { + my_successors.built_successors().sender_extract(*this); // removes "my_owner" == this from each successor + my_active = false; + my_reserved = false; + if(my_has_cached_item) my_has_cached_item = false; + } +#endif + +protected: + + //! resets the source_node to its initial state + void reset_node( reset_flags f) __TBB_override { + my_active = false; + my_reserved = false; + my_has_cached_item = false; + + if(f & rf_clear_edges) my_successors.clear(); + if(f & rf_reset_bodies) { + internal::source_body *tmp = my_init_body->clone(); + delete my_body; + my_body = tmp; + } + } + +private: + spin_mutex my_mutex; + bool my_active; + internal::source_body *my_body; + internal::source_body *my_init_body; + internal::broadcast_cache< output_type > my_successors; + bool my_reserved; + bool my_has_cached_item; + output_type my_cached_item; + + // used by apply_body_bypass, can invoke body of node. + bool try_reserve_apply_body(output_type &v) { + spin_mutex::scoped_lock lock(my_mutex); + if ( my_reserved ) { + return false; + } + if ( !my_has_cached_item ) { + tbb::internal::fgt_begin_body( my_body ); + bool r = (*my_body)(my_cached_item); + tbb::internal::fgt_end_body( my_body ); + if (r) { + my_has_cached_item = true; + } + } + if ( my_has_cached_item ) { + v = my_cached_item; + my_reserved = true; + return true; + } else { + return false; + } + } + + task* create_put_task() { + return ( new ( task::allocate_additional_child_of( *(this->my_graph.root_task()) ) ) + internal:: source_task_bypass < input_node< output_type > >( *this ) ); + } + + //! Spawns a task that applies the body + void spawn_put( ) { + if(internal::is_graph_active(this->my_graph)) { + internal::spawn_in_graph_arena(this->my_graph, *create_put_task()); + } + } + + friend class internal::source_task_bypass< input_node< output_type > >; + //! Applies the body. Returning SUCCESSFULLY_ENQUEUED okay; forward_task_bypass will handle it. + task * apply_body_bypass( ) { + output_type v; + if ( !try_reserve_apply_body(v) ) + return NULL; + + task *last_task = my_successors.try_put_task(v); + if ( last_task ) + try_consume(); + else + try_release(); + return last_task; + } +}; // class input_node + +#if TBB_USE_SOURCE_NODE_AS_ALIAS +template < typename Output > +class source_node : public input_node { +public: + //! Constructor for a node with a successor + template< typename Body > + __TBB_NOINLINE_SYM source_node( graph &g, Body body ) + : input_node(g, body) + { + } + +#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET + template + source_node( const node_set& successors, Body body ) + : input_node(successors, body) { + } +#endif +}; +#else // TBB_USE_SOURCE_NODE_AS_ALIAS +//! An executable node that acts as a source, i.e. it has no predecessors +template < typename Output > class +__TBB_DEPRECATED_MSG("TBB Warning: tbb::flow::source_node is deprecated, use tbb::flow::input_node." ) +source_node : public graph_node, public sender< Output > { public: //! The type of the output message, which is complete typedef Output output_type; @@ -1155,15 +1440,37 @@ class source_node : public graph_node, public sender< Output > { return last_task; } }; // class source_node +#endif // TBB_USE_SOURCE_NODE_AS_ALIAS //! Implements a function node that supports Input -> Output -template < typename Input, typename Output = continue_msg, typename Policy = queueing, typename Allocator=cache_aligned_allocator > -class function_node : public graph_node, public internal::function_input, public internal::function_output { +template +class function_node + : public graph_node +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + , public internal::function_input< Input, Output, Policy, Allocator > +#else + , public internal::function_input< Input, Output, Policy, cache_aligned_allocator > +#endif + , public internal::function_output { + +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + typedef Allocator internals_allocator; +#else + typedef cache_aligned_allocator internals_allocator; + + __TBB_STATIC_ASSERT( + (tbb::internal::is_same_type::value), + "Allocator template parameter for flow graph nodes is deprecated and will be removed. " + "Specify TBB_DEPRECATED_FLOW_NODE_ALLOCATOR to temporary enable the deprecated interface." + ); +#endif + public: typedef Input input_type; typedef Output output_type; - typedef internal::function_input input_impl_type; - typedef internal::function_input_queue input_queue_type; + typedef internal::function_input input_impl_type; + typedef internal::function_input_queue input_queue_type; typedef internal::function_output fOutput_type; typedef typename input_impl_type::predecessor_type predecessor_type; typedef typename fOutput_type::successor_type successor_type; @@ -1256,7 +1563,8 @@ class function_node : public graph_node, public internal::function_input (set of outputs) // Output is a tuple of output types. -template < typename Input, typename Output, typename Policy = queueing, typename Allocator=cache_aligned_allocator > +template class multifunction_node : public graph_node, public internal::multifunction_input @@ -1268,29 +1576,45 @@ class multifunction_node : Output // the tuple providing the types >::type, Policy, +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR Allocator +#else + cache_aligned_allocator +#endif > { +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + typedef Allocator internals_allocator; +#else + typedef cache_aligned_allocator internals_allocator; + + __TBB_STATIC_ASSERT( + (tbb::internal::is_same_type::value), + "Allocator template parameter for flow graph nodes is deprecated and will be removed. " + "Specify TBB_DEPRECATED_FLOW_NODE_ALLOCATOR to temporary enable the deprecated interface." + ); +#endif + protected: static const int N = tbb::flow::tuple_size::value; public: typedef Input input_type; typedef null_type output_type; typedef typename internal::wrap_tuple_elements::type output_ports_type; - typedef internal::multifunction_input input_impl_type; - typedef internal::function_input_queue input_queue_type; + typedef internal::multifunction_input< + input_type, output_ports_type, Policy, internals_allocator> input_impl_type; + typedef internal::function_input_queue input_queue_type; private: - typedef typename internal::multifunction_input base_type; using input_impl_type::my_predecessors; public: template - __TBB_NOINLINE_SYM multifunction_node( + __TBB_NOINLINE_SYM multifunction_node( graph &g, size_t concurrency, #if __TBB_CPP11_PRESENT Body body, __TBB_FLOW_GRAPH_PRIORITY_ARG1( Policy = Policy(), node_priority_t priority = tbb::flow::internal::no_priority ) #else __TBB_FLOW_GRAPH_PRIORITY_ARG1(Body body, node_priority_t priority = tbb::flow::internal::no_priority) #endif - ) : graph_node(g), base_type(g, concurrency, __TBB_FLOW_GRAPH_PRIORITY_ARG1(body, priority)) { + ) : graph_node(g), input_impl_type(g, concurrency, __TBB_FLOW_GRAPH_PRIORITY_ARG1(body, priority)) { tbb::internal::fgt_multioutput_node_with_body( CODEPTR(), tbb::internal::FLOW_MULTIFUNCTION_NODE, &this->my_graph, static_cast *>(this), @@ -1320,7 +1644,7 @@ class multifunction_node : #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET __TBB_NOINLINE_SYM multifunction_node( const multifunction_node &other) : - graph_node(other.my_graph), base_type(other) { + graph_node(other.my_graph), input_impl_type(other) { tbb::internal::fgt_multioutput_node_with_body( CODEPTR(), tbb::internal::FLOW_MULTIFUNCTION_NODE, &this->my_graph, static_cast *>(this), this->output_ports(), this->my_body ); @@ -1335,23 +1659,31 @@ class multifunction_node : #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION void extract( ) __TBB_override { my_predecessors.built_predecessors().receiver_extract(*this); - base_type::extract(); + input_impl_type::extract(); } #endif // all the guts are in multifunction_input... protected: - void reset_node(reset_flags f) __TBB_override { base_type::reset(f); } + void reset_node(reset_flags f) __TBB_override { input_impl_type::reset(f); } }; // multifunction_node //! split_node: accepts a tuple as input, forwards each element of the tuple to its // successors. The node has unlimited concurrency, so it does not reject inputs. -template > +template class split_node : public graph_node, public receiver { static const int N = tbb::flow::tuple_size::value; typedef receiver base_type; public: typedef TupleType input_type; +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR typedef Allocator allocator_type; +#else + __TBB_STATIC_ASSERT( + (tbb::internal::is_same_type::value), + "Allocator template parameter for flow graph nodes is deprecated and will be removed. " + "Specify TBB_DEPRECATED_FLOW_NODE_ALLOCATOR to temporary enable the deprecated interface." + ); +#endif #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION typedef typename base_type::predecessor_type predecessor_type; typedef typename base_type::predecessor_list_type predecessor_list_type; @@ -1700,18 +2032,38 @@ class broadcast_node : public graph_node, public receiver, public sender { }; // broadcast_node //! Forwards messages in arbitrary order -template > -class buffer_node : public graph_node, public internal::reservable_item_buffer, public receiver, public sender { +template +class buffer_node + : public graph_node +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + , public internal::reservable_item_buffer< T, Allocator > +#else + , public internal::reservable_item_buffer< T, cache_aligned_allocator > +#endif + , public receiver, public sender { +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + typedef Allocator internals_allocator; +#else + typedef cache_aligned_allocator internals_allocator; +#endif public: typedef T input_type; typedef T output_type; typedef typename receiver::predecessor_type predecessor_type; typedef typename sender::successor_type successor_type; - typedef buffer_node class_type; + typedef buffer_node class_type; #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION typedef typename receiver::predecessor_list_type predecessor_list_type; typedef typename sender::successor_list_type successor_list_type; #endif +#if !TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + __TBB_STATIC_ASSERT( + (tbb::internal::is_same_type::value), + "Allocator template parameter for flow graph nodes is deprecated and will be removed. " + "Specify TBB_DEPRECATED_FLOW_NODE_ALLOCATOR to temporary enable the deprecated interface." + ); +#endif + protected: typedef size_t size_type; internal::round_robin_cache< T, null_rw_mutex > my_successors; @@ -1720,7 +2072,7 @@ class buffer_node : public graph_node, public internal::reservable_item_buffer my_built_predecessors; #endif - friend class internal::forward_task_bypass< buffer_node< T, A > >; + friend class internal::forward_task_bypass< class_type >; enum op_type {reg_succ, rem_succ, req_item, res_item, rel_res, con_res, put_item, try_fwd_task #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION @@ -1808,8 +2160,7 @@ class buffer_node : public graph_node, public internal::reservable_item_buffermy_graph)) { forwarder_busy = true; task *new_task = new(task::allocate_additional_child_of(*(this->my_graph.root_task()))) internal:: - forward_task_bypass - < buffer_node >(*this); + forward_task_bypass(*this); // tmp should point to the last item handled by the aggregator. This is the operation // the handling thread enqueued. So modifying that record will be okay. // workaround for icc bug @@ -1997,8 +2348,10 @@ class buffer_node : public graph_node, public internal::reservable_item_buffer(), - forwarder_busy(false) { + __TBB_NOINLINE_SYM explicit buffer_node( graph &g ) + : graph_node(g), internal::reservable_item_buffer(), receiver(), + sender(), forwarder_busy(false) + { my_successors.set_owner(this); my_aggregator.initialize_handler(handler_type(this)); tbb::internal::fgt_node( CODEPTR(), tbb::internal::FLOW_BUFFER_NODE, &this->my_graph, @@ -2013,9 +2366,10 @@ class buffer_node : public graph_node, public internal::reservable_item_buffer(), receiver(), sender() { - forwarder_busy = false; + __TBB_NOINLINE_SYM buffer_node( const buffer_node& src ) + : graph_node(src.my_graph), internal::reservable_item_buffer(), + receiver(), sender(), forwarder_busy(false) + { my_successors.set_owner(this); my_aggregator.initialize_handler(handler_type(this)); tbb::internal::fgt_node( CODEPTR(), tbb::internal::FLOW_BUFFER_NODE, &this->my_graph, @@ -2189,7 +2543,7 @@ class buffer_node : public graph_node, public internal::reservable_item_buffer::reset(); + internal::reservable_item_buffer::reset(); // TODO: just clear structures if (f&rf_clear_edges) { my_successors.clear(); @@ -2202,10 +2556,17 @@ class buffer_node : public graph_node, public internal::reservable_item_buffer > -class queue_node : public buffer_node { +template +class queue_node : public buffer_node { +#if !TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + __TBB_STATIC_ASSERT( + (tbb::internal::is_same_type::value), + "Allocator template parameter for flow graph nodes is deprecated and will be removed. " + "Specify TBB_DEPRECATED_FLOW_NODE_ALLOCATOR to temporary enable the deprecated interface." + ); +#endif protected: - typedef buffer_node base_type; + typedef buffer_node base_type; typedef typename base_type::size_type size_type; typedef typename base_type::buffer_operation queue_operation; typedef queue_node class_type; @@ -2295,12 +2656,19 @@ class queue_node : public buffer_node { }; // queue_node //! Forwards messages in sequence order -template< typename T, typename A=cache_aligned_allocator > -class sequencer_node : public queue_node { +template< typename T, typename Allocator=__TBB_DEFAULT_NODE_ALLOCATOR(T) > +class sequencer_node : public queue_node { internal::function_body< T, size_t > *my_sequencer; // my_sequencer should be a benign function and must be callable // from a parallel context. Does this mean it needn't be reset? public: +#if !TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + __TBB_STATIC_ASSERT( + (tbb::internal::is_same_type::value), + "Allocator template parameter for flow graph nodes is deprecated and will be removed. " + "Specify TBB_DEPRECATED_FLOW_NODE_ALLOCATOR to temporary enable the deprecated interface." + ); +#endif typedef T input_type; typedef T output_type; typedef typename receiver::predecessor_type predecessor_type; @@ -2308,7 +2676,7 @@ class sequencer_node : public queue_node { //! Constructor template< typename Sequencer > - __TBB_NOINLINE_SYM sequencer_node( graph &g, const Sequencer& s ) : queue_node(g), + __TBB_NOINLINE_SYM sequencer_node( graph &g, const Sequencer& s ) : queue_node(g), my_sequencer(new internal::function_body_leaf< T, size_t, Sequencer>(s) ) { tbb::internal::fgt_node( CODEPTR(), tbb::internal::FLOW_SEQUENCER_NODE, &(this->my_graph), static_cast *>(this), @@ -2324,7 +2692,7 @@ class sequencer_node : public queue_node { #endif //! Copy constructor - __TBB_NOINLINE_SYM sequencer_node( const sequencer_node& src ) : queue_node(src), + __TBB_NOINLINE_SYM sequencer_node( const sequencer_node& src ) : queue_node(src), my_sequencer( src.my_sequencer->clone() ) { tbb::internal::fgt_node( CODEPTR(), tbb::internal::FLOW_SEQUENCER_NODE, &(this->my_graph), static_cast *>(this), @@ -2341,8 +2709,8 @@ class sequencer_node : public queue_node { #endif protected: - typedef typename buffer_node::size_type size_type; - typedef typename buffer_node::buffer_operation sequencer_operation; + typedef typename buffer_node::size_type size_type; + typedef typename buffer_node::buffer_operation sequencer_operation; private: bool internal_push(sequencer_operation *op) __TBB_override { @@ -2369,19 +2737,26 @@ class sequencer_node : public queue_node { }; // sequencer_node //! Forwards messages in priority order -template< typename T, typename Compare = std::less, typename A=cache_aligned_allocator > -class priority_queue_node : public buffer_node { +template, typename Allocator=__TBB_DEFAULT_NODE_ALLOCATOR(T)> +class priority_queue_node : public buffer_node { public: +#if !TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + __TBB_STATIC_ASSERT( + (tbb::internal::is_same_type::value), + "Allocator template parameter for flow graph nodes is deprecated and will removed in the future. " + "To temporary enable the deprecated interface specify TBB_ENABLE_DEPRECATED_NODE_ALLOCATOR." + ); +#endif typedef T input_type; typedef T output_type; - typedef buffer_node base_type; + typedef buffer_node base_type; typedef priority_queue_node class_type; typedef typename receiver::predecessor_type predecessor_type; typedef typename sender::successor_type successor_type; //! Constructor __TBB_NOINLINE_SYM explicit priority_queue_node( graph &g, const Compare& comp = Compare() ) - : buffer_node(g), compare(comp), mark(0) { + : buffer_node(g), compare(comp), mark(0) { tbb::internal::fgt_node( CODEPTR(), tbb::internal::FLOW_PRIORITY_QUEUE_NODE, &(this->my_graph), static_cast *>(this), static_cast *>(this) ); @@ -2396,7 +2771,9 @@ class priority_queue_node : public buffer_node { #endif //! Copy constructor - __TBB_NOINLINE_SYM priority_queue_node( const priority_queue_node &src ) : buffer_node(src), mark(0) { + __TBB_NOINLINE_SYM priority_queue_node( const priority_queue_node &src ) + : buffer_node(src), mark(0) + { tbb::internal::fgt_node( CODEPTR(), tbb::internal::FLOW_PRIORITY_QUEUE_NODE, &(this->my_graph), static_cast *>(this), static_cast *>(this) ); @@ -2415,9 +2792,9 @@ class priority_queue_node : public buffer_node { base_type::reset_node(f); } - typedef typename buffer_node::size_type size_type; - typedef typename buffer_node::item_type item_type; - typedef typename buffer_node::buffer_operation prio_operation; + typedef typename buffer_node::size_type size_type; + typedef typename buffer_node::item_type item_type; + typedef typename buffer_node::buffer_operation prio_operation; //! Tries to forward valid items to successors void internal_forward_task(prio_operation *op) __TBB_override { @@ -3822,8 +4199,17 @@ namespace interface11 { //! Implements async node template < typename Input, typename Output, typename Policy = queueing_lightweight, - typename Allocator=cache_aligned_allocator > -class async_node : public multifunction_node< Input, tuple< Output >, Policy, Allocator >, public sender< Output > { + typename Allocator=__TBB_DEFAULT_NODE_ALLOCATOR(Input) > +class async_node + : public multifunction_node< Input, tuple< Output >, Policy, Allocator >, public sender< Output > +{ +#if !TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + __TBB_STATIC_ASSERT( + (tbb::internal::is_same_type::value), + "Allocator template parameter for flow graph nodes is deprecated and will removed in the future. " + "To temporary enable the deprecated interface specify TBB_ENABLE_DEPRECATED_NODE_ALLOCATOR." + ); +#endif typedef multifunction_node< Input, tuple< Output >, Policy, Allocator > base_type; typedef typename internal::multifunction_input mfn_input_type; @@ -4280,8 +4666,8 @@ class write_once_node : public overwrite_node { using interface11::graph; using interface11::graph_node; using interface11::continue_msg; - using interface11::source_node; + using interface11::input_node; using interface11::function_node; using interface11::multifunction_node; using interface11::split_node; @@ -4337,6 +4723,7 @@ class write_once_node : public overwrite_node { #undef __TBB_PFG_RESET_ARG #undef __TBB_COMMA +#undef __TBB_DEFAULT_NODE_ALLOCATOR #include "internal/_warning_suppress_disable_notice.h" #undef __TBB_flow_graph_H_include_area diff --git a/include/tbb/flow_graph_opencl_node.h b/include/tbb/flow_graph_opencl_node.h index 33e1cdef86..e6670db6a4 100644 --- a/include/tbb/flow_graph_opencl_node.h +++ b/include/tbb/flow_graph_opencl_node.h @@ -14,6 +14,17 @@ limitations under the License. */ +#include "internal/_deprecated_header_message_guard.h" + +#if !defined(__TBB_show_deprecation_message_flow_graph_opencl_node_H) && defined(__TBB_show_deprecated_header_message) +#define __TBB_show_deprecation_message_flow_graph_opencl_node_H +#pragma message("TBB Warning: tbb/flow_graph_opencl_node.h is deprecated. For details, please see Deprecated Features appendix in the TBB reference manual.") +#endif + +#if defined(__TBB_show_deprecated_header_message) +#undef __TBB_show_deprecated_header_message +#endif + #ifndef __TBB_flow_graph_opencl_node_H #define __TBB_flow_graph_opencl_node_H @@ -105,7 +116,7 @@ inline std::string platform_info(cl_platform_id p, cl_platform_info } -class opencl_device { +class __TBB_DEPRECATED_IN_VERBOSE_MODE opencl_device { public: typedef size_t device_id_type; enum : device_id_type { @@ -253,7 +264,7 @@ class opencl_device { #endif }; -class opencl_device_list { +class __TBB_DEPRECATED_IN_VERBOSE_MODE opencl_device_list { typedef std::vector container_type; public: typedef container_type::iterator iterator; @@ -351,7 +362,7 @@ class callback : public callback_base { }; template -class opencl_async_msg : public async_msg { +class __TBB_DEPRECATED_IN_VERBOSE_MODE opencl_async_msg : public async_msg { public: typedef T value_type; @@ -626,10 +637,12 @@ enum access_type { }; template -class opencl_subbuffer; +class __TBB_DEPRECATED_IN_VERBOSE_MODE +opencl_subbuffer; template -class opencl_buffer { +class __TBB_DEPRECATED_IN_VERBOSE_MODE +opencl_buffer { public: typedef cl_mem native_object_type; typedef opencl_buffer memory_object_type; @@ -703,7 +716,8 @@ class opencl_buffer { }; template -class opencl_subbuffer : public opencl_buffer { +class __TBB_DEPRECATED_IN_VERBOSE_MODE +opencl_subbuffer : public opencl_buffer { opencl_buffer my_owner; public: opencl_subbuffer() {} @@ -779,7 +793,7 @@ typename std::enable_if::value>::type receive_if_memory template typename std::enable_if::value>::type receive_if_memory_object( const T& ) {} -class opencl_range { +class __TBB_DEPRECATED_IN_VERBOSE_MODE opencl_range { public: typedef size_t range_index_type; typedef std::array nd_range_type; @@ -807,7 +821,7 @@ class opencl_range { }; template -class opencl_factory { +class __TBB_DEPRECATED_IN_VERBOSE_MODE opencl_factory { public: template using async_msg_type = opencl_async_msg>; typedef opencl_device device_type; @@ -1218,7 +1232,7 @@ enum class opencl_program_type { }; template -class opencl_program : tbb::internal::no_assign { +class __TBB_DEPRECATED_IN_VERBOSE_MODE opencl_program : tbb::internal::no_assign { public: typedef typename Factory::kernel_type kernel_type; @@ -1401,10 +1415,11 @@ class opencl_program : tbb::internal::no_assign { }; template -class opencl_node; +class __TBB_DEPRECATED_IN_VERBOSE_MODE opencl_node; template -class opencl_node< tuple, JP, Factory > : public streaming_node< tuple, JP, Factory > { +class __TBB_DEPRECATED_IN_VERBOSE_MODE +opencl_node< tuple, JP, Factory > : public streaming_node< tuple, JP, Factory > { typedef streaming_node < tuple, JP, Factory > base_type; public: typedef typename base_type::kernel_type kernel_type; @@ -1430,7 +1445,8 @@ class opencl_node< tuple, JP, Factory > : public streaming_node< tuple }; template -class opencl_node< tuple, JP > : public opencl_node < tuple, JP, opencl_info::default_opencl_factory > { +class __TBB_DEPRECATED_IN_VERBOSE_MODE +opencl_node< tuple, JP > : public opencl_node < tuple, JP, opencl_info::default_opencl_factory > { typedef opencl_node < tuple, JP, opencl_info::default_opencl_factory > base_type; public: typedef typename base_type::kernel_type kernel_type; @@ -1446,7 +1462,8 @@ class opencl_node< tuple, JP > : public opencl_node < tuple, }; template -class opencl_node< tuple > : public opencl_node < tuple, queueing, opencl_info::default_opencl_factory > { +class __TBB_DEPRECATED_IN_VERBOSE_MODE +opencl_node< tuple > : public opencl_node < tuple, queueing, opencl_info::default_opencl_factory > { typedef opencl_node < tuple, queueing, opencl_info::default_opencl_factory > base_type; public: typedef typename base_type::kernel_type kernel_type; diff --git a/include/tbb/internal/_flow_graph_async_msg_impl.h b/include/tbb/internal/_flow_graph_async_msg_impl.h index 1995c92ca0..9f269ffd57 100644 --- a/include/tbb/internal/_flow_graph_async_msg_impl.h +++ b/include/tbb/internal/_flow_graph_async_msg_impl.h @@ -118,7 +118,7 @@ class async_storage { } // namespace internal template -class async_msg { +class __TBB_DEPRECATED async_msg { template< typename > friend class receiver; template< typename, typename > friend struct internal::async_helpers; public: diff --git a/include/tbb/internal/_flow_graph_item_buffer_impl.h b/include/tbb/internal/_flow_graph_item_buffer_impl.h index da76da1fb2..e5a97d1ced 100644 --- a/include/tbb/internal/_flow_graph_item_buffer_impl.h +++ b/include/tbb/internal/_flow_graph_item_buffer_impl.h @@ -44,8 +44,7 @@ namespace internal { protected: typedef size_t size_type; typedef typename aligned_pair::type buffer_item_type; - typedef typename A::template rebind::other allocator_type; - + typedef typename tbb::internal::allocator_rebind::type allocator_type; buffer_item_type *my_array; size_type my_array_size; static const size_type initial_buffer_size = 4; diff --git a/include/tbb/internal/_flow_graph_node_impl.h b/include/tbb/internal/_flow_graph_node_impl.h index 744c39e7c7..dbc56ecdf5 100644 --- a/include/tbb/internal/_flow_graph_node_impl.h +++ b/include/tbb/internal/_flow_graph_node_impl.h @@ -74,7 +74,7 @@ namespace internal { typedef typename receiver::predecessor_type predecessor_type; typedef predecessor_cache predecessor_cache_type; typedef function_input_queue input_queue_type; - typedef typename A::template rebind< input_queue_type >::other queue_allocator_type; + typedef typename tbb::internal::allocator_rebind::type queue_allocator_type; __TBB_STATIC_ASSERT(!((internal::has_policy::value) && (internal::has_policy::value)), "queueing and rejecting policies can't be specified simultaneously"); diff --git a/include/tbb/internal/_flow_graph_nodes_deduction.h b/include/tbb/internal/_flow_graph_nodes_deduction.h index f4da244733..ffdfae2edf 100644 --- a/include/tbb/internal/_flow_graph_nodes_deduction.h +++ b/include/tbb/internal/_flow_graph_nodes_deduction.h @@ -80,9 +80,19 @@ template decltype(decide_on_operator_overload(std::declval())) decide_on_callable_type(...); // Deduction guides for Flow Graph nodes +#if TBB_USE_SOURCE_NODE_AS_ALIAS +template +source_node(GraphOrSet&&, Body) +->source_node(0))>>; +#else template source_node(GraphOrSet&&, Body, bool = true) ->source_node(0))>>; +#endif + +template +input_node(GraphOrSet&&, Body, bool = true) +->input_node(0))>>; #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET diff --git a/include/tbb/internal/_flow_graph_streaming_node.h b/include/tbb/internal/_flow_graph_streaming_node.h index abb8c1393a..4ef990bf13 100644 --- a/include/tbb/internal/_flow_graph_streaming_node.h +++ b/include/tbb/internal/_flow_graph_streaming_node.h @@ -38,7 +38,7 @@ struct port_ref_impl { // The purpose of the port_ref_impl is the pretty syntax: the deduction of a compile-time constant is processed from the return type. // So it is possible to use this helper without parentheses, e.g. "port_ref<0>". template -internal::port_ref_impl port_ref() { +__TBB_DEPRECATED internal::port_ref_impl port_ref() { return internal::port_ref_impl(); }; @@ -299,10 +299,11 @@ O---O | | O---O | | \--------------------------------------------------------------------------------------------/ */ template -class streaming_node; +class __TBB_DEPRECATED streaming_node; template -class streaming_node< tuple, JP, StreamFactory > +class __TBB_DEPRECATED +streaming_node< tuple, JP, StreamFactory > : public composite_node < typename internal::streaming_node_traits::input_tuple, typename internal::streaming_node_traits::output_tuple > , public internal::kernel_executor_helper< StreamFactory, typename internal::streaming_node_traits::kernel_input_tuple > diff --git a/include/tbb/mutex.h b/include/tbb/mutex.h index 76a9da8926..94269f3d47 100644 --- a/include/tbb/mutex.h +++ b/include/tbb/mutex.h @@ -46,7 +46,7 @@ namespace tbb { //! Wrapper around the platform's native lock. /** @ingroup synchronization */ -class __TBB_DEPRECATED_VERBOSE_MSG("tbb::critical_section is deprecated, use std::mutex") mutex : internal::mutex_copy_deprecated_and_disabled { +class __TBB_DEPRECATED_IN_VERBOSE_MODE_MSG("tbb::critical_section is deprecated, use std::mutex") mutex : internal::mutex_copy_deprecated_and_disabled { public: //! Construct unacquired mutex. mutex() { diff --git a/include/tbb/reader_writer_lock.h b/include/tbb/reader_writer_lock.h index e55e8a8d7d..509ff7b775 100644 --- a/include/tbb/reader_writer_lock.h +++ b/include/tbb/reader_writer_lock.h @@ -41,7 +41,7 @@ namespace interface5 { /** Loosely adapted from Mellor-Crummey and Scott pseudocode at http://www.cs.rochester.edu/research/synchronization/pseudocode/rw.html#s_wp @ingroup synchronization */ - class __TBB_DEPRECATED_VERBOSE_MSG("tbb::reader_writer_lock is deprecated, use std::shared_mutex") + class __TBB_DEPRECATED_IN_VERBOSE_MODE_MSG("tbb::reader_writer_lock is deprecated, use std::shared_mutex") reader_writer_lock : tbb::internal::no_copy { public: friend class scoped_lock; diff --git a/include/tbb/recursive_mutex.h b/include/tbb/recursive_mutex.h index 6ac881987c..d5be2c4f68 100644 --- a/include/tbb/recursive_mutex.h +++ b/include/tbb/recursive_mutex.h @@ -46,7 +46,7 @@ namespace tbb { //! Mutex that allows recursive mutex acquisition. /** Mutex that allows recursive mutex acquisition. @ingroup synchronization */ -class __TBB_DEPRECATED_VERBOSE_MSG("tbb::recursive_mutex is deprecated, use std::recursive_mutex") +class __TBB_DEPRECATED_IN_VERBOSE_MODE_MSG("tbb::recursive_mutex is deprecated, use std::recursive_mutex") recursive_mutex : internal::mutex_copy_deprecated_and_disabled { public: //! Construct unacquired recursive_mutex. diff --git a/include/tbb/runtime_loader.h b/include/tbb/runtime_loader.h index e790603137..9aaeea5b46 100644 --- a/include/tbb/runtime_loader.h +++ b/include/tbb/runtime_loader.h @@ -92,7 +92,7 @@ There are some implications: */ -class __TBB_DEPRECATED_VERBOSE runtime_loader : tbb::internal::no_copy { +class __TBB_DEPRECATED_IN_VERBOSE_MODE runtime_loader : tbb::internal::no_copy { public: diff --git a/include/tbb/task.h b/include/tbb/task.h index 085f30e80a..d58fb361c6 100644 --- a/include/tbb/task.h +++ b/include/tbb/task.h @@ -14,6 +14,17 @@ limitations under the License. */ +#include "internal/_deprecated_header_message_guard.h" + +#if !defined(__TBB_show_deprecation_message_task_H) && defined(__TBB_show_deprecated_header_message) +#define __TBB_show_deprecation_message_task_H +#pragma message("TBB Warning: tbb/task.h is deprecated. For details, please see Deprecated Features appendix in the TBB reference manual.") +#endif + +#if defined(__TBB_show_deprecated_header_message) +#undef __TBB_show_deprecated_header_message +#endif + #ifndef __TBB_task_H #define __TBB_task_H @@ -557,10 +568,10 @@ class task_group_context : internal::no_copy { #if __TBB_TASK_PRIORITY //! Changes priority of the task group - __TBB_DEPRECATED void set_priority ( priority_t ); + __TBB_DEPRECATED_IN_VERBOSE_MODE void set_priority ( priority_t ); //! Retrieves current priority of the current task group - __TBB_DEPRECATED priority_t priority () const; + __TBB_DEPRECATED_IN_VERBOSE_MODE priority_t priority () const; #endif /* __TBB_TASK_PRIORITY */ //! Returns the context's trait @@ -601,7 +612,7 @@ class task_group_context : internal::no_copy { //! Base class for user-defined tasks. /** @ingroup task_scheduling */ -class task: __TBB_TASK_BASE_ACCESS interface5::internal::task_base { +class __TBB_DEPRECATED_IN_VERBOSE_MODE task: __TBB_TASK_BASE_ACCESS interface5::internal::task_base { //! Set reference count void __TBB_EXPORTED_METHOD internal_set_ref_count( int count ); @@ -828,7 +839,7 @@ class task: __TBB_TASK_BASE_ACCESS interface5::internal::task_base { #if __TBB_TASK_PRIORITY //! Enqueue task for starvation-resistant execution on the specified priority level. - __TBB_DEPRECATED static void enqueue( task& t, priority_t p ) { + static void enqueue( task& t, priority_t p ) { #if __TBB_PREVIEW_CRITICAL_TASKS __TBB_ASSERT(p == priority_low || p == priority_normal || p == priority_high || p == internal::priority_critical, "Invalid priority level value"); @@ -842,7 +853,7 @@ class task: __TBB_TASK_BASE_ACCESS interface5::internal::task_base { //! Enqueue task in task_arena //! The implementation is in task_arena.h #if __TBB_TASK_PRIORITY - __TBB_DEPRECATED inline static void enqueue( task& t, task_arena& arena, priority_t p = priority_t(0) ); + inline static void enqueue( task& t, task_arena& arena, priority_t p = priority_t(0) ); #else inline static void enqueue( task& t, task_arena& arena); #endif @@ -1028,7 +1039,7 @@ inline void task::resume(suspend_point tag) { //! task that does nothing. Useful for synchronization. /** @ingroup task_scheduling */ -class empty_task: public task { +class __TBB_DEPRECATED_IN_VERBOSE_MODE empty_task: public task { task* execute() __TBB_override { return NULL; } @@ -1060,7 +1071,7 @@ namespace internal { //! A list of children. /** Used for method task::spawn_children @ingroup task_scheduling */ -class task_list: internal::no_copy { +class __TBB_DEPRECATED_IN_VERBOSE_MODE task_list: internal::no_copy { private: task* first; task** next_ptr; diff --git a/include/tbb/task_scheduler_init.h b/include/tbb/task_scheduler_init.h index 0483704956..c025454b76 100644 --- a/include/tbb/task_scheduler_init.h +++ b/include/tbb/task_scheduler_init.h @@ -63,7 +63,7 @@ namespace internal { and will persist until this thread exits. Default concurrency level is defined as described in task_scheduler_init::initialize(). @ingroup task_scheduling */ -class __TBB_DEPRECATED_VERBOSE task_scheduler_init: internal::no_copy { +class __TBB_DEPRECATED_IN_VERBOSE_MODE task_scheduler_init: internal::no_copy { enum ExceptionPropagationMode { propagation_mode_exact = 1u, propagation_mode_captured = 2u, diff --git a/include/tbb/tbb_config.h b/include/tbb/tbb_config.h index f469b4b6ff..7a8d06a03b 100644 --- a/include/tbb/tbb_config.h +++ b/include/tbb/tbb_config.h @@ -641,11 +641,11 @@ There are four cases that are supported: #endif #if defined(TBB_SUPPRESS_DEPRECATED_MESSAGES) && (TBB_SUPPRESS_DEPRECATED_MESSAGES == 0) - #define __TBB_DEPRECATED_VERBOSE __TBB_DEPRECATED - #define __TBB_DEPRECATED_VERBOSE_MSG(msg) __TBB_DEPRECATED_MSG(msg) + #define __TBB_DEPRECATED_IN_VERBOSE_MODE __TBB_DEPRECATED + #define __TBB_DEPRECATED_IN_VERBOSE_MODE_MSG(msg) __TBB_DEPRECATED_MSG(msg) #else - #define __TBB_DEPRECATED_VERBOSE - #define __TBB_DEPRECATED_VERBOSE_MSG(msg) + #define __TBB_DEPRECATED_IN_VERBOSE_MODE + #define __TBB_DEPRECATED_IN_VERBOSE_MODE_MSG(msg) #endif // (TBB_SUPPRESS_DEPRECATED_MESSAGES == 0) #if (!defined(TBB_SUPPRESS_DEPRECATED_MESSAGES) || (TBB_SUPPRESS_DEPRECATED_MESSAGES == 0)) && !__TBB_CPP11_PRESENT diff --git a/include/tbb/tbb_exception.h b/include/tbb/tbb_exception.h index 668ee564d1..3c5fb7dd4c 100644 --- a/include/tbb/tbb_exception.h +++ b/include/tbb/tbb_exception.h @@ -188,7 +188,7 @@ class __TBB_DEPRECATED tbb_exception : public std::exception algorithm ) if an unhandled exception was intercepted during the algorithm execution in one of the workers. \sa tbb::tbb_exception **/ -class __TBB_DEPRECATED captured_exception : public tbb_exception +class __TBB_DEPRECATED_IN_VERBOSE_MODE captured_exception : public tbb_exception { public: captured_exception( const captured_exception& src ) diff --git a/include/tbb/tbb_stddef.h b/include/tbb/tbb_stddef.h index 1523a551e8..aed4d1c4ef 100644 --- a/include/tbb/tbb_stddef.h +++ b/include/tbb/tbb_stddef.h @@ -19,10 +19,10 @@ // Marketing-driven product version #define TBB_VERSION_MAJOR 2020 -#define TBB_VERSION_MINOR 1 +#define TBB_VERSION_MINOR 2 // Engineering-focused interface version -#define TBB_INTERFACE_VERSION 11101 +#define TBB_INTERFACE_VERSION 11102 #define TBB_INTERFACE_VERSION_MAJOR TBB_INTERFACE_VERSION/1000 // The oldest major interface version still supported diff --git a/include/tbb/tbb_thread.h b/include/tbb/tbb_thread.h index 17e87d96d1..48c117113f 100644 --- a/include/tbb/tbb_thread.h +++ b/include/tbb/tbb_thread.h @@ -307,7 +307,7 @@ namespace internal { } // namespace internal; //! Users reference thread class by name tbb_thread -__TBB_DEPRECATED_VERBOSE_MSG("tbb::thread is deprecated, use std::thread") typedef internal::tbb_thread_v3 tbb_thread; +__TBB_DEPRECATED_IN_VERBOSE_MODE_MSG("tbb::thread is deprecated, use std::thread") typedef internal::tbb_thread_v3 tbb_thread; using internal::operator==; using internal::operator!=; @@ -328,11 +328,11 @@ inline void swap( internal::tbb_thread_v3& t1, internal::tbb_thread_v3& t2 ) __ } namespace this_tbb_thread { - __TBB_DEPRECATED_VERBOSE inline tbb_thread::id get_id() { return internal::thread_get_id_v3(); } + __TBB_DEPRECATED_IN_VERBOSE_MODE inline tbb_thread::id get_id() { return internal::thread_get_id_v3(); } //! Offers the operating system the opportunity to schedule another thread. - __TBB_DEPRECATED_VERBOSE inline void yield() { internal::thread_yield_v3(); } + __TBB_DEPRECATED_IN_VERBOSE_MODE inline void yield() { internal::thread_yield_v3(); } //! The current thread blocks at least until the time specified. - __TBB_DEPRECATED_VERBOSE inline void sleep(const tick_count::interval_t &i) { + __TBB_DEPRECATED_IN_VERBOSE_MODE inline void sleep(const tick_count::interval_t &i) { internal::thread_sleep_v3(i); } } // namespace this_tbb_thread diff --git a/src/tbb/arena.cpp b/src/tbb/arena.cpp index 85a14ec400..8e95460b1a 100644 --- a/src/tbb/arena.cpp +++ b/src/tbb/arena.cpp @@ -891,14 +891,14 @@ void task_arena_base::internal_initialize( ) { #endif /*__TBB_TASK_GROUP_CONTEXT*/ #if __TBB_TASK_GROUP_CONTEXT || __TBB_NUMA_SUPPORT } else { -#if __TBB_TASK_GROUP_CONTEXT - new_arena->my_default_ctx->my_version_and_traits |= my_version_and_traits & exact_exception_flag; - as_atomic(my_context) = new_arena->my_default_ctx; -#endif /*__TBB_TASK_GROUP_CONTEXT*/ #if __TBB_NUMA_SUPPORT my_arena->my_numa_binding_observer = tbb::internal::construct_binding_observer( static_cast(this), numa_id(), my_arena->my_num_slots); #endif /*__TBB_NUMA_SUPPORT*/ +#if __TBB_TASK_GROUP_CONTEXT + new_arena->my_default_ctx->my_version_and_traits |= my_version_and_traits & exact_exception_flag; + as_atomic(my_context) = new_arena->my_default_ctx; +#endif /*__TBB_TASK_GROUP_CONTEXT*/ } #endif /*__TBB_TASK_GROUP_CONTEXT || __TBB_NUMA_SUPPORT*/ diff --git a/src/tbb/custom_scheduler.h b/src/tbb/custom_scheduler.h index 12cd460a3f..f43a3862e8 100644 --- a/src/tbb/custom_scheduler.h +++ b/src/tbb/custom_scheduler.h @@ -338,7 +338,12 @@ task* custom_scheduler::receive_or_steal_task( __TBB_ISOLATION_ } } #endif /* __TBB_TASK_PRIORITY */ +#if __APPLE__ + // threshold value tuned separately for macOS due to high cost of sched_yield there + const int yield_threshold = 10; +#else const int yield_threshold = 100; +#endif if( yield_count++ >= yield_threshold ) { // When a worker thread has nothing to do, return it to RML. // For purposes of affinity support, the thread is considered idle while in RML. diff --git a/src/tbb/mailbox.h b/src/tbb/mailbox.h index 588f44da1d..795f01b87e 100644 --- a/src/tbb/mailbox.h +++ b/src/tbb/mailbox.h @@ -87,6 +87,9 @@ class unpadded_mail_outbox { //! Pointer to pointer that will point to next item in the queue. Never NULL. proxy_ptr* __TBB_atomic my_last; + //! Approximate number of tasks in mailbox to prevent an unlimited grow when the owner is not available. + tbb::atomic my_task_count; + //! Owner of mailbox is not executing a task, and has drained its own task pool. bool my_is_idle; }; @@ -94,6 +97,7 @@ class unpadded_mail_outbox { //! Class representing where mail is put. /** Padded to occupy a cache line. */ class mail_outbox : padded { + static const int mailbox_task_limit = 32; task_proxy* internal_pop( __TBB_ISOLATION_EXPR(isolation_tag isolation) ) { task_proxy* curr = __TBB_load_relaxed( my_first ); @@ -129,6 +133,8 @@ class mail_outbox : padded { *prev_ptr = second; } } + --my_task_count; + __TBB_ASSERT( my_task_count >= 0, NULL ); __TBB_ASSERT( curr, NULL ); return curr; } @@ -136,14 +142,19 @@ class mail_outbox : padded { friend class mail_inbox; //! Push task_proxy onto the mailbox queue of another thread. - /** Implementation is wait-free. */ - void push( task_proxy* t ) { + /** Implementation is wait-free. + Returns false if there are too many tasks. */ + bool push( task_proxy* t ) { + if (my_task_count > mailbox_task_limit) + return false; + ++my_task_count; __TBB_ASSERT(t, NULL); t->next_in_mailbox = NULL; proxy_ptr * const link = (proxy_ptr *)__TBB_FetchAndStoreW(&my_last,(intptr_t)&t->next_in_mailbox); // No release fence required for the next store, because there are no memory operations // between the previous fully fenced atomic operation and the store. __TBB_store_relaxed(*link, t); + return true; } //! Return true if mailbox is empty diff --git a/src/tbb/scheduler.cpp b/src/tbb/scheduler.cpp index 35790bcd5d..f98440d4a4 100644 --- a/src/tbb/scheduler.cpp +++ b/src/tbb/scheduler.cpp @@ -623,9 +623,11 @@ inline task* generic_scheduler::prepare_for_spawning( task* t ) { #endif /* __TBB_TASK_PRIORITY */ __TBB_ISOLATION_EXPR( proxy.prefix().isolation = isolation ); ITT_NOTIFY( sync_releasing, proxy.outbox ); - // Mail the proxy - after this point t may be destroyed by another thread at any moment. - proxy.outbox->push(&proxy); - return &proxy; + // Mail the proxy, if success, it may be destroyed by another thread at any moment after this point. + if ( proxy.outbox->push(&proxy) ) + return &proxy; + // The mailbox is overfilled, deallocate the proxy and return the initial task. + free_task(proxy); } return t; } diff --git a/src/tbb/tbb_bind.cpp b/src/tbb/tbb_bind.cpp index aae63edba0..36bd5bce65 100644 --- a/src/tbb/tbb_bind.cpp +++ b/src/tbb/tbb_bind.cpp @@ -42,31 +42,46 @@ namespace internal { class platform_topology { friend class numa_affinity_handler; - static hwloc_topology_t topology; - static hwloc_cpuset_t process_cpu_affinity_mask; - static hwloc_nodeset_t process_node_affinity_mask; - static std::vector affinity_masks_list; - - static std::vector default_concurrency_list; - static std::vector numa_indexes_list; - static int numa_nodes_count; - - enum init_stages { uninitialized, started, topology_allocated, topology_loaded, topology_parsed }; - static init_stages initialization_state; + // TODO: add the `my_` prefix to the members + hwloc_topology_t topology; + hwloc_cpuset_t process_cpu_affinity_mask; + hwloc_nodeset_t process_node_affinity_mask; + std::vector affinity_masks_list; + + std::vector default_concurrency_list; + std::vector numa_indexes_list; + int numa_nodes_count; + + enum init_stages { uninitialized, + started, + topology_allocated, + topology_loaded, + topology_parsed } initialization_state; // Binding threads to NUMA nodes that locates in another Windows Processor groups // is allowed only if machine topology contains several Windows Processors groups // and process affinity mask wasn`t limited manually (affinity mask cannot violates // processors group boundaries). - static bool intergroup_binding_allowed(size_t groups_num) { return groups_num > 1; } + bool intergroup_binding_allowed(size_t groups_num) { return groups_num > 1; } + + platform_topology() : topology(NULL), + process_cpu_affinity_mask(NULL), + process_node_affinity_mask(NULL), + numa_nodes_count(0), + initialization_state(uninitialized) {} public: typedef hwloc_cpuset_t affinity_mask; typedef hwloc_const_cpuset_t const_affinity_mask; - static bool is_topology_parsed() { return initialization_state == topology_parsed; } + static platform_topology& instance() { + static platform_topology topology; + return topology; + } + + bool is_topology_parsed() { return initialization_state == topology_parsed; } - static void initialize( size_t groups_num ) { + void initialize( size_t groups_num ) { if ( initialization_state != uninitialized ) return; initialization_state = started; @@ -172,23 +187,23 @@ class platform_topology { initialization_state = uninitialized; } - static void fill(int& nodes_count, int*& indexes_list, int*& concurrency_list ) { + void fill(int& nodes_count, int*& indexes_list, int*& concurrency_list ) { __TBB_ASSERT(is_topology_parsed(), "Trying to get access to uninitialized platform_topology"); nodes_count = numa_nodes_count; indexes_list = &numa_indexes_list.front(); concurrency_list = &default_concurrency_list.front(); } - static affinity_mask allocate_process_affinity_mask() { + affinity_mask allocate_process_affinity_mask() { __TBB_ASSERT(is_topology_parsed(), "Trying to get access to uninitialized platform_topology"); return hwloc_bitmap_dup(process_cpu_affinity_mask); } - static void free_affinity_mask( affinity_mask mask_to_free ) { + void free_affinity_mask( affinity_mask mask_to_free ) { hwloc_bitmap_free(mask_to_free); // If bitmap is NULL, no operation is performed. } - static void store_current_affinity_mask( affinity_mask current_mask ) { + void store_current_affinity_mask( affinity_mask current_mask ) { assertion_hwloc_wrapper(hwloc_get_cpubind, topology, current_mask, HWLOC_CPUBIND_THREAD); hwloc_bitmap_and(current_mask, current_mask, process_cpu_affinity_mask); @@ -196,28 +211,17 @@ class platform_topology { "Current affinity mask must intersects with process affinity mask"); } - static void set_new_affinity_mask( const_affinity_mask new_mask ) { + void set_new_affinity_mask( const_affinity_mask new_mask ) { assertion_hwloc_wrapper(hwloc_set_cpubind, topology, new_mask, HWLOC_CPUBIND_THREAD); } - static const_affinity_mask get_node_affinity_mask( int node_index ) { + const_affinity_mask get_node_affinity_mask( int node_index ) { __TBB_ASSERT((int)affinity_masks_list.size() > node_index, "Trying to get affinity mask for uninitialized NUMA node"); return affinity_masks_list[node_index]; } }; -hwloc_topology_t platform_topology::topology = NULL; -hwloc_cpuset_t platform_topology::process_cpu_affinity_mask = NULL; -hwloc_nodeset_t platform_topology::process_node_affinity_mask = NULL; -std::vector platform_topology::affinity_masks_list; - -std::vector platform_topology::default_concurrency_list; -std::vector platform_topology::numa_indexes_list; -int platform_topology::numa_nodes_count = 0; - -platform_topology::init_stages platform_topology::initialization_state = uninitialized; - class binding_handler { // Following vector saves thread affinity mask on scheduler entry to return it to this thread // on scheduler exit. @@ -228,32 +232,32 @@ class binding_handler { binding_handler( size_t size ) : affinity_backup(size) { for (affinity_masks_container::iterator it = affinity_backup.begin(); it != affinity_backup.end(); it++) { - *it = platform_topology::allocate_process_affinity_mask(); + *it = platform_topology::instance().allocate_process_affinity_mask(); } } ~binding_handler() { for (affinity_masks_container::iterator it = affinity_backup.begin(); it != affinity_backup.end(); it++) { - platform_topology::free_affinity_mask(*it); + platform_topology::instance().free_affinity_mask(*it); } } void bind_thread_to_node( unsigned slot_num, unsigned numa_node_id ) { __TBB_ASSERT(slot_num < affinity_backup.size(), "The slot number is greater than the number of slots in the arena"); - __TBB_ASSERT(platform_topology::is_topology_parsed(), + __TBB_ASSERT(platform_topology::instance().is_topology_parsed(), "Trying to get access to uninitialized platform_topology"); - platform_topology::store_current_affinity_mask(affinity_backup[slot_num]); + platform_topology::instance().store_current_affinity_mask(affinity_backup[slot_num]); - platform_topology::set_new_affinity_mask( - platform_topology::get_node_affinity_mask(numa_node_id)); + platform_topology::instance().set_new_affinity_mask( + platform_topology::instance().get_node_affinity_mask(numa_node_id)); } void restore_previous_affinity_mask( unsigned slot_num ) { - __TBB_ASSERT(platform_topology::is_topology_parsed(), + __TBB_ASSERT(platform_topology::instance().is_topology_parsed(), "Trying to get access to uninitialized platform_topology"); - platform_topology::set_new_affinity_mask(affinity_backup[slot_num]); + platform_topology::instance().set_new_affinity_mask(affinity_backup[slot_num]); }; }; @@ -262,8 +266,8 @@ extern "C" { // exported to TBB interfaces void initialize_numa_topology( size_t groups_num, int& nodes_count, int*& indexes_list, int*& concurrency_list ) { - platform_topology::initialize(groups_num); - platform_topology::fill(nodes_count, indexes_list, concurrency_list); + platform_topology::instance().initialize(groups_num); + platform_topology::instance().fill(nodes_count, indexes_list, concurrency_list); } binding_handler* allocate_binding_handler(int slot_num) { @@ -278,15 +282,15 @@ void deallocate_binding_handler(binding_handler* handler_ptr) { void bind_to_node(binding_handler* handler_ptr, int slot_num, int numa_id) { __TBB_ASSERT(handler_ptr != NULL, "Trying to get access to uninitialized metadata."); - __TBB_ASSERT(platform_topology::is_topology_parsed(), "Trying to get access " - "to uninitialized platform_topology."); + __TBB_ASSERT(platform_topology::instance().is_topology_parsed(), + "Trying to get access to uninitialized platform_topology."); handler_ptr->bind_thread_to_node(slot_num, numa_id); } void restore_affinity(binding_handler* handler_ptr, int slot_num) { __TBB_ASSERT(handler_ptr != NULL, "Trying to get access to uninitialized metadata."); - __TBB_ASSERT(platform_topology::is_topology_parsed(), "Trying to get access " - "to uninitialized platform_topology."); + __TBB_ASSERT(platform_topology::instance().is_topology_parsed(), + "Trying to get access to uninitialized platform_topology."); handler_ptr->restore_previous_affinity_mask(slot_num); } diff --git a/src/tbbmalloc/proxy.cpp b/src/tbbmalloc/proxy.cpp index 57c81e7ce1..2de5233398 100644 --- a/src/tbbmalloc/proxy.cpp +++ b/src/tbbmalloc/proxy.cpp @@ -146,7 +146,15 @@ static inline void initPageSize() 1) detection that the proxy library is loaded 2) check that dlsym("malloc") found something different from our replacement malloc */ +// Starting from GCC 9, the -Wmissing-attributes warning was extended for alias below +#if __GNUC__ == 9 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wmissing-attributes" +#endif extern "C" void *__TBB_malloc_proxy(size_t) __attribute__ ((alias ("malloc"))); +#if __GNUC__ == 9 + #pragma GCC diagnostic pop +#endif static void *orig_msize; @@ -293,11 +301,20 @@ void *aligned_alloc(size_t alignment, size_t size) __attribute__ ((alias ("memal // in conjunction with standard malloc/free, so we must ovberload them. // Bionic doesn't have them. Not removing from the linker scripts, // as absent entry points are ignored by the linker. + +// Starting from GCC 9, the -Wmissing-attributes warning was extended for aliases below +#if __GNUC__ == 9 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wmissing-attributes" +#endif void *__libc_malloc(size_t size) __attribute__ ((alias ("malloc"))); void *__libc_calloc(size_t num, size_t size) __attribute__ ((alias ("calloc"))); void *__libc_memalign(size_t alignment, size_t size) __attribute__ ((alias ("memalign"))); void *__libc_pvalloc(size_t size) __attribute__ ((alias ("pvalloc"))); void *__libc_valloc(size_t size) __attribute__ ((alias ("valloc"))); +#if __GNUC__ == 9 + #pragma GCC diagnostic pop +#endif // call original __libc_* to support naive replacement of free via __libc_free etc void __libc_free(void *ptr) diff --git a/src/test/harness_graph.h b/src/test/harness_graph.h index 155ae2d34a..ae5e8e537d 100644 --- a/src/test/harness_graph.h +++ b/src/test/harness_graph.h @@ -1226,7 +1226,11 @@ void test_lightweight(unsigned N) { template class NodeType> void test(unsigned N) { typedef tbb::tbb_thread::id input_type; +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR typedef tbb::cache_aligned_allocator allocator_type; +#else + typedef tbb::flow::interface11::null_type allocator_type; +#endif typedef NodeType node_type; test_lightweight(N); } diff --git a/src/test/test_arena_constraints_hwloc.cpp b/src/test/test_arena_constraints_hwloc.cpp index 3bba5e75c0..bffe707ec0 100644 --- a/src/test/test_arena_constraints_hwloc.cpp +++ b/src/test/test_arena_constraints_hwloc.cpp @@ -358,6 +358,7 @@ void test_arena_constraints_copying(std::vector numa_indexes) { } #endif /*__TBB_CPP11_PRESENT*/ +//TODO: Write a test that checks for memory leaks during dynamic link/unlink of TBBbind. int TestMain() { #if _WIN32 && !_WIN64 // HWLOC cannot proceed affinity masks on Windows in 32-bit mode if there are more than 32 logical CPU. diff --git a/src/test/test_async_node.cpp b/src/test/test_async_node.cpp index f73ecc0427..78e0fcb855 100644 --- a/src/test/test_async_node.cpp +++ b/src/test/test_async_node.cpp @@ -14,6 +14,8 @@ limitations under the License. */ +#define TBB_DEPRECATED_FLOW_NODE_ALLOCATOR __TBB_CPF_BUILD + #include "harness.h" #include "harness_graph.h" #include "harness_barrier.h" @@ -819,6 +821,19 @@ void test_follows_and_precedes_api() { } #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR +typedef tbb::flow::async_node< int, int, tbb::flow::queueing, std::allocator > async_node_type; + +struct async_body { + void operator()( const int&, async_node_type::gateway_type& ) {} +}; + +void test_node_allocator() { + tbb::flow::graph g; + async_node_type tmp(g, tbb::flow::unlimited, async_body()); +} +#endif + int TestMain() { tbb::task_scheduler_init init(4); run_tests(); @@ -833,6 +848,9 @@ int TestMain() { run_test_equeueing_on_inner_level(); #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET test_follows_and_precedes_api(); +#endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + test_node_allocator(); #endif return Harness::Done; } diff --git a/src/test/test_buffer_node.cpp b/src/test/test_buffer_node.cpp index 087bb8a23f..0f236bf326 100644 --- a/src/test/test_buffer_node.cpp +++ b/src/test/test_buffer_node.cpp @@ -14,9 +14,8 @@ limitations under the License. */ -#if __TBB_CPF_BUILD -#define TBB_DEPRECATED_FLOW_NODE_EXTRACTION 1 -#endif +#define TBB_DEPRECATED_FLOW_NODE_EXTRACTION __TBB_CPF_BUILD +#define TBB_DEPRECATED_FLOW_NODE_ALLOCATOR __TBB_CPF_BUILD #include "harness.h" #include "harness_graph.h" @@ -459,6 +458,13 @@ void test_deduction_guides() { } #endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR +void test_node_allocator() { + tbb::flow::graph g; + tbb::flow::buffer_node< int, std::allocator > tmp(g); +} +#endif + int TestMain() { tbb::tick_count start = tbb::tick_count::now(), stop; for (int p = 2; p <= 4; ++p) { @@ -470,14 +476,17 @@ int TestMain() { REMARK("Buffer_Node Time=%6.6f\n", (stop-start).seconds()); test_resets >(); test_resets >(); -#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION - test_buffer_extract >().run_tests(); -#endif #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET test_follow_and_precedes_api(); #endif #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT test_deduction_guides(); +#endif +#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION + test_buffer_extract >().run_tests(); +#endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + test_node_allocator(); #endif return Harness::Done; } diff --git a/src/test/test_composite_node.cpp b/src/test/test_composite_node.cpp index e1c648c4f3..e2d80f6099 100644 --- a/src/test/test_composite_node.cpp +++ b/src/test/test_composite_node.cpp @@ -97,7 +97,7 @@ void add_all_nodes (){ //node types tbb::flow::continue_node ct(g, ct_body()); tbb::flow::split_node< tbb::flow::tuple > s(g); - tbb::flow::source_node src(g, src_body(20,5), false); + tbb::flow::input_node src(g, src_body(20,5)); tbb::flow::function_node fxn(g, tbb::flow::unlimited, passthru_body()); tbb::flow::multifunction_node > m_fxn(g, tbb::flow::unlimited, m_fxn_body()); tbb::flow::broadcast_node bc(g); @@ -511,7 +511,7 @@ void input_only_output_only_composite(bool hidden) { #endif typedef tbb::flow::composite_node, tbb::flow::tuple<> > input_only_composite; typedef tbb::flow::composite_node, tbb::flow::tuple > output_only_composite; - typedef tbb::flow::source_node src_type; + typedef tbb::flow::input_node src_type; typedef tbb::flow::queue_node q_type; typedef tbb::flow::function_node f_type; typedef tbb::flow::sequencer_node sequencer_type; @@ -523,7 +523,7 @@ void input_only_output_only_composite(bool hidden) { input_only_composite a_in(g); output_only_composite a_out(g); - src_type src(g, src_body(finish, step), false); + src_type src(g, src_body(finish, step)); q_type que(g); f_type f(g, 1, passthru_body()); diff --git a/src/test/test_eh_flow_graph.cpp b/src/test/test_eh_flow_graph.cpp index 4da0a36cc1..5819570613 100644 --- a/src/test/test_eh_flow_graph.cpp +++ b/src/test/test_eh_flow_graph.cpp @@ -365,7 +365,7 @@ void run_one_source_node_test(bool throwException, bool flog) { o.observe(true); #endif - tbb::flow::source_node sn(g, src_body_type(source_body_count),/*is_active*/false); + tbb::flow::input_node sn(g, src_body_type(source_body_count)); parallel_absorb_body_type ab2(absorber_body_count); tbb::flow::function_node parallel_fn(g,tbb::flow::unlimited,ab2); make_edge(sn, parallel_fn); @@ -390,29 +390,29 @@ void run_one_source_node_test(bool throwException, bool flog) { if(throwException) { ASSERT(g.exception_thrown() || okayNoExceptionsCaught, "Exception flag in flow::graph not set"); ASSERT(g.is_cancelled() || okayNoExceptionsCaught, "canceled flag not set"); - ASSERT(src_cnt <= g_NumItems, "Too many source_node items emitted"); - ASSERT(sink_cnt <= src_cnt, "Too many source_node items received"); + ASSERT(src_cnt <= g_NumItems, "Too many input_node items emitted"); + ASSERT(sink_cnt <= src_cnt, "Too many input_node items received"); } else { ASSERT(!g.exception_thrown(), "Exception flag in flow::graph set but no throw occurred"); ASSERT(!g.is_cancelled(), "canceled flag set but no throw occurred"); - ASSERT(src_cnt == g_NumItems, "Incorrect # source_node items emitted"); - ASSERT(sink_cnt == src_cnt, "Incorrect # source_node items received"); + ASSERT(src_cnt == g_NumItems, "Incorrect # input_node items emitted"); + ASSERT(sink_cnt == src_cnt, "Incorrect # input_node items received"); } - g.reset(); // resets the body of the source_node and the absorb_nodes. + g.reset(); // resets the body of the input_node and the absorb_nodes. source_body_count = 0; absorber_body_count = 0; ASSERT(!g.exception_thrown(), "Reset didn't clear exception_thrown()"); ASSERT(!g.is_cancelled(), "Reset didn't clear is_cancelled()"); src_cnt = tbb::flow::copy_body(sn).count_value(); sink_cnt = tbb::flow::copy_body(parallel_fn).count_value(); - ASSERT(src_cnt == 0, "source_node count not reset"); + ASSERT(src_cnt == 0, "input_node count not reset"); ASSERT(sink_cnt == 0, "sink_node count not reset"); } #if USE_TASK_SCHEDULER_OBSERVER o.observe(false); #endif -} // run_one_source_node_test +} // run_one_input_node_test template @@ -500,8 +500,8 @@ run_one_functype_node_test(bool throwException, bool flog, const char * /*name*/ #endif g_Master = Harness::CurrentTid(); - SourceNodeType source0(g, SourceNodeBodyType0(source0_count),/*is_active*/false); - SourceNodeType source1(g, SourceNodeBodyType1(source1_count),/*is_active*/false); + SourceNodeType source0(g, SourceNodeBodyType0(source0_count)); + SourceNodeType source1(g, SourceNodeBodyType1(source1_count)); TestNodeType node_to_test(g, Conc, TestNodeBodyType(test_count)); SinkNodeType0 sink0(g,tbb::flow::unlimited,SinkNodeBodyType0(sink0_count)); SinkNodeType1 sink1(g,tbb::flow::unlimited,SinkNodeBodyType1(sink1_count)); @@ -545,11 +545,11 @@ run_one_functype_node_test(bool throwException, bool flog, const char * /*name*/ else { ASSERT(!g.exception_thrown(), "Exception flag in flow::graph set but no throw occurred"); ASSERT(!g.is_cancelled(), "canceled flag set but no throw occurred"); - ASSERT(sb0_cnt + sb1_cnt == 2*g_NumItems, "Missing invocations of source_nodes"); + ASSERT(sb0_cnt + sb1_cnt == 2*g_NumItems, "Missing invocations of input_nodes"); ASSERT(t_cnt == 2*g_NumItems, "Not all items reached test node"); ASSERT(nb0_cnt == 2*g_NumItems && nb1_cnt == 2*g_NumItems, "Missing items in absorbers"); } - g.reset(); // resets the body of the source_nodes, test_node and the absorb_nodes. + g.reset(); // resets the body of the input_nodes, test_node and the absorb_nodes. source0_count = source1_count = sink0_count = sink1_count = test_count = 0; ASSERT(0 == tbb::flow::copy_body(source0).count_value(),"Reset source 0 failed"); ASSERT(0 == tbb::flow::copy_body(source1).count_value(),"Reset source 1 failed"); @@ -568,11 +568,11 @@ run_one_functype_node_test(bool throwException, bool flog, const char * /*name*/ // // graph being tested is // -// source_node -\ /- parallel function_node +// input_node -\ /- parallel function_node // \ / // +function_node+ // / \ x -// source_node -/ \- parallel function_node +// input_node -/ \- parallel function_node // // After each run the graph is reset(), to test the reset functionality. // @@ -595,7 +595,7 @@ void run_function_node_test() { typedef absorber_body SinkBodyType1; typedef absorber_body SinkBodyType2; - typedef tbb::flow::source_node SrcType; + typedef tbb::flow::input_node SrcType; typedef tbb::flow::function_node TestType; typedef tbb::flow::function_node SnkType; @@ -670,11 +670,11 @@ void test_function_node() { // // graph being tested is // -// source_node -\ /- parallel function_node +// input_node -\ /- parallel function_node // \ / // +multifunction_node+ // / \ x -// source_node -/ \- parallel function_node +// input_node -/ \- parallel function_node // // After each run the graph is reset(), to test the reset functionality. The // multifunction_node will put an item to each successor for every item @@ -701,7 +701,7 @@ void run_multifunction_node_test() { typedef absorber_body SinkBodyType1; typedef absorber_body SinkBodyType2; - typedef tbb::flow::source_node SrcType; + typedef tbb::flow::input_node SrcType; typedef tbb::flow::multifunction_node TestType; typedef tbb::flow::function_node SnkType0; typedef tbb::flow::function_node SnkType1; @@ -782,7 +782,7 @@ void test_multifunction_node() { // // +broadcast_node+ // / \ ___ -// source_node+------>+broadcast_node+ +continue_node+--->+absorber +// input_node+------>+broadcast_node+ +continue_node+--->+absorber // \ / // +broadcast_node+ // @@ -805,7 +805,7 @@ void run_one_continue_node_test (bool throwException, bool flog) { o.observe(true); #endif g_Master = Harness::CurrentTid(); - SourceNodeType source(g, SourceNodeBodyType(source_count),/*is_active*/false); + SourceNodeType source(g, SourceNodeBodyType(source_count)); TTestNodeType node_to_test(g, TestNodeBodyType(test_count)); SinkNodeType sink(g,tbb::flow::unlimited,SinkNodeBodyType(sink_count)); tbb::flow::broadcast_node b1(g), b2(g), b3(g); @@ -843,11 +843,11 @@ void run_one_continue_node_test (bool throwException, bool flog) { else { ASSERT(!g.exception_thrown(), "Exception flag in flow::graph set but no throw occurred"); ASSERT(!g.is_cancelled(), "canceled flag set but no throw occurred"); - ASSERT(sb_cnt == g_NumItems, "Missing invocations of source_node"); + ASSERT(sb_cnt == g_NumItems, "Missing invocations of input_node"); ASSERT(t_cnt == g_NumItems, "Not all items reached test node"); ASSERT(nb_cnt == g_NumItems, "Missing items in absorbers"); } - g.reset(); // resets the body of the source_nodes, test_node and the absorb_nodes. + g.reset(); // resets the body of the input_nodes, test_node and the absorb_nodes. source_count = test_count = sink_count = 0; ASSERT(0 == (int)test_count, "Atomic wasn't reset properly"); ASSERT(0 == tbb::flow::copy_body(source).count_value(),"Reset source failed"); @@ -869,7 +869,7 @@ void run_continue_node_test() { typedef absorber_body ContBodyType; typedef absorber_body SinkBodyType; - typedef tbb::flow::source_node SrcType; + typedef tbb::flow::input_node SrcType; typedef tbb::flow::continue_node TestType; typedef tbb::flow::function_node SnkType; @@ -925,7 +925,7 @@ void run_one_buffer_node_test(bool throwException,bool flog) { o.observe(true); #endif g_Master = Harness::CurrentTid(); - SourceNodeType source(g, SourceNodeBodyType(source_count),/*is_active*/false); + SourceNodeType source(g, SourceNodeBodyType(source_count)); TestNodeType node_to_test(g); SinkNodeType sink(g,tbb::flow::unlimited,SinkNodeBodyType(sink_count)); make_edge(source,node_to_test); @@ -956,7 +956,7 @@ void run_one_buffer_node_test(bool throwException,bool flog) { else { ASSERT(!g.exception_thrown(), "Exception flag in flow::graph set but no throw occurred"); ASSERT(!g.is_cancelled(), "canceled flag set but no throw occurred"); - ASSERT(sb_cnt == g_NumItems, "Missing invocations of source_node"); + ASSERT(sb_cnt == g_NumItems, "Missing invocations of input_node"); ASSERT(nb_cnt == g_NumItems, "Missing items in absorbers"); } if(iter == 0) { @@ -989,7 +989,7 @@ void run_buffer_queue_and_overwrite_node_test() { typedef test_source_body SourceBodyType; typedef absorber_body SinkBodyType; - typedef tbb::flow::source_node SrcType; + typedef tbb::flow::input_node SrcType; typedef tbb::flow::buffer_node BufType; typedef tbb::flow::queue_node QueType; typedef tbb::flow::overwrite_node OvrType; @@ -1065,7 +1065,7 @@ void run_one_sequencer_node_test(bool throwException,bool flog) { o.observe(true); #endif g_Master = Harness::CurrentTid(); - SourceNodeType source(g, SourceNodeBodyType(source_count),/*is_active*/false); + SourceNodeType source(g, SourceNodeBodyType(source_count)); TestNodeType node_to_test(g,SeqBodyType()); SinkNodeType sink(g,tbb::flow::unlimited,SinkNodeBodyType(sink_count)); make_edge(source,node_to_test); @@ -1096,7 +1096,7 @@ void run_one_sequencer_node_test(bool throwException,bool flog) { else { ASSERT(!g.exception_thrown(), "Exception flag in flow::graph set but no throw occurred"); ASSERT(!g.is_cancelled(), "canceled flag set but no throw occurred"); - ASSERT(sb_cnt == g_NumItems, "Missing invocations of source_node"); + ASSERT(sb_cnt == g_NumItems, "Missing invocations of input_node"); ASSERT(nb_cnt == g_NumItems, "Missing items in absorbers"); } if(iter == 0) { @@ -1130,7 +1130,7 @@ void run_sequencer_node_test() { typedef absorber_body SinkBodyType; typedef sequencer_body SeqBodyType; - typedef tbb::flow::source_node SrcType; + typedef tbb::flow::input_node SrcType; typedef tbb::flow::sequencer_node SeqType; typedef tbb::flow::function_node SnkType; @@ -1185,7 +1185,7 @@ void run_one_priority_queue_node_test(bool throwException,bool flog) { o.observe(true); #endif g_Master = Harness::CurrentTid(); - SourceNodeType source(g, SourceNodeBodyType(source_count),/*is_active*/false); + SourceNodeType source(g, SourceNodeBodyType(source_count)); TestNodeType node_to_test(g); @@ -1219,7 +1219,7 @@ void run_one_priority_queue_node_test(bool throwException,bool flog) { else { ASSERT(!g.exception_thrown(), "Exception flag in flow::graph set but no throw occurred"); ASSERT(!g.is_cancelled(), "canceled flag set but no throw occurred"); - ASSERT(sb_cnt == g_NumItems, "Missing invocations of source_node"); + ASSERT(sb_cnt == g_NumItems, "Missing invocations of input_node"); ASSERT(nb_cnt == g_NumItems, "Missing items in absorbers"); } if(iter == 0) { @@ -1254,7 +1254,7 @@ void run_priority_queue_node_test() { typedef absorber_body SinkBodyType; typedef less_body LessBodyType; - typedef tbb::flow::source_node SrcType; + typedef tbb::flow::input_node SrcType; typedef tbb::flow::priority_queue_node PrqType; typedef tbb::flow::function_node SnkType; @@ -1328,8 +1328,8 @@ struct run_one_join_node_test { o.observe(true); #endif g_Master = Harness::CurrentTid(); - SourceType0 source0(g, SourceBodyType0(source0_count),/*is_active*/false); - SourceType1 source1(g, SourceBodyType1(source1_count),/*is_active*/false); + SourceType0 source0(g, SourceBodyType0(source0_count)); + SourceType1 source1(g, SourceBodyType1(source1_count)); TestJoinType node_to_test(g); SinkType sink(g,tbb::flow::unlimited,SinkBodyType(sink_count)); make_edge(source0,tbb::flow::input_port<0>(node_to_test)); @@ -1370,8 +1370,8 @@ struct run_one_join_node_test { REMARK("sb0_cnt == %d\n", (int)sb0_cnt); REMARK("g_NumItems == %d\n", (int)g_NumItems); } - ASSERT(sb0_cnt == g_NumItems, "Missing invocations of source_node0"); // this one - ASSERT(sb1_cnt == g_NumItems, "Missing invocations of source_node1"); + ASSERT(sb0_cnt == g_NumItems, "Missing invocations of input_node0"); // this one + ASSERT(sb1_cnt == g_NumItems, "Missing invocations of input_node1"); ASSERT(nb_cnt == g_NumItems, "Missing items in absorbers"); } if(iter == 0) { @@ -1438,8 +1438,8 @@ struct run_one_join_node_test< o.observe(true); #endif g_Master = Harness::CurrentTid(); - SourceType0 source0(g, SourceBodyType0(source0_count, 2),/*is_active*/false); - SourceType1 source1(g, SourceBodyType1(source1_count, 3),/*is_active*/false); + SourceType0 source0(g, SourceBodyType0(source0_count, 2)); + SourceType1 source1(g, SourceBodyType1(source1_count, 3)); TestJoinType node_to_test(g, tag_func(ItemType0(2)), tag_func(ItemType1(3))); SinkType sink(g,tbb::flow::unlimited,SinkBodyType(sink_count)); make_edge(source0,tbb::flow::input_port<0>(node_to_test)); @@ -1474,8 +1474,8 @@ struct run_one_join_node_test< else { ASSERT(!g.exception_thrown(), "Exception flag in flow::graph set but no throw occurred"); ASSERT(!g.is_cancelled(), "canceled flag set but no throw occurred"); - ASSERT(sb0_cnt == g_NumItems, "Missing invocations of source_node0"); - ASSERT(sb1_cnt == g_NumItems, "Missing invocations of source_node1"); + ASSERT(sb0_cnt == g_NumItems, "Missing invocations of input_node0"); + ASSERT(sb1_cnt == g_NumItems, "Missing invocations of input_node1"); ASSERT(nb_cnt == g_NumItems, "Missing items in absorbers"); } if(iter == 0) { @@ -1483,7 +1483,7 @@ struct run_one_join_node_test< tbb::flow::input_port<0>(node_to_test).try_put(ItemType0(g_NumItems + 4)); tbb::flow::input_port<1>(node_to_test).try_put(ItemType1(g_NumItems + 2)); g.wait_for_all(); // have to wait for the graph to stop again.... - g.reset(); // resets the body of the source_nodes, test_node and the absorb_nodes. + g.reset(); // resets the body of the input_nodes, test_node and the absorb_nodes. source0_count = source1_count = sink_count = 0; make_edge(node_to_test, sink); g.wait_for_all(); // have to wait for the graph to stop again.... @@ -1515,8 +1515,8 @@ void run_join_node_test() { typedef test_source_body SourceBodyType1; typedef absorber_body SinkBodyType; - typedef typename tbb::flow::source_node SourceType0; - typedef typename tbb::flow::source_node SourceType1; + typedef typename tbb::flow::input_node SourceType0; + typedef typename tbb::flow::input_node SourceType1; typedef typename tbb::flow::join_node TestJoinType; typedef typename tbb::flow::function_node SinkType; @@ -1572,7 +1572,7 @@ void run_one_limiter_node_test(bool throwException,bool flog) { o.observe(true); #endif g_Master = Harness::CurrentTid(); - SourceNodeType source(g, SourceNodeBodyType(source_count),/*is_active*/false); + SourceNodeType source(g, SourceNodeBodyType(source_count)); TestNodeType node_to_test(g,g_NumThreads + 1); SinkNodeType sink(g,tbb::flow::unlimited,SinkNodeBodyType(sink_count)); make_edge(source,node_to_test); @@ -1603,9 +1603,9 @@ void run_one_limiter_node_test(bool throwException,bool flog) { else { ASSERT(!g.exception_thrown(), "Exception flag in flow::graph set but no throw occurred"); ASSERT(!g.is_cancelled(), "canceled flag set but no throw occurred"); - // we stop after limiter's limit, which is g_NumThreads + 1. The source_node + // we stop after limiter's limit, which is g_NumThreads + 1. The input_node // is invoked one extra time, filling its buffer, so its limit is g_NumThreads + 2. - ASSERT(sb_cnt == g_NumThreads + 2, "Missing invocations of source_node"); + ASSERT(sb_cnt == g_NumThreads + 2, "Missing invocations of input_node"); ASSERT(nb_cnt == g_NumThreads + 1, "Missing items in absorbers"); } if(iter == 0) { @@ -1640,7 +1640,7 @@ void run_limiter_node_test() { typedef test_source_body SourceBodyType; typedef absorber_body SinkBodyType; - typedef tbb::flow::source_node SrcType; + typedef tbb::flow::input_node SrcType; typedef tbb::flow::limiter_node LmtType; typedef tbb::flow::function_node SnkType; @@ -1695,7 +1695,7 @@ void run_one_split_node_test(bool throwException, bool flog) { #endif g_Master = Harness::CurrentTid(); - SourceType source(g, SourceBodyType(source_count),/*is_active*/false); + SourceType source(g, SourceBodyType(source_count)); TestSplitType node_to_test(g); SinkType0 sink0(g,tbb::flow::unlimited,SinkBodyType0(sink0_count)); SinkType1 sink1(g,tbb::flow::unlimited,SinkBodyType1(sink1_count)); @@ -1730,10 +1730,10 @@ void run_one_split_node_test(bool throwException, bool flog) { else { ASSERT(!g.exception_thrown(), "Exception flag in flow::graph set but no throw occurred"); ASSERT(!g.is_cancelled(), "canceled flag set but no throw occurred"); - ASSERT(sb_cnt == g_NumItems, "Missing invocations of source_nodes"); + ASSERT(sb_cnt == g_NumItems, "Missing invocations of input_nodes"); ASSERT(nb0_cnt == g_NumItems && nb1_cnt == g_NumItems, "Missing items in absorbers"); } - g.reset(); // resets the body of the source_nodes and the absorb_nodes. + g.reset(); // resets the body of the input_nodes and the absorb_nodes. source_count = sink0_count = sink1_count = 0; ASSERT(0 == tbb::flow::copy_body(source).count_value(),"Reset source failed"); ASSERT(0 == tbb::flow::copy_body(sink0).count_value(),"Reset sink 0 failed"); @@ -1754,7 +1754,7 @@ void run_split_node_test() { typedef absorber_body SinkBodyType0; typedef absorber_body SinkBodyType1; - typedef typename tbb::flow::source_node SourceType; + typedef typename tbb::flow::input_node SourceType; typedef typename tbb::flow::split_node TestSplitType; typedef typename tbb::flow::function_node SinkType0; typedef typename tbb::flow::function_node SinkType1; @@ -1812,8 +1812,8 @@ void run_one_indexer_node_test(bool throwException,bool flog) { o.observe(true); #endif g_Master = Harness::CurrentTid(); - SourceType0 source0(g, SourceBodyType0(source0_count),/*is_active*/false); - SourceType1 source1(g, SourceBodyType1(source1_count),/*is_active*/false); + SourceType0 source0(g, SourceBodyType0(source0_count)); + SourceType1 source1(g, SourceBodyType1(source1_count)); TestNodeType node_to_test(g); SinkType sink(g,tbb::flow::unlimited,SinkBodyType(sink_count)); make_edge(source0,tbb::flow::input_port<0>(node_to_test)); @@ -1848,8 +1848,8 @@ void run_one_indexer_node_test(bool throwException,bool flog) { else { ASSERT(!g.exception_thrown(), "Exception flag in flow::graph set but no throw occurred"); ASSERT(!g.is_cancelled(), "canceled flag set but no throw occurred"); - ASSERT(sb0_cnt == g_NumItems, "Missing invocations of source_node0"); - ASSERT(sb1_cnt == g_NumItems, "Missing invocations of source_node1"); + ASSERT(sb0_cnt == g_NumItems, "Missing invocations of input_node0"); + ASSERT(sb1_cnt == g_NumItems, "Missing invocations of input_node1"); ASSERT(nb_cnt == 2*g_NumItems, "Missing items in absorbers"); } if(iter == 0) { @@ -1889,8 +1889,8 @@ void run_indexer_node_test() { typedef typename tbb::flow::indexer_node TestNodeType; typedef absorber_body SinkBodyType; - typedef typename tbb::flow::source_node SourceType0; - typedef typename tbb::flow::source_node SourceType1; + typedef typename tbb::flow::input_node SourceType0; + typedef typename tbb::flow::input_node SourceType1; typedef typename tbb::flow::function_node SinkType; for(int i = 0; i < 4; ++i) { diff --git a/src/test/test_flow_graph.cpp b/src/test/test_flow_graph.cpp index 45fcf8d672..99516aab9b 100644 --- a/src/test/test_flow_graph.cpp +++ b/src/test/test_flow_graph.cpp @@ -283,7 +283,7 @@ struct nodes_test_functor : tbb::internal::no_assign { // Continue, function, source nodes tbb::flow::continue_node< tbb::flow::continue_msg > c_n(my_graph, function_body(fg_arena)); tbb::flow::function_node< int > f_n(my_graph, tbb::flow::unlimited, function_body(fg_arena)); - tbb::flow::source_node< int > s_n(my_graph, source_body(fg_arena), false); + tbb::flow::input_node< int > s_n(my_graph, source_body(fg_arena)); // Multifunction node mf_node m_n(my_graph, tbb::flow::unlimited, multifunction_body(fg_arena)); diff --git a/src/test/test_flow_graph_priorities.cpp b/src/test/test_flow_graph_priorities.cpp index 9763eb13a0..c5f5e9621f 100644 --- a/src/test/test_flow_graph_priorities.cpp +++ b/src/test/test_flow_graph_priorities.cpp @@ -306,7 +306,7 @@ void test( int num_threads ) { AsyncActivity activity(barrier); graph g; - source_node starter_node(g, StartBody(), false); + input_node starter_node(g, StartBody()); function_node cpu_work_node( g, unlimited, CpuWorkBody(barrier, nested_cpu_tasks)); decider_node_type cpu_restarter_node(g, unlimited, DeciderBody(cpu_subgraph_reruns)); diff --git a/src/test/test_flow_graph_whitebox.cpp b/src/test/test_flow_graph_whitebox.cpp index b0ffee8039..5e991be845 100644 --- a/src/test/test_flow_graph_whitebox.cpp +++ b/src/test/test_flow_graph_whitebox.cpp @@ -643,8 +643,8 @@ struct snode_body { void TestSourceNode() { tbb::flow::graph g; - tbb::flow::source_node sn(g, snode_body(4), false); - REMARK("Testing source_node:"); + tbb::flow::input_node sn(g, snode_body(4)); + REMARK("Testing input_node:"); tbb::flow::queue_node qin(g); tbb::flow::join_node, tbb::flow::reserving> jn(g); tbb::flow::queue_node > qout(g); @@ -672,8 +672,8 @@ TestSourceNode() { g.wait_for_all(); g.reset(); - ASSERT(!sn.my_successors.empty(), "source_node has no successors after reset"); - ASSERT(tbb::flow::input_port<0>(jn).my_predecessors.empty(), "successor if source_node has pred after reset."); + ASSERT(!sn.my_successors.empty(), "input_node has no successors after reset"); + ASSERT(tbb::flow::input_port<0>(jn).my_predecessors.empty(), "successor of input_node has pred after reset."); REMARK(" done\n"); } diff --git a/src/test/test_function_node.cpp b/src/test/test_function_node.cpp index 4f039c21e1..b04719a9e3 100644 --- a/src/test/test_function_node.cpp +++ b/src/test/test_function_node.cpp @@ -14,9 +14,8 @@ limitations under the License. */ -#if __TBB_CPF_BUILD -#define TBB_DEPRECATED_FLOW_NODE_EXTRACTION 1 -#endif +#define TBB_DEPRECATED_FLOW_NODE_EXTRACTION __TBB_CPF_BUILD +#define TBB_DEPRECATED_FLOW_NODE_ALLOCATOR __TBB_CPF_BUILD #include "harness.h" #include "harness_graph.h" @@ -650,6 +649,15 @@ void test_deduction_guides() { #endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR +void test_node_allocator(){ + tbb::flow::graph g; + tbb::flow::function_node< int, int, tbb::flow::queueing, std::allocator > tmp( + g, tbb::flow::unlimited, pass_through() + ); +} +#endif + int TestMain() { if( MinThread<1 ) { REPORT("number of threads must be positive\n"); @@ -659,15 +667,18 @@ int TestMain() { test_concurrency(p); } lightweight_testing::test(10); -#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION - test_extract(); - test_extract(); -#endif #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET test_follows_and_precedes_api(); #endif #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT test_deduction_guides(); +#endif +#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION + test_extract(); + test_extract(); +#endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + test_node_allocator(); #endif return Harness::Done; } diff --git a/src/test/test_indexer_node.cpp b/src/test/test_indexer_node.cpp index 9320ecdf5d..c9c4317b53 100644 --- a/src/test/test_indexer_node.cpp +++ b/src/test/test_indexer_node.cpp @@ -456,7 +456,7 @@ class source_node_helper { typedef INT indexer_node_type; typedef typename indexer_node_type::output_type TT; typedef typename tbb::flow::tuple_element::type IT; - typedef typename tbb::flow::source_node my_source_node_type; + typedef typename tbb::flow::input_node my_source_node_type; static void print_remark() { source_node_helper::print_remark(); REMARK(", %s", name_of::name()); @@ -469,6 +469,7 @@ class source_node_helper { ASSERT(new_node->successor_count() == 1, NULL); #endif all_source_nodes[ELEM-1][i] = (void *)new_node; + new_node->activate(); } #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION ASSERT(tbb::flow::input_port(my_indexer).predecessor_count() == (size_t)nInputs, NULL); @@ -504,7 +505,7 @@ class source_node_helper<1, INT> { typedef INT indexer_node_type; typedef typename indexer_node_type::output_type TT; typedef typename tbb::flow::tuple_element<0, typename INT::tuple_types>::type IT; - typedef typename tbb::flow::source_node my_source_node_type; + typedef typename tbb::flow::input_node my_source_node_type; public: static void print_remark() { REMARK("Parallel test of indexer_node< %s", name_of::name()); @@ -514,6 +515,7 @@ class source_node_helper<1, INT> { my_source_node_type *new_node = new my_source_node_type(g, source_body((IT)2, i, nInputs)); tbb::flow::make_edge(*new_node, tbb::flow::input_port<0>(my_indexer)); all_source_nodes[0][i] = (void *)new_node; + new_node->activate(); } } static void check_value(TT &v) { diff --git a/src/test/test_input_node.cpp b/src/test/test_input_node.cpp new file mode 100644 index 0000000000..25ea789d44 --- /dev/null +++ b/src/test/test_input_node.cpp @@ -0,0 +1,357 @@ +/* + Copyright (c) 2020 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. +*/ + +// have to expose the reset_node method to be able to reset a function_body + +#include "harness.h" + +#include "harness_graph.h" +#include "tbb/flow_graph.h" +#include "tbb/task.h" +#include "tbb/task_scheduler_init.h" + +const int N = 1000; + +template< typename T > +class test_push_receiver : public tbb::flow::receiver, NoAssign { + + tbb::atomic my_counters[N]; + tbb::flow::graph& my_graph; + +public: + + test_push_receiver(tbb::flow::graph& g) : my_graph(g) { + for (int i = 0; i < N; ++i ) + my_counters[i] = 0; + } + + int get_count( int i ) { + int v = my_counters[i]; + return v; + } + + typedef typename tbb::flow::receiver::predecessor_type predecessor_type; + +#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION + typedef typename tbb::flow::receiver::built_predecessors_type built_predecessors_type; + typedef typename tbb::flow::receiver::predecessor_list_type predecessor_list_type; + built_predecessors_type bpt; + built_predecessors_type &built_predecessors() __TBB_override { return bpt; } + void internal_add_built_predecessor( predecessor_type & ) __TBB_override { } + void internal_delete_built_predecessor( predecessor_type & ) __TBB_override { } + void copy_predecessors( predecessor_list_type & ) __TBB_override { } + size_t predecessor_count() __TBB_override { return 0; } +#endif + + tbb::task *try_put_task( const T &v ) __TBB_override { + int i = (int)v; + ++my_counters[i]; + return const_cast(SUCCESSFULLY_ENQUEUED); + } + + tbb::flow::graph& graph_reference() const __TBB_override { + return my_graph; + } + + void reset_receiver(tbb::flow::reset_flags /*f*/) __TBB_override {} +}; + +template< typename T > +class source_body { + + unsigned my_count; + int *ninvocations; + +public: + + source_body() : ninvocations(NULL) { my_count = 0; } + source_body(int &_inv) : ninvocations(&_inv) { my_count = 0; } + + bool operator()( T &v ) { + v = (T)my_count++; + if(ninvocations) ++(*ninvocations); + if ( (int)v < N ) + return true; + else + return false; + } + +}; + +template< typename T > +class function_body { + + tbb::atomic *my_counters; + +public: + + function_body( tbb::atomic *counters ) : my_counters(counters) { + for (int i = 0; i < N; ++i ) + my_counters[i] = 0; + } + + bool operator()( T v ) { + ++my_counters[(int)v]; + return true; + } + +}; + +template< typename T > +void test_single_dest() { + + // push only + tbb::flow::graph g; + tbb::flow::input_node src(g, source_body() ); + test_push_receiver dest(g); + tbb::flow::make_edge( src, dest ); + src.activate(); + g.wait_for_all(); + for (int i = 0; i < N; ++i ) { + ASSERT( dest.get_count(i) == 1, NULL ); + } + + // push only + tbb::atomic counters3[N]; + tbb::flow::input_node src3(g, source_body() ); + + function_body b3( counters3 ); + tbb::flow::function_node dest3(g, tbb::flow::unlimited, b3 ); + tbb::flow::make_edge( src3, dest3 ); + src3.activate(); + g.wait_for_all(); + for (int i = 0; i < N; ++i ) { + int v = counters3[i]; + ASSERT( v == 1, NULL ); + } + + // push & pull + tbb::flow::input_node src2(g, source_body() ); + tbb::atomic counters2[N]; + function_body b2( counters2 ); + tbb::flow::function_node dest2(g, tbb::flow::serial, b2 ); + tbb::flow::make_edge( src2, dest2 ); + src2.activate(); + g.wait_for_all(); + for (int i = 0; i < N; ++i ) { + int v = counters2[i]; + ASSERT( v == 1, NULL ); + } + + // test copy constructor + tbb::flow::input_node src_copy(src); + test_push_receiver dest_c(g); + ASSERT( src_copy.register_successor(dest_c), NULL ); + src_copy.activate(); + g.wait_for_all(); + for (int i = 0; i < N; ++i ) { + ASSERT( dest_c.get_count(i) == 1, NULL ); + } +} + +void test_reset() { + // source_node -> function_node + tbb::flow::graph g; + tbb::atomic counters3[N]; + tbb::flow::input_node src3(g, source_body() ); + tbb::flow::input_node src_inactive(g, source_body()); + function_body b3( counters3 ); + tbb::flow::function_node dest3(g, tbb::flow::unlimited, b3 ); + tbb::flow::make_edge( src3, dest3 ); + src3.activate(); + // source_node is now in active state. Let the graph run, + g.wait_for_all(); + // check the array for each value. + for (int i = 0; i < N; ++i ) { + int v = counters3[i]; + ASSERT( v == 1, NULL ); + counters3[i] = 0; + } + + g.reset(tbb::flow::rf_reset_bodies); // <-- re-initializes the counts. + // and spawns task to run source + src3.activate(); + + g.wait_for_all(); + // check output queue again. Should be the same contents. + for (int i = 0; i < N; ++i ) { + int v = counters3[i]; + ASSERT( v == 1, NULL ); + counters3[i] = 0; + } + g.reset(); // doesn't reset the source_node_body to initial state, but does spawn a task + // to run the source_node. + + g.wait_for_all(); + // array should be all zero + for (int i = 0; i < N; ++i ) { + int v = counters3[i]; + ASSERT( v == 0, NULL ); + } + + remove_edge(src3, dest3); + make_edge(src_inactive, dest3); + + // src_inactive doesn't run + g.wait_for_all(); + for (int i = 0; i < N; ++i ) { + int v = counters3[i]; + ASSERT( v == 0, NULL ); + } + + // run graph + src_inactive.activate(); + g.wait_for_all(); + // check output + for (int i = 0; i < N; ++i ) { + int v = counters3[i]; + ASSERT( v == 1, NULL ); + counters3[i] = 0; + } + g.reset(tbb::flow::rf_reset_bodies); // <-- reinitializes the counts + // src_inactive doesn't run + g.wait_for_all(); + for (int i = 0; i < N; ++i ) { + int v = counters3[i]; + ASSERT( v == 0, NULL ); + } + + // start it up + src_inactive.activate(); + g.wait_for_all(); + for (int i = 0; i < N; ++i ) { + int v = counters3[i]; + ASSERT( v == 1, NULL ); + counters3[i] = 0; + } + g.reset(); // doesn't reset the source_node_body to initial state, and doesn't + // spawn a task to run the source_node. + + g.wait_for_all(); + // array should be all zero + for (int i = 0; i < N; ++i ) { + int v = counters3[i]; + ASSERT( v == 0, NULL ); + } + src_inactive.activate(); + // source_node_body is already in final state, so source_node will not forward a message. + g.wait_for_all(); + for (int i = 0; i < N; ++i ) { + int v = counters3[i]; + ASSERT( v == 0, NULL ); + } +} + +#if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT +bool source_body_f(int& i) { return i > 5; } + +void test_deduction_guides() { + using namespace tbb::flow; + graph g; + + auto lambda = [](int& i) { return i > 5; }; + auto non_const_lambda = [](int& i) mutable { return i > 5; }; + + // Tests for source_node(graph&, Body) + input_node s1(g, lambda); + static_assert(std::is_same_v>); + + input_node s2(g, non_const_lambda); + static_assert(std::is_same_v>); + + input_node s3(g, source_body_f); + static_assert(std::is_same_v>); + + input_node s4(s3); + static_assert(std::is_same_v>); + +#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET + broadcast_node bc(g); + + // Tests for source_node(const node_set&, Body) + input_node s5(precedes(bc), lambda); + static_assert(std::is_same_v>); + + input_node s6(precedes(bc), non_const_lambda); + static_assert(std::is_same_v>); + + input_node s7(precedes(bc), source_body_f); + static_assert(std::is_same_v>); +#endif + g.wait_for_all(); +} + +#endif // __TBB_CPP17_DEDUCTION_GUIDES_PRESENT + +#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET +#include +void test_follows_and_precedes_api() { + using namespace tbb::flow; + + graph g; + + std::array, 3> successors {{ + buffer_node(g), + buffer_node(g), + buffer_node(g) + }}; + + bool do_try_put = true; + input_node src(precedes(successors[0], successors[1], successors[2]), [&](bool& v) -> bool { + if(do_try_put) { + v = do_try_put; + do_try_put = false; + return true; + } + else { + return false; + } + }); + + src.activate(); + g.wait_for_all(); + + bool storage; + for(auto& successor: successors) { + ASSERT((successor.try_get(storage) && !successor.try_get(storage)), + "Not exact edge quantity was made"); + } +} +#endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET + +int TestMain() { + if( MinThread<1 ) { + REPORT("number of threads must be positive\n"); + exit(1); + } + for ( int p = MinThread; p < MaxThread; ++p ) { + tbb::task_scheduler_init init(p); + test_single_dest(); + test_single_dest(); + } + test_reset(); +#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION + test_extract(); +#endif +#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET + test_follows_and_precedes_api(); +#endif +#if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT + test_deduction_guides(); +#endif + return Harness::Done; +} + diff --git a/src/test/test_join_node.cpp b/src/test/test_join_node.cpp index a36b963008..cd86fd74b6 100644 --- a/src/test/test_join_node.cpp +++ b/src/test/test_join_node.cpp @@ -54,7 +54,7 @@ class tag_recirculation_test { // this is the tag-matching join we're testing JType * my_join = makeJoin::create(g); // source_node for continue messages - tbb::flow::source_node snode(g, recirc_source_node_body(), false); + tbb::flow::input_node snode(g, recirc_source_node_body()); // reserving join that matches recirculating tags with continue messages. input_join_type * my_input_join = makeJoin<2, input_join_type, tbb::flow::reserving>::create(g); // tbb::flow::make_edge(snode, tbb::flow::input_port<1>(*my_input_join)); diff --git a/src/test/test_join_node.h b/src/test/test_join_node.h index 5f2792f82d..88f998930b 100644 --- a/src/test/test_join_node.h +++ b/src/test/test_join_node.h @@ -1359,7 +1359,7 @@ class source_node_helper { typedef tbb::flow::join_node, tbb::flow::reserving> input_join_type; typedef typename join_node_type::output_type TT; typedef typename tbb::flow::tuple_element::type IT; - typedef typename tbb::flow::source_node my_source_node_type; + typedef typename tbb::flow::input_node my_source_node_type; typedef typename tbb::flow::function_node, IT> my_recirc_function_type; static void print_remark(const char * str) { source_node_helper::print_remark(str); @@ -1370,6 +1370,7 @@ class source_node_helper { my_source_node_type *new_node = new my_source_node_type(g, source_body(i, nInputs)); tbb::flow::make_edge(*new_node, tbb::flow::input_port(my_join)); all_source_nodes[ELEM-1][i] = (void *)new_node; + new_node->activate(); } // add the next source_node source_node_helper::add_source_nodes(my_join, g, nInputs); @@ -1423,7 +1424,7 @@ class source_node_helper<1, JNT> { typedef tbb::flow::join_node, tbb::flow::reserving> input_join_type; typedef typename join_node_type::output_type TT; typedef typename tbb::flow::tuple_element<0, TT>::type IT; - typedef typename tbb::flow::source_node my_source_node_type; + typedef typename tbb::flow::input_node my_source_node_type; typedef typename tbb::flow::function_node, IT> my_recirc_function_type; public: static void print_remark(const char * str) { @@ -1434,6 +1435,7 @@ class source_node_helper<1, JNT> { my_source_node_type *new_node = new my_source_node_type(g, source_body(i, nInputs)); tbb::flow::make_edge(*new_node, tbb::flow::input_port<0>(my_join)); all_source_nodes[0][i] = (void *)new_node; + new_node->activate(); } } diff --git a/src/test/test_multifunction_node.cpp b/src/test/test_multifunction_node.cpp index 8deca129b4..b5af423fcc 100644 --- a/src/test/test_multifunction_node.cpp +++ b/src/test/test_multifunction_node.cpp @@ -14,9 +14,8 @@ limitations under the License. */ -#if __TBB_CPF_BUILD -#define TBB_DEPRECATED_FLOW_NODE_EXTRACTION 1 -#endif +#define TBB_DEPRECATED_FLOW_NODE_EXTRACTION __TBB_CPF_BUILD +#define TBB_DEPRECATED_FLOW_NODE_ALLOCATOR __TBB_CPF_BUILD #include "harness.h" #include "harness_graph.h" @@ -731,6 +730,22 @@ void test_follows_and_precedes_api() { } #endif // __TBB_PREVIEW_FLOW_GRAPH_NODE_SET +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR +typedef tbb::flow::multifunction_node< int, tbb::flow::tuple, + tbb::flow::queueing, + std::allocator > multifunction_type; +struct multipass_through { + void operator()( int, multifunction_type::output_ports_type& ) {} +}; + +void test_node_allocator() { + tbb::flow::graph g; + multifunction_type tmp( + g, tbb::flow::unlimited, multipass_through() + ); +} +#endif + int TestMain() { if( MinThread<1 ) { REPORT("number of threads must be positive\n"); @@ -742,12 +757,15 @@ int TestMain() { test_ports_return_references(); test_ports_return_references(); lightweight_testing::test(10); +#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET + test_follows_and_precedes_api(); +#endif #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION test_extract(); test_extract(); #endif -#if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET - test_follows_and_precedes_api(); +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + test_node_allocator(); #endif return Harness::Done; } diff --git a/src/test/test_priority_queue_node.cpp b/src/test/test_priority_queue_node.cpp index 53030fc13d..73724fb961 100644 --- a/src/test/test_priority_queue_node.cpp +++ b/src/test/test_priority_queue_node.cpp @@ -16,9 +16,8 @@ // TO DO: Add overlapping put / receive tests -#if __TBB_CPF_BUILD -#define TBB_DEPRECATED_FLOW_NODE_EXTRACTION 1 -#endif +#define TBB_DEPRECATED_FLOW_NODE_EXTRACTION __TBB_CPF_BUILD +#define TBB_DEPRECATED_FLOW_NODE_ALLOCATOR __TBB_CPF_BUILD #include "harness.h" @@ -374,6 +373,13 @@ void test_deduction_guides() { } #endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR +void test_node_allocator() { + tbb::flow::graph g; + tbb::flow::priority_queue_node< int, std::less, std::allocator > tmp(g); +} +#endif + int TestMain() { tbb::tick_count start = tbb::tick_count::now(), stop; for (int p = 2; p <= 4; ++p) { @@ -388,14 +394,17 @@ int TestMain() { REMARK("Testing resets\n"); test_resets >(); test_resets >(); -#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION - test_buffer_extract >().run_tests(); -#endif #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET test_follows_and_precedes_api(); #endif #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT test_deduction_guides(); +#endif +#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION + test_buffer_extract >().run_tests(); +#endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + test_node_allocator(); #endif return Harness::Done; } diff --git a/src/test/test_queue_node.cpp b/src/test/test_queue_node.cpp index 5d7939a6c2..d29b9916b6 100644 --- a/src/test/test_queue_node.cpp +++ b/src/test/test_queue_node.cpp @@ -16,9 +16,8 @@ // TO DO: Add overlapping put / receive tests -#if __TBB_CPF_BUILD -#define TBB_DEPRECATED_FLOW_NODE_EXTRACTION 1 -#endif +#define TBB_DEPRECATED_FLOW_NODE_EXTRACTION __TBB_CPF_BUILD +#define TBB_DEPRECATED_FLOW_NODE_ALLOCATOR __TBB_CPF_BUILD #include "harness.h" @@ -481,6 +480,14 @@ void test_deduction_guides() { } #endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR +void test_node_allocator() { + tbb::flow::graph g; + tbb::flow::queue_node< int, std::allocator > tmp(g); +} +#endif + + int TestMain() { tbb::tick_count start = tbb::tick_count::now(), stop; for (int p = 2; p <= 4; ++p) { @@ -495,14 +502,17 @@ int TestMain() { REMARK("Testing resets\n"); test_resets >(); test_resets >(); -#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION - test_buffer_extract >().run_tests(); -#endif #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET test_follows_and_precedes_api(); #endif #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT test_deduction_guides(); +#endif +#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION + test_buffer_extract >().run_tests(); +#endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + test_node_allocator(); #endif return Harness::Done; } diff --git a/src/test/test_sequencer_node.cpp b/src/test/test_sequencer_node.cpp index 5d002d9637..e2f7d4c11a 100644 --- a/src/test/test_sequencer_node.cpp +++ b/src/test/test_sequencer_node.cpp @@ -14,9 +14,8 @@ limitations under the License. */ -#if __TBB_CPF_BUILD -#define TBB_DEPRECATED_FLOW_NODE_EXTRACTION 1 -#endif +#define TBB_DEPRECATED_FLOW_NODE_EXTRACTION __TBB_CPF_BUILD +#define TBB_DEPRECATED_FLOW_NODE_ALLOCATOR __TBB_CPF_BUILD #include "harness.h" #include "harness_graph.h" @@ -433,6 +432,13 @@ void test_deduction_guides() { } #endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR +void test_node_allocator() { + tbb::flow::graph g; + tbb::flow::sequencer_node< int, std::allocator > tmp(g, seq_inspector()); +} +#endif + int TestMain() { tbb::tick_count start = tbb::tick_count::now(), stop; for (int p = 2; p <= 4; ++p) { @@ -440,14 +446,17 @@ int TestMain() { test_serial(); test_parallel(p); } -#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION - test_buffer_extract >().run_tests(); -#endif #if __TBB_PREVIEW_FLOW_GRAPH_NODE_SET test_follows_and_precedes_api(); #endif #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT test_deduction_guides(); +#endif +#if TBB_DEPRECATED_FLOW_NODE_EXTRACTION + test_buffer_extract >().run_tests(); +#endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + test_node_allocator(); #endif stop = tbb::tick_count::now(); REMARK("Sequencer_Node Time=%6.6f\n", (stop-start).seconds()); diff --git a/src/test/test_source_node.cpp b/src/test/test_source_node.cpp index 21aba75084..b2594e7d59 100644 --- a/src/test/test_source_node.cpp +++ b/src/test/test_source_node.cpp @@ -16,6 +16,8 @@ // have to expose the reset_node method to be able to reset a function_body +#define TBB_USE_SOURCE_NODE_AS_ALIAS __TBB_CPF_BUILD + #include "harness.h" #if __TBB_CPF_BUILD @@ -122,6 +124,9 @@ void test_single_dest() { tbb::flow::source_node src(g, source_body() ); test_push_receiver dest(g); tbb::flow::make_edge( src, dest ); +#if TBB_USE_SOURCE_NODE_AS_ALIAS + src.activate(); +#endif g.wait_for_all(); for (int i = 0; i < N; ++i ) { ASSERT( dest.get_count(i) == 1, NULL ); @@ -133,6 +138,9 @@ void test_single_dest() { function_body b3( counters3 ); tbb::flow::function_node dest3(g, tbb::flow::unlimited, b3 ); tbb::flow::make_edge( src3, dest3 ); +#if TBB_USE_SOURCE_NODE_AS_ALIAS + src3.activate(); +#endif g.wait_for_all(); for (int i = 0; i < N; ++i ) { int v = counters3[i]; @@ -143,14 +151,19 @@ void test_single_dest() { tbb::flow::source_node src2(g, source_body() ); tbb::atomic counters2[N]; function_body b2( counters2 ); - tbb::flow::function_node dest2(g, tbb::flow::serial, b2 ); + tbb::flow::function_node dest2(g, tbb::flow::serial, b2 ); tbb::flow::make_edge( src2, dest2 ); + #if TBB_DEPRECATED_FLOW_NODE_EXTRACTION ASSERT(src2.successor_count() == 1, NULL); typename tbb::flow::source_node::successor_list_type my_succs; src2.copy_successors(my_succs); ASSERT(my_succs.size() == 1, NULL); #endif + +#if TBB_USE_SOURCE_NODE_AS_ALIAS + src2.activate(); +#endif g.wait_for_all(); for (int i = 0; i < N; ++i ) { int v = counters2[i]; @@ -161,6 +174,9 @@ void test_single_dest() { tbb::flow::source_node src_copy(src); test_push_receiver dest_c(g); ASSERT( src_copy.register_successor(dest_c), NULL ); +#if TBB_USE_SOURCE_NODE_AS_ALIAS + src_copy.activate(); +#endif g.wait_for_all(); for (int i = 0; i < N; ++i ) { ASSERT( dest_c.get_count(i) == 1, NULL ); @@ -172,11 +188,19 @@ void test_reset() { tbb::flow::graph g; tbb::atomic counters3[N]; tbb::flow::source_node src3(g, source_body() ); - tbb::flow::source_node src_inactive(g, source_body(), /*active*/ false ); +#if TBB_USE_SOURCE_NODE_AS_ALIAS + tbb::flow::source_node src_inactive(g, source_body() ); +#else + tbb::flow::source_node src_inactive(g, source_body(), /*is_active=*/ false ); +#endif function_body b3( counters3 ); tbb::flow::function_node dest3(g, tbb::flow::unlimited, b3 ); tbb::flow::make_edge( src3, dest3 ); - // source_node already in active state. Let the graph run, + + #if TBB_USE_SOURCE_NODE_AS_ALIAS + src3.activate(); + #endif + // source_node is now in active state. Let the graph run, g.wait_for_all(); // check the array for each value. for (int i = 0; i < N; ++i ) { @@ -185,6 +209,9 @@ void test_reset() { counters3[i] = 0; } g.reset(tbb::flow::rf_reset_bodies); // <-- re-initializes the counts. + #if TBB_USE_SOURCE_NODE_AS_ALIAS + src3.activate(); + #endif // and spawns task to run source g.wait_for_all(); // check output queue again. Should be the same contents. @@ -263,7 +290,11 @@ void test_extract() { tbb::flow::graph g; typedef tbb::flow::source_node snode_type; typedef snode_type::successor_list_type successor_list_type; - snode_type s0(g, source_body(counts), /*is_active*/false ); +#if TBB_USE_SOURCE_NODE_AS_ALIAS + snode_type s0(g, source_body(counts)); +#else + snode_type s0(g, source_body(counts), false); +#endif tbb::flow::join_node< tbb::flow::tuple, tbb::flow::reserving > j0(g); tbb::flow::join_node< tbb::flow::tuple, tbb::flow::reserving > j1(g); tbb::flow::join_node< tbb::flow::tuple, tbb::flow::reserving > j2(g); @@ -413,13 +444,13 @@ void test_deduction_guides() { auto non_const_lambda = [](int& i) mutable { return i > 5; }; // Tests for source_node(graph&, Body) - source_node s1(g, lambda, /*is_active=*/false); + source_node s1(g, lambda); static_assert(std::is_same_v>); - source_node s2(g, non_const_lambda, /*is_active=*/false); + source_node s2(g, non_const_lambda); static_assert(std::is_same_v>); - source_node s3(g, source_body_f, /*is_active=*/false); + source_node s3(g, source_body_f); static_assert(std::is_same_v>); source_node s4(s3); @@ -429,13 +460,13 @@ void test_deduction_guides() { broadcast_node bc(g); // Tests for source_node(const node_set&, Body) - source_node s5(precedes(bc), lambda, /*is_active=*/false); + source_node s5(precedes(bc), lambda); static_assert(std::is_same_v>); - source_node s6(precedes(bc), non_const_lambda, /*is_active=*/false); + source_node s6(precedes(bc), non_const_lambda); static_assert(std::is_same_v>); - source_node s7(precedes(bc), source_body_f, /*is_active=*/false); + source_node s7(precedes(bc), source_body_f); static_assert(std::is_same_v>); #endif g.wait_for_all(); @@ -452,11 +483,12 @@ void test_follows_and_precedes_api() { std::array, 3> successors {{ buffer_node(g), - buffer_node(g), - buffer_node(g) + buffer_node(g), + buffer_node(g) }}; bool do_try_put = true; + source_node src(precedes(successors[0], successors[1], successors[2]), [&](bool& v) -> bool { if(do_try_put) { v = do_try_put; @@ -466,7 +498,7 @@ void test_follows_and_precedes_api() { else { return false; } - }, false); + }); src.activate(); g.wait_for_all(); diff --git a/src/test/test_split_node.cpp b/src/test/test_split_node.cpp index 27cd4d2b18..59e7462534 100644 --- a/src/test/test_split_node.cpp +++ b/src/test/test_split_node.cpp @@ -14,6 +14,8 @@ limitations under the License. */ +#define TBB_DEPRECATED_FLOW_NODE_ALLOCATOR __TBB_CPF_BUILD + #include "harness.h" #include "harness_graph.h" #include "tbb/flow_graph.h" @@ -207,7 +209,7 @@ template class parallel_test { public: typedef typename SType::input_type TType; - typedef tbb::flow::source_node source_type; + typedef tbb::flow::input_node source_type; static const int N = tbb::flow::tuple_size::value; static void test() { source_type* all_source_nodes[MaxNSources]; @@ -231,6 +233,7 @@ class parallel_test { source_type *s = new source_type(g, source_body(i, nInputs) ); tbb::flow::make_edge(*s, *my_split); all_source_nodes[i] = s; + s->activate(); } g.wait_for_all(); @@ -381,6 +384,13 @@ void test_deduction_guides() { #endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR +void test_node_allocator() { + tbb::flow::graph g; + tbb::flow::split_node< tbb::flow::tuple, std::allocator > tmp(g); +} +#endif + int TestMain() { #if __TBB_USE_TBB_TUPLE REMARK(" Using TBB tuple\n"); @@ -420,6 +430,9 @@ int TestMain() { #endif #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT test_deduction_guides(); +#endif +#if TBB_DEPRECATED_FLOW_NODE_ALLOCATOR + test_node_allocator(); #endif return Harness::Done; } diff --git a/src/test/test_task_leaks.cpp b/src/test/test_task_leaks.cpp index 8e800d23c7..dda2ae132b 100644 --- a/src/test/test_task_leaks.cpp +++ b/src/test/test_task_leaks.cpp @@ -150,6 +150,22 @@ void RunTaskGenerators( bool switchProducer = false, bool checkProducer = false tbb::task::destroy( *dummy_root ); } +#include "tbb/parallel_for.h" +#include "tbb/task_arena.h" +tbb::task_arena* BigArena; + +struct AffParFor { + void operator()() const { + for (int i = 0; i < 10; ++i) + tbb::parallel_for(0, BigArena->max_concurrency(), AffParFor(), tbb::static_partitioner()); + } + void operator()(int) const {} +}; + +void RunAffinityTaskGenerator() { + BigArena->execute(AffParFor()); +} + class TaskList: public tbb::task { const int my_num_childs; public: @@ -196,6 +212,12 @@ void TestTaskReclamation() { tbb::task_scheduler_init init (MinThread); REMARK("Starting with %d threads\n", MinThread); + + // Reserve multiple slots for masters to have slots that are never occupied. + // "+1" to avoid warning about maximum number of threads. + int num_threads = tbb::task_scheduler_init::default_num_threads() < 8 ? tbb::task_scheduler_init::default_num_threads() : 8; + BigArena = new tbb::task_arena(2*num_threads, num_threads+1); + // For now, the master will produce "additional" tasks; later a worker will replace it; Producer = internal::governor::local_scheduler(); int N = InitialStatsIterations; @@ -204,6 +226,7 @@ void TestTaskReclamation() { // First N iterations fill internal buffers and collect initial statistics RunTaskGenerators(); RunTaskListGenerator(); + RunAffinityTaskGenerator(); size_t m = GetMemoryUsage(); if( m-initial_amount_of_memory > 0) @@ -229,6 +252,7 @@ void TestTaskReclamation() { // These iterations check for excessive memory use and unreasonable task count RunTaskGenerators( switchProducer, checkProducer ); RunTaskListGenerator(); + RunAffinityTaskGenerator(); intptr_t n = internal::governor::local_scheduler()->get_task_node_count( /*count_arena_workers=*/true ); size_t m = GetMemoryUsage(); @@ -256,6 +280,7 @@ void TestTaskReclamation() { } } ASSERT( last_error_iteration < MaxIterations - AsymptoticRange, "The amount of allocated tasks keeps growing. Leak is possible." ); + delete BigArena; } int TestMain () { diff --git a/src/test/test_tbb_header.cpp b/src/test/test_tbb_header.cpp index 5a97cfdf2c..d47bb1ef79 100644 --- a/src/test/test_tbb_header.cpp +++ b/src/test/test_tbb_header.cpp @@ -243,6 +243,7 @@ int TestMain () TestFuncDefinitionPresence( flow::remove_edge, (tbb::flow::sender&, tbb::flow::receiver&), void ); typedef tbb::flow::tuple intpair; TestTypeDefinitionPresence( flow::source_node ); + TestTypeDefinitionPresence( flow::input_node ); TestTypeDefinitionPresence3(flow::function_node ); TestTypeDefinitionPresence3(flow::multifunction_node ); TestTypeDefinitionPresence3(flow::async_node ); diff --git a/src/test/test_tbb_version.cpp b/src/test/test_tbb_version.cpp index d7314610cd..8248995d12 100644 --- a/src/test/test_tbb_version.cpp +++ b/src/test/test_tbb_version.cpp @@ -224,8 +224,8 @@ int main(int argc, char *argv[] ) { // Fill dictionary with version strings for platforms void initialize_strings_vector(std::vector * vector) { - vector->push_back(string_pair("TBB: VERSION\t\t2020.1", required)); // check TBB_VERSION - vector->push_back(string_pair("TBB: INTERFACE VERSION\t11101", required)); // check TBB_INTERFACE_VERSION + vector->push_back(string_pair("TBB: VERSION\t\t2020.2", required)); // check TBB_VERSION + vector->push_back(string_pair("TBB: INTERFACE VERSION\t11102", 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)); diff --git a/third-party-programs.txt b/third-party-programs.txt index 8389d3aa49..7360813be8 100644 --- a/third-party-programs.txt +++ b/third-party-programs.txt @@ -1,8 +1,18 @@ -This file is the "third-party-programs.txt" file specified in the associated Intel end user license -agreement for the Intel software you are licensing. The third party programs and their corresponding -required notices and/or license terms are listed below. +Intel(R) Threading Building Blocks Third Party Programs File -1. Portable Hardware Locality (hwloc): +This file contains the list of third party software ("third party programs") +contained in the Intel software and their required notices and/or license terms. +This third party software, even if included with the distribution of the Intel +software, may be governed by separate license terms, including without limitation, +third party license terms, other Intel software license terms, and open source +software license terms. These separate license terms govern your use of the third +party programs as set forth in the "third-party-programs.txt" or other similarly named text file. + +Third party programs and their corresponding required notices and/or license +terms are listed below. +____________________________________________________________________________________________________ + +1. Portable Hardware Locality (hwloc): Copyright (c) 2004-2006 The Trustees of Indiana University and Indiana University Research and Technology Corporation. All rights reserved. Copyright (c) 2004-2005 The University of Tennessee and The University of Tennessee Research Foundation. All rights reserved. Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, University of Stuttgart. All rights reserved. @@ -46,7 +56,7 @@ required notices and/or license terms are listed below. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. _______________________________________________________________________________________________________ -2. Instrumentation and Tracing Technology (ITT) Notify User API: +2. Instrumentation and Tracing Technology (ITT) Notify User API: Copyright (c) 2005-2014 Intel Corporation. All rights reserved. The 3-Clause BSD License @@ -112,6 +122,8 @@ ________________________________________________________________________________ 4. gperftools: Copyright (c) 2011, Google Inc. + Tachyon: Copyright (c) 1994-2008 John E. Stone. All rights reserved. + BSD 3-Clause "New" or "Revised" License Redistribution and use in source and binary forms, with or without @@ -141,135 +153,12 @@ ________________________________________________________________________________ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. _______________________________________________________________________________________________________ -5. C Runtime Library (CRT): (c) 2015 Microsoft Corporation. - - MICROSOFT* VISUAL STUDIO ENTERPRISE 2015, VISUAL STUDIO PROFESSIONAL 2015, VISUAL STUDIO TEST PROFESSIONAL 2015 AND TRIAL EDITION - - These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. Please read them. They apply to the software named above. The terms also apply to any Microsoft services and updates for the software, except to the extent these come with any different terms. - - BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS. IF YOU DO NOT ACCEPT THEM, DO NOT USE THE SOFTWARE. INSTEAD, RETURN IT TO THE RETAILER FOR A REFUND OR CREDIT. If you cannot obtain a refund there, contact Microsoft or the Microsoft affiliate serving your country for information about Microsoft's refund policies. See www.microsoft.com/worldwide. In the United States and Canada, call (800) MICROSOFT or see https://aka.ms/nareturn. - - TRIAL EDITION USE RIGHTS. If the software is a trial edition, then this Section applies to your use of the trial edition. - - GENERAL. You may use any number of copies of the trial edition on your devices. You may only use the trial edition for internal evaluation purposes, and only during the trial period. You may not deploy any applications you make with the trial edition to a production environment. You may run load tests of up to 250 virtual users during the trial period. - TRIAL PERIOD AND CONVERSION. The length of the trial period is the first thirty (30) days after you install the trial edition, plus any permitted extension period. After the expiration of the trial period, the trial edition will stop running. You may extend the trial period an additional ninety (90) days if you sign in to the software. You may not be able to access data used with the trial edition when it stops running. You may convert your trial rights at any time to the full-use rights described below by acquiring a valid full-use license. - DISCLAIMER OF WARRANTY. THE TRIAL EDITION IS LICENSED "AS-IS." YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.FOR AUSTRALIA – YOU HAVE STATUTORY GUARANTEES UNDER THE AUSTRALIAN CONSUMER LAW AND NOTHING IN THESE TERMS IS INTENDED TO AFFECT THOSE RIGHTS. - Because the trial edition is "as is," we may not provide support services for it. - LIMITATION ON AND EXCLUSION OF DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES. - This limitation applies to (a) anything related to the trial edition, services, content (including code) on third party Internet sites, or third party programs; and (b) claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law. - It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages. - FULL-USE LICENSE TERMS FOR THE SOFTWARE: When you acquire a valid license and either enter a product key or sign in to the software, the full-use terms below apply. You may not share your product key or access credentials. - - OVERVIEW. - Software. The software includes development tools, applications and documentation. - License Model. The software is licensed on a per user basis. - USE RIGHTS. - General. One user may use copies of the software to develop and test your applications. This includes using copies of the software on your own internal servers that remain fully dedicated to your own use. You may not, however, separate the components of the software and run those in a production environment, or on different devices (except as otherwise stated in this agreement), or for any purpose other than developing and testing your applications. Running the software on Microsoft Azure Platform Services requires a separate license. - Demo Use. The use permitted above includes use of the software in demonstrating your applications. - Backup copy. You may make one backup copy of the software, for reinstalling the software. - TERMS FOR SPECIFIC COMPONENTS. - Utilities. The software contains some items on the Utilities List at http://go.microsoft.com/fwlink/?LinkId=523763&clcid=0x409. You may copy and install those items, if included with the software, on to yours or other third party machines, to debug and deploy your applications and databases you developed with the software. Please note that Utilities are designed for temporary use, that Microsoft may not be able to patch or update Utilities separately from the rest of the software, and that some Utilities by their nature may make it possible for others to access allow machines on which they are installed. As a result, you should delete all Utilities you have installed after you finish debugging or deploying your applications and databases. Microsoft is not responsible for any third party use or access of Utilities you install on any machine. - Build Server. The software contains some items on the Build Server List at http://go.microsoft.com/fwlink/?LinkId=523763&clcid=0x409. You may copy and install those items, if included in the software, onto your build machines. You and others in your organization may use these items on your build machines solely for the purpose of compiling, building, verifying and archiving your applications or running quality or performance tests as part of the build process. - Font Components. While the software is running, you may use its fonts to display and print content. You may only: (i) embed fonts in content as permitted by the embedding restrictions in the fonts; and (ii) temporarily download them to a printer or other output device to help print content. - Licenses for Other Components. - Microsoft Platforms. The software may include components from Microsoft Windows; Microsoft Windows Server; Microsoft SQL Server; Microsoft Exchange; Microsoft Office; and Microsoft SharePoint. These components are governed by separate agreements and their own product support policies, as described in the license terms found in the installation directory for that component or in the "Licenses" folder accompanying the software. - Developer resources. The software includes compilers, languages, runtimes, environments, and other resources. These components may be governed by separate agreements and have their own product support policies. A list of these other components is located at www.support.microsoft.com/common/international.aspx. - Third Party Components. The software may include third party components with separate legal notices or governed by other agreements, as described in the ThirdPartyNotices file accompanying the software. Even if such components are governed by other agreements, the disclaimers on limitations on and exclusions of damages below also apply.The software may also include components licensed under open source licenses with source code availability obligations. Copies of those licenses, if applicable, are included in the ThirdPartyNotices file. You may obtain this source code from us, if and as required under the relevant open source licenses, by sending a money order or check for $5.00 to: Source Code Compliance Team, Microsoft Corporation, 1 Microsoft Way, Redmond, WA 98052. Please write "source code for Microsoft Visual Studio Enterprise 2015, Microsoft Visual Studio Professional 2015 or Microsoft Visual Studio Test Professional 2015" in the memo line of your payment. We may also make a copy of the source code available at Thirdpartysource.microsoft.com. - PACKAGE MANAGERS. The software includes package managers, like NuGet, that give you the option to download other Microsoft and third party software packages to use with your application. Those packages are under their own licenses, and not this agreement. Microsoft does not distribute, license or provide any warranties for any of the third party packages. - DISTRIBUTABLE CODE. The software contains code that you are permitted to distribute in applications you develop as described in this Section. (For this Section the term "distribution" also means deployment of your applications for third parties to access over the Internet.) - Right to Use and Distribute. The code and text files listed below are "Distributable Code." - REDIST.TXT Files. You may copy and distribute the object code form of code listed on the REDIST list located at http://go.microsoft.com/fwlink/?LinkId=523763&clcid=0x409. - Sample Code, Templates and Styles. You may copy, modify and distribute the source and object code form of code marked as "sample", "template", "simple styles" and "sketch styles". - Image Library. You may copy and distribute images, graphics and animations in the Image Library as described in the software documentation. - Third Party Distribution. You may permit distributors of your applications to copy and distribute the Distributable Code as part of those applications. - Distribution Requirements. For any Distributable Code you distribute, you must: - add significant primary functionality to it in your applications; - require distributors and external end users to agree to terms that protect the Distributable Code at least as much as this agreement; and - indemnify, defend, and hold harmless Microsoft from any claims, including attorneys' fees, related to the distribution or use of your applications, except to the extent that any claim is based solely on the Distributable Code. - Distribution Restrictions. You may not: - use Microsoft's trademarks in your applications' names or branding in a way that suggests your applications come from or are endorsed by Microsoft; or - modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. An Excluded License is one that requires, as a condition of use, modification or distribution, that (i) the code be disclosed or distributed in source code form; or (ii) others have the right to modify it. - DATA. The software may collect information about you and your use of the software, and send that to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may opt-out of many of these scenarios, but not all, as described in the product documentation. There are also some features in the software that may enable you to collect data from users of your applications. If you use these features to enable data collection in your applications, you must comply with applicable law, including providing appropriate notices to users of your applications. You can learn more about data collection and use in the help documentation and the privacy statement at http://go.microsoft.com/fwlink/?LinkId=528096&clcid=0x409. Your use of the software operates as your consent to these practices. - SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. For more information, see www.microsoft.com/licensing. You may not - work around any technical limitations in the software; - reverse engineer, decompile or disassemble the software, or otherwise attempt to derive the source code for the software except, and solely to the extent: (i) permitted by applicable law, despite this limitation; or (ii) required to debug changes to any libraries licensed under the GNU Lesser General Public License which are included with and linked to by the software; - remove, minimize, block or modify any notices of Microsoft or its suppliers in the software; - use the software in any way that is against the law; - share, publish, rent or lease the software, or provide the software as a stand-alone hosted solution for others to use. - DOCUMENTATION. Any person that has valid access to your computer or internal network may copy and use the documentation for your internal, reference purposes. - NOT FOR RESALE SOFTWARE. You may not sell software marked as "NFR" or "Not for Resale." - RIGHTS TO USE OTHER VERSIONS AND LOWER EDITIONS. You may use the software and any prior version on any device. You may create, store, install, run or access in place of the version licensed, a copy or instance of a prior version, different permitted language version or lower edition. - PROOF OF LICENSE. If you acquired the software on a disc or other media, your proof of license is the Microsoft certificate of authenticity label, the accompanying product key and your receipt. If you purchased an online copy of the software, your proof of license is the Microsoft product key you received with your purchase and your receipt and/or being able to access the software service through your Microsoft account. To identify genuine Microsoft software, see www.howtotell.com. - TRANSFER TO A THIRD PARTY. If you are a valid licensee of the software you may transfer it and this license agreement directly to another party. Before the transfer, that party must agree that this agreement applies to the transfer and use of the software. The transfer must include the software, genuine Microsoft product key, and (if applicable) the Proof of License label. The transferor must uninstall all copies of the software after transferring it from the device. The transferor may not retain any copies of the genuine Microsoft product key to be transferred, and may only retain copies of the software if otherwise licensed to do so. If you have acquired a non-perpetual license to use the software or if the software is marked Not for Resale you may not transfer the software or the software license agreement to another party. - EXPORT RESTRICTIONS. Microsoft software, online services, professional services and related technology are subject to U.S. export jurisdiction. You must comply with all applicable international and national, laws including the U.S. Export Administration Regulations, the International Traffic in Arms Regulations, Office of Foreign Assets Control sanctions programs, and end-user, end use and destination restrictions by the U.S. and other governments related to Microsoft products, services and technologies. For additional information, see www.microsoft.com/exporting. - SUPPORT SERVICES. Microsoft provides support services for the software as described at www.support.microsoft.com/common/international.aspx. - ENTIRE AGREEMENT. This agreement (including the warranty below), and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services. - APPLICABLE LAW. If you acquired the software in the United States, Washington law applies to interpretation of and claims for breach of this agreement, and the laws of the state where you live govern all other claims. If you acquire the software in any other country, its laws apply. - LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the laws of your state or country. You may also have rights with respect to the party from whom you acquired the software. This agreement does not change your rights under the laws of your state or country if the laws of your state or country do not permit it to do so. - LIMITATION ON AND EXCLUSION OF DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO THE AMOUNT YOU PAID FOR THE SOFTWARE. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES.This limitation applies to a) anything related to the software, services, content (including code) on third party Internet sites, or b) third party applications; and claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law. - It also applies even if - - repair, replacement or a refund for the software does not fully compensate you for any losses; or - Microsoft knew or should have known about the possibility of the damages.Some states do not allow the exclusion or limitation of incidental or consequential damages, so the above limitation or exclusion may not apply to you. They also may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages. - LIMITED WARRANTY - LIMITED WARRANTY. If you follow the instructions, the software will perform substantially as described in the Microsoft materials that you receive in or with the software.References to "limited warranty" are references to the express warranty provided by Microsoft. This warranty is given in addition to other rights and remedies you may have under law, including your rights and remedies in accordance with the statutory guarantees under local Consumer Law. - TERM OF WARRANTY; WARRANTY RECIPIENT; LENGTH OF ANY IMPLIED WARRANTIES. THE LIMITED WARRANTY COVERS THE SOFTWARE FOR ONE YEAR AFTER ACQUIRED BY THE FIRST USER. IF YOU RECEIVE SUPPLEMENTS, UPDATES, OR REPLACEMENT SOFTWARE DURING THAT YEAR, THEY WILL BE COVERED FOR THE REMAINDER OF THE WARRANTY OR 30 DAYS, WHICHEVER IS LONGER. If the first user transfers the software, the remainder of the warranty will apply to the recipient.TO THE EXTENT PERMITTED BY LAW, ANY IMPLIED WARRANTIES, GUARANTEES OR CONDITIONS LAST ONLY DURING THE TERM OF THE LIMITED WARRANTY. Some states do not allow limitations on how long an implied warranty lasts, so these limitations may not apply to you. They also might not apply to you because some countries may not allow limitations on how long an implied warranty, guarantee or condition lasts. - EXCLUSIONS FROM WARRANTY. This warranty does not cover problems caused by your acts (or failures to act), the acts of others, or events beyond Microsoft's reasonable control. - REMEDY FOR BREACH OF WARRANTY. MICROSOFT WILL REPAIR OR REPLACE THE SOFTWARE AT NO CHARGE. IF MICROSOFT CANNOT REPAIR OR REPLACE IT, MICROSOFT WILL REFUND THE AMOUNT SHOWN ON YOUR RECEIPT FOR THE SOFTWARE. IT WILL ALSO REPAIR OR REPLACE SUPPLEMENTS, UPDATES AND REPLACEMENT SOFTWARE AT NO CHARGE. IF MICROSOFT CANNOT REPAIR OR REPLACE THEM, IT WILL REFUND THE AMOUNT YOU PAID FOR THEM, IF ANY. YOU MUST UNINSTALL THE SOFTWARE AND RETURN ANY MEDIA AND OTHER ASSOCIATED MATERIALS TO MICROSOFT WITH PROOF OF PURCHASE TO OBTAIN A REFUND. THESE ARE YOUR ONLY REMEDIES FOR BREACH OF THE LIMITED WARRANTY. - CONSUMER RIGHTS NOT AFFECTED. YOU MAY HAVE ADDITIONAL CONSUMER RIGHTS UNDER YOUR LOCAL LAWS, WHICH THIS AGREEMENT CANNOT CHANGE. - WARRANTY PROCEDURES. You need proof of purchase for warranty service. - United States and Canada. For warranty service or information about how to obtain a refund for software acquired in the United States and Canada, contact Microsoft at - (800) MICROSOFT; - Microsoft Customer Service and Support, One Microsoft Way, Redmond, WA 98052-6399; or - visit https://aka.ms/nareturn. - Europe, Middle East and Africa. If you acquired the software in Europe, the Middle East or Africa, Microsoft Ireland Operations Limited makes this limited warranty. To make a claim under this warranty, you should contact either - Microsoft Ireland Operations Limited, Customer Care Centre, Atrium Building Block B, Carmanhall Road, Sandyford Industrial Estate, Dublin 18, Ireland; or - the Microsoft affiliate serving your country (see www.microsoft.com/worldwide). - Australia. If you acquired the software in Australia, contact Microsoft to make a claim at - 13 20 58; or - Microsoft Pty Ltd, 1 Epping Road, North Ryde NSW 2113, Australia. - Outside United States, Canada, Europe, Middle East, Africa and Australia. If you acquired the software outside the United States, Canada, Europe, the Middle East, Africa and Australia, contact the Microsoft affiliate serving your country (see www.microsoft.com/worldwide). - NO OTHER WARRANTIES. THE LIMITED WARRANTY IS THE ONLY DIRECT WARRANTY FROM MICROSOFT. MICROSOFT GIVES NO OTHER EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. WHERE ALLOWED BY YOUR LOCAL LAWS, MICROSOFT EXCLUDES IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. If your local laws give you any implied warranties, guarantees or conditions, despite this exclusion, your remedies are described in the Remedy for Breach of Warranty clause above, to the extent permitted by your local laws.FOR AUSTRALIA ONLY. In this paragraph, "goods" refers to the software for which Microsoft provides the express warranty. Our goods come with guarantees that cannot be excluded under the Australian Consumer Law. You are entitled to a replacement or refund for a major failure and compensation for any other reasonably foreseeable loss or damage. You are also entitled to have the goods repaired or replaced if the goods fail to be of acceptable quality and the failure does not amount to a maj or failure. Goods presented for repair may be replaced by refurbished goods of the same type rather than being replaced. Refurbished parts may be used to repair the goods. - LIMITATION ON AND EXCLUSION OF DAMAGES FOR BREACH OF WARRANTY. THE LIMITATION ON AND EXCLUSION OF DAMAGES CLAUSE ABOVE APPLIES TO BREACHES OF THIS LIMITED WARRANTY.THIS WARRANTY GIVES YOU SPECIFIC LEGAL RIGHTS, AND YOU MAY ALSO HAVE OTHER RIGHTS WHICH VARY FROM STATE TO STATE. YOU MAY ALSO HAVE OTHER RIGHTS WHICH VARY FROM COUNTRY TO COUNTRY. -_______________________________________________________________________________________________________ - -6. Mateusz Kwiatkowski Workaround for bug 62258 in libstdc++ +5. Mateusz Kwiatkowski Workaround for bug 62258 in libstdc++ Public domain _______________________________________________________________________________________________________ -7. Tachyon: Copyright (c) 1994-2008 John E. Stone. All rights reserved. - - BSD 3-Clause "New" or "Revised" License - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the - distribution. - * Neither the name of Google Inc. nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -_______________________________________________________________________________________________________ - -8. Bzip2: Copyright (c) 1996-2019 Julian Seward. +6. Bzip2: Copyright (c) 1996-2019 Julian Seward. Bzip 2 License @@ -288,9 +177,9 @@ ________________________________________________________________________________ THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. _______________________________________________________________________________________________________ -9. Apple OpenGL Image Sample Source Code +7. Apple OpenGL Image Sample Source Code - Apple MIT License + Apple License ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. @@ -299,10 +188,9 @@ ________________________________________________________________________________ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - _______________________________________________________________________________________________________ -10. LodePNG: Copyright (c) 2005-2019 by Lode Vandevenne. +8. LodePNG: Copyright (c) 2005-2019 by Lode Vandevenne. zlib License @@ -324,20 +212,11 @@ ________________________________________________________________________________ 3. This notice may not be removed or altered from any source distribution. - _______________________________________________________________________________________________________ -11. prism: Copyright (c) 2012-2013 Lea Verou. - - MIT License - - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -_______________________________________________________________________________________________________ -12. jquery: Copyright (c) 2005, 2014 jQuery Foundation, Inc. +9. prism: Copyright (c) 2012-2013 Lea Verou. + + jquery: Copyright (c) 2005, 2014 jQuery Foundation, Inc. MIT License @@ -346,5 +225,6 @@ ________________________________________________________________________________ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +_______________________________________________________________________________________________________ *Other names and brands may be claimed as the property of others.