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