/* 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 ((void)0, 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 ((void)0, 0)
#else
# define CHECK assert
#endif
// support for stlport in stlp_std:: namespace (or other custom ns)
#ifdef TS_STL_NS
# define STD TS_STL_NS
#else
# define STD std
#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 <new>
#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 "new"
#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>
#include <new>
// 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::string;
using STD::set;
using STD::multiset;
using STD::multimap;
using STD::map;
using STD::deque;
using STD::stack;
using STD::vector;
using STD::bitset;
using STD::nothrow_t;
using STD::nothrow;
using STD::min;
using STD::max;
using STD::sort;
using STD::pair;
using STD::make_pair;
using STD::unique_copy;
using STD::count;
using STD::set_intersection;
using STD::lower_bound;
using STD::copy;
using STD::binary_search;
#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((void)0, 0)
#define DEBUG_MODE (0)
#endif
#ifndef ALWAYS_INLINE
#if defined (__GNUC__)
#define ALWAYS_INLINE inline __attribute__ ((always_inline))
#elif defined(_MSC_VER)
#define ALWAYS_INLINE __forceinline
#else
#error "Unknown Configuration"
#endif
#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
#elif defined(TS_GO)
# 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 void PROCESSOR_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
typedef unsigned prng_t;
/// Simple stand-alone pseudorandom number generator.
/// Current algorithm is ANSI C linear congruential PRNG.
inline unsigned tsan_prng(prng_t* state) {
return (*state = *state * 1103515245 + 12345) >> 16;
}
#endif // TS_UTIL_H_
// end. {{{1
// vim:shiftwidth=2:softtabstop=2:expandtab:tw=80