Commit 4879aac7 by zhanyong.wan

Simplifies the threading implementation and improves some comments.

parent 0d27868d
......@@ -81,10 +81,8 @@ const int kStdErrFileno = STDERR_FILENO;
// newly created test threads until signalled. Instances of this class must
// be created and destroyed in the controller thread.
ThreadStartSemaphore::ThreadStartSemaphore() : signalled_(false) {
int err = pthread_mutex_init(&mutex_, NULL);
GTEST_CHECK_(err == 0) << "pthread_mutex_init failed with error " << err;
err = pthread_cond_init(&cond_, NULL);
GTEST_CHECK_(err == 0) << "pthread_cond_init failed with error " << err;
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_init(&cond_, NULL));
pthread_mutex_lock(&mutex_);
}
......@@ -92,75 +90,29 @@ ThreadStartSemaphore::~ThreadStartSemaphore() {
// Every ThreadStartSemaphore object must be signalled. It locks
// internal mutex upon creation and Signal unlocks it.
GTEST_CHECK_(signalled_);
int err = pthread_mutex_destroy(&mutex_);
GTEST_CHECK_(err == 0)
<< "pthread_mutex_destroy failed with error " << err;
err = pthread_cond_destroy(&cond_);
GTEST_CHECK_(err == 0)
<< "pthread_cond_destroy failed with error " << err;
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_));
GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_destroy(&cond_));
}
// Signals to all test threads to start. Must be called from the
// controlling thread.
void ThreadStartSemaphore::Signal() {
signalled_ = true;
int err = pthread_cond_signal(&cond_);
GTEST_CHECK_(err == 0)
<< "pthread_cond_signal failed with error " << err;
err = pthread_mutex_unlock(&mutex_);
GTEST_CHECK_(err == 0)
<< "pthread_mutex_unlock failed with error " << err;
GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_signal(&cond_));
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
}
// Blocks until the controlling thread signals. Should be called from a
// test thread.
void ThreadStartSemaphore::Wait() {
int err = pthread_mutex_lock(&mutex_);
GTEST_CHECK_(err == 0) << "pthread_mutex_lock failed with error " << err;
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_));
while (!signalled_) {
err = pthread_cond_wait(&cond_, &mutex_);
GTEST_CHECK_(err == 0)
<< "pthread_cond_wait failed with error " << err;
GTEST_CHECK_POSIX_SUCCESS_(pthread_cond_wait(&cond_, &mutex_));
}
err = pthread_mutex_unlock(&mutex_);
GTEST_CHECK_(err == 0)
<< "pthread_mutex_unlock failed with error " << err;
}
void MutexBase::Lock() {
const int err = pthread_mutex_lock(&mutex_);
GTEST_CHECK_(err == 0) << "pthread_mutex_lock failed with error " << err;
owner_ = pthread_self();
}
void MutexBase::Unlock() {
// We don't protect writing to owner_ here, as it's the caller's
// responsibility to ensure that the current thread holds the mutex when
// this is called.
owner_ = 0;
const int err = pthread_mutex_unlock(&mutex_);
GTEST_CHECK_(err == 0) << "pthread_mutex_unlock failed with error " << err;
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
}
// Does nothing if the current thread holds the mutex. Otherwise, crashes
// with high probability.
void MutexBase::AssertHeld() const {
GTEST_CHECK_(owner_ == pthread_self())
<< "Current thread is not holding mutex." << this;
}
Mutex::Mutex() {
owner_ = 0;
const int err = pthread_mutex_init(&mutex_, NULL);
GTEST_CHECK_(err == 0) << "pthread_mutex_init failed with error " << err;
}
Mutex::~Mutex() {
const int err = pthread_mutex_destroy(&mutex_);
GTEST_CHECK_(err == 0) << "pthread_mutex_destroy failed with error " << err;
}
#endif // GTEST_HAS_PTHREAD
#if GTEST_OS_MAC
......
......@@ -770,18 +770,6 @@ TEST(ThreadLocalTest, SingleParamConstructorInitializesToParam) {
EXPECT_EQ(&i, t2.get());
}
class NoCopyConstructor {
public:
NoCopyConstructor() {}
private:
GTEST_DISALLOW_COPY_AND_ASSIGN_(NoCopyConstructor);
};
TEST(ThreadLocalTest, ValueCopyConstructorIsNotRequiredForDefaultVersion) {
ThreadLocal<NoCopyConstructor> bar;
bar.get();
}
class NoDefaultContructor {
public:
explicit NoDefaultContructor(const char*) {}
......@@ -796,9 +784,6 @@ TEST(ThreadLocalTest, ValueDefaultContructorIsNotRequiredForParamVersion) {
TEST(ThreadLocalTest, GetAndPointerReturnSameValue) {
ThreadLocal<String> thread_local;
// This is why EXPECT_TRUE is used here rather than EXPECT_EQ because
// we don't care about a particular value of thread_local.pointer() here;
// we only care about pointer and reference referring to the same lvalue.
EXPECT_EQ(thread_local.pointer(), &(thread_local.get()));
// Verifies the condition still holds after calling set.
......@@ -825,7 +810,7 @@ TEST(MutexTestDeathTest, AssertHeldShouldAssertWhenNotLocked) {
{ MutexLock lock(&m); }
m.AssertHeld();
},
"Current thread is not holding mutex..+");
"The current thread is not holding the mutex @.+");
}
void SleepMilliseconds(int time) {
......@@ -847,16 +832,13 @@ class AtomicCounterWithMutex {
// 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;
int err = pthread_mutex_init(&memory_barrier_mutex, NULL);
GTEST_CHECK_(err == 0) << "pthread_mutex_init failed with error " << err;
err = pthread_mutex_lock(&memory_barrier_mutex);
GTEST_CHECK_(err == 0) << "pthread_mutex_lock failed with error " << err;
GTEST_CHECK_POSIX_SUCCESS_(
pthread_mutex_init(&memory_barrier_mutex, NULL));
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&memory_barrier_mutex));
SleepMilliseconds(random_.Generate(30));
err = pthread_mutex_unlock(&memory_barrier_mutex);
GTEST_CHECK_(err == 0)
<< "pthread_mutex_unlock failed with error " << err;
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&memory_barrier_mutex));
}
value_ = temp + 1;
}
......@@ -937,7 +919,7 @@ int CountedDestructor::counter_ = 0;
template <typename T>
void CallThreadLocalGet(ThreadLocal<T>* threadLocal) {
threadLocal->get();
threadLocal->get();
}
TEST(ThreadLocalTest, DestroysManagedObjectsNoLaterThanSelf) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment