Implement threading support for gtest on Windows.
Also, stop using localtime(). Instead, use localtime_r() on most systems, localtime_s() on Windows.
This commit is contained in:
parent
ffea2d6040
commit
a6340420b9
@ -379,16 +379,23 @@
|
||||
// Brings in definitions for functions used in the testing::internal::posix
|
||||
// namespace (read, write, close, chdir, isatty, stat). We do not currently
|
||||
// use them on Windows Mobile.
|
||||
#if !GTEST_OS_WINDOWS
|
||||
#if GTEST_OS_WINDOWS
|
||||
# if !GTEST_OS_WINDOWS_MOBILE
|
||||
# include <direct.h>
|
||||
# include <io.h>
|
||||
# endif
|
||||
// In order to avoid having to include <windows.h>, use forward declaration
|
||||
// assuming CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION.
|
||||
// This assumption is verified by
|
||||
// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION.
|
||||
struct _RTL_CRITICAL_SECTION;
|
||||
#else
|
||||
// This assumes that non-Windows OSes provide unistd.h. For OSes where this
|
||||
// is not the case, we need to include headers that provide the functions
|
||||
// mentioned above.
|
||||
# include <unistd.h>
|
||||
# include <strings.h>
|
||||
#elif !GTEST_OS_WINDOWS_MOBILE
|
||||
# include <direct.h>
|
||||
# include <io.h>
|
||||
#endif
|
||||
#endif // GTEST_OS_WINDOWS
|
||||
|
||||
#if GTEST_OS_LINUX_ANDROID
|
||||
// Used to define __ANDROID_API__ matching the target NDK API level.
|
||||
@ -871,6 +878,9 @@ using ::std::tuple_size;
|
||||
# define GTEST_HAS_SEH 0
|
||||
# endif
|
||||
|
||||
#define GTEST_IS_THREADSAFE \
|
||||
(GTEST_OS_WINDOWS || GTEST_HAS_PTHREAD)
|
||||
|
||||
#endif // GTEST_HAS_SEH
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@ -1340,12 +1350,11 @@ extern ::std::vector<testing::internal::string> g_argvs;
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
// Defines synchronization primitives.
|
||||
|
||||
#if GTEST_HAS_PTHREAD
|
||||
|
||||
// Sleeps for (roughly) n milli-seconds. This function is only for
|
||||
// testing Google Test's own constructs. Don't use it in user tests,
|
||||
// either directly or indirectly.
|
||||
#if GTEST_IS_THREADSAFE
|
||||
# if GTEST_HAS_PTHREAD
|
||||
// Sleeps for (roughly) n milliseconds. This function is only for testing
|
||||
// Google Test's own constructs. Don't use it in user tests, either
|
||||
// directly or indirectly.
|
||||
inline void SleepMilliseconds(int n) {
|
||||
const timespec time = {
|
||||
0, // 0 seconds.
|
||||
@ -1353,7 +1362,10 @@ inline void SleepMilliseconds(int n) {
|
||||
};
|
||||
nanosleep(&time, NULL);
|
||||
}
|
||||
# endif // GTEST_HAS_PTHREAD
|
||||
|
||||
# if 0 // OS detection
|
||||
# elif GTEST_HAS_PTHREAD
|
||||
// Allows a controller thread to pause execution of newly created
|
||||
// threads until notified. Instances of this class must be created
|
||||
// and destroyed in the controller thread.
|
||||
@ -1397,6 +1409,62 @@ class Notification {
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
|
||||
};
|
||||
|
||||
# elif GTEST_OS_WINDOWS
|
||||
|
||||
GTEST_API_ void SleepMilliseconds(int n);
|
||||
|
||||
// Provides leak-safe Windows kernel handle ownership.
|
||||
// Used in death tests and in threading support.
|
||||
class GTEST_API_ AutoHandle {
|
||||
public:
|
||||
// Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to
|
||||
// avoid including <windows.h> in this header file. Including <windows.h> is
|
||||
// undesirable because it defines a lot of symbols and macros that tend to
|
||||
// conflict with client code. This assumption is verified by
|
||||
// WindowsTypesTest.HANDLEIsVoidStar.
|
||||
typedef void* Handle;
|
||||
AutoHandle();
|
||||
explicit AutoHandle(Handle handle);
|
||||
|
||||
~AutoHandle();
|
||||
|
||||
Handle Get() const;
|
||||
void Reset();
|
||||
void Reset(Handle handle);
|
||||
|
||||
private:
|
||||
// Returns true iff the handle is a valid handle object that can be closed.
|
||||
bool IsCloseable() const;
|
||||
|
||||
Handle handle_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
|
||||
};
|
||||
|
||||
// Allows a controller thread to pause execution of newly created
|
||||
// threads until notified. Instances of this class must be created
|
||||
// and destroyed in the controller thread.
|
||||
//
|
||||
// This class is only for testing Google Test's own constructs. Do not
|
||||
// use it in user tests, either directly or indirectly.
|
||||
class GTEST_API_ Notification {
|
||||
public:
|
||||
Notification();
|
||||
void Notify();
|
||||
void WaitForNotification();
|
||||
|
||||
private:
|
||||
AutoHandle event_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
|
||||
};
|
||||
# endif // OS detection
|
||||
|
||||
// On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD
|
||||
// defined, but we don't want to use MinGW's pthreads implementation, which
|
||||
// has conformance problems with some versions of the POSIX standard.
|
||||
# if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW
|
||||
|
||||
// As a C-function, ThreadFuncWithCLinkage cannot be templated itself.
|
||||
// Consequently, it cannot select a correct instantiation of ThreadWithParam
|
||||
// in order to call its Run(). Introducing ThreadWithParamBase as a
|
||||
@ -1434,10 +1502,9 @@ extern "C" inline void* ThreadFuncWithCLinkage(void* thread) {
|
||||
template <typename T>
|
||||
class ThreadWithParam : public ThreadWithParamBase {
|
||||
public:
|
||||
typedef void (*UserThreadFunc)(T);
|
||||
typedef void UserThreadFunc(T);
|
||||
|
||||
ThreadWithParam(
|
||||
UserThreadFunc func, T param, Notification* thread_can_start)
|
||||
ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start)
|
||||
: func_(func),
|
||||
param_(param),
|
||||
thread_can_start_(thread_can_start),
|
||||
@ -1464,7 +1531,7 @@ class ThreadWithParam : public ThreadWithParamBase {
|
||||
}
|
||||
|
||||
private:
|
||||
const UserThreadFunc func_; // User-supplied thread function.
|
||||
UserThreadFunc* const func_; // User-supplied thread function.
|
||||
const T param_; // User-supplied parameter to the thread function.
|
||||
// When non-NULL, used to block execution until the controller thread
|
||||
// notifies.
|
||||
@ -1474,26 +1541,255 @@ class ThreadWithParam : public ThreadWithParamBase {
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
|
||||
};
|
||||
# endif // GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW
|
||||
|
||||
// MutexBase and Mutex implement mutex on pthreads-based platforms. They
|
||||
// are used in conjunction with class MutexLock:
|
||||
# if 0 // OS detection
|
||||
# elif GTEST_OS_WINDOWS
|
||||
|
||||
// Mutex implements mutex on Windows platforms. It is 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 MutexBase directly. Instead, write
|
||||
// the following to define a static mutex:
|
||||
// MutexLock lock(&mutex); // Acquires the mutex and releases it at the
|
||||
// // end of the current scope.
|
||||
//
|
||||
// A static Mutex *must* be defined or declared using one of the following
|
||||
// macros:
|
||||
// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex);
|
||||
//
|
||||
// You can forward declare a static mutex like this:
|
||||
//
|
||||
// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
|
||||
//
|
||||
// To create a dynamic mutex, just define an object of type Mutex.
|
||||
// (A non-static Mutex is defined/declared in the usual way).
|
||||
class GTEST_API_ Mutex {
|
||||
public:
|
||||
enum MutexType { kStatic = 0, kDynamic = 1 };
|
||||
// We rely on kStaticMutex being 0 as it is to what the linker initializes
|
||||
// type_ in static mutexes. critical_section_ will be initialized lazily
|
||||
// in ThreadSafeLazyInit().
|
||||
enum StaticConstructorSelector { kStaticMutex = 0 };
|
||||
|
||||
// This constructor intentionally does nothing. It relies on type_ being
|
||||
// statically initialized to 0 (effectively setting it to kStatic) and on
|
||||
// ThreadSafeLazyInit() to lazily initialize the rest of the members.
|
||||
explicit Mutex(StaticConstructorSelector /*dummy*/) {}
|
||||
|
||||
Mutex();
|
||||
~Mutex();
|
||||
|
||||
void Lock();
|
||||
|
||||
void Unlock();
|
||||
|
||||
// Does nothing if the current thread holds the mutex. Otherwise, crashes
|
||||
// with high probability.
|
||||
void AssertHeld();
|
||||
|
||||
private:
|
||||
// Initializes owner_thread_id_ and critical_section_ in static mutexes.
|
||||
void ThreadSafeLazyInit();
|
||||
|
||||
// Per http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx,
|
||||
// we assume that 0 is an invalid value for thread IDs.
|
||||
unsigned int owner_thread_id_;
|
||||
|
||||
// For static mutexes, we rely on these members being initialized to zeros
|
||||
// by the linker.
|
||||
MutexType type_;
|
||||
long critical_section_init_phase_; // NOLINT
|
||||
_RTL_CRITICAL_SECTION* critical_section_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
|
||||
};
|
||||
|
||||
# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
|
||||
extern ::testing::internal::Mutex mutex
|
||||
|
||||
# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
|
||||
::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex)
|
||||
|
||||
// We cannot name this class MutexLock because the ctor declaration would
|
||||
// conflict with a macro named MutexLock, which is defined on some
|
||||
// platforms. That macro is used as a defensive measure to prevent against
|
||||
// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
|
||||
// "MutexLock l(&mu)". Hence the typedef trick below.
|
||||
class GTestMutexLock {
|
||||
public:
|
||||
explicit GTestMutexLock(Mutex* mutex)
|
||||
: mutex_(mutex) { mutex_->Lock(); }
|
||||
|
||||
~GTestMutexLock() { mutex_->Unlock(); }
|
||||
|
||||
private:
|
||||
Mutex* const mutex_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock);
|
||||
};
|
||||
|
||||
typedef GTestMutexLock MutexLock;
|
||||
|
||||
// Base class for ValueHolder<T>. Allows a caller to hold and delete a value
|
||||
// without knowing its type.
|
||||
class ThreadLocalValueHolderBase {
|
||||
public:
|
||||
virtual ~ThreadLocalValueHolderBase() {}
|
||||
};
|
||||
|
||||
// Provides a way for a thread to send notifications to a ThreadLocal
|
||||
// regardless of its parameter type.
|
||||
class ThreadLocalBase {
|
||||
public:
|
||||
// Creates a new ValueHolder<T> object holding a default value passed to
|
||||
// this ThreadLocal<T>'s constructor and returns it. It is the caller's
|
||||
// responsibility not to call this when the ThreadLocal<T> instance already
|
||||
// has a value on the current thread.
|
||||
virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0;
|
||||
|
||||
protected:
|
||||
ThreadLocalBase() {}
|
||||
virtual ~ThreadLocalBase() {}
|
||||
|
||||
private:
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocalBase);
|
||||
};
|
||||
|
||||
// Maps a thread to a set of ThreadLocals that have values instantiated on that
|
||||
// thread and notifies them when the thread exits. A ThreadLocal instance is
|
||||
// expected to persist until all threads it has values on have terminated.
|
||||
class GTEST_API_ ThreadLocalRegistry {
|
||||
public:
|
||||
// Registers thread_local_instance as having value on the current thread.
|
||||
// Returns a value that can be used to identify the thread from other threads.
|
||||
static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
|
||||
const ThreadLocalBase* thread_local_instance);
|
||||
|
||||
// Invoked when a ThreadLocal instance is destroyed.
|
||||
static void OnThreadLocalDestroyed(
|
||||
const ThreadLocalBase* thread_local_instance);
|
||||
};
|
||||
|
||||
class GTEST_API_ ThreadWithParamBase {
|
||||
public:
|
||||
void Join();
|
||||
|
||||
protected:
|
||||
class Runnable {
|
||||
public:
|
||||
virtual ~Runnable() {}
|
||||
virtual void Run() = 0;
|
||||
};
|
||||
|
||||
ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start);
|
||||
virtual ~ThreadWithParamBase();
|
||||
|
||||
private:
|
||||
AutoHandle thread_;
|
||||
};
|
||||
|
||||
// Helper class for testing Google Test's multi-threading constructs.
|
||||
template <typename T>
|
||||
class ThreadWithParam : public ThreadWithParamBase {
|
||||
public:
|
||||
typedef void UserThreadFunc(T);
|
||||
|
||||
ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start)
|
||||
: ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) {
|
||||
}
|
||||
virtual ~ThreadWithParam() {}
|
||||
|
||||
private:
|
||||
class RunnableImpl : public Runnable {
|
||||
public:
|
||||
RunnableImpl(UserThreadFunc* func, T param)
|
||||
: func_(func),
|
||||
param_(param) {
|
||||
}
|
||||
virtual ~RunnableImpl() {}
|
||||
virtual void Run() {
|
||||
func_(param_);
|
||||
}
|
||||
|
||||
private:
|
||||
UserThreadFunc* const func_;
|
||||
const T param_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl);
|
||||
};
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
|
||||
};
|
||||
|
||||
// Implements thread-local storage on Windows systems.
|
||||
//
|
||||
// // Thread 1
|
||||
// ThreadLocal<int> tl(100); // 100 is the default value for each thread.
|
||||
//
|
||||
// // Thread 2
|
||||
// tl.set(150); // Changes the value for thread 2 only.
|
||||
// EXPECT_EQ(150, tl.get());
|
||||
//
|
||||
// // Thread 1
|
||||
// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value.
|
||||
// tl.set(200);
|
||||
// EXPECT_EQ(200, tl.get());
|
||||
//
|
||||
// The template type argument T must have a public copy constructor.
|
||||
// In addition, the default ThreadLocal constructor requires T to have
|
||||
// a public default constructor.
|
||||
//
|
||||
// The users of a TheadLocal instance have to make sure that all but one
|
||||
// threads (including the main one) using that instance have exited before
|
||||
// destroying it. Otherwise, the per-thread objects managed for them by the
|
||||
// ThreadLocal instance are not guaranteed to be destroyed on all platforms.
|
||||
//
|
||||
// Google Test only uses global ThreadLocal objects. That means they
|
||||
// will die after main() has returned. Therefore, no per-thread
|
||||
// object managed by Google Test will be leaked as long as all threads
|
||||
// using Google Test have exited when main() returns.
|
||||
template <typename T>
|
||||
class ThreadLocal : public ThreadLocalBase {
|
||||
public:
|
||||
ThreadLocal() : default_() {}
|
||||
explicit ThreadLocal(const T& value) : default_(value) {}
|
||||
|
||||
~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); }
|
||||
|
||||
T* pointer() { return GetOrCreateValue(); }
|
||||
const T* pointer() const { return GetOrCreateValue(); }
|
||||
const T& get() const { return *pointer(); }
|
||||
void set(const T& value) { *pointer() = value; }
|
||||
|
||||
private:
|
||||
// Holds a value of T. Can be deleted via its base class without the caller
|
||||
// knowing the type of T.
|
||||
class ValueHolder : public ThreadLocalValueHolderBase {
|
||||
public:
|
||||
explicit ValueHolder(const T& value) : value_(value) {}
|
||||
|
||||
T* pointer() { return &value_; }
|
||||
|
||||
private:
|
||||
T value_;
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder);
|
||||
};
|
||||
|
||||
|
||||
T* GetOrCreateValue() const {
|
||||
return static_cast<ValueHolder*>(
|
||||
ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer();
|
||||
}
|
||||
|
||||
virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const {
|
||||
return new ValueHolder(default_);
|
||||
}
|
||||
|
||||
const T default_; // The default value for each thread.
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
|
||||
};
|
||||
|
||||
# elif GTEST_HAS_PTHREAD
|
||||
|
||||
// MutexBase and Mutex implement mutex on pthreads-based platforms.
|
||||
class MutexBase {
|
||||
public:
|
||||
// Acquires this mutex.
|
||||
@ -1538,8 +1834,8 @@ class MutexBase {
|
||||
};
|
||||
|
||||
// Forward-declares a static mutex.
|
||||
# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
|
||||
extern ::testing::internal::MutexBase mutex
|
||||
# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
|
||||
extern ::testing::internal::MutexBase mutex
|
||||
|
||||
// Defines and statically (i.e. at link time) initializes a static mutex.
|
||||
// The initialization list here does not explicitly initialize each field,
|
||||
@ -1547,8 +1843,8 @@ class MutexBase {
|
||||
// particular, the owner_ field (a pthread_t) is not explicitly initialized.
|
||||
// This allows initialization to work whether pthread_t is a scalar or struct.
|
||||
// The flag -Wmissing-field-initializers must not be specified for this to work.
|
||||
# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
|
||||
::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false }
|
||||
# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
|
||||
::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false }
|
||||
|
||||
// The Mutex class can only be used for mutexes created at runtime. It
|
||||
// shares its API with MutexBase otherwise.
|
||||
@ -1566,9 +1862,11 @@ class Mutex : public MutexBase {
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
|
||||
};
|
||||
|
||||
// We cannot name this class MutexLock as the ctor declaration would
|
||||
// We cannot name this class MutexLock because the ctor declaration would
|
||||
// conflict with a macro named MutexLock, which is defined on some
|
||||
// platforms. Hence the typedef trick below.
|
||||
// platforms. That macro is used as a defensive measure to prevent against
|
||||
// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
|
||||
// "MutexLock l(&mu)". Hence the typedef trick below.
|
||||
class GTestMutexLock {
|
||||
public:
|
||||
explicit GTestMutexLock(MutexBase* mutex)
|
||||
@ -1602,34 +1900,6 @@ extern "C" inline void DeleteThreadLocalValue(void* value_holder) {
|
||||
}
|
||||
|
||||
// Implements thread-local storage on pthreads-based systems.
|
||||
//
|
||||
// // Thread 1
|
||||
// ThreadLocal<int> tl(100); // 100 is the default value for each thread.
|
||||
//
|
||||
// // Thread 2
|
||||
// tl.set(150); // Changes the value for thread 2 only.
|
||||
// EXPECT_EQ(150, tl.get());
|
||||
//
|
||||
// // Thread 1
|
||||
// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value.
|
||||
// tl.set(200);
|
||||
// EXPECT_EQ(200, tl.get());
|
||||
//
|
||||
// The template type argument T must have a public copy constructor.
|
||||
// In addition, the default ThreadLocal constructor requires T to have
|
||||
// a public default constructor.
|
||||
//
|
||||
// An object managed for a thread by a ThreadLocal instance is deleted
|
||||
// when the thread exits. Or, if the ThreadLocal instance dies in
|
||||
// that thread, when the ThreadLocal dies. It's the user's
|
||||
// responsibility to ensure that all other threads using a ThreadLocal
|
||||
// have exited when it dies, or the per-thread objects for those
|
||||
// threads will not be deleted.
|
||||
//
|
||||
// Google Test only uses global ThreadLocal objects. That means they
|
||||
// will die after main() has returned. Therefore, no per-thread
|
||||
// object managed by Google Test will be leaked as long as all threads
|
||||
// using Google Test have exited when main() returns.
|
||||
template <typename T>
|
||||
class ThreadLocal {
|
||||
public:
|
||||
@ -1694,9 +1964,9 @@ class ThreadLocal {
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
|
||||
};
|
||||
|
||||
# define GTEST_IS_THREADSAFE 1
|
||||
# endif // OS detection
|
||||
|
||||
#else // GTEST_HAS_PTHREAD
|
||||
#else // GTEST_IS_THREADSAFE
|
||||
|
||||
// A dummy implementation of synchronization primitives (mutex, lock,
|
||||
// and thread-local variable). Necessary for compiling Google Test where
|
||||
@ -1716,6 +1986,11 @@ class Mutex {
|
||||
|
||||
# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex
|
||||
|
||||
// We cannot name this class MutexLock because the ctor declaration would
|
||||
// conflict with a macro named MutexLock, which is defined on some
|
||||
// platforms. That macro is used as a defensive measure to prevent against
|
||||
// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
|
||||
// "MutexLock l(&mu)". Hence the typedef trick below.
|
||||
class GTestMutexLock {
|
||||
public:
|
||||
explicit GTestMutexLock(Mutex*) {} // NOLINT
|
||||
@ -1736,11 +2011,7 @@ class ThreadLocal {
|
||||
T value_;
|
||||
};
|
||||
|
||||
// The above synchronization primitives have dummy implementations.
|
||||
// Therefore Google Test is not thread-safe.
|
||||
# define GTEST_IS_THREADSAFE 0
|
||||
|
||||
#endif // GTEST_HAS_PTHREAD
|
||||
#endif // GTEST_IS_THREADSAFE
|
||||
|
||||
// Returns the number of threads running in the process, or 0 to indicate that
|
||||
// we cannot detect it.
|
||||
|
@ -968,32 +968,6 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
|
||||
// platform.
|
||||
GTEST_API_ std::string GetLastErrnoDescription();
|
||||
|
||||
# if GTEST_OS_WINDOWS
|
||||
// Provides leak-safe Windows kernel handle ownership.
|
||||
class AutoHandle {
|
||||
public:
|
||||
AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}
|
||||
explicit AutoHandle(HANDLE handle) : handle_(handle) {}
|
||||
|
||||
~AutoHandle() { Reset(); }
|
||||
|
||||
HANDLE Get() const { return handle_; }
|
||||
void Reset() { Reset(INVALID_HANDLE_VALUE); }
|
||||
void Reset(HANDLE handle) {
|
||||
if (handle != handle_) {
|
||||
if (handle_ != INVALID_HANDLE_VALUE)
|
||||
::CloseHandle(handle_);
|
||||
handle_ = handle;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE handle_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
|
||||
};
|
||||
# endif // GTEST_OS_WINDOWS
|
||||
|
||||
// Attempts to parse a string into a positive integer pointed to by the
|
||||
// number parameter. Returns true if that is possible.
|
||||
// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use
|
||||
|
@ -36,14 +36,14 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if GTEST_OS_WINDOWS_MOBILE
|
||||
# include <windows.h> // For TerminateProcess()
|
||||
#elif GTEST_OS_WINDOWS
|
||||
#if GTEST_OS_WINDOWS
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
# include <sys/stat.h>
|
||||
# include <map> // Used in ThreadLocal.
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif // GTEST_OS_WINDOWS_MOBILE
|
||||
#endif // GTEST_OS_WINDOWS
|
||||
|
||||
#if GTEST_OS_MAC
|
||||
# include <mach/mach_init.h>
|
||||
@ -134,6 +134,389 @@ size_t GetThreadCount() {
|
||||
|
||||
#endif // GTEST_OS_MAC
|
||||
|
||||
#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
|
||||
|
||||
void SleepMilliseconds(int n) {
|
||||
::Sleep(n);
|
||||
}
|
||||
|
||||
AutoHandle::AutoHandle()
|
||||
: handle_(INVALID_HANDLE_VALUE) {}
|
||||
|
||||
AutoHandle::AutoHandle(Handle handle)
|
||||
: handle_(handle) {}
|
||||
|
||||
AutoHandle::~AutoHandle() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
AutoHandle::Handle AutoHandle::Get() const {
|
||||
return handle_;
|
||||
}
|
||||
|
||||
void AutoHandle::Reset() {
|
||||
Reset(INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
void AutoHandle::Reset(HANDLE handle) {
|
||||
// Resetting with the same handle we already own is invalid.
|
||||
if (handle_ != handle) {
|
||||
if (IsCloseable()) {
|
||||
::CloseHandle(handle_);
|
||||
}
|
||||
handle_ = handle;
|
||||
} else {
|
||||
GTEST_CHECK_(!IsCloseable())
|
||||
<< "Resetting a valid handle to itself is likely a programmer error "
|
||||
"and thus not allowed.";
|
||||
}
|
||||
}
|
||||
|
||||
bool AutoHandle::IsCloseable() const {
|
||||
// Different Windows APIs may use either of these values to represent an
|
||||
// invalid handle.
|
||||
return handle_ != NULL && handle_ != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
Notification::Notification()
|
||||
: event_(::CreateEvent(NULL, // Default security attributes.
|
||||
TRUE, // Do not reset automatically.
|
||||
FALSE, // Initially unset.
|
||||
NULL)) { // Anonymous event.
|
||||
GTEST_CHECK_(event_.Get() != NULL);
|
||||
}
|
||||
|
||||
void Notification::Notify() {
|
||||
GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE);
|
||||
}
|
||||
|
||||
void Notification::WaitForNotification() {
|
||||
GTEST_CHECK_(
|
||||
::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
Mutex::Mutex()
|
||||
: type_(kDynamic),
|
||||
owner_thread_id_(0),
|
||||
critical_section_init_phase_(0),
|
||||
critical_section_(new CRITICAL_SECTION) {
|
||||
::InitializeCriticalSection(critical_section_);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
// Static mutexes are leaked intentionally. It is not thread-safe to try
|
||||
// to clean them up.
|
||||
// TODO(yukawa): Switch to Slim Reader/Writer (SRW) Locks, which requires
|
||||
// nothing to clean it up but is available only on Vista and later.
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937.aspx
|
||||
if (type_ == kDynamic) {
|
||||
::DeleteCriticalSection(critical_section_);
|
||||
delete critical_section_;
|
||||
critical_section_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
ThreadSafeLazyInit();
|
||||
::EnterCriticalSection(critical_section_);
|
||||
owner_thread_id_ = ::GetCurrentThreadId();
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
ThreadSafeLazyInit();
|
||||
// We don't protect writing to owner_thread_id_ here, as it's the
|
||||
// caller's responsibility to ensure that the current thread holds the
|
||||
// mutex when this is called.
|
||||
owner_thread_id_ = 0;
|
||||
::LeaveCriticalSection(critical_section_);
|
||||
}
|
||||
|
||||
// Does nothing if the current thread holds the mutex. Otherwise, crashes
|
||||
// with high probability.
|
||||
void Mutex::AssertHeld() {
|
||||
ThreadSafeLazyInit();
|
||||
GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId())
|
||||
<< "The current thread is not holding the mutex @" << this;
|
||||
}
|
||||
|
||||
// Initializes owner_thread_id_ and critical_section_ in static mutexes.
|
||||
void Mutex::ThreadSafeLazyInit() {
|
||||
// Dynamic mutexes are initialized in the constructor.
|
||||
if (type_ == kStatic) {
|
||||
switch (
|
||||
::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) {
|
||||
case 0:
|
||||
// If critical_section_init_phase_ was 0 before the exchange, we
|
||||
// are the first to test it and need to perform the initialization.
|
||||
owner_thread_id_ = 0;
|
||||
critical_section_ = new CRITICAL_SECTION;
|
||||
::InitializeCriticalSection(critical_section_);
|
||||
// Updates the critical_section_init_phase_ to 2 to signal
|
||||
// initialization complete.
|
||||
GTEST_CHECK_(::InterlockedCompareExchange(
|
||||
&critical_section_init_phase_, 2L, 1L) ==
|
||||
1L);
|
||||
break;
|
||||
case 1:
|
||||
// Somebody else is already initializing the mutex; spin until they
|
||||
// are done.
|
||||
while (::InterlockedCompareExchange(&critical_section_init_phase_,
|
||||
2L,
|
||||
2L) != 2L) {
|
||||
// Possibly yields the rest of the thread's time slice to other
|
||||
// threads.
|
||||
::Sleep(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
break; // The mutex is already initialized and ready for use.
|
||||
|
||||
default:
|
||||
GTEST_CHECK_(false)
|
||||
<< "Unexpected value of critical_section_init_phase_ "
|
||||
<< "while initializing a static mutex.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class ThreadWithParamSupport : public ThreadWithParamBase {
|
||||
public:
|
||||
static HANDLE CreateThread(Runnable* runnable,
|
||||
Notification* thread_can_start) {
|
||||
ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start);
|
||||
DWORD thread_id;
|
||||
// TODO(yukawa): Consider to use _beginthreadex instead.
|
||||
HANDLE thread_handle = ::CreateThread(
|
||||
NULL, // Default security.
|
||||
0, // Default stack size.
|
||||
&ThreadWithParamSupport::ThreadMain,
|
||||
param, // Parameter to ThreadMainStatic
|
||||
0x0, // Default creation flags.
|
||||
&thread_id); // Need a valid pointer for the call to work under Win98.
|
||||
GTEST_CHECK_(thread_handle != NULL) << "CreateThread failed with error "
|
||||
<< ::GetLastError() << ".";
|
||||
if (thread_handle == NULL) {
|
||||
delete param;
|
||||
}
|
||||
return thread_handle;
|
||||
}
|
||||
|
||||
private:
|
||||
struct ThreadMainParam {
|
||||
ThreadMainParam(Runnable* runnable, Notification* thread_can_start)
|
||||
: runnable_(runnable),
|
||||
thread_can_start_(thread_can_start) {
|
||||
}
|
||||
scoped_ptr<Runnable> runnable_;
|
||||
// Does not own.
|
||||
Notification* thread_can_start_;
|
||||
};
|
||||
|
||||
static DWORD WINAPI ThreadMain(void* ptr) {
|
||||
// Transfers ownership.
|
||||
scoped_ptr<ThreadMainParam> param(static_cast<ThreadMainParam*>(ptr));
|
||||
if (param->thread_can_start_ != NULL)
|
||||
param->thread_can_start_->WaitForNotification();
|
||||
param->runnable_->Run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Prohibit instantiation.
|
||||
ThreadWithParamSupport();
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable,
|
||||
Notification* thread_can_start)
|
||||
: thread_(ThreadWithParamSupport::CreateThread(runnable,
|
||||
thread_can_start)) {
|
||||
}
|
||||
|
||||
ThreadWithParamBase::~ThreadWithParamBase() {
|
||||
Join();
|
||||
}
|
||||
|
||||
void ThreadWithParamBase::Join() {
|
||||
GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0)
|
||||
<< "Failed to join the thread with error " << ::GetLastError() << ".";
|
||||
}
|
||||
|
||||
// Maps a thread to a set of ThreadIdToThreadLocals that have values
|
||||
// instantiated on that thread and notifies them when the thread exits. A
|
||||
// ThreadLocal instance is expected to persist until all threads it has
|
||||
// values on have terminated.
|
||||
class ThreadLocalRegistryImpl {
|
||||
public:
|
||||
// Registers thread_local_instance as having value on the current thread.
|
||||
// Returns a value that can be used to identify the thread from other threads.
|
||||
static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
|
||||
const ThreadLocalBase* thread_local_instance) {
|
||||
DWORD current_thread = ::GetCurrentThreadId();
|
||||
MutexLock lock(&mutex_);
|
||||
ThreadIdToThreadLocals* const thread_to_thread_locals =
|
||||
GetThreadLocalsMapLocked();
|
||||
ThreadIdToThreadLocals::iterator thread_local_pos =
|
||||
thread_to_thread_locals->find(current_thread);
|
||||
if (thread_local_pos == thread_to_thread_locals->end()) {
|
||||
thread_local_pos = thread_to_thread_locals->insert(
|
||||
std::make_pair(current_thread, ThreadLocalValues())).first;
|
||||
StartWatcherThreadFor(current_thread);
|
||||
}
|
||||
ThreadLocalValues& thread_local_values = thread_local_pos->second;
|
||||
ThreadLocalValues::iterator value_pos =
|
||||
thread_local_values.find(thread_local_instance);
|
||||
if (value_pos == thread_local_values.end()) {
|
||||
value_pos =
|
||||
thread_local_values
|
||||
.insert(std::make_pair(
|
||||
thread_local_instance,
|
||||
linked_ptr<ThreadLocalValueHolderBase>(
|
||||
thread_local_instance->NewValueForCurrentThread())))
|
||||
.first;
|
||||
}
|
||||
return value_pos->second.get();
|
||||
}
|
||||
|
||||
static void OnThreadLocalDestroyed(
|
||||
const ThreadLocalBase* thread_local_instance) {
|
||||
std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders;
|
||||
// Clean up the ThreadLocalValues data structure while holding the lock, but
|
||||
// defer the destruction of the ThreadLocalValueHolderBases.
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
ThreadIdToThreadLocals* const thread_to_thread_locals =
|
||||
GetThreadLocalsMapLocked();
|
||||
for (ThreadIdToThreadLocals::iterator it =
|
||||
thread_to_thread_locals->begin();
|
||||
it != thread_to_thread_locals->end();
|
||||
++it) {
|
||||
ThreadLocalValues& thread_local_values = it->second;
|
||||
ThreadLocalValues::iterator value_pos =
|
||||
thread_local_values.find(thread_local_instance);
|
||||
if (value_pos != thread_local_values.end()) {
|
||||
value_holders.push_back(value_pos->second);
|
||||
thread_local_values.erase(value_pos);
|
||||
// This 'if' can only be successful at most once, so theoretically we
|
||||
// could break out of the loop here, but we don't bother doing so.
|
||||
}
|
||||
}
|
||||
}
|
||||
// Outside the lock, let the destructor for 'value_holders' deallocate the
|
||||
// ThreadLocalValueHolderBases.
|
||||
}
|
||||
|
||||
static void OnThreadExit(DWORD thread_id) {
|
||||
GTEST_CHECK_(thread_id != 0) << ::GetLastError();
|
||||
std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders;
|
||||
// Clean up the ThreadIdToThreadLocals data structure while holding the
|
||||
// lock, but defer the destruction of the ThreadLocalValueHolderBases.
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
ThreadIdToThreadLocals* const thread_to_thread_locals =
|
||||
GetThreadLocalsMapLocked();
|
||||
ThreadIdToThreadLocals::iterator thread_local_pos =
|
||||
thread_to_thread_locals->find(thread_id);
|
||||
if (thread_local_pos != thread_to_thread_locals->end()) {
|
||||
ThreadLocalValues& thread_local_values = thread_local_pos->second;
|
||||
for (ThreadLocalValues::iterator value_pos =
|
||||
thread_local_values.begin();
|
||||
value_pos != thread_local_values.end();
|
||||
++value_pos) {
|
||||
value_holders.push_back(value_pos->second);
|
||||
}
|
||||
thread_to_thread_locals->erase(thread_local_pos);
|
||||
}
|
||||
}
|
||||
// Outside the lock, let the destructor for 'value_holders' deallocate the
|
||||
// ThreadLocalValueHolderBases.
|
||||
}
|
||||
|
||||
private:
|
||||
// In a particular thread, maps a ThreadLocal object to its value.
|
||||
typedef std::map<const ThreadLocalBase*,
|
||||
linked_ptr<ThreadLocalValueHolderBase> > ThreadLocalValues;
|
||||
// Stores all ThreadIdToThreadLocals having values in a thread, indexed by
|
||||
// thread's ID.
|
||||
typedef std::map<DWORD, ThreadLocalValues> ThreadIdToThreadLocals;
|
||||
|
||||
// Holds the thread id and thread handle that we pass from
|
||||
// StartWatcherThreadFor to WatcherThreadFunc.
|
||||
typedef std::pair<DWORD, HANDLE> ThreadIdAndHandle;
|
||||
|
||||
static void StartWatcherThreadFor(DWORD thread_id) {
|
||||
// The returned handle will be kept in thread_map and closed by
|
||||
// watcher_thread in WatcherThreadFunc.
|
||||
HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION,
|
||||
FALSE,
|
||||
thread_id);
|
||||
GTEST_CHECK_(thread != NULL);
|
||||
// We need to to pass a valid thread ID pointer into CreateThread for it
|
||||
// to work correctly under Win98.
|
||||
DWORD watcher_thread_id;
|
||||
HANDLE watcher_thread = ::CreateThread(
|
||||
NULL, // Default security.
|
||||
0, // Default stack size
|
||||
&ThreadLocalRegistryImpl::WatcherThreadFunc,
|
||||
reinterpret_cast<LPVOID>(new ThreadIdAndHandle(thread_id, thread)),
|
||||
CREATE_SUSPENDED,
|
||||
&watcher_thread_id);
|
||||
GTEST_CHECK_(watcher_thread != NULL);
|
||||
// Give the watcher thread the same priority as ours to avoid being
|
||||
// blocked by it.
|
||||
::SetThreadPriority(watcher_thread,
|
||||
::GetThreadPriority(::GetCurrentThread()));
|
||||
::ResumeThread(watcher_thread);
|
||||
::CloseHandle(watcher_thread);
|
||||
}
|
||||
|
||||
// Monitors exit from a given thread and notifies those
|
||||
// ThreadIdToThreadLocals about thread termination.
|
||||
static DWORD WINAPI WatcherThreadFunc(LPVOID param) {
|
||||
const ThreadIdAndHandle* tah =
|
||||
reinterpret_cast<const ThreadIdAndHandle*>(param);
|
||||
GTEST_CHECK_(
|
||||
::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0);
|
||||
OnThreadExit(tah->first);
|
||||
::CloseHandle(tah->second);
|
||||
delete tah;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns map of thread local instances.
|
||||
static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() {
|
||||
mutex_.AssertHeld();
|
||||
static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals;
|
||||
return map;
|
||||
}
|
||||
|
||||
// Protects access to GetThreadLocalsMapLocked() and its return value.
|
||||
static Mutex mutex_;
|
||||
// Protects access to GetThreadMapLocked() and its return value.
|
||||
static Mutex thread_map_mutex_;
|
||||
};
|
||||
|
||||
Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex);
|
||||
Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex);
|
||||
|
||||
ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread(
|
||||
const ThreadLocalBase* thread_local_instance) {
|
||||
return ThreadLocalRegistryImpl::GetValueOnCurrentThread(
|
||||
thread_local_instance);
|
||||
}
|
||||
|
||||
void ThreadLocalRegistry::OnThreadLocalDestroyed(
|
||||
const ThreadLocalBase* thread_local_instance) {
|
||||
ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance);
|
||||
}
|
||||
|
||||
#endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
|
||||
|
||||
#if GTEST_USES_POSIX_RE
|
||||
|
||||
// Implements RE. Currently only needed for death tests.
|
||||
|
28
src/gtest.cc
28
src/gtest.cc
@ -3219,27 +3219,23 @@ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) {
|
||||
// Converts the given epoch time in milliseconds to a date string in the ISO
|
||||
// 8601 format, without the timezone information.
|
||||
std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) {
|
||||
// Using non-reentrant version as localtime_r is not portable.
|
||||
time_t seconds = static_cast<time_t>(ms / 1000);
|
||||
struct tm time_struct;
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push) // Saves the current warning state.
|
||||
# pragma warning(disable:4996) // Temporarily disables warning 4996
|
||||
// (function or variable may be unsafe).
|
||||
const struct tm* const time_struct = localtime(&seconds); // NOLINT
|
||||
# pragma warning(pop) // Restores the warning state again.
|
||||
#else
|
||||
const struct tm* const time_struct = localtime(&seconds); // NOLINT
|
||||
#endif
|
||||
if (time_struct == NULL)
|
||||
if (localtime_s(&time_struct, &seconds) != 0)
|
||||
return ""; // Invalid ms value
|
||||
#else
|
||||
if (localtime_r(&seconds, &time_struct) == NULL)
|
||||
return ""; // Invalid ms value
|
||||
#endif
|
||||
|
||||
// YYYY-MM-DDThh:mm:ss
|
||||
return StreamableToString(time_struct->tm_year + 1900) + "-" +
|
||||
String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" +
|
||||
String::FormatIntWidth2(time_struct->tm_mday) + "T" +
|
||||
String::FormatIntWidth2(time_struct->tm_hour) + ":" +
|
||||
String::FormatIntWidth2(time_struct->tm_min) + ":" +
|
||||
String::FormatIntWidth2(time_struct->tm_sec);
|
||||
return StreamableToString(time_struct.tm_year + 1900) + "-" +
|
||||
String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" +
|
||||
String::FormatIntWidth2(time_struct.tm_mday) + "T" +
|
||||
String::FormatIntWidth2(time_struct.tm_hour) + ":" +
|
||||
String::FormatIntWidth2(time_struct.tm_min) + ":" +
|
||||
String::FormatIntWidth2(time_struct.tm_sec);
|
||||
}
|
||||
|
||||
// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
|
||||
|
@ -699,7 +699,10 @@ TEST_F(TestForDeathTest, ExpectDebugDeathDoesNotAbort) {
|
||||
|
||||
void AssertDebugDeathHelper(bool* aborted) {
|
||||
*aborted = true;
|
||||
ASSERT_DEBUG_DEATH(return, "") << "This is expected to fail.";
|
||||
GTEST_LOG_(INFO) << "Before ASSERT_DEBUG_DEATH";
|
||||
ASSERT_DEBUG_DEATH(GTEST_LOG_(INFO) << "In ASSERT_DEBUG_DEATH"; return, "")
|
||||
<< "This is expected to fail.";
|
||||
GTEST_LOG_(INFO) << "After ASSERT_DEBUG_DEATH";
|
||||
*aborted = false;
|
||||
}
|
||||
|
||||
@ -712,6 +715,69 @@ TEST_F(TestForDeathTest, AssertDebugDeathAborts) {
|
||||
EXPECT_TRUE(aborted);
|
||||
}
|
||||
|
||||
TEST_F(TestForDeathTest, AssertDebugDeathAborts2) {
|
||||
static bool aborted;
|
||||
aborted = false;
|
||||
EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), "");
|
||||
EXPECT_TRUE(aborted);
|
||||
}
|
||||
|
||||
TEST_F(TestForDeathTest, AssertDebugDeathAborts3) {
|
||||
static bool aborted;
|
||||
aborted = false;
|
||||
EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), "");
|
||||
EXPECT_TRUE(aborted);
|
||||
}
|
||||
|
||||
TEST_F(TestForDeathTest, AssertDebugDeathAborts4) {
|
||||
static bool aborted;
|
||||
aborted = false;
|
||||
EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), "");
|
||||
EXPECT_TRUE(aborted);
|
||||
}
|
||||
|
||||
TEST_F(TestForDeathTest, AssertDebugDeathAborts5) {
|
||||
static bool aborted;
|
||||
aborted = false;
|
||||
EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), "");
|
||||
EXPECT_TRUE(aborted);
|
||||
}
|
||||
|
||||
TEST_F(TestForDeathTest, AssertDebugDeathAborts6) {
|
||||
static bool aborted;
|
||||
aborted = false;
|
||||
EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), "");
|
||||
EXPECT_TRUE(aborted);
|
||||
}
|
||||
|
||||
TEST_F(TestForDeathTest, AssertDebugDeathAborts7) {
|
||||
static bool aborted;
|
||||
aborted = false;
|
||||
EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), "");
|
||||
EXPECT_TRUE(aborted);
|
||||
}
|
||||
|
||||
TEST_F(TestForDeathTest, AssertDebugDeathAborts8) {
|
||||
static bool aborted;
|
||||
aborted = false;
|
||||
EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), "");
|
||||
EXPECT_TRUE(aborted);
|
||||
}
|
||||
|
||||
TEST_F(TestForDeathTest, AssertDebugDeathAborts9) {
|
||||
static bool aborted;
|
||||
aborted = false;
|
||||
EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), "");
|
||||
EXPECT_TRUE(aborted);
|
||||
}
|
||||
|
||||
TEST_F(TestForDeathTest, AssertDebugDeathAborts10) {
|
||||
static bool aborted;
|
||||
aborted = false;
|
||||
EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), "");
|
||||
EXPECT_TRUE(aborted);
|
||||
}
|
||||
|
||||
# endif // _NDEBUG
|
||||
|
||||
// Tests the *_EXIT family of macros, using a variety of predicates.
|
||||
|
@ -1062,11 +1062,13 @@ class AtomicCounterWithMutex {
|
||||
MutexLock lock(mutex_);
|
||||
int temp = value_;
|
||||
{
|
||||
// Locking a mutex puts up a memory barrier, preventing reads and
|
||||
// writes to value_ rearranged when observed from other threads.
|
||||
//
|
||||
// We cannot use Mutex and MutexLock here or rely on their memory
|
||||
// barrier functionality as we are testing them here.
|
||||
// We need to put up a memory barrier to prevent reads and writes to
|
||||
// value_ rearranged with the call to SleepMilliseconds when observed
|
||||
// from other threads.
|
||||
#if GTEST_HAS_PTHREAD
|
||||
// On POSIX, locking a mutex puts up a memory barrier. We cannot use
|
||||
// Mutex and MutexLock here or rely on their memory barrier
|
||||
// functionality as we are testing them here.
|
||||
pthread_mutex_t memory_barrier_mutex;
|
||||
GTEST_CHECK_POSIX_SUCCESS_(
|
||||
pthread_mutex_init(&memory_barrier_mutex, NULL));
|
||||
@ -1076,6 +1078,15 @@ class AtomicCounterWithMutex {
|
||||
|
||||
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&memory_barrier_mutex));
|
||||
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&memory_barrier_mutex));
|
||||
#elif GTEST_OS_WINDOWS
|
||||
// On Windows, performing an interlocked access puts up a memory barrier.
|
||||
volatile LONG dummy = 0;
|
||||
::InterlockedIncrement(&dummy);
|
||||
SleepMilliseconds(random_.Generate(30));
|
||||
::InterlockedIncrement(&dummy);
|
||||
#else
|
||||
# error "Memory barrier not implemented on this platform."
|
||||
#endif // GTEST_HAS_PTHREAD
|
||||
}
|
||||
value_ = temp + 1;
|
||||
}
|
||||
@ -1145,27 +1156,76 @@ TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) {
|
||||
EXPECT_STREQ("foo", result.c_str());
|
||||
}
|
||||
|
||||
// Keeps track of whether of destructors being called on instances of
|
||||
// DestructorTracker. On Windows, waits for the destructor call reports.
|
||||
class DestructorCall {
|
||||
public:
|
||||
DestructorCall() {
|
||||
invoked_ = false;
|
||||
#if GTEST_OS_WINDOWS
|
||||
wait_event_.Reset(::CreateEvent(NULL, TRUE, FALSE, NULL));
|
||||
GTEST_CHECK_(wait_event_.Get() != NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CheckDestroyed() const {
|
||||
#if GTEST_OS_WINDOWS
|
||||
if (::WaitForSingleObject(wait_event_.Get(), 1000) != WAIT_OBJECT_0)
|
||||
return false;
|
||||
#endif
|
||||
return invoked_;
|
||||
}
|
||||
|
||||
void ReportDestroyed() {
|
||||
invoked_ = true;
|
||||
#if GTEST_OS_WINDOWS
|
||||
::SetEvent(wait_event_.Get());
|
||||
#endif
|
||||
}
|
||||
|
||||
static std::vector<DestructorCall*>& List() { return *list_; }
|
||||
|
||||
static void ResetList() {
|
||||
for (size_t i = 0; i < list_->size(); ++i) {
|
||||
delete list_->at(i);
|
||||
}
|
||||
list_->clear();
|
||||
}
|
||||
|
||||
private:
|
||||
bool invoked_;
|
||||
#if GTEST_OS_WINDOWS
|
||||
AutoHandle wait_event_;
|
||||
#endif
|
||||
static std::vector<DestructorCall*>* const list_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(DestructorCall);
|
||||
};
|
||||
|
||||
std::vector<DestructorCall*>* const DestructorCall::list_ =
|
||||
new std::vector<DestructorCall*>;
|
||||
|
||||
// DestructorTracker keeps track of whether its instances have been
|
||||
// destroyed.
|
||||
static std::vector<bool> g_destroyed;
|
||||
|
||||
class DestructorTracker {
|
||||
public:
|
||||
DestructorTracker() : index_(GetNewIndex()) {}
|
||||
DestructorTracker(const DestructorTracker& /* rhs */)
|
||||
: index_(GetNewIndex()) {}
|
||||
~DestructorTracker() {
|
||||
// We never access g_destroyed concurrently, so we don't need to
|
||||
// protect the write operation under a mutex.
|
||||
g_destroyed[index_] = true;
|
||||
// We never access DestructorCall::List() concurrently, so we don't need
|
||||
// to protect this acccess with a mutex.
|
||||
DestructorCall::List()[index_]->ReportDestroyed();
|
||||
}
|
||||
|
||||
private:
|
||||
static int GetNewIndex() {
|
||||
g_destroyed.push_back(false);
|
||||
return g_destroyed.size() - 1;
|
||||
DestructorCall::List().push_back(new DestructorCall);
|
||||
return DestructorCall::List().size() - 1;
|
||||
}
|
||||
const int index_;
|
||||
|
||||
GTEST_DISALLOW_ASSIGN_(DestructorTracker);
|
||||
};
|
||||
|
||||
typedef ThreadLocal<DestructorTracker>* ThreadParam;
|
||||
@ -1177,63 +1237,63 @@ void CallThreadLocalGet(ThreadParam thread_local_param) {
|
||||
// Tests that when a ThreadLocal object dies in a thread, it destroys
|
||||
// the managed object for that thread.
|
||||
TEST(ThreadLocalTest, DestroysManagedObjectForOwnThreadWhenDying) {
|
||||
g_destroyed.clear();
|
||||
DestructorCall::ResetList();
|
||||
|
||||
{
|
||||
// The next line default constructs a DestructorTracker object as
|
||||
// the default value of objects managed by thread_local_tracker.
|
||||
ThreadLocal<DestructorTracker> thread_local_tracker;
|
||||
ASSERT_EQ(1U, g_destroyed.size());
|
||||
ASSERT_FALSE(g_destroyed[0]);
|
||||
ASSERT_EQ(1U, DestructorCall::List().size());
|
||||
ASSERT_FALSE(DestructorCall::List()[0]->CheckDestroyed());
|
||||
|
||||
// This creates another DestructorTracker object for the main thread.
|
||||
thread_local_tracker.get();
|
||||
ASSERT_EQ(2U, g_destroyed.size());
|
||||
ASSERT_FALSE(g_destroyed[0]);
|
||||
ASSERT_FALSE(g_destroyed[1]);
|
||||
ASSERT_EQ(2U, DestructorCall::List().size());
|
||||
ASSERT_FALSE(DestructorCall::List()[0]->CheckDestroyed());
|
||||
ASSERT_FALSE(DestructorCall::List()[1]->CheckDestroyed());
|
||||
}
|
||||
|
||||
// Now thread_local_tracker has died. It should have destroyed both the
|
||||
// default value shared by all threads and the value for the main
|
||||
// thread.
|
||||
ASSERT_EQ(2U, g_destroyed.size());
|
||||
EXPECT_TRUE(g_destroyed[0]);
|
||||
EXPECT_TRUE(g_destroyed[1]);
|
||||
ASSERT_EQ(2U, DestructorCall::List().size());
|
||||
EXPECT_TRUE(DestructorCall::List()[0]->CheckDestroyed());
|
||||
EXPECT_TRUE(DestructorCall::List()[1]->CheckDestroyed());
|
||||
|
||||
g_destroyed.clear();
|
||||
DestructorCall::ResetList();
|
||||
}
|
||||
|
||||
// Tests that when a thread exits, the thread-local object for that
|
||||
// thread is destroyed.
|
||||
TEST(ThreadLocalTest, DestroysManagedObjectAtThreadExit) {
|
||||
g_destroyed.clear();
|
||||
DestructorCall::ResetList();
|
||||
|
||||
{
|
||||
// The next line default constructs a DestructorTracker object as
|
||||
// the default value of objects managed by thread_local_tracker.
|
||||
ThreadLocal<DestructorTracker> thread_local_tracker;
|
||||
ASSERT_EQ(1U, g_destroyed.size());
|
||||
ASSERT_FALSE(g_destroyed[0]);
|
||||
ASSERT_EQ(1U, DestructorCall::List().size());
|
||||
ASSERT_FALSE(DestructorCall::List()[0]->CheckDestroyed());
|
||||
|
||||
// This creates another DestructorTracker object in the new thread.
|
||||
ThreadWithParam<ThreadParam> thread(
|
||||
&CallThreadLocalGet, &thread_local_tracker, NULL);
|
||||
thread.Join();
|
||||
|
||||
// Now the new thread has exited. The per-thread object for it
|
||||
// should have been destroyed.
|
||||
ASSERT_EQ(2U, g_destroyed.size());
|
||||
ASSERT_FALSE(g_destroyed[0]);
|
||||
ASSERT_TRUE(g_destroyed[1]);
|
||||
// The thread has exited, and we should have another DestroyedTracker
|
||||
// instance created for it. But it may not have been destroyed yet.
|
||||
// The instance for the main thread should still persist.
|
||||
ASSERT_EQ(2U, DestructorCall::List().size());
|
||||
ASSERT_FALSE(DestructorCall::List()[0]->CheckDestroyed());
|
||||
}
|
||||
|
||||
// Now thread_local_tracker has died. The default value should have been
|
||||
// destroyed too.
|
||||
ASSERT_EQ(2U, g_destroyed.size());
|
||||
EXPECT_TRUE(g_destroyed[0]);
|
||||
EXPECT_TRUE(g_destroyed[1]);
|
||||
// The thread has exited and thread_local_tracker has died. The default
|
||||
// value should have been destroyed too.
|
||||
ASSERT_EQ(2U, DestructorCall::List().size());
|
||||
EXPECT_TRUE(DestructorCall::List()[0]->CheckDestroyed());
|
||||
EXPECT_TRUE(DestructorCall::List()[1]->CheckDestroyed());
|
||||
|
||||
g_destroyed.clear();
|
||||
DestructorCall::ResetList();
|
||||
}
|
||||
|
||||
TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) {
|
||||
@ -1249,5 +1309,15 @@ TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) {
|
||||
|
||||
#endif // GTEST_IS_THREADSAFE
|
||||
|
||||
#if GTEST_OS_WINDOWS
|
||||
TEST(WindowsTypesTest, HANDLEIsVoidStar) {
|
||||
StaticAssertTypeEq<HANDLE, void*>();
|
||||
}
|
||||
|
||||
TEST(WindowsTypesTest, CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION) {
|
||||
StaticAssertTypeEq<CRITICAL_SECTION, _RTL_CRITICAL_SECTION>();
|
||||
}
|
||||
#endif // GTEST_OS_WINDOWS
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
@ -252,8 +252,8 @@ SUPPORTS_STACK_TRACES = False
|
||||
|
||||
CAN_GENERATE_GOLDEN_FILE = (SUPPORTS_DEATH_TESTS and
|
||||
SUPPORTS_TYPED_TESTS and
|
||||
SUPPORTS_THREADS)
|
||||
|
||||
SUPPORTS_THREADS and
|
||||
not IS_WINDOWS)
|
||||
|
||||
class GTestOutputTest(gtest_test_utils.TestCase):
|
||||
def RemoveUnsupportedTests(self, test_output):
|
||||
|
Loading…
Reference in New Issue
Block a user