Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(563)

Side by Side Diff: base/threading/simple_thread_unittest.cc

Issue 2204333003: Add joinable option to SimpleThread::Options as was just done for Thread. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@b1_nonjoinable_thread
Patch Set: fix TSan and ASan Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/threading/simple_thread.cc ('k') | content/renderer/categorized_worker_pool.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <memory>
6
5 #include "base/atomic_sequence_num.h" 7 #include "base/atomic_sequence_num.h"
8 #include "base/memory/ptr_util.h"
6 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_number_conversions.h"
7 #include "base/synchronization/waitable_event.h" 10 #include "base/synchronization/waitable_event.h"
11 #include "base/test/gtest_util.h"
8 #include "base/threading/simple_thread.h" 12 #include "base/threading/simple_thread.h"
9 #include "testing/gtest/include/gtest/gtest.h" 13 #include "testing/gtest/include/gtest/gtest.h"
10 14
11 namespace base { 15 namespace base {
12 16
13 namespace { 17 namespace {
14 18
15 class SetIntRunner : public DelegateSimpleThread::Delegate { 19 class SetIntRunner : public DelegateSimpleThread::Delegate {
16 public: 20 public:
17 SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { } 21 SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { }
18 ~SetIntRunner() override {} 22 ~SetIntRunner() override {}
19 23
24 private:
20 void Run() override { *ptr_ = val_; } 25 void Run() override { *ptr_ = val_; }
21 26
22 private:
23 int* ptr_; 27 int* ptr_;
24 int val_; 28 int val_;
29
30 DISALLOW_COPY_AND_ASSIGN(SetIntRunner);
31 };
32
33 // Signals |started_| when Run() is invoked and waits until |released_| is
34 // signaled to return, signaling |done_| before doing so. Useful for tests that
35 // care to control Run()'s flow.
36 class ControlledRunner : public DelegateSimpleThread::Delegate {
37 public:
38 ControlledRunner()
39 : started_(WaitableEvent::ResetPolicy::MANUAL,
40 WaitableEvent::InitialState::NOT_SIGNALED),
41 released_(WaitableEvent::ResetPolicy::MANUAL,
42 WaitableEvent::InitialState::NOT_SIGNALED),
43 done_(WaitableEvent::ResetPolicy::MANUAL,
44 WaitableEvent::InitialState::NOT_SIGNALED) {}
45
46 ~ControlledRunner() override { ReleaseAndWaitUntilDone(); }
47
48 void WaitUntilStarted() { started_.Wait(); }
49
50 void ReleaseAndWaitUntilDone() {
51 released_.Signal();
52 done_.Wait();
53 }
54
55 private:
56 void Run() override {
57 started_.Signal();
58 released_.Wait();
59 done_.Signal();
60 }
61
62 WaitableEvent started_;
63 WaitableEvent released_;
64 WaitableEvent done_;
65
66 DISALLOW_COPY_AND_ASSIGN(ControlledRunner);
25 }; 67 };
26 68
27 class WaitEventRunner : public DelegateSimpleThread::Delegate { 69 class WaitEventRunner : public DelegateSimpleThread::Delegate {
28 public: 70 public:
29 explicit WaitEventRunner(WaitableEvent* event) : event_(event) { } 71 explicit WaitEventRunner(WaitableEvent* event) : event_(event) { }
30 ~WaitEventRunner() override {} 72 ~WaitEventRunner() override {}
31 73
74 private:
32 void Run() override { 75 void Run() override {
33 EXPECT_FALSE(event_->IsSignaled()); 76 EXPECT_FALSE(event_->IsSignaled());
34 event_->Signal(); 77 event_->Signal();
35 EXPECT_TRUE(event_->IsSignaled()); 78 EXPECT_TRUE(event_->IsSignaled());
36 } 79 }
37 private: 80
38 WaitableEvent* event_; 81 WaitableEvent* event_;
82
83 DISALLOW_COPY_AND_ASSIGN(WaitEventRunner);
39 }; 84 };
40 85
41 class SeqRunner : public DelegateSimpleThread::Delegate { 86 class SeqRunner : public DelegateSimpleThread::Delegate {
42 public: 87 public:
43 explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { } 88 explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { }
89
90 private:
44 void Run() override { seq_->GetNext(); } 91 void Run() override { seq_->GetNext(); }
45 92
46 private:
47 AtomicSequenceNumber* seq_; 93 AtomicSequenceNumber* seq_;
94
95 DISALLOW_COPY_AND_ASSIGN(SeqRunner);
48 }; 96 };
49 97
50 // We count up on a sequence number, firing on the event when we've hit our 98 // We count up on a sequence number, firing on the event when we've hit our
51 // expected amount, otherwise we wait on the event. This will ensure that we 99 // expected amount, otherwise we wait on the event. This will ensure that we
52 // have all threads outstanding until we hit our expected thread pool size. 100 // have all threads outstanding until we hit our expected thread pool size.
53 class VerifyPoolRunner : public DelegateSimpleThread::Delegate { 101 class VerifyPoolRunner : public DelegateSimpleThread::Delegate {
54 public: 102 public:
55 VerifyPoolRunner(AtomicSequenceNumber* seq, 103 VerifyPoolRunner(AtomicSequenceNumber* seq,
56 int total, WaitableEvent* event) 104 int total, WaitableEvent* event)
57 : seq_(seq), total_(total), event_(event) { } 105 : seq_(seq), total_(total), event_(event) { }
58 106
107 private:
59 void Run() override { 108 void Run() override {
60 if (seq_->GetNext() == total_) { 109 if (seq_->GetNext() == total_) {
61 event_->Signal(); 110 event_->Signal();
62 } else { 111 } else {
63 event_->Wait(); 112 event_->Wait();
64 } 113 }
65 } 114 }
66 115
67 private:
68 AtomicSequenceNumber* seq_; 116 AtomicSequenceNumber* seq_;
69 int total_; 117 int total_;
70 WaitableEvent* event_; 118 WaitableEvent* event_;
119
120 DISALLOW_COPY_AND_ASSIGN(VerifyPoolRunner);
71 }; 121 };
72 122
73 } // namespace 123 } // namespace
74 124
75 TEST(SimpleThreadTest, CreateAndJoin) { 125 TEST(SimpleThreadTest, CreateAndJoin) {
76 int stack_int = 0; 126 int stack_int = 0;
77 127
78 SetIntRunner runner(&stack_int, 7); 128 SetIntRunner runner(&stack_int, 7);
79 EXPECT_EQ(0, stack_int); 129 EXPECT_EQ(0, stack_int);
80 130
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 176
127 EXPECT_TRUE(event.IsSignaled()); 177 EXPECT_TRUE(event.IsSignaled());
128 thread.Join(); 178 thread.Join();
129 179
130 // We keep the name and tid, even after the thread is gone. 180 // We keep the name and tid, even after the thread is gone.
131 EXPECT_EQ(thread.name_prefix(), "event_waiter"); 181 EXPECT_EQ(thread.name_prefix(), "event_waiter");
132 EXPECT_EQ(thread.name(), 182 EXPECT_EQ(thread.name(),
133 std::string("event_waiter/") + IntToString(thread.tid())); 183 std::string("event_waiter/") + IntToString(thread.tid()));
134 } 184 }
135 185
186 TEST(SimpleThreadTest, NonJoinableStartAndDieOnJoin) {
187 ControlledRunner runner;
188
189 SimpleThread::Options options;
190 options.joinable = false;
191 DelegateSimpleThread thread(&runner, "non_joinable", options);
192
193 EXPECT_FALSE(thread.HasBeenStarted());
194 thread.Start();
195 EXPECT_TRUE(thread.HasBeenStarted());
196
197 // Note: this is not quite the same as |thread.HasBeenStarted()| which
198 // represents ThreadMain() getting ready to invoke Run() whereas
199 // |runner.WaitUntilStarted()| ensures Run() was actually invoked.
200 runner.WaitUntilStarted();
201
202 EXPECT_FALSE(thread.HasBeenJoined());
203 EXPECT_DCHECK_DEATH({ thread.Join(); });
204 }
205
206 TEST(SimpleThreadTest, NonJoinableInactiveDelegateDestructionIsOkay) {
207 std::unique_ptr<ControlledRunner> runner(new ControlledRunner);
208
209 SimpleThread::Options options;
210 options.joinable = false;
211 std::unique_ptr<DelegateSimpleThread> thread(
212 new DelegateSimpleThread(runner.get(), "non_joinable", options));
213
214 thread->Start();
215 runner->WaitUntilStarted();
216
217 // Deleting a non-joinable SimpleThread after Run() was invoked is okay.
218 thread.reset();
219
220 runner->WaitUntilStarted();
221 runner->ReleaseAndWaitUntilDone();
222 // It should be safe to destroy a Delegate after its Run() method completed.
223 runner.reset();
224 }
225
136 TEST(SimpleThreadTest, ThreadPool) { 226 TEST(SimpleThreadTest, ThreadPool) {
137 AtomicSequenceNumber seq; 227 AtomicSequenceNumber seq;
138 SeqRunner runner(&seq); 228 SeqRunner runner(&seq);
139 DelegateSimpleThreadPool pool("seq_runner", 10); 229 DelegateSimpleThreadPool pool("seq_runner", 10);
140 230
141 // Add work before we're running. 231 // Add work before we're running.
142 pool.AddWork(&runner, 300); 232 pool.AddWork(&runner, 300);
143 233
144 EXPECT_EQ(seq.GetNext(), 0); 234 EXPECT_EQ(seq.GetNext(), 0);
145 pool.Start(); 235 pool.Start();
(...skipping 14 matching lines...) Expand all
160 VerifyPoolRunner verifier(&seq2, 9, &event); 250 VerifyPoolRunner verifier(&seq2, 9, &event);
161 pool.Start(); 251 pool.Start();
162 252
163 pool.AddWork(&verifier, 10); 253 pool.AddWork(&verifier, 10);
164 254
165 pool.JoinAll(); 255 pool.JoinAll();
166 EXPECT_EQ(seq2.GetNext(), 10); 256 EXPECT_EQ(seq2.GetNext(), 10);
167 } 257 }
168 258
169 } // namespace base 259 } // namespace base
OLDNEW
« no previous file with comments | « base/threading/simple_thread.cc ('k') | content/renderer/categorized_worker_pool.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698