1/*
2 Copyright (c) 2005-2019 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// Declarations for rock-bottom simple test harness.
18// Just include this file to use it.
19// Every test is presumed to have a command line of the form "test [-v] [MinThreads[:MaxThreads]]"
20// The default for MinThreads is 1, for MaxThreads 4.
21// The defaults can be overridden by defining macros HARNESS_DEFAULT_MIN_THREADS
22// and HARNESS_DEFAULT_MAX_THREADS before including harness.h
23
24#ifndef tbb_tests_harness_H
25#define tbb_tests_harness_H
26
27#include "tbb/tbb_config.h"
28#include "harness_defs.h"
29
30namespace Harness {
31 enum TestResult {
32 Done,
33 Skipped,
34 Unknown
35 };
36}
37
38//! Entry point to a TBB unit test application
39/** It MUST be defined by the test application.
40
41 If HARNESS_NO_PARSE_COMMAND_LINE macro was not explicitly set before including harness.h,
42 then global variables MinThread, and MaxThread will be available and
43 initialized when it is called.
44
45 Returns Harness::Done when the tests passed successfully. When the test fail, it must
46 not return, calling exit(errcode) or abort() instead. When the test is not supported
47 for the given platform/compiler/etc, it should return Harness::Skipped.
48
49 To provide non-standard variant of main() for the test, define HARNESS_CUSTOM_MAIN
50 before including harness.h **/
51int TestMain ();
52
53#if __SUNPRO_CC
54 #include <stdlib.h>
55 #include <string.h>
56 #include <ucontext.h>
57#else /* !__SUNPRO_CC */
58 #include <cstdlib>
59 #include <cstring>
60#endif /* !__SUNPRO_CC */
61
62#include <new>
63
64#if __TBB_MIC_NATIVE
65 #include "harness_mic.h"
66#else
67 #define HARNESS_EXPORT
68 #define REPORT_FATAL_ERROR REPORT
69#endif /* !__MIC__ */
70
71#if _WIN32||_WIN64
72 #include "tbb/machine/windows_api.h"
73 #if _WIN32_WINNT > 0x0501 && _MSC_VER && !_M_ARM
74 // Suppress "typedef ignored ... when no variable is declared" warning by vc14
75 #pragma warning (push)
76 #pragma warning (disable: 4091)
77 #include <dbghelp.h>
78 #pragma warning (pop)
79 #pragma comment (lib, "dbghelp.lib")
80 #endif
81 #if __TBB_WIN8UI_SUPPORT
82 #include <thread>
83 #endif
84 #if _MSC_VER
85 #include <crtdbg.h>
86 #endif
87 #include <process.h>
88#else
89 #include <pthread.h>
90#endif
91
92#if __linux__
93 #include <sys/utsname.h> /* for uname */
94 #include <errno.h> /* for use in LinuxKernelVersion() */
95 #include <features.h>
96#endif
97// at least GLIBC 2.1 or OSX 10.5
98#if __GLIBC__>2 || ( __GLIBC__==2 && __GLIBC_MINOR__ >= 1) || __APPLE__
99 #include <execinfo.h> /*backtrace*/
100 #define BACKTRACE_FUNCTION_AVAILABLE 1
101#endif
102
103namespace Harness {
104 class NativeMutex {
105#if _WIN32||_WIN64
106 CRITICAL_SECTION my_critical_section;
107 public:
108 NativeMutex() {
109 InitializeCriticalSectionEx(&my_critical_section, 4000, 0);
110 }
111 void lock() {
112 EnterCriticalSection(&my_critical_section);
113 }
114 void unlock() {
115 LeaveCriticalSection(&my_critical_section);
116 }
117 ~NativeMutex() {
118 DeleteCriticalSection(&my_critical_section);
119 }
120#else
121 pthread_mutex_t m_mutex;
122 public:
123 NativeMutex() {
124 pthread_mutex_init(&m_mutex, NULL);
125 }
126 void lock() {
127 pthread_mutex_lock(&m_mutex);
128 }
129 void unlock() {
130 pthread_mutex_unlock(&m_mutex);
131 }
132 ~NativeMutex() {
133 pthread_mutex_destroy(&m_mutex);
134 }
135#endif
136 };
137 namespace internal {
138 static NativeMutex print_stack_mutex;
139 }
140}
141
142#include "harness_runtime_loader.h"
143#include "harness_report.h"
144
145//! Prints current call stack
146void print_call_stack() {
147 Harness::internal::print_stack_mutex.lock();
148 fflush(stdout); fflush(stderr);
149 #if BACKTRACE_FUNCTION_AVAILABLE
150 const int sz = 100; // max number of frames to capture
151 void *buff[sz];
152 int n = backtrace(buff, sz);
153 REPORT("Call stack info (%d):\n", n);
154 backtrace_symbols_fd(buff, n, fileno(stdout));
155 #elif __SUNPRO_CC
156 REPORT("Call stack info:\n");
157 printstack(fileno(stdout));
158 #elif _WIN32_WINNT > 0x0501 && _MSC_VER>=1500 && !__TBB_WIN8UI_SUPPORT
159 const int sz = 62; // XP limitation for number of frames
160 void *buff[sz];
161 int n = CaptureStackBackTrace(0, sz, buff, NULL);
162 REPORT("Call stack info (%d):\n", n);
163 static LONG once = 0;
164 if( !InterlockedExchange(&once, 1) )
165 SymInitialize(GetCurrentProcess(), NULL, TRUE);
166 const int len = 255; // just some reasonable string buffer size
167 union { SYMBOL_INFO sym; char pad[sizeof(SYMBOL_INFO)+len]; };
168 sym.MaxNameLen = len;
169 sym.SizeOfStruct = sizeof( SYMBOL_INFO );
170 DWORD64 offset;
171 for(int i = 1; i < n; i++) { // skip current frame
172 if(!SymFromAddr( GetCurrentProcess(), DWORD64(buff[i]), &offset, &sym )) {
173 sym.Address = ULONG64(buff[i]); offset = 0; sym.Name[0] = 0;
174 }
175 REPORT("[%d] %016I64X+%04I64X: %s\n", i, sym.Address, offset, sym.Name); //TODO: print module name
176 }
177 #endif /*BACKTRACE_FUNCTION_AVAILABLE*/
178 Harness::internal::print_stack_mutex.unlock();
179}
180
181#if !HARNESS_NO_ASSERT
182 #include <exception> //for set_terminate
183 #include "harness_assert.h"
184 #if TEST_USES_TBB
185 #include <tbb/tbb_stddef.h> /*set_assertion_handler*/
186 #endif
187
188 struct InitReporter {
189 void (*default_terminate_handler)() ;
190 InitReporter(): default_terminate_handler(NULL) {
191 #if TEST_USES_TBB
192 #if TBB_USE_ASSERT
193 tbb::set_assertion_handler(ReportError);
194 #endif
195 ASSERT_WARNING(TBB_INTERFACE_VERSION <= tbb::TBB_runtime_interface_version(), "runtime version mismatch");
196 #endif
197 #if TBB_USE_EXCEPTIONS
198 default_terminate_handler = std::set_terminate(handle_terminate);
199 #endif
200 }
201 static void handle_terminate();
202 };
203 static InitReporter InitReportError;
204
205 void InitReporter::handle_terminate(){
206 REPORT("std::terminate called.\n");
207 print_call_stack();
208 if (InitReportError.default_terminate_handler){
209 InitReportError.default_terminate_handler();
210 }
211 }
212
213 typedef void (*test_error_extra_t)(void);
214 static test_error_extra_t ErrorExtraCall;
215 //! Set additional handler to process failed assertions
216 void SetHarnessErrorProcessing( test_error_extra_t extra_call ) {
217 ErrorExtraCall = extra_call;
218 }
219
220 //! Reports errors issued by failed assertions
221 void ReportError( const char* filename, int line, const char* expression, const char * message ) {
222 print_call_stack();
223 #if __TBB_ICL_11_1_CODE_GEN_BROKEN
224 printf("%s:%d, assertion %s: %s\n", filename, line, expression, message ? message : "failed" );
225 #else
226 REPORT_FATAL_ERROR("%s:%d, assertion %s: %s\n", filename, line, expression, message ? message : "failed" );
227 #endif
228
229 if( ErrorExtraCall )
230 (*ErrorExtraCall)();
231 fflush(stdout); fflush(stderr);
232 #if HARNESS_TERMINATE_ON_ASSERT
233 TerminateProcess(GetCurrentProcess(), 1);
234 #elif HARNESS_EXIT_ON_ASSERT
235 exit(1);
236 #elif HARNESS_CONTINUE_ON_ASSERT
237 // continue testing
238 #elif _MSC_VER && _DEBUG
239 // aligned with tbb_assert_impl.h behavior
240 if(1 == _CrtDbgReport(_CRT_ASSERT, filename, line, NULL, "%s\r\n%s", expression, message?message:""))
241 _CrtDbgBreak();
242 #else
243 abort();
244 #endif /* HARNESS_EXIT_ON_ASSERT */
245 }
246 //! Reports warnings issued by failed warning assertions
247 void ReportWarning( const char* filename, int line, const char* expression, const char * message ) {
248 REPORT("Warning: %s:%d, assertion %s: %s\n", filename, line, expression, message ? message : "failed" );
249 }
250
251#else /* !HARNESS_NO_ASSERT */
252
253 #define ASSERT(p,msg) (Harness::suppress_unused_warning(p), (void)0)
254 #define ASSERT_WARNING(p,msg) (Harness::suppress_unused_warning(p), (void)0)
255
256#endif /* !HARNESS_NO_ASSERT */
257
258namespace Harness {
259 //TODO: unify with utility::internal::array_length from examples common utilities
260 template<typename T, size_t N>
261 inline size_t array_length(const T(&)[N])
262 {
263 return N;
264 }
265
266 template<typename T, size_t N>
267 inline T* end( T(& array)[N])
268 {
269 return array+ array_length(array) ;
270 }
271
272} //namespace Harness
273
274#if TEST_USES_TBB
275 #include "tbb/blocked_range.h"
276
277 namespace Harness {
278 template<typename T, size_t N>
279 tbb::blocked_range<T*> make_blocked_range( T(& array)[N]){ return tbb::blocked_range<T*>(array, array + N);}
280 }
281#endif
282
283#if !HARNESS_NO_PARSE_COMMAND_LINE
284
285//! Controls level of commentary printed via printf-like REMARK() macro.
286/** If true, makes the test print commentary. If false, test should print "done" and nothing more. */
287static bool Verbose;
288
289#ifndef HARNESS_DEFAULT_MIN_THREADS
290 #define HARNESS_DEFAULT_MIN_THREADS 1
291#endif
292
293//! Minimum number of threads
294static int MinThread = HARNESS_DEFAULT_MIN_THREADS;
295
296#ifndef HARNESS_DEFAULT_MAX_THREADS
297 #define HARNESS_DEFAULT_MAX_THREADS 4
298#endif
299
300//! Maximum number of threads
301static int MaxThread = HARNESS_DEFAULT_MAX_THREADS;
302
303//! Parse command line of the form "name [-v] [MinThreads[:MaxThreads]]"
304/** Sets Verbose, MinThread, and MaxThread accordingly.
305 The nthread argument can be a single number or a range of the form m:n.
306 A single number m is interpreted as if written m:m.
307 The numbers must be non-negative.
308 Clients often treat the value 0 as "run sequentially." */
309inline void ParseCommandLine( int argc, char* argv[] ) {
310 if( !argc ) REPORT("Command line with 0 arguments\n");
311 int i = 1;
312 if( i<argc ) {
313 if( strncmp( argv[i], "-v", 2 )==0 ) {
314 Verbose = true;
315 ++i;
316 }
317 }
318 if( i<argc ) {
319 char* endptr;
320 MinThread = strtol( argv[i], &endptr, 0 );
321 if( *endptr==':' )
322 MaxThread = strtol( endptr+1, &endptr, 0 );
323 else if( *endptr=='\0' )
324 MaxThread = MinThread;
325 if( *endptr!='\0' ) {
326 REPORT_FATAL_ERROR("garbled nthread range\n");
327 exit(1);
328 }
329 if( MinThread<0 ) {
330 REPORT_FATAL_ERROR("nthread must be nonnegative\n");
331 exit(1);
332 }
333 if( MaxThread<MinThread ) {
334 REPORT_FATAL_ERROR("nthread range is backwards\n");
335 exit(1);
336 }
337 ++i;
338 }
339#if __TBB_STDARGS_BROKEN
340 if ( !argc )
341 argc = 1;
342 else {
343 while ( i < argc && argv[i][0] == 0 )
344 ++i;
345 }
346#endif /* __TBB_STDARGS_BROKEN */
347 if( i!=argc ) {
348 REPORT_FATAL_ERROR("Usage: %s [-v] [nthread|minthread:maxthread]\n", argv[0] );
349 exit(1);
350 }
351}
352#endif /* HARNESS_NO_PARSE_COMMAND_LINE */
353
354#if !HARNESS_CUSTOM_MAIN
355
356#if __TBB_MPI_INTEROP
357#undef SEEK_SET
358#undef SEEK_CUR
359#undef SEEK_END
360#include "mpi.h"
361#endif
362
363#if __TBB_MIC_OFFLOAD && __MIC__
364extern "C" int COIProcessProxyFlush();
365#endif
366
367HARNESS_EXPORT
368#if HARNESS_NO_PARSE_COMMAND_LINE
369int main() {
370#if __TBB_MPI_INTEROP
371 MPI_Init(NULL,NULL);
372#endif
373#else
374int main(int argc, char* argv[]) {
375 ParseCommandLine( argc, argv );
376#if __TBB_MPI_INTEROP
377 MPI_Init(&argc,&argv);
378#endif
379#endif
380#if HARNESS_SKIP_TEST
381 REPORT( "skip\n" );
382 return 0;
383#else
384#if __TBB_MPI_INTEROP
385 // Simple TBB/MPI interoperability harness for most of tests
386 // Worker processes send blocking messages to the master process about their rank and group size
387 // Master process receives this info and print it in verbose mode
388 int rank, size, myrank;
389 MPI_Status status;
390 MPI_Comm_size(MPI_COMM_WORLD,&size);
391 MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
392 if (myrank == 0) {
393#if !HARNESS_NO_PARSE_COMMAND_LINE
394 REMARK("Hello mpi world. I am %d of %d\n", myrank, size);
395#endif
396 for ( int i = 1; i < size; i++ ) {
397 MPI_Recv (&rank, 1, MPI_INT, i, 1, MPI_COMM_WORLD, &status);
398 MPI_Recv (&size, 1, MPI_INT, i, 1, MPI_COMM_WORLD, &status);
399#if !HARNESS_NO_PARSE_COMMAND_LINE
400 REMARK("Hello mpi world. I am %d of %d\n", rank, size);
401#endif
402 }
403 } else {
404 MPI_Send (&myrank, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
405 MPI_Send (&size, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
406 }
407#endif
408
409 int res = Harness::Unknown;
410#if __TBB_MIC_OFFLOAD
411 // "mic:-1" or "mandatory" specifies execution on the target. The runtime
412 // system chooses the specific target. Execution on the CPU is not allowed.
413#if __INTEL_COMPILER < 1400
414 #pragma offload target(mic:-1) out(res)
415#else
416 #pragma offload target(mic) out(res) mandatory
417#endif
418#endif
419 {
420 res = TestMain();
421#if __TBB_MIC_OFFLOAD && __MIC__
422 // It is recommended not to use the __MIC__ macro directly in the offload block but it is Ok here
423 // since it does not lead to an unexpected difference between host and target compilation phases.
424 // We need to flush internal Intel(R) Coprocessor Offload Infrastructure (Intel(R) COI) buffers
425 // to order output from the offload part before the host part.
426 // Also it is work-around for the issue with missed output.
427 COIProcessProxyFlush();
428#endif
429 }
430
431 ASSERT( res==Harness::Done || res==Harness::Skipped, "Wrong return code by TestMain");
432#if __TBB_MPI_INTEROP
433 if (myrank == 0) {
434 REPORT( res==Harness::Done ? "done\n" : "skip\n" );
435 }
436 MPI_Finalize();
437#else
438 REPORT( res==Harness::Done ? "done\n" : "skip\n" );
439#endif
440 return 0;
441#endif /* HARNESS_SKIP_TEST */
442}
443
444#endif /* !HARNESS_CUSTOM_MAIN */
445
446//! Base class for prohibiting compiler-generated operator=
447class NoAssign {
448 //! Assignment not allowed
449 void operator=( const NoAssign& );
450public:
451 NoAssign() {} // explicitly defined to prevent gratuitous warnings
452};
453
454//! Base class for prohibiting compiler-generated copy constructor or operator=
455class NoCopy: NoAssign {
456 //! Copy construction not allowed
457 NoCopy( const NoCopy& );
458public:
459 NoCopy() {}
460};
461
462#if __TBB_CPP11_RVALUE_REF_PRESENT
463#include <utility>
464
465//! Base class for objects which support move ctors
466class Movable {
467public:
468 Movable() : alive(true) {}
469 void Reset() { alive = true; }
470 Movable(Movable&& other) {
471 ASSERT(other.alive, "Moving from a dead object");
472 alive = true;
473 other.alive = false;
474 }
475 Movable& operator=(Movable&& other) {
476 ASSERT(alive, "Assignment to a dead object");
477 ASSERT(other.alive, "Assignment of a dead object");
478 other.alive = false;
479 return *this;
480 }
481 Movable& operator=(const Movable& other) {
482 ASSERT(alive, "Assignment to a dead object");
483 ASSERT(other.alive, "Assignment of a dead object");
484 return *this;
485 }
486 Movable(const Movable& other) {
487 ASSERT(other.alive, "Const reference to a dead object");
488 alive = true;
489 }
490 ~Movable() { alive = false; }
491 volatile bool alive;
492};
493
494class MoveOnly : Movable, NoCopy {
495public:
496 MoveOnly() : Movable() {}
497 MoveOnly(MoveOnly&& other) : Movable( std::move(other) ) {}
498};
499#endif /* __TBB_CPP11_RVALUE_REF_PRESENT */
500
501#if HARNESS_TBBMALLOC_THREAD_SHUTDOWN && __TBB_SOURCE_DIRECTLY_INCLUDED && (_WIN32||_WIN64)
502#include "../tbbmalloc/tbbmalloc_internal_api.h"
503#endif
504
505//! For internal use by template function NativeParallelFor
506template<typename Index, typename Body>
507class NativeParallelForTask: NoCopy {
508public:
509 NativeParallelForTask( Index index_, const Body& body_ ) :
510 index(index_),
511 body(body_)
512 {}
513
514 //! Start task
515 void start() {
516#if _WIN32||_WIN64
517 unsigned thread_id;
518#if __TBB_WIN8UI_SUPPORT
519 std::thread* thread_tmp=new std::thread(thread_function, this);
520 thread_handle = thread_tmp->native_handle();
521 thread_id = 0;
522#else
523 unsigned stack_size = 0;
524#if HARNESS_THREAD_STACK_SIZE
525 stack_size = HARNESS_THREAD_STACK_SIZE;
526#endif
527 thread_handle = (HANDLE)_beginthreadex( NULL, stack_size, thread_function, this, 0, &thread_id );
528#endif
529 ASSERT( thread_handle!=0, "NativeParallelFor: _beginthreadex failed" );
530#else
531#if __ICC==1100
532 #pragma warning (push)
533 #pragma warning (disable: 2193)
534#endif /* __ICC==1100 */
535 // Some machines may have very large hard stack limit. When the test is
536 // launched by make, the default stack size is set to the hard limit, and
537 // calls to pthread_create fail with out-of-memory error.
538 // Therefore we set the stack size explicitly (as for TBB worker threads).
539#if !defined(HARNESS_THREAD_STACK_SIZE)
540#if __i386__||__i386||__arm__
541 const size_t stack_size = 1*MByte;
542#elif __x86_64__
543 const size_t stack_size = 2*MByte;
544#else
545 const size_t stack_size = 4*MByte;
546#endif
547#else
548 const size_t stack_size = HARNESS_THREAD_STACK_SIZE;
549#endif /* HARNESS_THREAD_STACK_SIZE */
550 pthread_attr_t attr_stack;
551 int status = pthread_attr_init(&attr_stack);
552 ASSERT(0==status, "NativeParallelFor: pthread_attr_init failed");
553 status = pthread_attr_setstacksize( &attr_stack, stack_size );
554 ASSERT(0==status, "NativeParallelFor: pthread_attr_setstacksize failed");
555 status = pthread_create(&thread_id, &attr_stack, thread_function, this);
556 ASSERT(0==status, "NativeParallelFor: pthread_create failed");
557 pthread_attr_destroy(&attr_stack);
558#if __ICC==1100
559 #pragma warning (pop)
560#endif
561#endif /* _WIN32||_WIN64 */
562 }
563
564 //! Wait for task to finish
565 void wait_to_finish() {
566#if _WIN32||_WIN64
567 DWORD status = WaitForSingleObjectEx( thread_handle, INFINITE, FALSE );
568 ASSERT( status!=WAIT_FAILED, "WaitForSingleObject failed" );
569 CloseHandle( thread_handle );
570#else
571 int status = pthread_join( thread_id, NULL );
572 ASSERT( !status, "pthread_join failed" );
573#endif
574#if HARNESS_NO_ASSERT
575 (void)status;
576#endif
577 }
578
579private:
580#if _WIN32||_WIN64
581 HANDLE thread_handle;
582#else
583 pthread_t thread_id;
584#endif
585
586 //! Range over which task will invoke the body.
587 const Index index;
588
589 //! Body to invoke over the range.
590 const Body body;
591
592#if _WIN32||_WIN64
593 static unsigned __stdcall thread_function( void* object )
594#else
595 static void* thread_function(void* object)
596#endif
597 {
598 NativeParallelForTask& self = *static_cast<NativeParallelForTask*>(object);
599 (self.body)(self.index);
600#if HARNESS_TBBMALLOC_THREAD_SHUTDOWN && __TBB_SOURCE_DIRECTLY_INCLUDED && (_WIN32||_WIN64)
601 // in those cases can't release per-thread cache automatically,
602 // so do it manually
603 // TODO: investigate less-intrusive way to do it, for example via FLS keys
604 __TBB_mallocThreadShutdownNotification();
605#endif
606 return 0;
607 }
608};
609
610//! Execute body(i) in parallel for i in the interval [0,n).
611/** Each iteration is performed by a separate thread. */
612template<typename Index, typename Body>
613void NativeParallelFor( Index n, const Body& body ) {
614 typedef NativeParallelForTask<Index,Body> task;
615
616 if( n>0 ) {
617 // Allocate array to hold the tasks
618 task* array = static_cast<task*>(operator new( n*sizeof(task) ));
619
620 // Construct the tasks
621 for( Index i=0; i!=n; ++i )
622 new( &array[i] ) task(i,body);
623
624 // Start the tasks
625 for( Index i=0; i!=n; ++i )
626 array[i].start();
627
628 // Wait for the tasks to finish and destroy each one.
629 for( Index i=n; i; --i ) {
630 array[i-1].wait_to_finish();
631 array[i-1].~task();
632 }
633
634 // Deallocate the task array
635 operator delete(array);
636 }
637}
638
639//! The function to zero-initialize arrays; useful to avoid warnings
640template <typename T>
641void zero_fill(void* array, size_t n) {
642 memset(array, 0, sizeof(T)*n);
643}
644
645#if __SUNPRO_CC && defined(min)
646#undef min
647#undef max
648#endif
649
650#ifndef min
651//! Utility template function returning lesser of the two values.
652/** Provided here to avoid including not strict safe <algorithm>.\n
653 In case operands cause signed/unsigned or size mismatch warnings it is caller's
654 responsibility to do the appropriate cast before calling the function. **/
655template<typename T1, typename T2>
656T1 min ( const T1& val1, const T2& val2 ) {
657 return val1 < val2 ? val1 : val2;
658}
659#endif /* !min */
660
661#ifndef max
662//! Utility template function returning greater of the two values.
663/** Provided here to avoid including not strict safe <algorithm>.\n
664 In case operands cause signed/unsigned or size mismatch warnings it is caller's
665 responsibility to do the appropriate cast before calling the function. **/
666template<typename T1, typename T2>
667T1 max ( const T1& val1, const T2& val2 ) {
668 return val1 < val2 ? val2 : val1;
669}
670#endif /* !max */
671
672template<typename T>
673static inline bool is_aligned(T arg, size_t alignment) {
674 return 0==((size_t)arg & (alignment-1));
675}
676
677#if __linux__
678inline unsigned LinuxKernelVersion()
679{
680 unsigned digit1, digit2, digit3;
681 struct utsname utsnameBuf;
682
683 if (-1 == uname(&utsnameBuf)) {
684 REPORT_FATAL_ERROR("Can't call uname: errno %d\n", errno);
685 exit(1);
686 }
687 if (3 != sscanf(utsnameBuf.release, "%u.%u.%u", &digit1, &digit2, &digit3)) {
688 REPORT_FATAL_ERROR("Unable to parse OS release '%s'\n", utsnameBuf.release);
689 exit(1);
690 }
691 return 1000000*digit1+1000*digit2+digit3;
692}
693#endif
694
695namespace Harness {
696
697#if !HARNESS_NO_ASSERT
698//! Base class that asserts that no operations are made with the object after its destruction.
699class NoAfterlife {
700protected:
701 enum state_t {
702 LIVE=0x56781234,
703 DEAD=0xDEADBEEF
704 } m_state;
705
706public:
707 NoAfterlife() : m_state(LIVE) {}
708 NoAfterlife( const NoAfterlife& src ) : m_state(LIVE) {
709 ASSERT( src.IsLive(), "Constructing from the dead source" );
710 }
711 ~NoAfterlife() {
712 ASSERT( IsLive(), "Repeated destructor call" );
713 m_state = DEAD;
714 }
715 const NoAfterlife& operator=( const NoAfterlife& src ) {
716 ASSERT( IsLive(), NULL );
717 ASSERT( src.IsLive(), NULL );
718 return *this;
719 }
720 void AssertLive() const {
721 ASSERT( IsLive(), "Already dead" );
722 }
723 bool IsLive() const {
724 return m_state == LIVE;
725 }
726}; // NoAfterlife
727#endif /* !HARNESS_NO_ASSERT */
728
729#if _WIN32 || _WIN64
730 void Sleep ( int ms ) {
731#if !__TBB_WIN8UI_SUPPORT
732 ::Sleep(ms);
733#else
734 std::chrono::milliseconds sleep_time( ms );
735 std::this_thread::sleep_for( sleep_time );
736#endif
737
738 }
739
740 typedef DWORD tid_t;
741 tid_t CurrentTid () { return GetCurrentThreadId(); }
742
743#else /* !WIN */
744
745 void Sleep ( int ms ) {
746 timespec requested = { ms / 1000, (ms % 1000)*1000000 };
747 timespec remaining = { 0, 0 };
748 nanosleep(&requested, &remaining);
749 }
750
751 typedef pthread_t tid_t;
752 tid_t CurrentTid () { return pthread_self(); }
753#endif /* !WIN */
754
755 static const unsigned Primes[] = {
756 0x9e3779b1, 0xffe6cc59, 0x2109f6dd, 0x43977ab5, 0xba5703f5, 0xb495a877, 0xe1626741, 0x79695e6b,
757 0xbc98c09f, 0xd5bee2b3, 0x287488f9, 0x3af18231, 0x9677cd4d, 0xbe3a6929, 0xadc6a877, 0xdcf0674b,
758 0xbe4d6fe9, 0x5f15e201, 0x99afc3fd, 0xf3f16801, 0xe222cfff, 0x24ba5fdb, 0x0620452d, 0x79f149e3,
759 0xc8b93f49, 0x972702cd, 0xb07dd827, 0x6c97d5ed, 0x085a3d61, 0x46eb5ea7, 0x3d9910ed, 0x2e687b5b,
760 0x29609227, 0x6eb081f1, 0x0954c4e1, 0x9d114db9, 0x542acfa9, 0xb3e6bd7b, 0x0742d917, 0xe9f3ffa7,
761 0x54581edb, 0xf2480f45, 0x0bb9288f, 0xef1affc7, 0x85fa0ca7, 0x3ccc14db, 0xe6baf34b, 0x343377f7,
762 0x5ca19031, 0xe6d9293b, 0xf0a9f391, 0x5d2e980b, 0xfc411073, 0xc3749363, 0xb892d829, 0x3549366b,
763 0x629750ad, 0xb98294e5, 0x892d9483, 0xc235baf3, 0x3d2402a3, 0x6bdef3c9, 0xbec333cd, 0x40c9520f
764 };
765
766 class FastRandom {
767 unsigned x, a;
768 public:
769 unsigned short get() {
770 unsigned short r = (unsigned short)(x >> 16);
771 x = x*a + 1;
772 return r;
773 }
774 explicit FastRandom( unsigned seed ) {
775 x = seed;
776 a = Primes[seed % (sizeof(Primes) / sizeof(Primes[0]))];
777 }
778 };
779 template<typename T>
780 class FastRandomBody {
781 FastRandom r;
782 public:
783 explicit FastRandomBody( unsigned seed ) : r(seed) {}
784 // Depending on the input type T the result distribution formed from this operator()
785 // might possess different characteristics than the original one used in FastRandom instance.
786 T operator()() { return T(r.get()); }
787 };
788
789 int SetEnv( const char *envname, const char *envval ) {
790 ASSERT( envname && envval, "Harness::SetEnv() requires two valid C strings" );
791#if __TBB_WIN8UI_SUPPORT
792 ASSERT( false, "Harness::SetEnv() should not be called in code built for win8ui" );
793 return -1;
794#elif !(_MSC_VER || __MINGW32__ || __MINGW64__)
795 // On POSIX systems use setenv
796 return setenv(envname, envval, /*overwrite=*/1);
797#elif __STDC_SECURE_LIB__>=200411
798 // this macro is set in VC & MinGW if secure API functions are present
799 return _putenv_s(envname, envval);
800#else
801 // If no secure API on Windows, use _putenv
802 size_t namelen = strlen(envname), valuelen = strlen(envval);
803 char* buf = new char[namelen+valuelen+2];
804 strncpy(buf, envname, namelen);
805 buf[namelen] = '=';
806 strncpy(buf+namelen+1, envval, valuelen);
807 buf[namelen+1+valuelen] = char(0);
808 int status = _putenv(buf);
809 delete[] buf;
810 return status;
811#endif
812 }
813
814 char* GetEnv(const char *envname) {
815 ASSERT(envname, "Harness::GetEnv() requires a valid C string");
816#if __TBB_WIN8UI_SUPPORT
817 return NULL;
818#else
819 return std::getenv(envname);
820#endif
821 }
822
823 class DummyBody {
824 int m_numIters;
825 public:
826 explicit DummyBody( int iters ) : m_numIters( iters ) {}
827 void operator()( int ) const {
828 for ( volatile int i = 0; i < m_numIters; ++i ) {}
829 }
830 };
831} // namespace Harness
832
833#endif /* tbb_tests_harness_H */
834