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

Side by Side Diff: base/message_loop/message_loop_proxy_unittest.cc

Issue 1641513004: Update //base to chromium 9659b08ea5a34f889dc4166217f438095ddc10d2 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 10 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
OLDNEW
(Empty)
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/message_loop/message_loop_proxy.h"
6
7 #include "base/atomic_sequence_num.h"
8 #include "base/bind.h"
9 #include "base/debug/leak_annotations.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/threading/thread.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace base {
18
19 namespace {
20
21 class MessageLoopProxyTest : public testing::Test {
22 public:
23 MessageLoopProxyTest()
24 : current_loop_(new MessageLoop()),
25 task_thread_("task_thread"),
26 thread_sync_(true, false) {
27 }
28
29 void DeleteCurrentMessageLoop() {
30 current_loop_.reset();
31 }
32
33 protected:
34 void SetUp() override {
35 // Use SetUp() instead of the constructor to avoid posting a task to a
36 // partialy constructed object.
37 task_thread_.Start();
38
39 // Allow us to pause the |task_thread_|'s MessageLoop.
40 task_thread_.message_loop()->PostTask(
41 FROM_HERE,
42 Bind(&MessageLoopProxyTest::BlockTaskThreadHelper, Unretained(this)));
43 }
44
45 void TearDown() override {
46 // Make sure the |task_thread_| is not blocked, and stop the thread
47 // fully before destuction because its tasks may still depend on the
48 // |thread_sync_| event.
49 thread_sync_.Signal();
50 task_thread_.Stop();
51 DeleteCurrentMessageLoop();
52 }
53
54 // Make LoopRecorder threadsafe so that there is defined behavior even if a
55 // threading mistake sneaks into the PostTaskAndReplyRelay implementation.
56 class LoopRecorder : public RefCountedThreadSafe<LoopRecorder> {
57 public:
58 LoopRecorder(MessageLoop** run_on, MessageLoop** deleted_on,
59 int* destruct_order)
60 : run_on_(run_on),
61 deleted_on_(deleted_on),
62 destruct_order_(destruct_order) {
63 }
64
65 void RecordRun() {
66 *run_on_ = MessageLoop::current();
67 }
68
69 private:
70 friend class RefCountedThreadSafe<LoopRecorder>;
71 ~LoopRecorder() {
72 *deleted_on_ = MessageLoop::current();
73 *destruct_order_ = g_order.GetNext();
74 }
75
76 MessageLoop** run_on_;
77 MessageLoop** deleted_on_;
78 int* destruct_order_;
79 };
80
81 static void RecordLoop(scoped_refptr<LoopRecorder> recorder) {
82 recorder->RecordRun();
83 }
84
85 static void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) {
86 recorder->RecordRun();
87 MessageLoop::current()->QuitWhenIdle();
88 }
89
90 void UnblockTaskThread() {
91 thread_sync_.Signal();
92 }
93
94 void BlockTaskThreadHelper() {
95 thread_sync_.Wait();
96 }
97
98 static StaticAtomicSequenceNumber g_order;
99
100 scoped_ptr<MessageLoop> current_loop_;
101 Thread task_thread_;
102
103 private:
104 base::WaitableEvent thread_sync_;
105 };
106
107 StaticAtomicSequenceNumber MessageLoopProxyTest::g_order;
108
109 TEST_F(MessageLoopProxyTest, PostTaskAndReply_Basic) {
110 MessageLoop* task_run_on = NULL;
111 MessageLoop* task_deleted_on = NULL;
112 int task_delete_order = -1;
113 MessageLoop* reply_run_on = NULL;
114 MessageLoop* reply_deleted_on = NULL;
115 int reply_delete_order = -1;
116
117 scoped_refptr<LoopRecorder> task_recoder =
118 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
119 scoped_refptr<LoopRecorder> reply_recoder =
120 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
121
122 ASSERT_TRUE(task_thread_.message_loop_proxy()->PostTaskAndReply(
123 FROM_HERE,
124 Bind(&RecordLoop, task_recoder),
125 Bind(&RecordLoopAndQuit, reply_recoder)));
126
127 // Die if base::Bind doesn't retain a reference to the recorders.
128 task_recoder = NULL;
129 reply_recoder = NULL;
130 ASSERT_FALSE(task_deleted_on);
131 ASSERT_FALSE(reply_deleted_on);
132
133 UnblockTaskThread();
134 current_loop_->Run();
135
136 EXPECT_EQ(task_thread_.message_loop(), task_run_on);
137 EXPECT_EQ(current_loop_.get(), task_deleted_on);
138 EXPECT_EQ(current_loop_.get(), reply_run_on);
139 EXPECT_EQ(current_loop_.get(), reply_deleted_on);
140 EXPECT_LT(task_delete_order, reply_delete_order);
141 }
142
143 TEST_F(MessageLoopProxyTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
144 MessageLoop* task_run_on = NULL;
145 MessageLoop* task_deleted_on = NULL;
146 int task_delete_order = -1;
147 MessageLoop* reply_run_on = NULL;
148 MessageLoop* reply_deleted_on = NULL;
149 int reply_delete_order = -1;
150
151 scoped_refptr<LoopRecorder> task_recoder =
152 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
153 scoped_refptr<LoopRecorder> reply_recoder =
154 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
155
156 // Grab a MessageLoopProxy to a dead MessageLoop.
157 scoped_refptr<MessageLoopProxy> task_loop_proxy =
158 task_thread_.message_loop_proxy();
159 UnblockTaskThread();
160 task_thread_.Stop();
161
162 ASSERT_FALSE(task_loop_proxy->PostTaskAndReply(
163 FROM_HERE,
164 Bind(&RecordLoop, task_recoder),
165 Bind(&RecordLoopAndQuit, reply_recoder)));
166
167 // The relay should have properly deleted its resources leaving us as the only
168 // reference.
169 EXPECT_EQ(task_delete_order, reply_delete_order);
170 ASSERT_TRUE(task_recoder->HasOneRef());
171 ASSERT_TRUE(reply_recoder->HasOneRef());
172
173 // Nothing should have run though.
174 EXPECT_FALSE(task_run_on);
175 EXPECT_FALSE(reply_run_on);
176 }
177
178 TEST_F(MessageLoopProxyTest, PostTaskAndReply_SameLoop) {
179 MessageLoop* task_run_on = NULL;
180 MessageLoop* task_deleted_on = NULL;
181 int task_delete_order = -1;
182 MessageLoop* reply_run_on = NULL;
183 MessageLoop* reply_deleted_on = NULL;
184 int reply_delete_order = -1;
185
186 scoped_refptr<LoopRecorder> task_recoder =
187 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
188 scoped_refptr<LoopRecorder> reply_recoder =
189 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
190
191 // Enqueue the relay.
192 ASSERT_TRUE(current_loop_->message_loop_proxy()->PostTaskAndReply(
193 FROM_HERE,
194 Bind(&RecordLoop, task_recoder),
195 Bind(&RecordLoopAndQuit, reply_recoder)));
196
197 // Die if base::Bind doesn't retain a reference to the recorders.
198 task_recoder = NULL;
199 reply_recoder = NULL;
200 ASSERT_FALSE(task_deleted_on);
201 ASSERT_FALSE(reply_deleted_on);
202
203 current_loop_->Run();
204
205 EXPECT_EQ(current_loop_.get(), task_run_on);
206 EXPECT_EQ(current_loop_.get(), task_deleted_on);
207 EXPECT_EQ(current_loop_.get(), reply_run_on);
208 EXPECT_EQ(current_loop_.get(), reply_deleted_on);
209 EXPECT_LT(task_delete_order, reply_delete_order);
210 }
211
212 TEST_F(MessageLoopProxyTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
213 // Annotate the scope as having memory leaks to suppress heapchecker reports.
214 ANNOTATE_SCOPED_MEMORY_LEAK;
215 MessageLoop* task_run_on = NULL;
216 MessageLoop* task_deleted_on = NULL;
217 int task_delete_order = -1;
218 MessageLoop* reply_run_on = NULL;
219 MessageLoop* reply_deleted_on = NULL;
220 int reply_delete_order = -1;
221
222 scoped_refptr<LoopRecorder> task_recoder =
223 new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
224 scoped_refptr<LoopRecorder> reply_recoder =
225 new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
226
227 // Enqueue the relay.
228 task_thread_.message_loop_proxy()->PostTaskAndReply(
229 FROM_HERE,
230 Bind(&RecordLoop, task_recoder),
231 Bind(&RecordLoopAndQuit, reply_recoder));
232
233 // Die if base::Bind doesn't retain a reference to the recorders.
234 task_recoder = NULL;
235 reply_recoder = NULL;
236 ASSERT_FALSE(task_deleted_on);
237 ASSERT_FALSE(reply_deleted_on);
238
239 UnblockTaskThread();
240
241 // Mercilessly whack the current loop before |reply| gets to run.
242 current_loop_.reset();
243
244 // This should ensure the relay has been run. We need to record the
245 // MessageLoop pointer before stopping the thread because Thread::Stop() will
246 // NULL out its own pointer.
247 MessageLoop* task_loop = task_thread_.message_loop();
248 task_thread_.Stop();
249
250 EXPECT_EQ(task_loop, task_run_on);
251 ASSERT_FALSE(task_deleted_on);
252 EXPECT_FALSE(reply_run_on);
253 ASSERT_FALSE(reply_deleted_on);
254 EXPECT_EQ(task_delete_order, reply_delete_order);
255
256 // The PostTaskAndReplyRelay is leaked here. Even if we had a reference to
257 // it, we cannot just delete it because PostTaskAndReplyRelay's destructor
258 // checks that MessageLoop::current() is the the same as when the
259 // PostTaskAndReplyRelay object was constructed. However, this loop must have
260 // aleady been deleted in order to perform this test. See
261 // http://crbug.com/86301.
262 }
263
264 } // namespace
265
266 } // namespace base
OLDNEW
« no previous file with comments | « base/message_loop/message_loop_proxy_impl_unittest.cc ('k') | base/message_loop/message_loop_task_runner.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698