2 Copyright (c) 2005-2019 Intel Corporation
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
8 http://www.apache.org/licenses/LICENSE-2.0
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.
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
24 #ifndef tbb_tests_harness_H
25 #define tbb_tests_harness_H
27 #include "tbb/tbb_config.h"
28 #include "harness_defs.h"
38 //! Entry point to a TBB unit test application
39 /** It MUST be defined by the test application.
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.
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.
49 To provide non-standard variant of main() for the test, define HARNESS_CUSTOM_MAIN
50 before including harness.h **/
57 #else /* !__SUNPRO_CC */
60 #endif /* !__SUNPRO_CC */
65 #include "harness_mic.h"
67 #define HARNESS_EXPORT
68 #define REPORT_FATAL_ERROR REPORT
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)
79 #pragma comment (lib, "dbghelp.lib")
81 #if __TBB_WIN8UI_SUPPORT
93 #include <sys/utsname.h> /* for uname */
94 #include <errno.h> /* for use in LinuxKernelVersion() */
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
106 CRITICAL_SECTION my_critical_section;
109 InitializeCriticalSectionEx(&my_critical_section, 4000, 0);
112 EnterCriticalSection(&my_critical_section);
115 LeaveCriticalSection(&my_critical_section);
118 DeleteCriticalSection(&my_critical_section);
121 pthread_mutex_t m_mutex;
124 pthread_mutex_init(&m_mutex, NULL);
127 pthread_mutex_lock(&m_mutex);
130 pthread_mutex_unlock(&m_mutex);
133 pthread_mutex_destroy(&m_mutex);
138 static NativeMutex print_stack_mutex;
142 #include "harness_runtime_loader.h"
143 #include "harness_report.h"
145 //! Prints current call stack
146 void 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
152 int n = backtrace(buff, sz);
153 REPORT("Call stack info (%d):\n", n);
154 backtrace_symbols_fd(buff, n, fileno(stdout));
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
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 );
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;
175 REPORT("[%d] %016I64X+%04I64X: %s\n", i, sym.Address, offset, sym.Name); //TODO: print module name
177 #endif /*BACKTRACE_FUNCTION_AVAILABLE*/
178 Harness::internal::print_stack_mutex.unlock();
181 #if !HARNESS_NO_ASSERT
182 #include <exception> //for set_terminate
183 #include "harness_assert.h"
185 #include <tbb/tbb_stddef.h> /*set_assertion_handler*/
188 struct InitReporter {
189 void (*default_terminate_handler)() ;
190 InitReporter(): default_terminate_handler(NULL) {
193 tbb::set_assertion_handler(ReportError);
195 ASSERT_WARNING(TBB_INTERFACE_VERSION <= tbb::TBB_runtime_interface_version(), "runtime version mismatch");
197 #if TBB_USE_EXCEPTIONS
198 default_terminate_handler = std::set_terminate(handle_terminate);
201 static void handle_terminate();
203 static InitReporter InitReportError;
205 void InitReporter::handle_terminate(){
206 REPORT("std::terminate called.\n");
208 if (InitReportError.default_terminate_handler){
209 InitReportError.default_terminate_handler();
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;
220 //! Reports errors issued by failed assertions
221 void ReportError( const char* filename, int line, const char* expression, const char * message ) {
223 #if __TBB_ICL_11_1_CODE_GEN_BROKEN
224 printf("%s:%d, assertion %s: %s\n", filename, line, expression, message ? message : "failed" );
226 REPORT_FATAL_ERROR("%s:%d, assertion %s: %s\n", filename, line, expression, message ? message : "failed" );
231 fflush(stdout); fflush(stderr);
232 #if HARNESS_TERMINATE_ON_ASSERT
233 TerminateProcess(GetCurrentProcess(), 1);
234 #elif HARNESS_EXIT_ON_ASSERT
236 #elif HARNESS_CONTINUE_ON_ASSERT
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:""))
244 #endif /* HARNESS_EXIT_ON_ASSERT */
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" );
251 #else /* !HARNESS_NO_ASSERT */
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)
256 #endif /* !HARNESS_NO_ASSERT */
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])
266 template<typename T, size_t N>
267 inline T* end( T(& array)[N])
269 return array+ array_length(array) ;
272 } //namespace Harness
275 #include "tbb/blocked_range.h"
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);}
283 #if !HARNESS_NO_PARSE_COMMAND_LINE
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. */
289 #ifndef HARNESS_DEFAULT_MIN_THREADS
290 #define HARNESS_DEFAULT_MIN_THREADS 1
293 //! Minimum number of threads
294 static int MinThread = HARNESS_DEFAULT_MIN_THREADS;
296 #ifndef HARNESS_DEFAULT_MAX_THREADS
297 #define HARNESS_DEFAULT_MAX_THREADS 4
300 //! Maximum number of threads
301 static int MaxThread = HARNESS_DEFAULT_MAX_THREADS;
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." */
309 inline void ParseCommandLine( int argc, char* argv[] ) {
310 if( !argc ) REPORT("Command line with 0 arguments\n");
313 if( strncmp( argv[i], "-v", 2 )==0 ) {
320 MinThread = strtol( argv[i], &endptr, 0 );
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");
330 REPORT_FATAL_ERROR("nthread must be nonnegative\n");
333 if( MaxThread<MinThread ) {
334 REPORT_FATAL_ERROR("nthread range is backwards\n");
339 #if __TBB_STDARGS_BROKEN
343 while ( i < argc && argv[i][0] == 0 )
346 #endif /* __TBB_STDARGS_BROKEN */
348 REPORT_FATAL_ERROR("Usage: %s [-v] [nthread|minthread:maxthread]\n", argv[0] );
352 #endif /* HARNESS_NO_PARSE_COMMAND_LINE */
354 #if !HARNESS_CUSTOM_MAIN
356 #if __TBB_MPI_INTEROP
363 #if __TBB_MIC_OFFLOAD && __MIC__
364 extern "C" int COIProcessProxyFlush();
368 #if HARNESS_NO_PARSE_COMMAND_LINE
370 #if __TBB_MPI_INTEROP
374 int main(int argc, char* argv[]) {
375 ParseCommandLine( argc, argv );
376 #if __TBB_MPI_INTEROP
377 MPI_Init(&argc,&argv);
380 #if HARNESS_SKIP_TEST
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;
390 MPI_Comm_size(MPI_COMM_WORLD,&size);
391 MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
393 #if !HARNESS_NO_PARSE_COMMAND_LINE
394 REMARK("Hello mpi world. I am %d of %d\n", myrank, size);
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);
404 MPI_Send (&myrank, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
405 MPI_Send (&size, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
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)
416 #pragma offload target(mic) out(res) mandatory
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();
431 ASSERT( res==Harness::Done || res==Harness::Skipped, "Wrong return code by TestMain");
432 #if __TBB_MPI_INTEROP
434 REPORT( res==Harness::Done ? "done\n" : "skip\n" );
438 REPORT( res==Harness::Done ? "done\n" : "skip\n" );
441 #endif /* HARNESS_SKIP_TEST */
444 #endif /* !HARNESS_CUSTOM_MAIN */
446 #if __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT
448 //! Base class for types that should not be assigned.
451 void operator=( const NoAssign& ) = delete;
452 NoAssign( const NoAssign& ) = default;
453 NoAssign() = default;
456 //! Base class for types that should not be copied or assigned.
457 class NoCopy: NoAssign {
459 NoCopy( const NoCopy& ) = delete;
463 #else /*__TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT*/
465 //! Base class for prohibiting compiler-generated operator=
467 //! Assignment not allowed
468 void operator=( const NoAssign& );
470 NoAssign() {} // explicitly defined to prevent gratuitous warnings
473 //! Base class for prohibiting compiler-generated copy constructor or operator=
474 class NoCopy: NoAssign {
475 //! Copy construction not allowed
476 NoCopy( const NoCopy& );
481 #endif /*__TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT*/
483 #if __TBB_CPP11_RVALUE_REF_PRESENT
486 //! Base class for objects which support move ctors
489 Movable() : alive(true) {}
490 void Reset() { alive = true; }
491 Movable(Movable&& other) {
492 ASSERT(other.alive, "Moving from a dead object");
496 Movable& operator=(Movable&& other) {
497 ASSERT(alive, "Assignment to a dead object");
498 ASSERT(other.alive, "Assignment of a dead object");
502 Movable& operator=(const Movable& other) {
503 ASSERT(alive, "Assignment to a dead object");
504 ASSERT(other.alive, "Assignment of a dead object");
507 Movable(const Movable& other) {
508 ASSERT(other.alive, "Const reference to a dead object");
511 ~Movable() { alive = false; }
515 class MoveOnly : Movable, NoCopy {
517 MoveOnly() : Movable() {}
518 MoveOnly(MoveOnly&& other) : Movable( std::move(other) ) {}
520 #endif /* __TBB_CPP11_RVALUE_REF_PRESENT */
522 #if HARNESS_TBBMALLOC_THREAD_SHUTDOWN && __TBB_SOURCE_DIRECTLY_INCLUDED && (_WIN32||_WIN64)
523 #include "../tbbmalloc/tbbmalloc_internal_api.h"
526 //! For internal use by template function NativeParallelFor
527 template<typename Index, typename Body>
528 class NativeParallelForTask: NoCopy {
530 NativeParallelForTask( Index index_, const Body& body_ ) :
539 #if __TBB_WIN8UI_SUPPORT
540 std::thread* thread_tmp=new std::thread(thread_function, this);
541 thread_handle = thread_tmp->native_handle();
544 unsigned stack_size = 0;
545 #if HARNESS_THREAD_STACK_SIZE
546 stack_size = HARNESS_THREAD_STACK_SIZE;
548 thread_handle = (HANDLE)_beginthreadex( NULL, stack_size, thread_function, this, 0, &thread_id );
550 ASSERT( thread_handle!=0, "NativeParallelFor: _beginthreadex failed" );
553 #pragma warning (push)
554 #pragma warning (disable: 2193)
555 #endif /* __ICC==1100 */
556 // Some machines may have very large hard stack limit. When the test is
557 // launched by make, the default stack size is set to the hard limit, and
558 // calls to pthread_create fail with out-of-memory error.
559 // Therefore we set the stack size explicitly (as for TBB worker threads).
560 #if !defined(HARNESS_THREAD_STACK_SIZE)
561 #if __i386__||__i386||__arm__
562 const size_t stack_size = 1*MByte;
564 const size_t stack_size = 2*MByte;
566 const size_t stack_size = 4*MByte;
569 const size_t stack_size = HARNESS_THREAD_STACK_SIZE;
570 #endif /* HARNESS_THREAD_STACK_SIZE */
571 pthread_attr_t attr_stack;
572 int status = pthread_attr_init(&attr_stack);
573 ASSERT(0==status, "NativeParallelFor: pthread_attr_init failed");
574 status = pthread_attr_setstacksize( &attr_stack, stack_size );
575 ASSERT(0==status, "NativeParallelFor: pthread_attr_setstacksize failed");
576 status = pthread_create(&thread_id, &attr_stack, thread_function, this);
577 ASSERT(0==status, "NativeParallelFor: pthread_create failed");
578 pthread_attr_destroy(&attr_stack);
580 #pragma warning (pop)
582 #endif /* _WIN32||_WIN64 */
585 //! Wait for task to finish
586 void wait_to_finish() {
588 DWORD status = WaitForSingleObjectEx( thread_handle, INFINITE, FALSE );
589 ASSERT( status!=WAIT_FAILED, "WaitForSingleObject failed" );
590 CloseHandle( thread_handle );
592 int status = pthread_join( thread_id, NULL );
593 ASSERT( !status, "pthread_join failed" );
595 #if HARNESS_NO_ASSERT
602 HANDLE thread_handle;
607 //! Range over which task will invoke the body.
610 //! Body to invoke over the range.
614 static unsigned __stdcall thread_function( void* object )
616 static void* thread_function(void* object)
619 NativeParallelForTask& self = *static_cast<NativeParallelForTask*>(object);
620 (self.body)(self.index);
621 #if HARNESS_TBBMALLOC_THREAD_SHUTDOWN && __TBB_SOURCE_DIRECTLY_INCLUDED && (_WIN32||_WIN64)
622 // in those cases can't release per-thread cache automatically,
624 // TODO: investigate less-intrusive way to do it, for example via FLS keys
625 __TBB_mallocThreadShutdownNotification();
631 //! Execute body(i) in parallel for i in the interval [0,n).
632 /** Each iteration is performed by a separate thread. */
633 template<typename Index, typename Body>
634 void NativeParallelFor( Index n, const Body& body ) {
635 typedef NativeParallelForTask<Index,Body> task;
638 // Allocate array to hold the tasks
639 task* array = static_cast<task*>(operator new( n*sizeof(task) ));
641 // Construct the tasks
642 for( Index i=0; i!=n; ++i )
643 new( &array[i] ) task(i,body);
646 for( Index i=0; i!=n; ++i )
649 // Wait for the tasks to finish and destroy each one.
650 for( Index i=n; i; --i ) {
651 array[i-1].wait_to_finish();
655 // Deallocate the task array
656 operator delete(array);
660 //! The function to zero-initialize arrays; useful to avoid warnings
661 template <typename T>
662 void zero_fill(void* array, size_t n) {
663 memset(array, 0, sizeof(T)*n);
666 #if __SUNPRO_CC && defined(min)
672 //! Utility template function returning lesser of the two values.
673 /** Provided here to avoid including not strict safe <algorithm>.\n
674 In case operands cause signed/unsigned or size mismatch warnings it is caller's
675 responsibility to do the appropriate cast before calling the function. **/
676 template<typename T1, typename T2>
677 T1 min ( const T1& val1, const T2& val2 ) {
678 return val1 < val2 ? val1 : val2;
683 //! Utility template function returning greater of the two values.
684 /** Provided here to avoid including not strict safe <algorithm>.\n
685 In case operands cause signed/unsigned or size mismatch warnings it is caller's
686 responsibility to do the appropriate cast before calling the function. **/
687 template<typename T1, typename T2>
688 T1 max ( const T1& val1, const T2& val2 ) {
689 return val1 < val2 ? val2 : val1;
694 static inline bool is_aligned(T arg, size_t alignment) {
695 return 0==((size_t)arg & (alignment-1));
699 inline unsigned LinuxKernelVersion()
701 unsigned digit1, digit2, digit3;
702 struct utsname utsnameBuf;
704 if (-1 == uname(&utsnameBuf)) {
705 REPORT_FATAL_ERROR("Can't call uname: errno %d\n", errno);
708 if (3 != sscanf(utsnameBuf.release, "%u.%u.%u", &digit1, &digit2, &digit3)) {
709 REPORT_FATAL_ERROR("Unable to parse OS release '%s'\n", utsnameBuf.release);
712 return 1000000*digit1+1000*digit2+digit3;
718 #if !HARNESS_NO_ASSERT
719 //! Base class that asserts that no operations are made with the object after its destruction.
728 NoAfterlife() : m_state(LIVE) {}
729 NoAfterlife( const NoAfterlife& src ) : m_state(LIVE) {
730 ASSERT( src.IsLive(), "Constructing from the dead source" );
733 ASSERT( IsLive(), "Repeated destructor call" );
736 const NoAfterlife& operator=( const NoAfterlife& src ) {
737 ASSERT( IsLive(), NULL );
738 ASSERT( src.IsLive(), NULL );
741 void AssertLive() const {
742 ASSERT( IsLive(), "Already dead" );
744 bool IsLive() const {
745 return m_state == LIVE;
748 #endif /* !HARNESS_NO_ASSERT */
751 void Sleep ( int ms ) {
752 #if !__TBB_WIN8UI_SUPPORT
755 std::chrono::milliseconds sleep_time( ms );
756 std::this_thread::sleep_for( sleep_time );
762 tid_t CurrentTid () { return GetCurrentThreadId(); }
766 void Sleep ( int ms ) {
767 timespec requested = { ms / 1000, (ms % 1000)*1000000 };
768 timespec remaining = { 0, 0 };
769 nanosleep(&requested, &remaining);
772 typedef pthread_t tid_t;
773 tid_t CurrentTid () { return pthread_self(); }
776 static const unsigned Primes[] = {
777 0x9e3779b1, 0xffe6cc59, 0x2109f6dd, 0x43977ab5, 0xba5703f5, 0xb495a877, 0xe1626741, 0x79695e6b,
778 0xbc98c09f, 0xd5bee2b3, 0x287488f9, 0x3af18231, 0x9677cd4d, 0xbe3a6929, 0xadc6a877, 0xdcf0674b,
779 0xbe4d6fe9, 0x5f15e201, 0x99afc3fd, 0xf3f16801, 0xe222cfff, 0x24ba5fdb, 0x0620452d, 0x79f149e3,
780 0xc8b93f49, 0x972702cd, 0xb07dd827, 0x6c97d5ed, 0x085a3d61, 0x46eb5ea7, 0x3d9910ed, 0x2e687b5b,
781 0x29609227, 0x6eb081f1, 0x0954c4e1, 0x9d114db9, 0x542acfa9, 0xb3e6bd7b, 0x0742d917, 0xe9f3ffa7,
782 0x54581edb, 0xf2480f45, 0x0bb9288f, 0xef1affc7, 0x85fa0ca7, 0x3ccc14db, 0xe6baf34b, 0x343377f7,
783 0x5ca19031, 0xe6d9293b, 0xf0a9f391, 0x5d2e980b, 0xfc411073, 0xc3749363, 0xb892d829, 0x3549366b,
784 0x629750ad, 0xb98294e5, 0x892d9483, 0xc235baf3, 0x3d2402a3, 0x6bdef3c9, 0xbec333cd, 0x40c9520f
790 unsigned short get() {
791 unsigned short r = (unsigned short)(x >> 16);
795 explicit FastRandom( unsigned seed ) {
797 a = Primes[seed % (sizeof(Primes) / sizeof(Primes[0]))];
801 class FastRandomBody {
804 explicit FastRandomBody( unsigned seed ) : r(seed) {}
805 // Depending on the input type T the result distribution formed from this operator()
806 // might possess different characteristics than the original one used in FastRandom instance.
807 T operator()() { return T(r.get()); }
810 int SetEnv( const char *envname, const char *envval ) {
811 ASSERT( envname && envval, "Harness::SetEnv() requires two valid C strings" );
812 #if __TBB_WIN8UI_SUPPORT
813 ASSERT( false, "Harness::SetEnv() should not be called in code built for win8ui" );
815 #elif !(_MSC_VER || __MINGW32__ || __MINGW64__)
816 // On POSIX systems use setenv
817 return setenv(envname, envval, /*overwrite=*/1);
818 #elif __STDC_SECURE_LIB__>=200411
819 // this macro is set in VC & MinGW if secure API functions are present
820 return _putenv_s(envname, envval);
822 // If no secure API on Windows, use _putenv
823 size_t namelen = strlen(envname), valuelen = strlen(envval);
824 char* buf = new char[namelen+valuelen+2];
825 strncpy(buf, envname, namelen);
827 strncpy(buf+namelen+1, envval, valuelen);
828 buf[namelen+1+valuelen] = char(0);
829 int status = _putenv(buf);
835 char* GetEnv(const char *envname) {
836 ASSERT(envname, "Harness::GetEnv() requires a valid C string");
837 #if __TBB_WIN8UI_SUPPORT
840 return std::getenv(envname);
847 explicit DummyBody( int iters ) : m_numIters( iters ) {}
848 void operator()( int ) const {
849 for ( volatile int i = 0; i < m_numIters; ++i ) {}
852 } // namespace Harness
854 #endif /* tbb_tests_harness_H */