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