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