1// Copyright (c) 2012 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/strings/string_number_conversions.h"
7#include "base/synchronization/waitable_event.h"
8#include "base/threading/simple_thread.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11namespace base {
12
13namespace {
14
15class SetIntRunner : public DelegateSimpleThread::Delegate {
16 public:
17  SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { }
18  virtual ~SetIntRunner() { }
19
20  virtual void Run() OVERRIDE {
21    *ptr_ = val_;
22  }
23
24 private:
25  int* ptr_;
26  int val_;
27};
28
29class WaitEventRunner : public DelegateSimpleThread::Delegate {
30 public:
31  explicit WaitEventRunner(WaitableEvent* event) : event_(event) { }
32  virtual ~WaitEventRunner() { }
33
34  virtual void Run() OVERRIDE {
35    EXPECT_FALSE(event_->IsSignaled());
36    event_->Signal();
37    EXPECT_TRUE(event_->IsSignaled());
38  }
39 private:
40  WaitableEvent* event_;
41};
42
43class SeqRunner : public DelegateSimpleThread::Delegate {
44 public:
45  explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { }
46  virtual void Run() OVERRIDE {
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.
57class 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() OVERRIDE {
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
79TEST(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
100TEST(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
114TEST(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
138TEST(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