aboutsummaryrefslogtreecommitdiffstats
path: root/include/gtest/internal
diff options
context:
space:
mode:
authorzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2010-02-24 17:19:25 +0000
committerzhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925>2010-02-24 17:19:25 +0000
commit3bef459eac9aa84c579f34249aebc9ff56832054 (patch)
treec91cb1205fb45e4a96889ae478afa66a0559694c /include/gtest/internal
parentdd280cfa8dff2247f71a1177d7c8f0c2fde9789a (diff)
downloadgoogletest-3bef459eac9aa84c579f34249aebc9ff56832054.tar.gz
googletest-3bef459eac9aa84c579f34249aebc9ff56832054.tar.bz2
googletest-3bef459eac9aa84c579f34249aebc9ff56832054.zip
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.h2
-rw-r--r--include/gtest/internal/gtest-port.h326
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 f98af0b1..5304bcc2 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 c049a007..3894124c 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