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