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

Side by Side Diff: base/message_loop_proxy_unittest.cc

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

Powered by Google App Engine
This is Rietveld 408576698