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