1// Copyright 2013 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/run_loop.h" 7#include "base/synchronization/waitable_event.h" 8#include "base/threading/thread.h" 9#include "cc/layers/delegated_frame_resource_collection.h" 10#include "cc/resources/returned_resource.h" 11#include "cc/resources/transferable_resource.h" 12#include "testing/gtest/include/gtest/gtest.h" 13 14namespace cc { 15namespace { 16 17class DelegatedFrameResourceCollectionTest 18 : public testing::Test, 19 public DelegatedFrameResourceCollectionClient { 20 protected: 21 DelegatedFrameResourceCollectionTest() : resources_available_(false) {} 22 23 virtual void SetUp() OVERRIDE { CreateResourceCollection(); } 24 25 virtual void TearDown() OVERRIDE { DestroyResourceCollection(); } 26 27 void CreateResourceCollection() { 28 DCHECK(!resource_collection_); 29 resource_collection_ = new DelegatedFrameResourceCollection; 30 resource_collection_->SetClient(this); 31 } 32 33 void DestroyResourceCollection() { 34 if (resource_collection_) { 35 resource_collection_->SetClient(NULL); 36 resource_collection_ = NULL; 37 } 38 } 39 40 TransferableResourceArray CreateResourceArray() { 41 TransferableResourceArray resources; 42 TransferableResource resource; 43 resource.id = 444; 44 resources.push_back(resource); 45 return resources; 46 } 47 48 virtual void UnusedResourcesAreAvailable() OVERRIDE { 49 resources_available_ = true; 50 resource_collection_->TakeUnusedResourcesForChildCompositor( 51 &returned_resources_); 52 if (!resources_available_closure_.is_null()) 53 resources_available_closure_.Run(); 54 } 55 56 bool ReturnAndResetResourcesAvailable() { 57 bool r = resources_available_; 58 resources_available_ = false; 59 return r; 60 } 61 62 scoped_refptr<DelegatedFrameResourceCollection> resource_collection_; 63 bool resources_available_; 64 ReturnedResourceArray returned_resources_; 65 base::Closure resources_available_closure_; 66}; 67 68// This checks that taking the return callback doesn't take extra refcounts, 69// since it's sent to other threads. 70TEST_F(DelegatedFrameResourceCollectionTest, NoRef) { 71 // Start with one ref. 72 EXPECT_TRUE(resource_collection_->HasOneRef()); 73 74 ReturnCallback return_callback = 75 resource_collection_->GetReturnResourcesCallbackForImplThread(); 76 77 // Callback shouldn't take a ref since it's sent to other threads. 78 EXPECT_TRUE(resource_collection_->HasOneRef()); 79} 80 81void ReturnResourcesOnThread(ReturnCallback callback, 82 const ReturnedResourceArray& resources, 83 base::WaitableEvent* event) { 84 callback.Run(resources); 85 if (event) 86 event->Wait(); 87} 88 89// Tests that the ReturnCallback can run safely on threads even after the 90// last references to the collection were dropped. 91// Flaky: crbug.com/313441 92TEST_F(DelegatedFrameResourceCollectionTest, Thread) { 93 base::Thread thread("test thread"); 94 thread.Start(); 95 96 TransferableResourceArray resources = CreateResourceArray(); 97 resource_collection_->ReceivedResources(resources); 98 resource_collection_->RefResources(resources); 99 100 ReturnedResourceArray returned_resources; 101 TransferableResource::ReturnResources(resources, &returned_resources); 102 103 base::WaitableEvent event(false, false); 104 105 { 106 base::RunLoop run_loop; 107 resources_available_closure_ = run_loop.QuitClosure(); 108 109 thread.message_loop()->PostTask( 110 FROM_HERE, 111 base::Bind( 112 &ReturnResourcesOnThread, 113 resource_collection_->GetReturnResourcesCallbackForImplThread(), 114 returned_resources, 115 &event)); 116 117 run_loop.Run(); 118 } 119 EXPECT_TRUE(ReturnAndResetResourcesAvailable()); 120 EXPECT_EQ(1u, returned_resources_.size()); 121 EXPECT_EQ(444u, returned_resources_[0].id); 122 EXPECT_EQ(1, returned_resources_[0].count); 123 returned_resources_.clear(); 124 125 // The event prevents the return resources callback from being deleted. 126 // Destroy the last reference from this thread to the collection before 127 // signaling the event, to ensure any reference taken by the callback, if any, 128 // would be the last one. 129 DestroyResourceCollection(); 130 event.Signal(); 131 132 CreateResourceCollection(); 133 resource_collection_->ReceivedResources(resources); 134 resource_collection_->RefResources(resources); 135 136 // Destroy the collection before we have a chance to run the return callback. 137 ReturnCallback return_callback = 138 resource_collection_->GetReturnResourcesCallbackForImplThread(); 139 resource_collection_->LoseAllResources(); 140 DestroyResourceCollection(); 141 142 EXPECT_TRUE(ReturnAndResetResourcesAvailable()); 143 EXPECT_EQ(1u, returned_resources_.size()); 144 EXPECT_EQ(444u, returned_resources_[0].id); 145 EXPECT_EQ(1, returned_resources_[0].count); 146 EXPECT_TRUE(returned_resources_[0].lost); 147 returned_resources_.clear(); 148 149 base::WaitableEvent* null_event = NULL; 150 thread.message_loop()->PostTask(FROM_HERE, 151 base::Bind(&ReturnResourcesOnThread, 152 return_callback, 153 returned_resources, 154 null_event)); 155 156 thread.Stop(); 157} 158 159} // namespace 160} // namespace cc 161