1 /*
2 Copyright (c) 2005-2023 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 //! \file test_tbb_header.cpp
18 //! \brief Test for [all] specification
19
20 /**
21 This test ensures that tbb.h brings in all the public TBB interface definitions,
22 and if all the necessary symbols are exported from the library.
23
24 Most of the checks happen at the compilation or link phases.
25 **/
26
27 #if __INTEL_COMPILER && _MSC_VER
28 #pragma warning(disable : 2586) // decorated name length exceeded, name was truncated
29 #endif
30
31 #ifndef NOMINMAX
32 #define NOMINMAX
33 #endif // NOMINMAX
34
35 #define __TBB_NO_IMPLICIT_LINKAGE 1
36
37
38 #if __TBB_TEST_SECONDARY
39 // Test _DEBUG macro custom definitions.
40 #if TBB_USE_DEBUG
41 #ifdef _DEBUG
42 #undef _DEBUG
43 #endif /* _DEBUG */
44 // Check that empty value successfully enables the debug mode.
45 #define _DEBUG
46 static bool isDebugExpected = true;
47 #else
48 // Check that zero value does not enable the debug mode.
49 #define _DEBUG 0x0
50 static bool isDebugExpected = false;
51 #endif /* TBB_USE_DEBUG */
52 #define DO_TEST_DEBUG_MACRO 1
53 #else
54 // Test default definitions of _DEBUG.
55 #if _DEBUG
56 static bool isDebugExpected = true;
57 #define DO_TEST_DEBUG_MACRO 1
58 #elif _MSC_VER
59 // for MSVC, _DEBUG not defined indicates a release mode.
60 static bool isDebugExpected = false;
61 #define DO_TEST_DEBUG_MACRO 1
62 #endif /* _DEBUG */
63 #endif /* __TBB_TEST_SECONDARY */
64
65 #if DO_TEST_DEBUG_MACRO
66 // Reset TBB_USE_DEBUG defined in makefiles.
67 #undef TBB_USE_DEBUG
68 #endif /* DO_TEST_DEBUG_MACRO */
69 #define __TBB_CONFIG_PREPROC_ONLY _MSC_VER // For MSVC, prevent including standard headers in tbb_config.h
70 #include "common/config.h"
71
72 #include "oneapi/tbb/detail/_config.h"
73
74 #if !TBB_USE_DEBUG && defined(_DEBUG)
75 // TBB_USE_DEBUG is 0 but _DEBUG is defined, it means that _DEBUG is 0
76 // MSVC C++ headers consider any definition of _DEBUG, including 0, as debug mode
77 #undef _DEBUG
78 #endif /* !TBB_USE_DEBUG && defined(_DEBUG) */
79
80 #include "tbb/tbb.h"
81
82 #if !__TBB_TEST_SECONDARY
83 #include "common/test.h"
84 #endif
85
86 static volatile size_t g_sink;
87
88 #define TestTypeDefinitionPresence( Type ) g_sink = sizeof(tbb::Type);
89 #define TestTypeDefinitionPresence2(TypeStart, TypeEnd) g_sink = sizeof(tbb::TypeStart,TypeEnd);
90 #define TestTypeDefinitionPresence3(TypeStart, TypeMid, TypeEnd) g_sink = sizeof(tbb::TypeStart,TypeMid,TypeEnd);
91 #define TestFuncDefinitionPresence(Fn, Args, ReturnType) { ReturnType (*pfn)Args = &tbb::Fn; (void)pfn; }
92
93 struct Body {
operator ()Body94 void operator() () const {}
95 };
96 struct Body1 {
operator ()Body197 void operator() ( int ) const {}
98 };
99 struct Body1a { // feeder body for parallel_do
operator ()Body1a100 void operator() ( int, tbb::feeder<int>& ) const {}
101 };
102 struct Body1b { // binary operator for reduction
operator ()Body1b103 int operator() ( const int, const int ) const { return 0; }
104 };
105 struct Body1bc { // binary operator for comparison
operator ()Body1bc106 bool operator() (const int, const int) const { return false; }
107 };
108 struct Body2 {
Body2Body2109 Body2 () {}
Body2Body2110 Body2 ( const Body2&, tbb::split ) {}
operator ()Body2111 void operator() ( const tbb::blocked_range<int>& ) const {}
joinBody2112 void join( const Body2& ) {}
113 };
114 struct Body2a { // for lambda-friendly parallel_reduce
operator ()Body2a115 int operator() ( const tbb::blocked_range<int>&, const int ) const { return 0; }
116 };
117 struct Body3 { // for parallel_scan
Body3Body3118 Body3 () {}
Body3Body3119 Body3 ( const Body3&, tbb::split ) {}
operator ()Body3120 void operator() ( const tbb::blocked_range2d<int>&, tbb::pre_scan_tag ) const {}
operator ()Body3121 void operator() ( const tbb::blocked_range2d<int>&, tbb::final_scan_tag ) const {}
reverse_joinBody3122 void reverse_join( Body3& ) {}
assignBody3123 void assign( const Body3& ) {}
124 };
125 struct Body3a { // for lambda-friednly parallel_scan
operator ()Body3a126 int operator() ( const tbb::blocked_range<int>&, const int, bool ) const { return 0; }
127 };
128 struct Msg {};
129
130 // Test if all the necessary symbols are exported for the exceptions thrown by TBB.
131 // Missing exports result either in link error or in runtime assertion failure.
132 #include <stdexcept>
133
134 template <typename E>
TestExceptionClassExports(const E & exc,tbb::detail::exception_id eid)135 void TestExceptionClassExports ( const E& exc, tbb::detail::exception_id eid ) {
136 CHECK( eid < tbb::detail::exception_id::last_entry );
137 #if TBB_USE_EXCEPTIONS
138 for ( int i = 0; i < 2; ++i ) {
139 try {
140 if ( i == 0 )
141 throw exc;
142 else
143 tbb::detail::throw_exception( eid );
144 }
145 catch ( E& e ) {
146 CHECK_MESSAGE( e.what(), "Missing what() string" );
147 }
148 catch ( ... ) {
149 CHECK_MESSAGE( false, "Unrecognized exception. Likely RTTI related exports are missing" );
150 }
151 }
152 #else /* TBB_USE_EXCEPTIONS */
153 (void)exc;
154 #endif /* TBB_USE_EXCEPTIONS */
155 }
156
TestExceptionClassesExports()157 static void TestExceptionClassesExports () {
158 TestExceptionClassExports( std::bad_alloc(), tbb::detail::exception_id::bad_alloc );
159 TestExceptionClassExports( tbb::bad_last_alloc(), tbb::detail::exception_id::bad_last_alloc );
160 TestExceptionClassExports( std::invalid_argument("test"), tbb::detail::exception_id::nonpositive_step );
161 TestExceptionClassExports( std::out_of_range("test"), tbb::detail::exception_id::out_of_range );
162 TestExceptionClassExports( tbb::missing_wait(), tbb::detail::exception_id::missing_wait );
163 TestExceptionClassExports( std::out_of_range("test"), tbb::detail::exception_id::invalid_load_factor );
164 TestExceptionClassExports( std::length_error("test"), tbb::detail::exception_id::reservation_length_error );
165 TestExceptionClassExports( std::out_of_range("test"), tbb::detail::exception_id::invalid_key );
166 TestExceptionClassExports( tbb::user_abort(), tbb::detail::exception_id::user_abort );
167 TestExceptionClassExports( std::runtime_error("test"), tbb::detail::exception_id::bad_tagged_msg_cast );
168 }
169
170 #if __TBB_CPF_BUILD
171 // These names are only tested in "preview" configuration
172 // When a feature becomes fully supported, its names should be moved to the main test
TestPreviewNames()173 static void TestPreviewNames() {
174 TestTypeDefinitionPresence2( blocked_rangeNd<int,4> );
175 TestTypeDefinitionPresence2( concurrent_lru_cache<int, int> );
176 TestTypeDefinitionPresence( isolated_task_group );
177 }
178 #endif
179
DefinitionPresence()180 static void DefinitionPresence() {
181 TestTypeDefinitionPresence( cache_aligned_allocator<int> );
182 TestTypeDefinitionPresence( tbb_hash_compare<int> );
183 TestTypeDefinitionPresence2( concurrent_hash_map<int, int> );
184 TestTypeDefinitionPresence2( concurrent_unordered_map<int, int> );
185 TestTypeDefinitionPresence2( concurrent_unordered_multimap<int, int> );
186 TestTypeDefinitionPresence( concurrent_unordered_set<int> );
187 TestTypeDefinitionPresence( concurrent_unordered_multiset<int> );
188 TestTypeDefinitionPresence2( concurrent_map<int, int> );
189 TestTypeDefinitionPresence2( concurrent_multimap<int, int> );
190 TestTypeDefinitionPresence( concurrent_set<int> );
191 TestTypeDefinitionPresence( concurrent_multiset<int> );
192 TestTypeDefinitionPresence( concurrent_bounded_queue<int> );
193 TestTypeDefinitionPresence( concurrent_queue<int> );
194 TestTypeDefinitionPresence( concurrent_priority_queue<int> );
195 TestTypeDefinitionPresence( concurrent_vector<int> );
196 TestTypeDefinitionPresence( combinable<int> );
197 TestTypeDefinitionPresence( enumerable_thread_specific<int> );
198 /* Flow graph names */
199 TestTypeDefinitionPresence( flow::graph );
200 TestTypeDefinitionPresence( flow::continue_msg );
201 TestTypeDefinitionPresence2(flow::tagged_msg<int, int> );
202 TestFuncDefinitionPresence( flow::make_edge, (tbb::flow::sender<Msg>&, tbb::flow::receiver<Msg>&), void );
203 TestFuncDefinitionPresence( flow::remove_edge, (tbb::flow::sender<Msg>&, tbb::flow::receiver<Msg>&), void );
204 typedef std::tuple<int, int> intpair;
205 TestTypeDefinitionPresence( flow::input_node<int> );
206 TestTypeDefinitionPresence3(flow::function_node<int, int, tbb::flow::rejecting> );
207 TestTypeDefinitionPresence3(flow::multifunction_node<int, intpair, tbb::flow::queueing> );
208 TestTypeDefinitionPresence3(flow::async_node<int, int, tbb::flow::queueing_lightweight> );
209 TestTypeDefinitionPresence2(flow::continue_node<int, tbb::flow::lightweight> );
210 TestTypeDefinitionPresence2(flow::join_node<intpair, tbb::flow::reserving> );
211 TestTypeDefinitionPresence2(flow::join_node<intpair, tbb::flow::key_matching<int> > );
212 TestTypeDefinitionPresence( flow::split_node<intpair> );
213 TestTypeDefinitionPresence( flow::overwrite_node<int> );
214 TestTypeDefinitionPresence( flow::write_once_node<int> );
215 TestTypeDefinitionPresence( flow::broadcast_node<int> );
216 TestTypeDefinitionPresence( flow::buffer_node<int> );
217 TestTypeDefinitionPresence( flow::queue_node<int> );
218 TestTypeDefinitionPresence( flow::sequencer_node<int> );
219 TestTypeDefinitionPresence( flow::priority_queue_node<int> );
220 TestTypeDefinitionPresence( flow::limiter_node<int> );
221 TestTypeDefinitionPresence2(flow::indexer_node<int, int> );
222 TestTypeDefinitionPresence2(flow::composite_node<std::tuple<int>, std::tuple<int> > );
223 /* Mutex names */
224 TestTypeDefinitionPresence( null_mutex );
225 TestTypeDefinitionPresence( null_rw_mutex );
226 TestTypeDefinitionPresence( queuing_mutex );
227 TestTypeDefinitionPresence( queuing_rw_mutex );
228 TestTypeDefinitionPresence( spin_mutex );
229 TestTypeDefinitionPresence( spin_rw_mutex );
230 TestTypeDefinitionPresence( mutex );
231 TestTypeDefinitionPresence( rw_mutex );
232 TestTypeDefinitionPresence( speculative_spin_mutex );
233 TestTypeDefinitionPresence( speculative_spin_rw_mutex );
234 TestTypeDefinitionPresence( task_group_context );
235 TestTypeDefinitionPresence( task_group );
236 /* Algorithm related names */
237 TestTypeDefinitionPresence( blocked_range<int> );
238 TestTypeDefinitionPresence( blocked_range2d<int> );
239 TestTypeDefinitionPresence( blocked_range3d<int> );
240 TestTypeDefinitionPresence( collaborative_once_flag );
241 TestFuncDefinitionPresence( collaborative_call_once, (tbb::collaborative_once_flag&, const Body&), void );
242 TestFuncDefinitionPresence( parallel_invoke, (const Body&, const Body&, const Body&), void );
243 TestFuncDefinitionPresence( parallel_for_each, (int*, int*, const Body1&), void );
244 TestFuncDefinitionPresence( parallel_for, (int, int, int, const Body1&), void );
245 TestFuncDefinitionPresence( parallel_for, (const tbb::blocked_range<int>&, const Body2&, const tbb::simple_partitioner&), void );
246 TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, const int&, const Body2a&, const Body1b&), int );
247 TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::affinity_partitioner&), void );
248 TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, const int&, const Body2a&, const Body1b&), int );
249 TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::static_partitioner&), void );
250 TestFuncDefinitionPresence( parallel_scan, (const tbb::blocked_range2d<int>&, Body3&, const tbb::auto_partitioner&), void );
251 TestFuncDefinitionPresence( parallel_scan, (const tbb::blocked_range<int>&, const int&, const Body3a&, const Body1b&), int );
252 typedef int intarray[10];
253
254 TestFuncDefinitionPresence( parallel_sort, (int*, int*), void );
255 TestFuncDefinitionPresence( parallel_sort, (intarray&, const Body1bc&), void );
256 TestFuncDefinitionPresence( parallel_pipeline, (size_t, const tbb::filter<void,void>&), void );
257 TestFuncDefinitionPresence( parallel_invoke, (const Body&, const Body&, tbb::task_group_context&), void );
258 TestFuncDefinitionPresence( parallel_for_each, (const intarray&, const Body1a&, tbb::task_group_context&), void );
259 TestFuncDefinitionPresence( parallel_for, (int, int, const Body1&, const tbb::auto_partitioner&, tbb::task_group_context&), void );
260 TestFuncDefinitionPresence( parallel_for, (int, int, const Body1&, tbb::task_group_context&), void );
261 TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::auto_partitioner&, tbb::task_group_context&), void );
262 TestFuncDefinitionPresence( parallel_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::task_group_context&), void );
263 TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, const tbb::simple_partitioner&, tbb::task_group_context&), void );
264 TestFuncDefinitionPresence( parallel_deterministic_reduce, (const tbb::blocked_range<int>&, Body2&, tbb::task_group_context&), void );
265 TestTypeDefinitionPresence( proportional_split );
266
267 TestTypeDefinitionPresence( task_arena );
268 TestFuncDefinitionPresence( this_task_arena::current_thread_index, (), int );
269 TestFuncDefinitionPresence( this_task_arena::max_concurrency, (), int );
270 TestFuncDefinitionPresence( info::numa_nodes, (), std::vector<tbb::numa_node_id> );
271 TestFuncDefinitionPresence( info::default_concurrency, (tbb::numa_node_id), int );
272 TestTypeDefinitionPresence( task_scheduler_observer );
273 TestTypeDefinitionPresence( tbb_allocator<int> );
274 TestTypeDefinitionPresence( tick_count );
275 TestTypeDefinitionPresence( global_control );
276
277 #if __TBB_CPF_BUILD
278 TestPreviewNames();
279 #endif
280 #ifdef DO_TEST_DEBUG_MACRO
281 #if TBB_USE_DEBUG
282 CHECK_MESSAGE( isDebugExpected, "Debug mode is observed while release mode is expected." );
283 #else
284 CHECK_MESSAGE( !isDebugExpected, "Release mode is observed while debug mode is expected." );
285 #endif /* TBB_USE_DEBUG */
286 #endif /* DO_TEST_DEBUG_MACRO */
287 TestExceptionClassesExports();
288 }
289
290 #if __TBB_TEST_SECONDARY
291 /* This mode is used to produce a secondary object file that is linked with
292 the main one in order to detect "multiple definition" linker error.
293 */
Secondary()294 void Secondary() {
295 DefinitionPresence();
296 }
297 #else
298 //! Test for deifinition presence
299 //! \brief \ref interface
300 TEST_CASE("Test for deifinition presence") {
301 DefinitionPresence();
302 }
303
304 void Secondary();
305 //! Test for "multiple definition" linker error
306 //! \brief \ref error_guessing
307 TEST_CASE("Test for multiple definition linker error") {
308 Secondary();
309 }
310 #endif
311