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-2018 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 
192 #if __TBB_WIN8UI_SUPPORT
193 bool GetBoolEnvironmentVariable( const char * ) { return false;}
194 #else /* __TBB_WIN8UI_SUPPORT */
195 bool GetBoolEnvironmentVariable( const char * name ) {
196  if( const char* s = std::getenv(name) )
197  return strcmp(s,"0") != 0;
198  return false;
199 }
200 #endif /* __TBB_WIN8UI_SUPPORT */
201 
203 static const char VersionString[] = "\0" TBB_VERSION_STRINGS;
204 
205 static bool PrintVersionFlag = false;
206 
207 void PrintVersion() {
208  PrintVersionFlag = true;
209  fputs(VersionString+1,stderr);
210 }
211 
212 void PrintExtraVersionInfo( const char* category, const char* format, ... ) {
213  if( PrintVersionFlag ) {
214  char str[1024]; memset(str, 0, 1024);
215  va_list args; va_start(args, format);
216  // Note: correct vsnprintf definition obtained from tbb_assert_impl.h
217  vsnprintf( str, 1024-1, format, args);
218  va_end(args);
219  fprintf(stderr, "TBB: %s\t%s\n", category, str );
220  }
221 }
222 
223 void PrintRMLVersionInfo( void* arg, const char* server_info ) {
224  PrintExtraVersionInfo( server_info, (const char *)arg );
225 }
226 
228 #if _MSC_VER
229 #include <intrin.h> // for __cpuid
230 #endif
232 #if __TBB_TSX_AVAILABLE
233 #if (__INTEL_COMPILER || __GNUC__ || _MSC_VER || __SUNPRO_CC)
234  bool result = false;
235  const int rtm_ebx_mask = 1<<11;
236 #if _MSC_VER
237  int info[4] = {0,0,0,0};
238  const int reg_ebx = 1;
239  __cpuidex(info, 7, 0);
240  result = (info[reg_ebx] & rtm_ebx_mask)!=0;
241 #elif __GNUC__ || __SUNPRO_CC
242  int32_t reg_ebx = 0;
243  int32_t reg_eax = 7;
244  int32_t reg_ecx = 0;
245  __asm__ __volatile__ ( "movl %%ebx, %%esi\n"
246  "cpuid\n"
247  "movl %%ebx, %0\n"
248  "movl %%esi, %%ebx\n"
249  : "=a"(reg_ebx) : "0" (reg_eax), "c" (reg_ecx) : "esi",
250 #if __TBB_x86_64
251  "ebx",
252 #endif
253  "edx"
254  );
255  result = (reg_ebx & rtm_ebx_mask)!=0 ;
256 #endif
257  return result;
258 #else
259  #error Speculation detection not enabled for compiler
260 #endif /* __INTEL_COMPILER || __GNUC__ || _MSC_VER */
261 #else /* __TBB_TSX_AVAILABLE */
262  return false;
263 #endif /* __TBB_TSX_AVAILABLE */
264 }
265 
266 } // namespace internal
267 
269  return TBB_INTERFACE_VERSION;
270 }
271 
272 } // namespace tbb
273 
274 #if !__TBB_RML_STATIC
275 #if __TBB_x86_32
276 
277 #include "tbb/atomic.h"
278 
279 // in MSVC environment, int64_t defined in tbb::internal namespace only (see tbb_stddef.h)
280 #if _MSC_VER
281 using tbb::internal::int64_t;
282 #endif
283 
285 extern "C" void __TBB_machine_store8_slow_perf_warning( volatile void *ptr ) {
286  // Report run-time warning unless we have already recently reported warning for that address.
287  const unsigned n = 4;
288  static tbb::atomic<void*> cache[n];
289  static tbb::atomic<unsigned> k;
290  for( unsigned i=0; i<n; ++i )
291  if( ptr==cache[i] )
292  goto done;
293  cache[(k++)%n] = const_cast<void*>(ptr);
294  tbb::internal::runtime_warning( "atomic store on misaligned 8-byte location %p is slow", ptr );
295 done:;
296 }
297 
299 extern "C" void __TBB_machine_store8_slow( volatile void *ptr, int64_t value ) {
300  for( tbb::internal::atomic_backoff b;;b.pause() ) {
301  int64_t tmp = *(int64_t*)ptr;
302  if( __TBB_machine_cmpswp8(ptr,value,tmp)==tmp )
303  break;
304  }
305 }
306 
307 #endif /* __TBB_x86_32 */
308 #endif /* !__TBB_RML_STATIC */
309 
310 #if __TBB_ipf
311 /* It was found that on IA-64 architecture inlining of __TBB_machine_lockbyte leads
312  to serious performance regression with ICC. So keep it out-of-line.
313  */
314 extern "C" intptr_t __TBB_machine_lockbyte( volatile unsigned char& flag ) {
316  while( !__TBB_TryLockByte(flag) ) backoff.pause();
317  return 0;
318 }
319 #endif
int64_t __TBB_machine_lockbyte(volatile unsigned char &ptr)
Exception for PPL locks.
Definition: tbb_exception.h:41
Class that implements exponential backoff.
Definition: tbb_machine.h:349
#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
Specialization for atomic<void*>, for sake of not allowing arithmetic or operator->.
Definition: atomic.h:503
void const char const char int ITT_FORMAT __itt_group_sync s
Exception for missing wait on structured_task_group.
Definition: tbb_exception.h:53
Exception for concurrent containers.
Definition: tbb_exception.h:32
#define PRINT_ERROR_AND_ABORT(exc_name, msg)
Definition: tbb_misc.cpp:62
#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:52
Exception for user-initiated abort.
Definition: tbb_exception.h:47
The last enumerator tracks the number of defined IDs. It must remain the last one.
Definition: tbb_exception.h:97
#define __TBB_machine_cmpswp8
Definition: ibm_aix51.h:46
static bool PrintVersionFlag
Definition: tbb_misc.cpp:205
void pause()
Pause for a while.
Definition: tbb_machine.h:364
bool gcc_rethrow_exception_broken()
Definition: tbb_misc.cpp:189
const char * what() const __TBB_override
Definition: tbb_misc.cpp:51
void PrintExtraVersionInfo(const char *category, const char *format,...)
Prints arbitrary extra TBB version information on stderr.
Definition: tbb_misc.cpp:212
bool __TBB_TryLockByte(__TBB_atomic_flag &flag)
Definition: tbb_machine.h:917
void PrintRMLVersionInfo(void *arg, const char *server_info)
A callback routine to print RML version information on stderr.
Definition: tbb_misc.cpp:223
#define DO_THROW(exc, init_args)
Definition: tbb_misc.cpp:67
void __TBB_EXPORTED_FUNC runtime_warning(const char *format,...)
Report a runtime warning.
bool GetBoolEnvironmentVariable(const char *name)
True if environment variable with given name is set and not 0; otherwise false.
Definition: tbb_misc.cpp:195
void __TBB_EXPORTED_FUNC throw_exception_v4(exception_id)
Gathers all throw operators in one place.
Definition: tbb_misc.cpp:117
const char * what() const __TBB_override
Definition: tbb_misc.cpp:54
The graph class.
bool cpu_has_speculation()
check for transaction support.
Definition: tbb_misc.cpp:231
static const char VersionString[]
Definition: tbb_misc.cpp:203
void __TBB_machine_store8_slow_perf_warning(volatile void *ptr)
const char * what() const __TBB_override
Definition: tbb_misc.cpp:55
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
void PrintVersion()
Prints TBB version information on stderr.
Definition: tbb_misc.cpp:207
#define TBB_VERSION_STRINGS
Definition: tbb_version.h:109
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
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:268
void handle_win_error(int error_code)
Throws std::runtime_error with what() returning error_code description prefixed with aux_info.
const char * what() const __TBB_override
Definition: tbb_misc.cpp:53
Exception for repeated scheduling of the same task_handle.
Definition: tbb_exception.h:59
void __TBB_machine_store8_slow(volatile void *ptr, int64_t value)
Handles misaligned 8-byte store.
void const char const char int ITT_FORMAT __itt_group_sync x void const char * name
#define TBB_INTERFACE_VERSION
Definition: tbb_stddef.h:29
void fix_broken_rethrow()
Definition: tbb_misc.cpp:188
void __TBB_EXPORTED_FUNC throw_bad_last_alloc_exception_v4()
Obsolete.
Definition: tbb_misc.cpp:113

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