/* Copyright (c) 2008-2010, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // This file is part of ThreadSanitizer, a dynamic data race detector. // Author: Konstantin Serebryany. // Author: Timur Iskhodzhanov. // This file contains utility classes and functions used by ThreadSanitizer. // TODO(kcc): move more utilities from thread_sanitizer.cc to this file. #ifndef TS_UTIL_H_ #define TS_UTIL_H_ //--------- Head ------------------- {{{1 #if defined(TS_VALGRIND) # define CHECK tl_assert #elif defined(TS_PIN) extern void Printf(const char *format, ...); extern void ThreadSanitizerDumpAllStacks(); # define CHECK(x) do { if (!(x)) { \ Printf("Assertion failed: %s (%s:%d) %s\n", \ __FUNCTION__, __FILE__, __LINE__, #x); \ ThreadSanitizerDumpAllStacks(); \ exit(1); }} while (0) #elif defined(TS_OFFLINE) extern unsigned long offline_line_n; # define CHECK(x) do { if (!(x)) { \ Printf("ASSERT on line %ld\n", offline_line_n); \ assert(x);}} while (0) #else # define CHECK assert #endif #if defined(TS_VALGRIND) # include "ts_valgrind.h" # define TS_USE_STLPORT #if defined(VGP_arm_linux) // This macro is explicitly undefined in glibc for ARM. #define _GLIBCXX_USE_C99 1 #endif // ARM // __WORDSIZE is GLibC-specific. Get it from Valgrind if needed. #if !defined(__WORDSIZE) #if VG_WORDSIZE == 4 #define __WORDSIZE 32 #elif VG_WORDSIZE == 8 #define __WORDSIZE 64 #endif // VG_WORDSIZE #endif // TS_VALGRIND && !__WORDSIZE #elif defined(TS_LLVM) # define TS_USE_STLPORT # include <assert.h> # include <fcntl.h> # include <time.h> #elif defined(__GNUC__) # undef NDEBUG // Assert is always on. # include <assert.h> # include <sys/types.h> # include <sys/stat.h> # include <fcntl.h> # define TS_USE_GNUC_STL #elif defined(_MSC_VER) # undef NDEBUG // Assert is always on. # include <assert.h> # include <stdio.h> # include <intrin.h> # define TS_USE_WIN_STL #else # error "Unknown configuration" #endif //--------- STL ------------------- {{{1 #if defined(TS_USE_GNUC_STL) // ----------- g++ STL ----------- #include <string.h> #include <limits.h> #include <set> #include <map> #include <vector> #include <deque> #include <stack> #include <algorithm> #include <string> #include <bitset> #include "ext/algorithm" #ifdef __APPLE__ // Apple's unordered_map in gcc 4.0 does not support -fno-exceptions. #include "ext/hash_map" #include "ext/hash_set" #define unordered_map __gnu_cxx::hash_map #define unordered_set __gnu_cxx::hash_set #else #include "tr1/unordered_map" #include "tr1/unordered_set" using std::tr1::unordered_map; using std::tr1::unordered_set; #endif #elif defined(TS_USE_STLPORT) // ------------- STLport ---------- #include "set" #include "map" #include "hash_map" #include "hash_set" #include "vector" #include "deque" #include "stack" #include "algorithm" #include "string" #include "bitset" #include "algorithm" #include "unordered_map" #include "unordered_set" using std::tr1::unordered_map; using std::tr1::unordered_set; #elif defined(TS_USE_WIN_STL) // ------------- MSVC STL --------- #include <string.h> #include <limits.h> #include <set> #include <map> #include <vector> #include <deque> #include <stack> #include <algorithm> #include <string> #include <bitset> // No such thing in VC 2005 //#include <unordered_map> //#include <unordered_set> //using std::tr1::unordered_map; //using std::tr1::unordered_set; #include <hash_map> #include <hash_set> #define unordered_map stdext::hash_map #define unordered_set stdext::hash_set #else # error "Unknown STL" #endif // TS_USE_STANDARD_STL using std::set; using std::multiset; using std::multimap; using std::map; using std::deque; using std::stack; using std::string; using std::vector; using std::bitset; using std::min; using std::max; using std::sort; using std::pair; using std::make_pair; using std::unique_copy; #ifdef TS_LLVM # include "tsan_rtl_wrap.h" #endif //--------- defines ------------------- {{{1 #ifdef TS_VALGRIND // TODO(kcc) get rid of these macros. #define sprintf(arg1, arg2...) VG_(sprintf)((Char*)arg1, (HChar*)arg2) #define vsnprintf(a1, a2, a3, a4) VG_(vsnprintf)((Char*)a1, a2, a3, a4) #define getpid VG_(getpid) #define strchr(a,b) VG_(strchr)((Char*)a,b) #define strdup(a) (char*)VG_(strdup)((HChar*)"strdup", (const Char*)a) #define snprintf(a,b,c...) VG_(snprintf)((Char*)a,b,c) #define read VG_(read) #define getenv(x) VG_(getenv)((Char*)x) #define close VG_(close) #define write VG_(write) #define usleep(a) /*nothing. TODO.*/ #elif defined(__GNUC__) #include <unistd.h> #include <stdint.h> #include <stdio.h> #define UNLIKELY(x) __builtin_expect((x), 0) #define LIKELY(x) __builtin_expect(!!(x), 1) #elif defined(_MSC_VER) typedef __int8 int8_t; typedef __int16 int16_t; typedef __int32 int32_t; typedef __int64 int64_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; typedef int pthread_t; int getpid(); #define snprintf _snprintf #define strtoll strtol // TODO(kcc): _MSC_VER hmm... #define UNLIKELY(x) (x) // TODO(kcc): how to say this in MSVC? #define LIKELY(x) (x) #else # error "Unknown configuration" #endif // TS_VALGRIND #define CHECK_GT(X, Y) CHECK((X) > (Y)) #define CHECK_LT(X, Y) CHECK((X) < (Y)) #define CHECK_GE(X, Y) CHECK((X) >= (Y)) #define CHECK_LE(X, Y) CHECK((X) <= (Y)) #define CHECK_NE(X, Y) CHECK((X) != (Y)) #define CHECK_EQ(X, Y) CHECK((X) == (Y)) #if defined(DEBUG) && DEBUG >= 1 #define DCHECK(a) CHECK(a) #define DEBUG_MODE (1) #else #define DCHECK(a) do { if (0) { if (a) {} } } while(0) #define DEBUG_MODE (0) #endif #if defined (__GNUC__) #define ALWAYS_INLINE inline __attribute__ ((always_inline)) #elif defined(_MSC_VER) #define ALWAYS_INLINE __forceinline #else #error "Unknown Configuration" #endif #if defined(DEBUG) && DEBUG >= 1 #define INLINE #define NOINLINE #elif defined (__GNUC__) #define INLINE ALWAYS_INLINE #define NOINLINE __attribute__ ((noinline)) #elif defined(_MSC_VER) #define INLINE ALWAYS_INLINE #define NOINLINE __declspec(noinline) #else #error "Unknown Configuration" #endif // When TS_SERIALIZED==1, all calls to ThreadSanitizer* functions // should be serialized somehow. For example: // - Valgrind serializes threads by using a pipe-based semaphore. // - ThreadSanitizerOffline is single-threaded by nature. // - A Multi-threaded environment (e.g. PIN) can use a single global Mutex. // When TS_SERIALIZED==0, ThreadSanitizer takes care of synchronization itself. #if defined(TS_SERIALIZED) // someone defined this already, leave it as is. #elif defined(TS_PIN) # define TS_SERIALIZED 1 #elif defined(TS_LLVM) # define TS_SERIALIZED 0 #else # define TS_SERIALIZED 1 #endif #define TS_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) //--------- Malloc profiling ------------------- {{{1 class MallocCostCenterStack { public: void Push(const char *cc) { malloc_cost_centers_[size_++] = cc; } void Pop() { size_--; } const char *Top() { return size_ ? malloc_cost_centers_[size_ - 1] : "default_cc"; } private: enum { kMaxMallocStackSize = 100 }; int size_; const char *malloc_cost_centers_[kMaxMallocStackSize]; }; // Not thread-safe. Need to make it thread-local if we allow // malloc to be called concurrently. extern MallocCostCenterStack g_malloc_stack; class ScopedMallocCostCenter { public: ScopedMallocCostCenter(const char *cc) { #if defined(TS_VALGRIND) g_malloc_stack.Push(cc); #endif } ~ScopedMallocCostCenter() { #if defined(TS_VALGRIND) g_malloc_stack.Pop(); #endif } }; //--------- Forward decls ------------------- {{{1 class ThreadSanitizerReport; // Time since some moment before the program start. extern size_t TimeInMilliSeconds(); extern void YIELD(); extern "C" long my_strtol(const char *str, char **end, int base); extern void Printf(const char *format, ...); // Strip (.*) and <.*>, also handle "function returns a function pointer" case. string NormalizeFunctionName(const string &mangled_fname); string ReadFileToString(const string &file_name, bool die_if_failed); // Get the current memory footprint of myself (parse /proc/self/status). size_t GetVmSizeInMb(); // Sets the contents of the file 'file_name' to 'str'. void OpenFileWriteStringAndClose(const string &file_name, const string &str); // If host_and_port looks like myhost:12345, open a socket for writing // and returns a FILE object. Retuns NULL on failure. FILE *OpenSocketForWriting(const string &host_and_port); // If addr is inside a global object, returns true and sets 'name' and 'offset' bool GetNameAndOffsetOfGlobalObject(uintptr_t addr, string *name, uintptr_t *offset); extern uintptr_t GetPcOfCurrentThread(); extern void GetThreadStack(int tid, uintptr_t *min_addr, uintptr_t *max_addr); extern void SetNumberOfFoundErrors(int n_errs); extern int GetNumberOfFoundErrors(); bool LiteRaceSkipTrace(int tid, uint32_t trace_no, uint32_t sampling_rate); inline uintptr_t tsan_bswap(uintptr_t x) { #if defined(VGP_arm_linux) && __WORDSIZE == 64 return __builtin_bswap64(x); #elif defined(VGP_arm_linux) && __WORDSIZE == 32 return __builtin_bswap32(x); #elif defined(__GNUC__) && __WORDSIZE == 64 __asm__("bswapq %0" : "=r" (x) : "0" (x)); return x; #elif defined(__GNUC__) && __WORDSIZE == 32 __asm__("bswapl %0" : "=r" (x) : "0" (x)); return x; #elif defined(_WIN32) return x; // TODO(kcc) #else # error "Unknown Configuration" #endif // arch && VG_WORDSIZE } #ifdef _MSC_VER inline unsigned u32_log2(unsigned x) { unsigned long y; _BitScanReverse(&y, x); return y; } #endif #ifdef __GNUC__ inline unsigned u32_log2(unsigned x) { return 31 - __builtin_clz(x); } #endif #endif // TS_UTIL_H_ // end. {{{1 // vim:shiftwidth=2:softtabstop=2:expandtab:tw=80