Intel(R) Threading Building Blocks Doxygen Documentation version 4.2.3
tbb_misc.cpp
Go to the documentation of this file.
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// Source file for miscellaneous entities that are infrequently referenced by
18// an executing program.
19
20#include "tbb/tbb_stddef.h"
21#include "tbb_assert_impl.h" // Out-of-line TBB assertion handling routines are instantiated here.
22#include "tbb/tbb_exception.h"
23#include "tbb/tbb_machine.h"
24#include "tbb_misc.h"
25#include "tbb_version.h"
26
27#include <cstdio>
28#include <cstdlib>
29#include <stdexcept>
30#include <cstring>
31
32#if _WIN32||_WIN64
34#endif
35
36#if !_WIN32
37#include <unistd.h> // sysconf(_SC_PAGESIZE)
38#endif
39
40#define __TBB_STD_RETHROW_EXCEPTION_POSSIBLY_BROKEN \
41 (__GLIBCXX__ && __TBB_GLIBCXX_VERSION>=40700 && __TBB_GLIBCXX_VERSION<60000 \
42 && TBB_USE_EXCEPTIONS && !TBB_USE_CAPTURED_EXCEPTION)
43
44#if __TBB_STD_RETHROW_EXCEPTION_POSSIBLY_BROKEN
45// GCC ABI declarations necessary for a workaround
46#include <cxxabi.h>
47#endif
48
49namespace tbb {
50
51const char* bad_last_alloc::what() const throw() { return "bad allocation in previous or concurrent attempt"; }
52const char* improper_lock::what() const throw() { return "attempted recursive lock on critical section or non-recursive mutex"; }
53const char* user_abort::what() const throw() { return "User-initiated abort has terminated this operation"; }
54const char* invalid_multiple_scheduling::what() const throw() { return "The same task_handle object cannot be executed more than once"; }
55const char* missing_wait::what() const throw() { return "wait() was not called on the structured_task_group"; }
56
57namespace internal {
58
59#if TBB_USE_EXCEPTIONS
60 #define DO_THROW(exc, init_args) throw exc init_args;
61#else /* !TBB_USE_EXCEPTIONS */
62 #define PRINT_ERROR_AND_ABORT(exc_name, msg) \
63 fprintf (stderr, "Exception %s with message %s would've been thrown, " \
64 "if exception handling were not disabled. Aborting.\n", exc_name, msg); \
65 fflush(stderr); \
66 std::abort();
67 #define DO_THROW(exc, init_args) PRINT_ERROR_AND_ABORT(#exc, #init_args)
68#endif /* !TBB_USE_EXCEPTIONS */
69
71#if _WIN32
72 SYSTEM_INFO si;
73 GetSystemInfo(&si);
74 return si.dwPageSize;
75#else
76 return sysconf(_SC_PAGESIZE);
77#endif
78}
79
80/* The "what" should be fairly short, not more than about 128 characters.
81 Because we control all the call sites to handle_perror, it is pointless
82 to bullet-proof it for very long strings.
83
84 Design note: ADR put this routine off to the side in tbb_misc.cpp instead of
85 Task.cpp because the throw generates a pathetic lot of code, and ADR wanted
86 this large chunk of code to be placed on a cold page. */
87void handle_perror( int error_code, const char* what ) {
88 char buf[256];
89#if _MSC_VER
90 #define snprintf _snprintf
91#endif
92 int written = snprintf(buf, sizeof(buf), "%s: %s", what, strerror( error_code ));
93 // On overflow, the returned value exceeds sizeof(buf) (for GLIBC) or is negative (for MSVC).
94 __TBB_ASSERT_EX( written>0 && written<(int)sizeof(buf), "Error description is too long" );
95 // Ensure that buffer ends in terminator.
96 buf[sizeof(buf)-1] = 0;
97#if TBB_USE_EXCEPTIONS
98 throw std::runtime_error(buf);
99#else
100 PRINT_ERROR_AND_ABORT( "runtime_error", buf);
101#endif /* !TBB_USE_EXCEPTIONS */
102}
103
104#if _WIN32||_WIN64
105void handle_win_error( int error_code ) {
106 char buf[512];
107#if !__TBB_WIN8UI_SUPPORT
108 FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
109 NULL, error_code, 0, buf, sizeof(buf), NULL );
110#else
111//TODO: update with right replacement for FormatMessageA
112 sprintf_s((char*)&buf, 512, "error code %d", error_code);
113#endif
114#if TBB_USE_EXCEPTIONS
115 throw std::runtime_error(buf);
116#else
117 PRINT_ERROR_AND_ABORT( "runtime_error", buf);
118#endif /* !TBB_USE_EXCEPTIONS */
119}
120#endif // _WIN32||_WIN64
121
124}
125
127 __TBB_ASSERT ( eid > 0 && eid < eid_max, "Unknown exception ID" );
128 switch ( eid ) {
129 case eid_bad_alloc: DO_THROW(std::bad_alloc, () );
131 case eid_nonpositive_step: DO_THROW(std::invalid_argument, ("Step must be positive") );
132 case eid_out_of_range: DO_THROW(std::out_of_range, ("Index out of requested size range") );
133 case eid_segment_range_error: DO_THROW(std::range_error, ("Index out of allocated segment slots") );
134 case eid_index_range_error: DO_THROW(std::range_error, ("Index is not allocated") );
138 case eid_possible_deadlock: DO_THROW(std::runtime_error, ("Resource deadlock would occur") );
139 case eid_operation_not_permitted: DO_THROW(std::runtime_error, ("Operation not permitted") );
140 case eid_condvar_wait_failed: DO_THROW(std::runtime_error, ("Wait on condition variable failed") );
141 case eid_invalid_load_factor: DO_THROW(std::out_of_range, ("Invalid hash load factor") );
142 case eid_reserved: DO_THROW(std::out_of_range, ("[backward compatibility] Invalid number of buckets") );
143 case eid_invalid_swap: DO_THROW(std::invalid_argument, ("swap() is invalid on non-equal allocators") );
144 case eid_reservation_length_error: DO_THROW(std::length_error, ("reservation size exceeds permitted max size") );
145 case eid_invalid_key: DO_THROW(std::out_of_range, ("invalid key") );
147 case eid_bad_tagged_msg_cast: DO_THROW(std::runtime_error, ("Illegal tagged_msg cast") );
148#if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE
149 case eid_blocking_thread_join_impossible: DO_THROW(std::runtime_error, ("Blocking terminate failed") );
150#endif
151 default: break;
152 }
153#if !TBB_USE_EXCEPTIONS && __APPLE__
154 out_of_range e1("");
155 length_error e2("");
156 range_error e3("");
157 invalid_argument e4("");
158#endif /* !TBB_USE_EXCEPTIONS && __APPLE__ */
159}
160
161#if __TBB_STD_RETHROW_EXCEPTION_POSSIBLY_BROKEN
162// Runtime detection and workaround for the GCC bug 62258.
163// The problem is that std::rethrow_exception() does not increment a counter
164// of active exceptions, causing std::uncaught_exception() to return a wrong value.
165// The code is created after, and roughly reflects, the workaround
166// at https://gcc.gnu.org/bugzilla/attachment.cgi?id=34683
167
168void fix_broken_rethrow() {
169 struct gcc_eh_data {
170 void * caughtExceptions;
171 unsigned int uncaughtExceptions;
172 };
173 gcc_eh_data* eh_data = punned_cast<gcc_eh_data*>( abi::__cxa_get_globals() );
174 ++eh_data->uncaughtExceptions;
175}
176
178 bool is_broken;
179 __TBB_ASSERT( !std::uncaught_exception(),
180 "gcc_rethrow_exception_broken() must not be called when an exception is active" );
181 try {
182 // Throw, catch, and rethrow an exception
183 try {
184 throw __TBB_GLIBCXX_VERSION;
185 } catch(...) {
186 std::rethrow_exception( std::current_exception() );
187 }
188 } catch(...) {
189 // Check the bug presence
190 is_broken = std::uncaught_exception();
191 }
192 if( is_broken ) fix_broken_rethrow();
193 __TBB_ASSERT( !std::uncaught_exception(), NULL );
194 return is_broken;
195}
196#else
198bool gcc_rethrow_exception_broken() { return false; }
199#endif /* __TBB_STD_RETHROW_EXCEPTION_POSSIBLY_BROKEN */
200
202static const char VersionString[] = "\0" TBB_VERSION_STRINGS;
203
204static bool PrintVersionFlag = false;
205
207 PrintVersionFlag = true;
208 fputs(VersionString+1,stderr);
209}
210
211void PrintExtraVersionInfo( const char* category, const char* format, ... ) {
212 if( PrintVersionFlag ) {
213 char str[1024]; memset(str, 0, 1024);
214 va_list args; va_start(args, format);
215 // Note: correct vsnprintf definition obtained from tbb_assert_impl.h
216 vsnprintf( str, 1024-1, format, args);
217 va_end(args);
218 fprintf(stderr, "TBB: %s\t%s\n", category, str );
219 }
220}
221
222void PrintRMLVersionInfo( void* arg, const char* server_info ) {
223 PrintExtraVersionInfo( server_info, (const char *)arg );
224}
225
227#if _MSC_VER
228#include <intrin.h> // for __cpuid
229#endif
231#if __TBB_TSX_AVAILABLE
232#if (__INTEL_COMPILER || __GNUC__ || _MSC_VER || __SUNPRO_CC)
233 bool result = false;
234 const int rtm_ebx_mask = 1<<11;
235#if _MSC_VER
236 int info[4] = {0,0,0,0};
237 const int reg_ebx = 1;
238 __cpuidex(info, 7, 0);
239 result = (info[reg_ebx] & rtm_ebx_mask)!=0;
240#elif __GNUC__ || __SUNPRO_CC
241 int32_t reg_ebx = 0;
242 int32_t reg_eax = 7;
243 int32_t reg_ecx = 0;
244 __asm__ __volatile__ ( "movl %%ebx, %%esi\n"
245 "cpuid\n"
246 "movl %%ebx, %0\n"
247 "movl %%esi, %%ebx\n"
248 : "=a"(reg_ebx) : "0" (reg_eax), "c" (reg_ecx) : "esi",
249#if __TBB_x86_64
250 "ebx",
251#endif
252 "edx"
253 );
254 result = (reg_ebx & rtm_ebx_mask)!=0 ;
255#endif
256 return result;
257#else
258 #error Speculation detection not enabled for compiler
259#endif /* __INTEL_COMPILER || __GNUC__ || _MSC_VER */
260#else /* __TBB_TSX_AVAILABLE */
261 return false;
262#endif /* __TBB_TSX_AVAILABLE */
263}
264
265} // namespace internal
266
269}
270
271} // namespace tbb
272
273#if !__TBB_RML_STATIC
274#if __TBB_x86_32
275
276#include "tbb/atomic.h"
277
278// in MSVC environment, int64_t defined in tbb::internal namespace only (see tbb_stddef.h)
279#if _MSC_VER
280using tbb::internal::int64_t;
281#endif
282
284extern "C" void __TBB_machine_store8_slow_perf_warning( volatile void *ptr ) {
285 // Report run-time warning unless we have already recently reported warning for that address.
286 const unsigned n = 4;
287 static tbb::atomic<void*> cache[n];
288 static tbb::atomic<unsigned> k;
289 for( unsigned i=0; i<n; ++i )
290 if( ptr==cache[i] )
291 goto done;
292 cache[(k++)%n] = const_cast<void*>(ptr);
293 tbb::internal::runtime_warning( "atomic store on misaligned 8-byte location %p is slow", ptr );
294done:;
295}
296
298extern "C" void __TBB_machine_store8_slow( volatile void *ptr, int64_t value ) {
300 int64_t tmp = *(int64_t*)ptr;
301 if( __TBB_machine_cmpswp8(ptr,value,tmp)==tmp )
302 break;
303 }
304}
305
306#endif /* __TBB_x86_32 */
307#endif /* !__TBB_RML_STATIC */
308
309#if __TBB_ipf
310/* It was found that on IA-64 architecture inlining of __TBB_machine_lockbyte leads
311 to serious performance regression with ICC. So keep it out-of-line.
312 */
313extern "C" intptr_t __TBB_machine_lockbyte( volatile unsigned char& flag ) {
315 while( !__TBB_TryLockByte(flag) ) backoff.pause();
316 return 0;
317}
318#endif
bool __TBB_TryLockByte(__TBB_atomic_flag &flag)
Definition: tbb_machine.h:913
#define __TBB_ASSERT_EX(predicate, comment)
"Extended" version is useful to suppress warnings if a variable is only used with an assert
Definition: tbb_stddef.h:167
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:165
#define TBB_INTERFACE_VERSION
Definition: tbb_stddef.h:25
int64_t __TBB_machine_lockbyte(volatile unsigned char &ptr)
#define __TBB_machine_cmpswp8
Definition: ibm_aix51.h:42
void __TBB_machine_store8_slow(volatile void *ptr, int64_t value)
Handles misaligned 8-byte store.
void __TBB_machine_store8_slow_perf_warning(volatile void *ptr)
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function void size_t int ITT_FORMAT d __itt_heap_function void ITT_FORMAT p __itt_heap_function void void size_t int ITT_FORMAT d no args no args unsigned int ITT_FORMAT u const __itt_domain __itt_id ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain __itt_id ITT_FORMAT p const __itt_domain __itt_id __itt_timestamp __itt_timestamp ITT_FORMAT lu const __itt_domain __itt_id __itt_id __itt_string_handle ITT_FORMAT p const __itt_domain ITT_FORMAT p const __itt_domain __itt_string_handle unsigned long long value
#define PRINT_ERROR_AND_ABORT(exc_name, msg)
Definition: tbb_misc.cpp:62
#define DO_THROW(exc, init_args)
Definition: tbb_misc.cpp:67
#define TBB_VERSION_STRINGS
Definition: tbb_version.h:105
The graph class.
int __TBB_EXPORTED_FUNC TBB_runtime_interface_version()
The function returns the interface version of the TBB shared library being used.
Definition: tbb_misc.cpp:267
bool gcc_rethrow_exception_broken()
Definition: tbb_misc.cpp:198
void __TBB_EXPORTED_FUNC runtime_warning(const char *format,...)
Report a runtime warning.
void __TBB_EXPORTED_FUNC throw_bad_last_alloc_exception_v4()
Obsolete.
Definition: tbb_misc.cpp:122
void fix_broken_rethrow()
Definition: tbb_misc.cpp:197
void __TBB_EXPORTED_FUNC handle_perror(int error_code, const char *aux_info)
Throws std::runtime_error with what() returning error_code description prefixed with aux_info.
Definition: tbb_misc.cpp:87
size_t DefaultSystemPageSize()
Returns OS regular memory page size.
Definition: tbb_misc.cpp:70
void PrintExtraVersionInfo(const char *category, const char *format,...)
Prints arbitrary extra TBB version information on stderr.
Definition: tbb_misc.cpp:211
void PrintRMLVersionInfo(void *arg, const char *server_info)
A callback routine to print RML version information on stderr.
Definition: tbb_misc.cpp:222
static bool PrintVersionFlag
Definition: tbb_misc.cpp:204
void handle_win_error(int error_code)
Throws std::runtime_error with what() returning error_code description prefixed with aux_info.
bool cpu_has_speculation()
check for transaction support.
Definition: tbb_misc.cpp:230
static const char VersionString[]
Definition: tbb_misc.cpp:202
@ eid_reservation_length_error
Definition: tbb_exception.h:83
@ eid_max
The last enumerator tracks the number of defined IDs. It must remain the last one.
Definition: tbb_exception.h:96
@ eid_invalid_multiple_scheduling
Definition: tbb_exception.h:75
@ eid_operation_not_permitted
Definition: tbb_exception.h:78
void __TBB_EXPORTED_FUNC throw_exception_v4(exception_id)
Gathers all throw operators in one place.
Definition: tbb_misc.cpp:126
void PrintVersion()
Prints TBB version information on stderr.
Definition: tbb_misc.cpp:206
Exception for concurrent containers.
Definition: tbb_exception.h:31
const char * what() const __TBB_override
Definition: tbb_misc.cpp:51
Exception for PPL locks.
Definition: tbb_exception.h:40
const char * what() const __TBB_override
Definition: tbb_misc.cpp:52
Exception for user-initiated abort.
Definition: tbb_exception.h:46
const char * what() const __TBB_override
Definition: tbb_misc.cpp:53
Exception for missing wait on structured_task_group.
Definition: tbb_exception.h:52
const char * what() const __TBB_override
Definition: tbb_misc.cpp:55
Exception for repeated scheduling of the same task_handle.
Definition: tbb_exception.h:58
const char * what() const __TBB_override
Definition: tbb_misc.cpp:54
Class that implements exponential backoff.
Definition: tbb_machine.h:345
void pause()
Pause for a while.
Definition: tbb_machine.h:360

Copyright © 2005-2020 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.