1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be 3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file. 4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/atomic_sequence_num.h" 6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/strings/string_number_conversions.h" 7b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/synchronization/waitable_event.h" 8b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/threading/simple_thread.h" 9b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "testing/gtest/include/gtest/gtest.h" 10b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base { 12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 13b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace { 14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 15b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass SetIntRunner : public DelegateSimpleThread::Delegate { 16b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public: 17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { } 18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat ~SetIntRunner() override {} 19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void Run() override { *ptr_ = val_; } 21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private: 23b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int* ptr_; 24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int val_; 25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}; 26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass WaitEventRunner : public DelegateSimpleThread::Delegate { 28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public: 29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat explicit WaitEventRunner(WaitableEvent* event) : event_(event) { } 30b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat ~WaitEventRunner() override {} 31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void Run() override { 33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_FALSE(event_->IsSignaled()); 34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat event_->Signal(); 35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_TRUE(event_->IsSignaled()); 36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private: 38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat WaitableEvent* event_; 39b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}; 40b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass SeqRunner : public DelegateSimpleThread::Delegate { 42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public: 43b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { } 44b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void Run() override { seq_->GetNext(); } 45b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 46b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private: 47b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat AtomicSequenceNumber* seq_; 48b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}; 49b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 50b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// We count up on a sequence number, firing on the event when we've hit our 51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// expected amount, otherwise we wait on the event. This will ensure that we 52b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// have all threads outstanding until we hit our expected thread pool size. 53b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass VerifyPoolRunner : public DelegateSimpleThread::Delegate { 54b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public: 55b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat VerifyPoolRunner(AtomicSequenceNumber* seq, 56b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int total, WaitableEvent* event) 57b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat : seq_(seq), total_(total), event_(event) { } 58b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 59b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void Run() override { 60b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (seq_->GetNext() == total_) { 61b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat event_->Signal(); 62b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } else { 63b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat event_->Wait(); 64b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 65b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 66b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 67b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private: 68b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat AtomicSequenceNumber* seq_; 69b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int total_; 70b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat WaitableEvent* event_; 71b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}; 72b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 73b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace 74b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 75b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTEST(SimpleThreadTest, CreateAndJoin) { 76b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int stack_int = 0; 77b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 78b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat SetIntRunner runner(&stack_int, 7); 79b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(0, stack_int); 80b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 81b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DelegateSimpleThread thread(&runner, "int_setter"); 82b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_FALSE(thread.HasBeenStarted()); 83b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_FALSE(thread.HasBeenJoined()); 84b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(0, stack_int); 85b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 86b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat thread.Start(); 87b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_TRUE(thread.HasBeenStarted()); 88b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_FALSE(thread.HasBeenJoined()); 89b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 90b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat thread.Join(); 91b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_TRUE(thread.HasBeenStarted()); 92b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_TRUE(thread.HasBeenJoined()); 93b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(7, stack_int); 94b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTEST(SimpleThreadTest, WaitForEvent) { 97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Create a thread, and wait for it to signal us. 980c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, 990c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez WaitableEvent::InitialState::NOT_SIGNALED); 100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat WaitEventRunner runner(&event); 102b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DelegateSimpleThread thread(&runner, "event_waiter"); 103b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 104b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_FALSE(event.IsSignaled()); 105b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat thread.Start(); 106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat event.Wait(); 107b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_TRUE(event.IsSignaled()); 108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat thread.Join(); 109b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 110b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 111b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTEST(SimpleThreadTest, NamedWithOptions) { 1120c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, 1130c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez WaitableEvent::InitialState::NOT_SIGNALED); 114b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 115b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat WaitEventRunner runner(&event); 116b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat SimpleThread::Options options; 117b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DelegateSimpleThread thread(&runner, "event_waiter", options); 118b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(thread.name_prefix(), "event_waiter"); 119b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_FALSE(event.IsSignaled()); 120b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 121b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat thread.Start(); 122b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(thread.name_prefix(), "event_waiter"); 123b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(thread.name(), 124b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat std::string("event_waiter/") + IntToString(thread.tid())); 125b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat event.Wait(); 126b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 127b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_TRUE(event.IsSignaled()); 128b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat thread.Join(); 129b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 130b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // We keep the name and tid, even after the thread is gone. 131b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(thread.name_prefix(), "event_waiter"); 132b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(thread.name(), 133b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat std::string("event_waiter/") + IntToString(thread.tid())); 134b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 135b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 136b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratTEST(SimpleThreadTest, ThreadPool) { 137b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat AtomicSequenceNumber seq; 138b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat SeqRunner runner(&seq); 139b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DelegateSimpleThreadPool pool("seq_runner", 10); 140b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 141b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Add work before we're running. 142b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pool.AddWork(&runner, 300); 143b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 144b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(seq.GetNext(), 0); 145b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pool.Start(); 146b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 147b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Add work while we're running. 148b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pool.AddWork(&runner, 300); 149b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 150b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pool.JoinAll(); 151b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 152b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(seq.GetNext(), 601); 153b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 154b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // We can reuse our pool. Verify that all 10 threads can actually run in 155b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // parallel, so this test will only pass if there are actually 10 threads. 156b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat AtomicSequenceNumber seq2; 1570c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez WaitableEvent event(WaitableEvent::ResetPolicy::MANUAL, 1580c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez WaitableEvent::InitialState::NOT_SIGNALED); 159b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Changing 9 to 10, for example, would cause us JoinAll() to never return. 160b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat VerifyPoolRunner verifier(&seq2, 9, &event); 161b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pool.Start(); 162b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 163b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pool.AddWork(&verifier, 10); 164b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 165b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat pool.JoinAll(); 166b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat EXPECT_EQ(seq2.GetNext(), 10); 167b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 168b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 169b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace base 170