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

Copyright © 2005-2019 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.