diff options
author | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2010-02-24 17:19:25 (GMT) |
---|---|---|
committer | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2010-02-24 17:19:25 (GMT) |
commit | 3bef459eac9aa84c579f34249aebc9ff56832054 (patch) | |
tree | c91cb1205fb45e4a96889ae478afa66a0559694c /include/gtest/internal | |
parent | dd280cfa8dff2247f71a1177d7c8f0c2fde9789a (diff) | |
download | googletest-3bef459eac9aa84c579f34249aebc9ff56832054.zip googletest-3bef459eac9aa84c579f34249aebc9ff56832054.tar.gz googletest-3bef459eac9aa84c579f34249aebc9ff56832054.tar.bz2 |
Adds threading support (by Miklos Fazekas, Vlad Losev, and Chandler Carruth); adds wide InitGoogleTest to gtest.def (by Vlad Losev); updates the version number (by Zhanyong Wan); updates the release notes for 1.5.0 (by Vlad Losev); removes scons scripts from the distribution (by Zhanyong Wan); adds the cmake build script to the distribution (by Zhanyong Wan); adds fused source files to the distribution (by Vlad Losev and Chandler Carruth).
Diffstat (limited to 'include/gtest/internal')
-rw-r--r-- | include/gtest/internal/gtest-linked_ptr.h | 2 | ||||
-rw-r--r-- | include/gtest/internal/gtest-port.h | 326 |
2 files changed, 294 insertions, 34 deletions
diff --git a/include/gtest/internal/gtest-linked_ptr.h b/include/gtest/internal/gtest-linked_ptr.h index f98af0b..5304bcc 100644 --- a/include/gtest/internal/gtest-linked_ptr.h +++ b/include/gtest/internal/gtest-linked_ptr.h @@ -77,7 +77,7 @@ namespace testing { namespace internal { // Protects copying of all linked_ptr objects. -extern Mutex g_linked_ptr_mutex; +GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); // This is used internally by all instances of linked_ptr<>. It needs to be // a non-template class because different types of linked_ptr<> can refer to diff --git a/include/gtest/internal/gtest-port.h b/include/gtest/internal/gtest-port.h index c049a00..3894124 100644 --- a/include/gtest/internal/gtest-port.h +++ b/include/gtest/internal/gtest-port.h @@ -343,10 +343,14 @@ #endif // GTEST_HAS_RTTI -// Determines whether <pthread.h> is available. +// Determines whether Google Test can use the pthreads library. #ifndef GTEST_HAS_PTHREAD -// The user didn't tell us, so we need to figure it out. -#define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_SOLARIS) +// The user didn't tell us explicitly, so we assume pthreads support is +// available on Linux and Mac. +// +// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 +// to your compiler flags. +#define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC) #endif // GTEST_HAS_PTHREAD // Determines whether Google Test can use tr1/tuple. You can define @@ -708,6 +712,27 @@ class GTestLog { inline void LogToStderr() {} inline void FlushInfoLog() { fflush(NULL); } +// INTERNAL IMPLEMENTATION - DO NOT USE. +// +// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition +// is not satisfied. +// Synopsys: +// GTEST_CHECK_(boolean_condition); +// or +// GTEST_CHECK_(boolean_condition) << "Additional message"; +// +// This checks the condition and if the condition is not satisfied +// it prints message about the condition violation, including the +// condition itself, plus additional message streamed into it, if any, +// and then it aborts the program. It aborts the program irrespective of +// whether it is built in the debug mode or not. +#define GTEST_CHECK_(condition) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::IsTrue(condition)) \ + ; \ + else \ + GTEST_LOG_(FATAL) << "Condition " #condition " failed. " + #if GTEST_HAS_STREAM_REDIRECTION_ // Defines the stderr capturer: @@ -736,6 +761,260 @@ const ::std::vector<String>& GetArgvs(); // Defines synchronization primitives. +#if GTEST_HAS_PTHREAD + +// gtest-port.h guarantees to #include <pthread.h> when GTEST_HAS_PTHREAD is +// true. +#include <pthread.h> + +// MutexBase and Mutex implement mutex on pthreads-based platforms. They +// are used in conjunction with class MutexLock: +// +// Mutex mutex; +// ... +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end +// // of the current scope. +// +// MutexBase implements behavior for both statically and dynamically +// allocated mutexes. Do not use the MutexBase type directly. Instead, +// define a static mutex using the GTEST_DEFINE_STATIC_MUTEX_ macro: +// +// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// +// Such mutex may also be forward-declared: +// +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// Do not use MutexBase for dynamic mutexes either. Use the Mutex class +// for them. +class MutexBase { + public: + void Lock(); + void Unlock(); + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld() const; + + // We must be able to initialize objects of MutexBase used as static + // mutexes with initializer lists. This means MutexBase has to be a POD. + // The class members have to be public. + public: + pthread_mutex_t mutex_; + pthread_t owner_; +}; + +// Forward-declares a static mutex. +#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex + +// Defines and statically initializes a static mutex. +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 } + +// The class Mutex supports only mutexes created at runtime. It shares its +// API with MutexBase otherwise. +class Mutex : public MutexBase { + public: + Mutex(); + ~Mutex(); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +// We cannot call it MutexLock directly as the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(MutexBase* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + MutexBase* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Implements thread-local storage on pthreads-based systems. +// +// // Thread 1 +// ThreadLocal<int> tl(100); +// +// // Thread 2 +// tl.set(150); +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // On Thread 1, tl.get() returns original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); +// +// The default ThreadLocal constructor requires T to have a default +// constructor. The single param constructor requires a copy contructor +// from T. A per-thread object managed by a ThreadLocal instance for a +// thread is guaranteed to exist at least until the earliest of the two +// events: (a) the thread terminates or (b) the ThreadLocal object +// managing it is destroyed. +template <typename T> +class ThreadLocal { + public: + ThreadLocal() + : key_(CreateKey()), + default_(), + instance_creator_func_(DefaultConstructNewInstance) {} + + explicit ThreadLocal(const T& value) + : key_(CreateKey()), + default_(value), + instance_creator_func_(CopyConstructNewInstance) {} + + ~ThreadLocal() { + const int err = pthread_key_delete(key_); + GTEST_CHECK_(err == 0) << "pthread_key_delete failed with error " << err; + } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + static pthread_key_t CreateKey() { + pthread_key_t key; + const int err = pthread_key_create(&key, &DeleteData); + GTEST_CHECK_(err == 0) << "pthread_key_create failed with error " << err; + return key; + } + + T* GetOrCreateValue() const { + T* value = static_cast<T*>(pthread_getspecific(key_)); + if (value == NULL) { + value = (*instance_creator_func_)(default_); + const int err = pthread_setspecific(key_, value); + GTEST_CHECK_(err == 0) << "pthread_setspecific failed with error " << err; + } + return value; + } + + static void DeleteData(void* data) { delete static_cast<T*>(data); } + + static T* DefaultConstructNewInstance(const T&) { return new T(); } + + // Copy constructs new instance of T from default_. Will not be + // instantiated unless this ThreadLocal is constructed by the single + // parameter constructor. + static T* CopyConstructNewInstance(const T& t) { return new T(t); } + + // A key pthreads uses for looking up per-thread values. + const pthread_key_t key_; + // Contains the value that CopyConstructNewInstance copies from. + const T default_; + // Points to either DefaultConstructNewInstance or CopyConstructNewInstance. + T* (*const instance_creator_func_)(const T& default_); + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +// Allows the controller thread pause execution of newly created test +// threads until signalled. Instances of this class must be created and +// destroyed in the controller thread. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. +class ThreadStartSemaphore { + public: + ThreadStartSemaphore(); + ~ThreadStartSemaphore(); + // Signals to all test threads created with this semaphore to start. Must + // be called from the controlling thread. + void Signal(); + // Blocks until the controlling thread signals. Must be called from a test + // thread. + void Wait(); + + private: + // We cannot use Mutex here as this class is intended for testing it. + pthread_mutex_t mutex_; + pthread_cond_t cond_; + bool signalled_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadStartSemaphore); +}; + +// Helper class for testing Google Test's multithreading constructs. +// Use: +// +// void ThreadFunc(int param) { /* Do things with param */ } +// ThreadSemaphore semaphore; +// ... +// // The semaphore parameter is optional; you can supply NULL. +// ThredWithParam<int> thread(&ThreadFunc, 5, &semaphore); +// sem.Signal(); // Allows the thread to start. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. +template <typename T> +class ThreadWithParam { + public: + typedef void (*UserThreadFunc)(T); + + ThreadWithParam(UserThreadFunc func, T param, ThreadStartSemaphore* semaphore) + : func_(func), + param_(param), + start_semaphore_(semaphore), + finished_(false) { + // func_, param_, and start_semaphore_ must be initialized before + // pthread_create() is called. + const int err = pthread_create(&thread_, 0, ThreadMainStatic, this); + GTEST_CHECK_(err == 0) << "pthread_create failed with error: " + << strerror(err) << "(" << err << ")"; + } + ~ThreadWithParam() { Join(); } + + void Join() { + if (!finished_) { + const int err = pthread_join(thread_, 0); + GTEST_CHECK_(err == 0) << "pthread_join failed with error:" + << strerror(err) << "(" << err << ")"; + finished_ = true; + } + } + + private: + void ThreadMain() { + if (start_semaphore_ != NULL) + start_semaphore_->Wait(); + func_(param_); + } + static void* ThreadMainStatic(void* param) { + static_cast<ThreadWithParam<T>*>(param)->ThreadMain(); + return NULL; // We are not interested in thread exit code. + } + + // User supplied thread function. + const UserThreadFunc func_; + // User supplied parameter to UserThreadFunc. + const T param_; + + // Native thread object. + pthread_t thread_; + // When non-NULL, used to block execution until the controller thread + // signals. + ThreadStartSemaphore* const start_semaphore_; + // true iff UserThreadFunc has not completed yet. + bool finished_; +}; + +#define GTEST_IS_THREADSAFE 1 + +#else // GTEST_HAS_PTHREAD + // A dummy implementation of synchronization primitives (mutex, lock, // and thread-local variable). Necessary for compiling Google Test where // mutex is not supported - using Google Test in multiple threads is not @@ -744,14 +1023,14 @@ const ::std::vector<String>& GetArgvs(); class Mutex { public: Mutex() {} - explicit Mutex(int /*unused*/) {} void AssertHeld() const {} - enum { NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX = 0 }; }; -// We cannot call it MutexLock directly as the ctor declaration would -// conflict with a macro named MutexLock, which is defined on some -// platforms. Hence the typedef trick below. +#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +#define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex + class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT @@ -772,14 +1051,16 @@ class ThreadLocal { T value_; }; -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. -size_t GetThreadCount(); - // The above synchronization primitives have dummy implementations. // Therefore Google Test is not thread-safe. #define GTEST_IS_THREADSAFE 0 +#endif // GTEST_HAS_PTHREAD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount(); + // Passing non-POD classes through ellipsis (...) crashes the ARM // compiler and generates a warning in Sun Studio. The Nokia Symbian // and the IBM XL C/C++ compiler try to instantiate a copy constructor @@ -1024,27 +1305,6 @@ typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Utilities for command line flags and environment variables. -// INTERNAL IMPLEMENTATION - DO NOT USE. -// -// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition -// is not satisfied. -// Synopsys: -// GTEST_CHECK_(boolean_condition); -// or -// GTEST_CHECK_(boolean_condition) << "Additional message"; -// -// This checks the condition and if the condition is not satisfied -// it prints message about the condition violation, including the -// condition itself, plus additional message streamed into it, if any, -// and then it aborts the program. It aborts the program irrespective of -// whether it is built in the debug mode or not. -#define GTEST_CHECK_(condition) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::IsTrue(condition)) \ - ; \ - else \ - GTEST_LOG_(FATAL) << "Condition " #condition " failed. " - // Macro for referencing flags. #define GTEST_FLAG(name) FLAGS_gtest_##name |