Renames ThreadStartSempahore to Notificaton (by Vlad Losev); adds threading tests for SCOPED_TRACE() (by Vlad Losev); replaces native pthread calls with gtest's threading constructs (by Vlad Losev); fixes flakiness in CountedDestructor (by Vlad Losev); minor MSVC 7.1 clean-up (by Zhanyong Wan).

This commit is contained in:
zhanyong.wan
2010-03-04 22:15:53 +00:00
parent 0928f00c6b
commit 12a92c26fc
12 changed files with 359 additions and 179 deletions

View File

@@ -463,13 +463,10 @@
#include <vector> // NOLINT
#endif
// Determines whether to support value-parameterized tests.
#if defined(__GNUC__) || (_MSC_VER >= 1400)
// TODO(vladl@google.com): get the implementation rid of vector and list
// to compile on MSVC 7.1.
// We don't support MSVC 7.1 with exceptions disabled now. Therefore
// all the compilers we care about are adequate for supporting
// value-parameterized tests.
#define GTEST_HAS_PARAM_TEST 1
#endif // defined(__GNUC__) || (_MSC_VER >= 1400)
// Determines whether to support type-driven tests.
@@ -774,6 +771,97 @@ const ::std::vector<String>& GetArgvs();
#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.
inline void SleepMilliseconds(int n) {
const timespec time = {
0, // 0 seconds.
n * 1000L * 1000L, // And n ms.
};
nanosleep(&time, NULL);
}
// 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 Notification {
public:
Notification() : notified_(false) {}
// Notifies all threads created with this notification to start. Must
// be called from the controller thread.
void Notify() { notified_ = true; }
// Blocks until the controller thread notifies. Must be called from a test
// thread.
void WaitForNotification() {
while(!notified_) {
SleepMilliseconds(10);
}
}
private:
volatile bool notified_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
};
// Helper class for testing Google Test's multi-threading constructs.
// To use it, derive a class template ThreadWithParam<T> from
// ThreadWithParamBase<T> and implement thread creation and startup in
// the constructor and joining the thread in JoinUnderlyingThread().
// Then you can write:
//
// void ThreadFunc(int param) { /* Do things with param */ }
// Notification thread_can_start;
// ...
// // The thread_can_start parameter is optional; you can supply NULL.
// ThreadWithParam<int> thread(&ThreadFunc, 5, &thread_can_start);
// thread_can_start.Notify();
//
// These classes are only for testing Google Test's own constructs. Do
// not use them in user tests, either directly or indirectly.
template <typename T>
class ThreadWithParamBase {
public:
typedef void (*UserThreadFunc)(T);
ThreadWithParamBase(
UserThreadFunc func, T param, Notification* thread_can_start)
: func_(func),
param_(param),
thread_can_start_(thread_can_start),
finished_(false) {}
virtual ~ThreadWithParamBase() {}
void Join() {
if (!finished_) {
JoinUnderlyingThread();
finished_ = true;
}
}
virtual void JoinUnderlyingThread() = 0;
void ThreadMain() {
if (thread_can_start_ != NULL)
thread_can_start_->WaitForNotification();
func_(param_);
}
protected:
const UserThreadFunc 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.
Notification* const thread_can_start_;
bool finished_; // true iff we know that the thread function has finished.
};
// gtest-port.h guarantees to #include <pthread.h> when GTEST_HAS_PTHREAD is
// true.
#include <pthread.h>
@@ -936,99 +1024,32 @@ class ThreadLocal {
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
};
// 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.
inline void SleepMilliseconds(int n) {
const timespec time = {
0, // 0 seconds.
n * 1000L * 1000L, // And n ms.
};
nanosleep(&time, NULL);
}
// Allows a controller thread to pause execution of newly created
// threads until signalled. 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 ThreadStartSemaphore {
public:
ThreadStartSemaphore() : signalled_(false) {}
// Signals to all threads created with this semaphore to start. Must
// be called from the controller thread.
void Signal() { signalled_ = true; }
// Blocks until the controller thread signals. Must be called from a test
// thread.
void Wait() {
while(!signalled_) {
SleepMilliseconds(10);
}
}
private:
volatile bool signalled_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadStartSemaphore);
};
// Helper class for testing Google Test's multi-threading constructs.
// Use:
//
// void ThreadFunc(int param) { /* Do things with param */ }
// ThreadStartSemaphore semaphore;
// ...
// // The semaphore parameter is optional; you can supply NULL.
// ThreadWithParam<int> thread(&ThreadFunc, 5, &semaphore);
// semaphore.Signal(); // Allows the thread to start.
//
// This class is only for testing Google Test's own constructs. Do not
// use it in user tests, either directly or indirectly.
template <typename T>
class ThreadWithParam {
class ThreadWithParam : public ThreadWithParamBase<T> {
public:
typedef void (*UserThreadFunc)(T);
ThreadWithParam(UserThreadFunc func, T param, ThreadStartSemaphore* semaphore)
: func_(func),
param_(param),
start_semaphore_(semaphore),
finished_(false) {
ThreadWithParam(void (*func)(T), T param, Notification* thread_can_start)
: ThreadWithParamBase<T>(func, param, thread_can_start) {
// The thread can be created only after all fields except thread_
// have been initialized.
GTEST_CHECK_POSIX_SUCCESS_(
pthread_create(&thread_, 0, ThreadMainStatic, this));
}
~ThreadWithParam() { Join(); }
virtual ~ThreadWithParam() { this->Join(); }
void Join() {
if (!finished_) {
GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0));
finished_ = true;
}
virtual void JoinUnderlyingThread() {
GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0));
}
private:
void ThreadMain() {
if (start_semaphore_ != NULL)
start_semaphore_->Wait();
func_(param_);
}
static void* ThreadMainStatic(void* thread_with_param) {
static_cast<ThreadWithParam<T>*>(thread_with_param)->ThreadMain();
return NULL; // We are not interested in the thread exit code.
}
const UserThreadFunc 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
// signals.
ThreadStartSemaphore* const start_semaphore_;
bool finished_; // Has the thread function finished?
pthread_t thread_; // The native thread object.
GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
};
#define GTEST_IS_THREADSAFE 1

View File

@@ -51,14 +51,13 @@ namespace internal {
// String - a UTF-8 string class.
//
// We cannot use std::string as Microsoft's STL implementation in
// Visual C++ 7.1 has problems when exception is disabled. There is a
// hack to work around this, but we've seen cases where the hack fails
// to work.
// For historic reasons, we don't use std::string.
//
// Also, String is different from std::string in that it can represent
// both NULL and the empty string, while std::string cannot represent
// NULL.
// TODO(wan@google.com): replace this class with std::string or
// implement it in terms of the latter.
//
// Note that String can represent both NULL and the empty string,
// while std::string cannot represent NULL.
//
// NULL and the empty string are considered different. NULL is less
// than anything (including the empty string) except itself.