| Index: base/threading/simple_thread_unittest.cc
|
| diff --git a/base/threading/simple_thread_unittest.cc b/base/threading/simple_thread_unittest.cc
|
| index 14dd4591f1819d8e505911cd9f4cb9fb09cd54f2..f65f25e0b634323574c1dfd734211cae75479a22 100644
|
| --- a/base/threading/simple_thread_unittest.cc
|
| +++ b/base/threading/simple_thread_unittest.cc
|
| @@ -2,10 +2,16 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include <memory>
|
| +
|
| #include "base/atomic_sequence_num.h"
|
| +#include "base/memory/ptr_util.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/synchronization/waitable_event.h"
|
| +#include "base/test/gtest_util.h"
|
| +#include "base/threading/platform_thread.h"
|
| #include "base/threading/simple_thread.h"
|
| +#include "base/time/time.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| namespace base {
|
| @@ -17,11 +23,46 @@ class SetIntRunner : public DelegateSimpleThread::Delegate {
|
| SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { }
|
| ~SetIntRunner() override {}
|
|
|
| + private:
|
| void Run() override { *ptr_ = val_; }
|
|
|
| - private:
|
| int* ptr_;
|
| int val_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(SetIntRunner);
|
| +};
|
| +
|
| +// Signals |started_| when Run() is invoked and waits until |released_| is
|
| +// signaled to return, signaling |done_| before doing so. Useful for tests that
|
| +// care to control Run()'s flow. Note: the WaitableEvents need to be owned by
|
| +// the test as neither the ControlledRunner nor Run() live long enough to
|
| +// fullfil this task in all tests. All tests must wait for |done_| to be
|
| +// signaled before destroying the provided WaitableEvents.
|
| +class ControlledRunner : public DelegateSimpleThread::Delegate {
|
| + public:
|
| + ControlledRunner(WaitableEvent* started,
|
| + WaitableEvent* released,
|
| + WaitableEvent* done)
|
| + : started_(started), released_(released), done_(done) {}
|
| +
|
| + private:
|
| + void Run() override {
|
| + started_->Signal();
|
| +
|
| + // The WaitableEvents are guaranteed to outlive Run() but the
|
| + // ControlledRunner isn't after |started_| is signaled in some death tests,
|
| + // copy required member state to avoid use-after-frees.
|
| + WaitableEvent* const released_copy = released_;
|
| + WaitableEvent* const done_copy = done_;
|
| + released_copy->Wait();
|
| + done_copy->Signal();
|
| + }
|
| +
|
| + WaitableEvent* const started_;
|
| + WaitableEvent* const released_;
|
| + WaitableEvent* const done_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ControlledRunner);
|
| };
|
|
|
| class WaitEventRunner : public DelegateSimpleThread::Delegate {
|
| @@ -29,22 +70,28 @@ class WaitEventRunner : public DelegateSimpleThread::Delegate {
|
| explicit WaitEventRunner(WaitableEvent* event) : event_(event) { }
|
| ~WaitEventRunner() override {}
|
|
|
| + private:
|
| void Run() override {
|
| EXPECT_FALSE(event_->IsSignaled());
|
| event_->Signal();
|
| EXPECT_TRUE(event_->IsSignaled());
|
| }
|
| - private:
|
| +
|
| WaitableEvent* event_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(WaitEventRunner);
|
| };
|
|
|
| class SeqRunner : public DelegateSimpleThread::Delegate {
|
| public:
|
| explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { }
|
| - void Run() override { seq_->GetNext(); }
|
|
|
| private:
|
| + void Run() override { seq_->GetNext(); }
|
| +
|
| AtomicSequenceNumber* seq_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(SeqRunner);
|
| };
|
|
|
| // We count up on a sequence number, firing on the event when we've hit our
|
| @@ -56,6 +103,7 @@ class VerifyPoolRunner : public DelegateSimpleThread::Delegate {
|
| int total, WaitableEvent* event)
|
| : seq_(seq), total_(total), event_(event) { }
|
|
|
| + private:
|
| void Run() override {
|
| if (seq_->GetNext() == total_) {
|
| event_->Signal();
|
| @@ -64,10 +112,11 @@ class VerifyPoolRunner : public DelegateSimpleThread::Delegate {
|
| }
|
| }
|
|
|
| - private:
|
| AtomicSequenceNumber* seq_;
|
| int total_;
|
| WaitableEvent* event_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(VerifyPoolRunner);
|
| };
|
|
|
| } // namespace
|
| @@ -133,6 +182,88 @@ TEST(SimpleThreadTest, NamedWithOptions) {
|
| std::string("event_waiter/") + IntToString(thread.tid()));
|
| }
|
|
|
| +namespace {
|
| +
|
| +// A test fixture which allows stepping through phases of a non-joinable
|
| +// DelegateSimpleThread. SimpleThreadControlledNonJoinableTest instances will
|
| +// remain alive at least until |done_| is signaled by the ControlledRunner's
|
| +// Run() method.
|
| +class SimpleThreadControlledNonJoinableTest : public testing::Test {
|
| + public:
|
| + SimpleThreadControlledNonJoinableTest()
|
| + : started_(WaitableEvent::ResetPolicy::MANUAL,
|
| + WaitableEvent::InitialState::NOT_SIGNALED),
|
| + released_(WaitableEvent::ResetPolicy::MANUAL,
|
| + WaitableEvent::InitialState::NOT_SIGNALED),
|
| + done_(WaitableEvent::ResetPolicy::MANUAL,
|
| + WaitableEvent::InitialState::NOT_SIGNALED) {}
|
| +
|
| + void SetUp() override {
|
| + runner_ = MakeUnique<ControlledRunner>(&started_, &released_, &done_);
|
| +
|
| + SimpleThread::Options options;
|
| + options.joinable = false;
|
| + thread_ = MakeUnique<DelegateSimpleThread>(runner_.get(), "non_joinable",
|
| + options);
|
| +
|
| + EXPECT_FALSE(thread_->HasBeenStarted());
|
| + thread_->Start();
|
| + EXPECT_TRUE(thread_->HasBeenStarted());
|
| + }
|
| +
|
| + void TearDown() override {
|
| + // Ensure |runner_| has been released and is done with the WaitableEvents
|
| + // provided to it.
|
| + ReleaseAndWaitUntilDone();
|
| + }
|
| +
|
| + void WaitUntilStarted() { started_.Wait(); }
|
| +
|
| + void ReleaseAndWaitUntilDone() {
|
| + released_.Signal();
|
| + done_.Wait();
|
| + }
|
| +
|
| + protected:
|
| + std::unique_ptr<ControlledRunner> runner_;
|
| + std::unique_ptr<DelegateSimpleThread> thread_;
|
| +
|
| + private:
|
| + WaitableEvent started_;
|
| + WaitableEvent released_;
|
| + WaitableEvent done_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(SimpleThreadControlledNonJoinableTest);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +TEST_F(SimpleThreadControlledNonJoinableTest, DieOnJoin) {
|
| + EXPECT_FALSE(thread_->HasBeenJoined());
|
| + EXPECT_DCHECK_DEATH({ thread_->Join(); });
|
| +}
|
| +
|
| +TEST_F(SimpleThreadControlledNonJoinableTest,
|
| + DeathOnActiveDelegateDestruction) {
|
| + WaitUntilStarted();
|
| +
|
| + // Non-joinable DelegateSimpleThread is allowed to go away the minute Run() is
|
| + // active.
|
| + thread_.reset();
|
| +
|
| + // The Delegate can't go away while Run() is in progress however.
|
| + EXPECT_DCHECK_DEATH({ runner_.reset(); });
|
| +}
|
| +
|
| +TEST_F(SimpleThreadControlledNonJoinableTest,
|
| + InactiveDelegateDestructionIsOkay) {
|
| + WaitUntilStarted();
|
| + ReleaseAndWaitUntilDone();
|
| + // The Delegate should be safe to be destroyed after its Run() method
|
| + // completed.
|
| + runner_.reset();
|
| +}
|
| +
|
| TEST(SimpleThreadTest, ThreadPool) {
|
| AtomicSequenceNumber seq;
|
| SeqRunner runner(&seq);
|
|
|