added more multithreaded tests that are useful with tsan
Also made various small cleanups while writing and checking these tests.
diff --git a/aos/common/util/run_command_test.cc b/aos/common/util/run_command_test.cc
index b440e47..daff3c5 100644
--- a/aos/common/util/run_command_test.cc
+++ b/aos/common/util/run_command_test.cc
@@ -2,6 +2,8 @@
#include "gtest/gtest.h"
+#include "aos/common/util/thread.h"
+
namespace aos {
namespace util {
namespace testing {
@@ -34,6 +36,26 @@
EXPECT_EQ(SIGQUIT, WTERMSIG(result));
}
+TEST(RunCommandTest, MultipleThreads) {
+ int result1, result2;
+ util::FunctionThread t1([&result1](util::Thread *) {
+ result1 = RunCommand("true");
+ });
+ util::FunctionThread t2([&result2](util::Thread *) {
+ result2 = RunCommand("true");
+ });
+ t1.Start();
+ t2.Start();
+ t1.WaitUntilDone();
+ t2.WaitUntilDone();
+ ASSERT_NE(-1, result1);
+ ASSERT_NE(-1, result2);
+ ASSERT_TRUE(WIFEXITED(result1));
+ ASSERT_TRUE(WIFEXITED(result2));
+ EXPECT_EQ(0, WEXITSTATUS(result1));
+ EXPECT_EQ(0, WEXITSTATUS(result2));
+}
+
} // namespace testing
} // namespace util
} // namespace aos
diff --git a/aos/common/util/thread.cc b/aos/common/util/thread.cc
index fab62eb..dbb638e 100644
--- a/aos/common/util/thread.cc
+++ b/aos/common/util/thread.cc
@@ -1,7 +1,8 @@
#include "aos/common/util/thread.h"
#include <pthread.h>
-#include <assert.h>
+
+#include "aos/common/logging/logging.h"
namespace aos {
namespace util {
@@ -10,24 +11,30 @@
Thread::~Thread() {
if (started_ && !joined_) {
- assert(false);
+ CHECK(false);
}
}
void Thread::Start() {
- assert(!started_);
+ CHECK(!started_);
started_ = true;
- assert(pthread_create(&thread_, NULL, &Thread::StaticRun, this) == 0);
+ CHECK(pthread_create(&thread_, NULL, &Thread::StaticRun, this) == 0);
}
void Thread::Join() {
- assert(!joined_ && started_);
+ CHECK(!joined_ && started_);
joined_ = true;
{
MutexLocker locker(&should_terminate_mutex_);
should_terminate_ = true;
}
- assert(pthread_join(thread_, NULL) == 0);
+ CHECK(pthread_join(thread_, NULL) == 0);
+}
+
+void Thread::WaitUntilDone() {
+ CHECK(!joined_ && started_);
+ joined_ = true;
+ CHECK(pthread_join(thread_, NULL) == 0);
}
void *Thread::StaticRun(void *self) {
diff --git a/aos/common/util/thread.h b/aos/common/util/thread.h
index ab6f09c..97123d5 100644
--- a/aos/common/util/thread.h
+++ b/aos/common/util/thread.h
@@ -1,7 +1,10 @@
#ifndef AOS_COMMON_UTIL_THREAD_H_
#define AOS_COMMON_UTIL_THREAD_H_
+#include <functional>
+
#include "aos/common/mutex.h"
+#include "aos/common/macros.h"
namespace aos {
namespace util {
@@ -20,6 +23,9 @@
// Asks the code to stop and then waits until it has done so.
void Join();
+ // Waits until the code has stopped. Does not ask it to do so.
+ void WaitUntilDone();
+
protected:
// Subclasses need to call this periodically if they are going to loop to
// check whether they have been asked to stop.
@@ -42,6 +48,21 @@
bool joined_;
bool should_terminate_;
Mutex should_terminate_mutex_;
+
+ DISALLOW_COPY_AND_ASSIGN(Thread);
+};
+
+class FunctionThread : public Thread {
+ public:
+ FunctionThread(::std::function<void(FunctionThread *)> function)
+ : function_(function) {}
+
+ private:
+ virtual void Run() override {
+ function_(this);
+ }
+
+ const ::std::function<void(FunctionThread *)> function_;
};
} // namespace util
diff --git a/aos/common/util/util.gyp b/aos/common/util/util.gyp
index 7c0adf3..fb29d7f 100644
--- a/aos/common/util/util.gyp
+++ b/aos/common/util/util.gyp
@@ -20,6 +20,7 @@
'run_command',
'<(EXTERNALS):gtest',
'<(AOS)/build/aos.gyp:logging',
+ 'thread',
],
},
{