1 /*
2 Copyright (c) 2005-2020 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 #include "tbb/tbb_config.h"
18
19 #if !(_WIN32||_WIN64) || (__MINGW64__||__MINGW32__) || __TBB_WIN8UI_SUPPORT
20
21 #include "harness.h"
22
TestMain()23 int TestMain () {
24 return Harness::Skipped;
25 }
26
27 #else // !(_WIN32||_WIN64)
28
29 #define TBB_PREVIEW_RUNTIME_LOADER 1
30 #include "tbb/runtime_loader.h"
31 #include "tbb/tbb_stddef.h"
32 #include "tbb/task_scheduler_init.h"
33 #include "tbb/tbb_exception.h"
34
35 #include <cstdio>
36 #include <cstdlib>
37 #include <cerrno>
38 #include <vector>
39 #include <string>
40 #include <utility>
41 #include <typeinfo>
42 #include <stdexcept>
43
44 #ifdef HARNESS_USE_RUNTIME_LOADER
45 #undef HARNESS_USE_RUNTIME_LOADER // We do not want harness to preload TBB.
46 #endif
47 #include "harness.h"
48
49 static int errors = 0;
50
51 #define CHECK( cond ) { \
52 if ( ! (cond) ) { \
53 ++ errors; \
54 REPORT( "%s:%d: --- TEST FAILED ---\n", __FILE__, __LINE__ ); \
55 }; \
56 }
57
58 #define SAY( msg ) \
59 REMARK( "%s:%d: %s\n", __FILE__, __LINE__, msg )
60
61 typedef int (*int_func_t)();
62
63 namespace tbb {
64 namespace interface6 {
65 namespace internal {
66 namespace runtime_loader {
67 extern tbb::runtime_loader::error_mode stub_mode;
68 } } } } // namespaces runtime_loader, internal, interface6, tbb
69
70 using tbb::interface6::internal::runtime_loader::stub_mode;
71
72 #define _CHECK_TBB( code ) { \
73 stub_mode = tbb::runtime_loader::em_status; \
74 int ver = tbb::TBB_runtime_interface_version(); \
75 stub_mode = tbb::runtime_loader::em_abort; \
76 CHECK( ver == code ); \
77 }
78
79 #define CHECK_TBB_IS_LOADED() \
80 _CHECK_TBB( TBB_INTERFACE_VERSION )
81
82 #define CHECK_TBB_IS_NOT_LOADED() \
83 _CHECK_TBB( tbb::runtime_loader::ec_no_lib )
84
TestMain()85 int TestMain() {
86
87
88 __TBB_TRY {
89
90 {
91 SAY( "Call a function when library is not yet loaded, stub should return a error." );
92 CHECK_TBB_IS_NOT_LOADED();
93 }
94
95 {
96 SAY( "Create a runtime_loader object, do not load library but make some bad calls." );
97 tbb::runtime_loader rtl( tbb::runtime_loader::em_status );
98 SAY( "After creating status should be ok." );
99 CHECK( rtl.status() == tbb::runtime_loader::ec_ok );
100 SAY( "Call a function, stub should return a error." );
101 CHECK_TBB_IS_NOT_LOADED();
102 }
103
104 {
105 SAY( "Create a runtime_loader object and call load() with bad arguments." );
106 char const * path[] = { ".", NULL };
107 tbb::runtime_loader rtl( tbb::runtime_loader::em_status );
108 SAY( "Min version is bad." );
109 rtl.load( path, -1 );
110 CHECK( rtl.status() == tbb::runtime_loader::ec_bad_arg );
111 SAY( "Max version is bad." );
112 rtl.load( path, TBB_INTERFACE_VERSION, -1 );
113 CHECK( rtl.status() == tbb::runtime_loader::ec_bad_arg );
114 SAY( "Both versions are bad." );
115 rtl.load( path, -1, -1 );
116 CHECK( rtl.status() == tbb::runtime_loader::ec_bad_arg );
117 SAY( "Min is bigger than max." );
118 rtl.load( path, TBB_INTERFACE_VERSION + 1, TBB_INTERFACE_VERSION - 1 );
119 CHECK( rtl.status() == tbb::runtime_loader::ec_bad_arg );
120 }
121
122 {
123 SAY( "Create a proxy object and call load() with good arguments but not available version." );
124 char const * path[] = { ".", NULL };
125 tbb::runtime_loader rtl( tbb::runtime_loader::em_status );
126 SAY( "Min version too big." );
127 rtl.load( path, TBB_INTERFACE_VERSION + 1, TBB_INTERFACE_VERSION + 1 );
128 CHECK( rtl.status() == tbb::runtime_loader::ec_no_lib );
129 SAY( "Max version is too small." );
130 rtl.load( path, TBB_INTERFACE_VERSION - 1, TBB_INTERFACE_VERSION - 1 );
131 CHECK( rtl.status() == tbb::runtime_loader::ec_no_lib );
132 }
133
134 {
135 SAY( "Test em_throw mode." );
136 char const * path[] = { ".", NULL };
137 tbb::runtime_loader rtl( tbb::runtime_loader::em_throw );
138 tbb::runtime_loader::error_code code = tbb::runtime_loader::ec_ok;
139 __TBB_TRY {
140 rtl.load( path, -1 );
141 } __TBB_CATCH ( tbb::runtime_loader::error_code c ) {
142 code = c;
143 }; // __TBB_TRY
144 CHECK( code == tbb::runtime_loader::ec_bad_arg );
145 __TBB_TRY {
146 rtl.load( path, TBB_INTERFACE_VERSION + 1 );
147 } __TBB_CATCH ( tbb::runtime_loader::error_code c ) {
148 code = c;
149 }; // __TBB_TRY
150 CHECK( code == tbb::runtime_loader::ec_no_lib );
151 }
152
153 {
154 SAY( "Load current version, but specify wrong directories." );
155 tbb::runtime_loader rtl( tbb::runtime_loader::em_status );
156 SAY( "Specify no directories." );
157 char const * path0[] = { NULL };
158 rtl.load( path0 );
159 CHECK( rtl.status() == tbb::runtime_loader::ec_no_lib );
160 SAY( "Specify directories without library." );
161 char const * path1[] = { "..", "/", NULL };
162 rtl.load( path1 );
163 CHECK( rtl.status() == tbb::runtime_loader::ec_no_lib );
164 }
165
166 {
167 SAY( "Now really load library and do various tests." );
168 char const * path[] = { ".", NULL };
169 tbb::runtime_loader rtl( tbb::runtime_loader::em_status );
170 SAY( "Load current version." );
171 rtl.load( path, TBB_INTERFACE_VERSION, TBB_INTERFACE_VERSION );
172 CHECK( rtl.status() == tbb::runtime_loader::ec_ok );
173 if ( rtl.status() == tbb::runtime_loader::ec_ok ) {
174 {
175 SAY( "Make sure the library really loaded." );
176 CHECK_TBB_IS_LOADED();
177 }
178 SAY( "Call load() again, it should return a error." );
179 rtl.load( path, TBB_INTERFACE_VERSION, TBB_INTERFACE_VERSION );
180 CHECK( rtl.status() == tbb::runtime_loader::ec_bad_call );
181 {
182 SAY( "Initialize task_scheduler." );
183 tbb::task_scheduler_init init( 1 );
184 // Check what?
185 }
186
187 // There was a problem on Linux* OS, and still a problem on macOS*.
188 SAY( "Throw an exception." );
189 // Iterate through all the ids first.
190 for ( int id = 1; id < tbb::internal::eid_max; ++ id ) {
191 bool ex_caught = false;
192 __TBB_TRY {
193 tbb::internal::throw_exception( tbb::internal::exception_id( id ) );
194 } __TBB_CATCH ( std::exception const & ) {
195 SAY( "Expected exception caught." );
196 ex_caught = true;
197 } __TBB_CATCH ( ... ) {
198 SAY( "Unexpected exception caught." );
199 }; // try
200 CHECK( ex_caught );
201 }; // for
202 // Now try to catch exceptions of specific types.
203 #define CHECK_EXCEPTION( id, type ) \
204 { \
205 SAY( "Trowing " #id " exception of " #type " type..." ); \
206 bool ex_caught = false; \
207 __TBB_TRY { \
208 tbb::internal::throw_exception( tbb::internal::id ); \
209 } __TBB_CATCH ( type const & ) { \
210 SAY( #type " exception caught." ); \
211 ex_caught = true; \
212 } __TBB_CATCH ( ... ) { \
213 SAY( "Unexpected exception caught." ); \
214 }; /* try */ \
215 CHECK( ex_caught ); \
216 }
217 CHECK_EXCEPTION( eid_bad_alloc, std::bad_alloc );
218 CHECK_EXCEPTION( eid_bad_last_alloc, tbb::bad_last_alloc );
219 CHECK_EXCEPTION( eid_nonpositive_step, std::invalid_argument );
220 CHECK_EXCEPTION( eid_out_of_range, std::out_of_range );
221 CHECK_EXCEPTION( eid_segment_range_error, std::range_error );
222 CHECK_EXCEPTION( eid_missing_wait, tbb::missing_wait );
223 CHECK_EXCEPTION( eid_invalid_multiple_scheduling, tbb::invalid_multiple_scheduling );
224 CHECK_EXCEPTION( eid_improper_lock, tbb::improper_lock );
225 CHECK_EXCEPTION( eid_possible_deadlock, std::runtime_error );
226 CHECK_EXCEPTION( eid_reservation_length_error, std::length_error );
227 CHECK_EXCEPTION( eid_user_abort, tbb::user_abort );
228 #undef CHECK_EXCEPTION
229 {
230 bool ex_caught = false;
231 __TBB_TRY {
232 tbb::internal::handle_perror( EAGAIN, "apple" );
233 } __TBB_CATCH ( std::runtime_error const & ) {
234 SAY( "Expected exception caught." );
235 ex_caught = true;
236 } __TBB_CATCH ( ... ) {
237 SAY( "Unexpected exception caught." );
238 }; // try
239 CHECK( ex_caught );
240 }
241 }; // if
242 }
243
244 {
245 SAY( "Test multiple proxies." );
246 char const * path[] = { ".", NULL };
247 tbb::runtime_loader rtl0( tbb::runtime_loader::em_status );
248 tbb::runtime_loader rtl1( tbb::runtime_loader::em_status );
249 CHECK( rtl0.status() == tbb::runtime_loader::ec_ok );
250 CHECK( rtl1.status() == tbb::runtime_loader::ec_ok );
251 SAY( "Load current version with the first rtl." );
252 rtl0.load( path );
253 CHECK( rtl0.status() == tbb::runtime_loader::ec_ok );
254 CHECK_TBB_IS_LOADED();
255 SAY( "Load another version with the second proxy, it should return a error." );
256 rtl1.load( path, TBB_INTERFACE_VERSION + 1 );
257 CHECK( rtl1.status() == tbb::runtime_loader::ec_bad_ver );
258 SAY( "Load the same version with the second proxy, it should return ok." );
259 rtl1.load( path );
260 CHECK( rtl1.status() == tbb::runtime_loader::ec_ok );
261 CHECK_TBB_IS_LOADED();
262 }
263
264 } __TBB_CATCH( ... ) {
265
266 ASSERT( 0, "unexpected exception" );
267
268 }; // __TBB_TRY
269
270 if ( errors > 0 ) {
271 REPORT( "Some tests failed.\n" );
272 exit( 1 );
273 }; // if
274
275 return Harness::Done;
276
277 } // main
278
279 #endif // !(_WIN32||_WIN64)
280
281 // end of file //
282