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

Side by Side Diff: ppapi/proxy/tracked_callback_unittest.cc

Issue 869883003: Never lock the Pepper proxy lock on the IO thread (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix GN build, fix tests Created 5 years, 9 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/bind.h"
6 #include "base/memory/ref_counted.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/run_loop.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "base/threading/simple_thread.h"
11 #include "ppapi/c/pp_completion_callback.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/proxy/ppapi_proxy_test.h"
14 #include "ppapi/proxy/ppb_message_loop_proxy.h"
15 #include "ppapi/shared_impl/callback_tracker.h"
16 #include "ppapi/shared_impl/proxy_lock.h"
17 #include "ppapi/shared_impl/resource.h"
18 #include "ppapi/shared_impl/resource_tracker.h"
19 #include "ppapi/shared_impl/scoped_pp_resource.h"
20 #include "ppapi/shared_impl/test_globals.h"
21 #include "ppapi/shared_impl/tracked_callback.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 // Note, this file tests TrackedCallback which lives in ppapi/shared_impl.
25 // Unfortunately, we need the test to live in ppapi/proxy so that it can use
26 // the thread support there.
27 namespace ppapi {
28 namespace proxy {
29
30 namespace {
31
32 class CallbackThread : public base::SimpleThread {
33 public:
34 explicit CallbackThread(PP_Instance instance)
35 : SimpleThread("CallbackThread"), instance_(instance) {}
36 ~CallbackThread() override {}
37
38 // base::SimpleThread overrides.
39 void Start() override {
40 {
41 ProxyAutoLock acquire;
42 // Create the message loop here, after PpapiGlobals has been created.
43 message_loop_ = new MessageLoopResource(instance_);
44 }
45 base::SimpleThread::Start();
46 }
47 void Join() override {
48 {
49 ProxyAutoLock acquire;
50 message_loop()->PostQuit(PP_TRUE);
51 message_loop_ = nullptr;
52 }
53 base::SimpleThread::Join();
54 }
55 void Run() override {
56 ProxyAutoLock acquire;
57 // Make a local copy of message_loop_ for this thread so we can interact
58 // with it even after the main thread releases it.
59 scoped_refptr<MessageLoopResource> message_loop(message_loop_);
60 message_loop->AttachToCurrentThread();
61 // Note, run releases the lock to run events.
62 message_loop->Run();
63 message_loop->DetachFromThread();
64 }
65
66 MessageLoopResource* message_loop() { return message_loop_.get(); }
67
68 private:
69 PP_Instance instance_;
70 scoped_refptr<MessageLoopResource> message_loop_;
71 };
72
73 class TrackedCallbackTest : public PluginProxyTest {
74 public:
75 TrackedCallbackTest() : thread_(pp_instance()) {}
76 CallbackThread& thread() { return thread_; }
77
78 private:
79 // PluginProxyTest overrides.
80 void SetUp() override {
81 PluginProxyTest::SetUp();
82 thread_.Start();
83 }
84 void TearDown() override {
85 thread_.Join();
86 PluginProxyTest::TearDown();
87 base::RunLoop run_loop;
88 run_loop.RunUntilIdle();
89 }
90 CallbackThread thread_;
91 };
92
93 // All valid results (PP_OK, PP_ERROR_...) are nonpositive.
94 const int32_t kInitializedResultValue = 1;
95 const int32_t kOverrideResultValue = 2;
96
97 struct CallbackRunInfo {
98 explicit CallbackRunInfo(base::ThreadChecker* thread_checker)
99 : run_count_(0),
100 result_(kInitializedResultValue),
101 completion_task_run_count_(0),
102 completion_task_result_(kInitializedResultValue),
103 thread_checker_(thread_checker),
104 callback_did_run_event_(true, false) {}
105 void CallbackDidRun(int32_t result) {
106 CHECK(thread_checker_->CalledOnValidThread());
107 if (!run_count_)
108 result_ = result;
109 ++run_count_;
110 callback_did_run_event_.Signal();
111 }
112 void CompletionTaskDidRun(int32_t result) {
113 CHECK(thread_checker_->CalledOnValidThread());
114 if (!completion_task_run_count_)
115 completion_task_result_ = result;
116 ++completion_task_run_count_;
117 }
118 void WaitUntilCompleted() { callback_did_run_event_.Wait(); }
119 unsigned run_count() { return run_count_; }
120 int32_t result() { return result_; }
121 unsigned completion_task_run_count() { return completion_task_run_count_; }
122 int32_t completion_task_result() { return completion_task_result_; }
123
124 private:
125 unsigned run_count_;
126 int32_t result_;
127 unsigned completion_task_run_count_;
128 int32_t completion_task_result_;
129 // Weak; owned by the creator of CallbackRunInfo.
130 base::ThreadChecker* thread_checker_;
131
132 base::WaitableEvent callback_did_run_event_;
133 };
134
135 void TestCallback(void* user_data, int32_t result) {
136 CallbackRunInfo* info = static_cast<CallbackRunInfo*>(user_data);
137 info->CallbackDidRun(result);
138 }
139
140 // CallbackShutdownTest --------------------------------------------------------
141
142 class CallbackShutdownTest : public TrackedCallbackTest {
143 public:
144 CallbackShutdownTest()
145 : info_did_run_(&thread_checker_),
146 info_did_abort_(&thread_checker_),
147 info_didnt_run_(&thread_checker_) {}
148
149 // Cases:
150 // (1) A callback which is run (so shouldn't be aborted on shutdown).
151 // (2) A callback which is aborted (so shouldn't be aborted on shutdown).
152 // (3) A callback which isn't run (so should be aborted on shutdown).
153 CallbackRunInfo& info_did_run() { return info_did_run_; } // (1)
154 CallbackRunInfo& info_did_abort() { return info_did_abort_; } // (2)
155 CallbackRunInfo& info_didnt_run() { return info_didnt_run_; } // (3)
156
157 private:
158 base::ThreadChecker thread_checker_;
159 CallbackRunInfo info_did_run_;
160 CallbackRunInfo info_did_abort_;
161 CallbackRunInfo info_didnt_run_;
162 };
163
164 } // namespace
165
166 // Tests that callbacks are properly aborted on module shutdown.
167 TEST_F(CallbackShutdownTest, AbortOnShutdown) {
168 ProxyAutoLock lock;
169 scoped_refptr<Resource> resource(
170 new Resource(OBJECT_IS_PROXY, pp_instance()));
171
172 // Set up case (1) (see above).
173 EXPECT_EQ(0U, info_did_run().run_count());
174 // TODO(dmichael): Test this on a background thread?
175 scoped_refptr<TrackedCallback> callback_did_run = new TrackedCallback(
176 resource.get(),
177 PP_MakeCompletionCallback(&TestCallback, &info_did_run()));
178 EXPECT_EQ(0U, info_did_run().run_count());
179 callback_did_run->Run(PP_OK);
180 EXPECT_EQ(1U, info_did_run().run_count());
181 EXPECT_EQ(PP_OK, info_did_run().result());
182
183 // Set up case (2).
184 EXPECT_EQ(0U, info_did_abort().run_count());
185 scoped_refptr<TrackedCallback> callback_did_abort = new TrackedCallback(
186 resource.get(),
187 PP_MakeCompletionCallback(&TestCallback, &info_did_abort()));
188 EXPECT_EQ(0U, info_did_abort().run_count());
189 callback_did_abort->Abort();
190 EXPECT_EQ(1U, info_did_abort().run_count());
191 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort().result());
192
193 // Set up case (3).
194 EXPECT_EQ(0U, info_didnt_run().run_count());
195 scoped_refptr<TrackedCallback> callback_didnt_run = new TrackedCallback(
196 resource.get(),
197 PP_MakeCompletionCallback(&TestCallback, &info_didnt_run()));
198 EXPECT_EQ(0U, info_didnt_run().run_count());
199
200 GetGlobals()->GetCallbackTrackerForInstance(pp_instance())->AbortAll();
201
202 // Check case (1).
203 EXPECT_EQ(1U, info_did_run().run_count());
204
205 // Check case (2).
206 EXPECT_EQ(1U, info_did_abort().run_count());
207
208 // Check case (3).
209 EXPECT_EQ(1U, info_didnt_run().run_count());
210 EXPECT_EQ(PP_ERROR_ABORTED, info_didnt_run().result());
211 }
212
213 // CallbackResourceTest --------------------------------------------------------
214
215 namespace {
216
217 class CallbackResourceTest : public TrackedCallbackTest {
218 public:
219 CallbackResourceTest() {}
220 };
221
222 class CallbackMockResource : public Resource {
223 public:
224 static scoped_refptr<CallbackMockResource> Create(PP_Instance instance) {
225 ProxyAutoLock acquire;
226 return scoped_refptr<CallbackMockResource>(
227 new CallbackMockResource(instance));
228 }
229 ~CallbackMockResource() {}
230
231 // Take a reference to this resource, which will add it to the tracker.
232 void TakeRef() {
233 ProxyAutoLock acquire;
234 ScopedPPResource temp_resource(ScopedPPResource::PassRef(), GetReference());
235 EXPECT_NE(0, temp_resource.get());
236 reference_holder_ = temp_resource;
237 }
238 // Release it, removing it from the tracker.
239 void ReleaseRef() {
240 ProxyAutoLock acquire;
241 reference_holder_ = 0;
242 }
243
244 // Create the test callbacks on a background thread, so that we can verify
245 // they are run on the same thread where they were created.
246 void CreateCallbacksOnLoop(MessageLoopResource* loop_resource) {
247 ProxyAutoLock acquire;
248 // |thread_checker_| will bind to the background thread.
249 thread_checker_.DetachFromThread();
250 loop_resource->message_loop_proxy()->PostTask(
251 FROM_HERE, RunWhileLocked(base::Bind(
252 &CallbackMockResource::CreateCallbacks, this)));
253 }
254
255 int32_t CompletionTask(CallbackRunInfo* info, int32_t result) {
256 // The completion task must run on the thread where the callback was
257 // created, and must hold the proxy lock.
258 CHECK(thread_checker_.CalledOnValidThread());
259 ProxyLock::AssertAcquired();
260
261 // We should run before the callback.
262 CHECK_EQ(0U, info->run_count());
263 info->CompletionTaskDidRun(result);
264 return kOverrideResultValue;
265 }
266
267 void CheckInitialState() {
268 callbacks_created_event_.Wait();
269 EXPECT_EQ(0U, info_did_run_.run_count());
270 EXPECT_EQ(0U, info_did_run_.completion_task_run_count());
271
272 EXPECT_EQ(0U, info_did_run_with_completion_task_.run_count());
273 EXPECT_EQ(0U,
274 info_did_run_with_completion_task_.completion_task_run_count());
275
276 EXPECT_EQ(0U, info_did_abort_.run_count());
277 EXPECT_EQ(0U, info_did_abort_.completion_task_run_count());
278
279 EXPECT_EQ(0U, info_didnt_run_.run_count());
280 EXPECT_EQ(0U, info_didnt_run_.completion_task_run_count());
281 }
282
283 void RunCallbacks() {
284 callback_did_run_->Run(PP_OK);
285 callback_did_run_with_completion_task_->Run(PP_OK);
286 callback_did_abort_->Abort();
287 info_did_run_.WaitUntilCompleted();
288 info_did_run_with_completion_task_.WaitUntilCompleted();
289 info_did_abort_.WaitUntilCompleted();
290 }
291
292 void CheckIntermediateState() {
293 EXPECT_EQ(1U, info_did_run_.run_count());
294 EXPECT_EQ(PP_OK, info_did_run_.result());
295 EXPECT_EQ(0U, info_did_run_.completion_task_run_count());
296
297 EXPECT_EQ(1U, info_did_run_with_completion_task_.run_count());
298 // completion task should override the result.
299 EXPECT_EQ(kOverrideResultValue,
300 info_did_run_with_completion_task_.result());
301 EXPECT_EQ(1U,
302 info_did_run_with_completion_task_.completion_task_run_count());
303 EXPECT_EQ(PP_OK,
304 info_did_run_with_completion_task_.completion_task_result());
305
306 EXPECT_EQ(1U, info_did_abort_.run_count());
307 // completion task shouldn't override an abort.
308 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort_.result());
309 EXPECT_EQ(1U, info_did_abort_.completion_task_run_count());
310 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort_.completion_task_result());
311
312 EXPECT_EQ(0U, info_didnt_run_.completion_task_run_count());
313 EXPECT_EQ(0U, info_didnt_run_.run_count());
314 }
315
316 void CheckFinalState() {
317 info_didnt_run_.WaitUntilCompleted();
318 EXPECT_EQ(1U, info_did_run_with_completion_task_.run_count());
319 EXPECT_EQ(kOverrideResultValue,
320 info_did_run_with_completion_task_.result());
321 callback_did_run_with_completion_task_ = nullptr;
322 EXPECT_EQ(1U, info_did_run_.run_count());
323 EXPECT_EQ(PP_OK, info_did_run_.result());
324 callback_did_run_ = nullptr;
325 EXPECT_EQ(1U, info_did_abort_.run_count());
326 EXPECT_EQ(PP_ERROR_ABORTED, info_did_abort_.result());
327 callback_did_abort_ = nullptr;
328 EXPECT_EQ(1U, info_didnt_run_.run_count());
329 EXPECT_EQ(PP_ERROR_ABORTED, info_didnt_run_.result());
330 callback_didnt_run_ = nullptr;
331 }
332
333 private:
334 explicit CallbackMockResource(PP_Instance instance)
335 : Resource(OBJECT_IS_PROXY, instance),
336 info_did_run_(&thread_checker_),
337 info_did_run_with_completion_task_(&thread_checker_),
338 info_did_abort_(&thread_checker_),
339 info_didnt_run_(&thread_checker_),
340 callbacks_created_event_(true, false) {}
341 void CreateCallbacks() {
342 // Bind thread_checker_ to the thread where we create the callbacks.
343 // Later, when the callback runs, it will check that it was invoked on this
344 // same thread.
345 CHECK(thread_checker_.CalledOnValidThread());
346
347 callback_did_run_ = new TrackedCallback(
348 this, PP_MakeCompletionCallback(&TestCallback, &info_did_run_));
349
350 // In order to test that the completion task can override the callback
351 // result, we need to test callbacks with and without a completion task.
352 callback_did_run_with_completion_task_ = new TrackedCallback(
353 this, PP_MakeCompletionCallback(&TestCallback,
354 &info_did_run_with_completion_task_));
355 callback_did_run_with_completion_task_->set_completion_task(
356 Bind(&CallbackMockResource::CompletionTask, this,
357 &info_did_run_with_completion_task_));
358
359 callback_did_abort_ = new TrackedCallback(
360 this, PP_MakeCompletionCallback(&TestCallback, &info_did_abort_));
361 callback_did_abort_->set_completion_task(
362 Bind(&CallbackMockResource::CompletionTask, this, &info_did_abort_));
363
364 callback_didnt_run_ = new TrackedCallback(
365 this, PP_MakeCompletionCallback(&TestCallback, &info_didnt_run_));
366 callback_didnt_run_->set_completion_task(
367 Bind(&CallbackMockResource::CompletionTask, this, &info_didnt_run_));
368
369 callbacks_created_event_.Signal();
370 }
371
372 // Used to verify that the callback runs on the same thread where it is
373 // created.
374 base::ThreadChecker thread_checker_;
375
376 scoped_refptr<TrackedCallback> callback_did_run_;
377 CallbackRunInfo info_did_run_;
378
379 scoped_refptr<TrackedCallback> callback_did_run_with_completion_task_;
380 CallbackRunInfo info_did_run_with_completion_task_;
381
382 scoped_refptr<TrackedCallback> callback_did_abort_;
383 CallbackRunInfo info_did_abort_;
384
385 scoped_refptr<TrackedCallback> callback_didnt_run_;
386 CallbackRunInfo info_didnt_run_;
387
388 base::WaitableEvent callbacks_created_event_;
389
390 ScopedPPResource reference_holder_;
391 };
392
393 } // namespace
394
395 // Test that callbacks get aborted on the last resource unref.
396 TEST_F(CallbackResourceTest, AbortOnNoRef) {
397 // Test several things: Unref-ing a resource (to zero refs) with callbacks
398 // which (1) have been run, (2) have been aborted, (3) haven't been completed.
399 // Check that the uncompleted one gets aborted, and that the others don't get
400 // called again.
401 scoped_refptr<CallbackMockResource> resource_1(
402 CallbackMockResource::Create(pp_instance()));
403 resource_1->CreateCallbacksOnLoop(thread().message_loop());
404 resource_1->CheckInitialState();
405 resource_1->RunCallbacks();
406 resource_1->TakeRef();
407 resource_1->CheckIntermediateState();
408
409 // Also do the same for a second resource, and make sure that unref-ing the
410 // first resource doesn't much up the second resource.
411 scoped_refptr<CallbackMockResource> resource_2(
412 CallbackMockResource::Create(pp_instance()));
413 resource_2->CreateCallbacksOnLoop(thread().message_loop());
414 resource_2->CheckInitialState();
415 resource_2->RunCallbacks();
416 resource_2->TakeRef();
417 resource_2->CheckIntermediateState();
418
419 // Double-check that resource #1 is still okay.
420 resource_1->CheckIntermediateState();
421
422 // Kill resource #1, spin the message loop to run posted calls, and check that
423 // things are in the expected states.
424 resource_1->ReleaseRef();
425
426 resource_1->CheckFinalState();
427 resource_2->CheckIntermediateState();
428
429 // Kill resource #2.
430 resource_2->ReleaseRef();
431
432 resource_1->CheckFinalState();
433 resource_2->CheckFinalState();
434
435 {
436 ProxyAutoLock lock;
437 resource_1 = nullptr;
438 resource_2 = nullptr;
439 }
440 }
441
442 // Test that "resurrecting" a resource (getting a new ID for a |Resource|)
443 // doesn't resurrect callbacks.
444 TEST_F(CallbackResourceTest, Resurrection) {
445 scoped_refptr<CallbackMockResource> resource(
446 CallbackMockResource::Create(pp_instance()));
447 resource->CreateCallbacksOnLoop(thread().message_loop());
448 resource->CheckInitialState();
449 resource->RunCallbacks();
450 resource->TakeRef();
451 resource->CheckIntermediateState();
452
453 // Unref it and check that things are in the expected states.
454 resource->ReleaseRef();
455 resource->CheckFinalState();
456
457 // "Resurrect" it and check that the callbacks are still dead.
458 resource->TakeRef();
459 resource->CheckFinalState();
460
461 // Unref it again and do the same.
462 resource->ReleaseRef();
463 resource->CheckFinalState();
464 {
465 ProxyAutoLock lock;
466 resource = nullptr;
467 }
468 }
469
470 } // namespace proxy
471 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698