• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
SetIntRunner(int * ptr,int val)17   SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { }
~SetIntRunner()18   ~SetIntRunner() { }
19 
Run()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:
WaitEventRunner(WaitableEvent * event)31   explicit WaitEventRunner(WaitableEvent* event) : event_(event) { }
~WaitEventRunner()32   ~WaitEventRunner() { }
33 
Run()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:
SeqRunner(AtomicSequenceNumber * seq)45   explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { }
Run()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:
VerifyPoolRunner(AtomicSequenceNumber * seq,int total,WaitableEvent * event)59   VerifyPoolRunner(AtomicSequenceNumber* seq,
60                    int total, WaitableEvent* event)
61       : seq_(seq), total_(total), event_(event) { }
62 
Run()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 
TEST(SimpleThreadTest,CreateAndJoin)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 
TEST(SimpleThreadTest,WaitForEvent)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 
TEST(SimpleThreadTest,NamedWithOptions)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 
TEST(SimpleThreadTest,ThreadPool)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