13345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/atomic_sequence_num.h" 63345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h" 73f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/simple_thread.h" 83f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/synchronization/waitable_event.h" 9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "testing/gtest/include/gtest/gtest.h" 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 113f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace base { 123f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace { 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 153f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenclass SetIntRunner : public DelegateSimpleThread::Delegate { 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { } 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ~SetIntRunner() { } 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott virtual void Run() { 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott *ptr_ = val_; 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private: 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int* ptr_; 26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int val_; 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 293f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenclass WaitEventRunner : public DelegateSimpleThread::Delegate { 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 313f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen explicit WaitEventRunner(WaitableEvent* event) : event_(event) { } 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ~WaitEventRunner() { } 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott virtual void Run() { 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_FALSE(event_->IsSignaled()); 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott event_->Signal(); 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_TRUE(event_->IsSignaled()); 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private: 403f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen WaitableEvent* event_; 41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 433f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenclass SeqRunner : public DelegateSimpleThread::Delegate { 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 453f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { } 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott virtual void Run() { 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott seq_->GetNext(); 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private: 513f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen AtomicSequenceNumber* seq_; 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// We count up on a sequence number, firing on the event when we've hit our 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// expected amount, otherwise we wait on the event. This will ensure that we 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// have all threads outstanding until we hit our expected thread pool size. 573f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenclass VerifyPoolRunner : public DelegateSimpleThread::Delegate { 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 593f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen VerifyPoolRunner(AtomicSequenceNumber* seq, 603f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen int total, WaitableEvent* event) 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott : seq_(seq), total_(total), event_(event) { } 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott virtual void Run() { 64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (seq_->GetNext() == total_) { 65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott event_->Signal(); 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } else { 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott event_->Wait(); 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private: 723f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen AtomicSequenceNumber* seq_; 73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int total_; 743f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen WaitableEvent* event_; 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST(SimpleThreadTest, CreateAndJoin) { 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int stack_int = 0; 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SetIntRunner runner(&stack_int, 7); 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(0, stack_int); 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 853f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen DelegateSimpleThread thread(&runner, "int_setter"); 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_FALSE(thread.HasBeenStarted()); 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_FALSE(thread.HasBeenJoined()); 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(0, stack_int); 89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott thread.Start(); 91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_TRUE(thread.HasBeenStarted()); 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_FALSE(thread.HasBeenJoined()); 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott thread.Join(); 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_TRUE(thread.HasBeenStarted()); 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_TRUE(thread.HasBeenJoined()); 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(7, stack_int); 98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST(SimpleThreadTest, WaitForEvent) { 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Create a thread, and wait for it to signal us. 1023f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen WaitableEvent event(true, false); 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott WaitEventRunner runner(&event); 1053f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen DelegateSimpleThread thread(&runner, "event_waiter"); 106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_FALSE(event.IsSignaled()); 108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott thread.Start(); 109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott event.Wait(); 110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_TRUE(event.IsSignaled()); 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott thread.Join(); 112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST(SimpleThreadTest, NamedWithOptions) { 1153f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen WaitableEvent event(true, false); 116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott WaitEventRunner runner(&event); 1183f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen SimpleThread::Options options; 1193f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen DelegateSimpleThread thread(&runner, "event_waiter", options); 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(thread.name_prefix(), "event_waiter"); 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_FALSE(event.IsSignaled()); 122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott thread.Start(); 124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(thread.name_prefix(), "event_waiter"); 1253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick EXPECT_EQ(thread.name(), 1263f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen std::string("event_waiter/") + IntToString(thread.tid())); 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott event.Wait(); 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_TRUE(event.IsSignaled()); 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott thread.Join(); 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We keep the name and tid, even after the thread is gone. 133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(thread.name_prefix(), "event_waiter"); 1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick EXPECT_EQ(thread.name(), 1353f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen std::string("event_waiter/") + IntToString(thread.tid())); 136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottTEST(SimpleThreadTest, ThreadPool) { 1393f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen AtomicSequenceNumber seq; 140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SeqRunner runner(&seq); 1413f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen DelegateSimpleThreadPool pool("seq_runner", 10); 142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Add work before we're running. 144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott pool.AddWork(&runner, 300); 145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(seq.GetNext(), 0); 147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott pool.Start(); 148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Add work while we're running. 150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott pool.AddWork(&runner, 300); 151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott pool.JoinAll(); 153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(seq.GetNext(), 601); 155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We can reuse our pool. Verify that all 10 threads can actually run in 157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // parallel, so this test will only pass if there are actually 10 threads. 1583f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen AtomicSequenceNumber seq2; 1593f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen WaitableEvent event(true, false); 160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Changing 9 to 10, for example, would cause us JoinAll() to never return. 161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott VerifyPoolRunner verifier(&seq2, 9, &event); 162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott pool.Start(); 163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott pool.AddWork(&verifier, 10); 165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott pool.JoinAll(); 167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott EXPECT_EQ(seq2.GetNext(), 10); 168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 1693f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen 1703f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen} // namespace base 171