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 "webkit/common/blob/shareable_file_reference.h" 6 7 #include <map> 8 9 #include "base/lazy_instance.h" 10 #include "base/message_loop/message_loop_proxy.h" 11 #include "base/task_runner.h" 12 #include "base/threading/non_thread_safe.h" 13 14 namespace webkit_blob { 15 16 namespace { 17 18 // A shareable file map with enforcement of thread checker. 19 class ShareableFileMap : public base::NonThreadSafe { 20 public: 21 typedef std::map<base::FilePath, ShareableFileReference*> FileMap; 22 typedef FileMap::iterator iterator; 23 typedef FileMap::key_type key_type; 24 typedef FileMap::value_type value_type; 25 26 ShareableFileMap() {} 27 28 ~ShareableFileMap() { 29 DetachFromThread(); 30 } 31 32 iterator Find(key_type key) { 33 DCHECK(CalledOnValidThread()); 34 return file_map_.find(key); 35 } 36 37 iterator End() { 38 DCHECK(CalledOnValidThread()); 39 return file_map_.end(); 40 } 41 42 std::pair<iterator, bool> Insert(value_type value) { 43 DCHECK(CalledOnValidThread()); 44 return file_map_.insert(value); 45 } 46 47 void Erase(key_type key) { 48 DCHECK(CalledOnValidThread()); 49 file_map_.erase(key); 50 } 51 52 private: 53 FileMap file_map_; 54 DISALLOW_COPY_AND_ASSIGN(ShareableFileMap); 55 }; 56 57 base::LazyInstance<ShareableFileMap> g_file_map = LAZY_INSTANCE_INITIALIZER; 58 59 } // namespace 60 61 // static 62 scoped_refptr<ShareableFileReference> ShareableFileReference::Get( 63 const base::FilePath& path) { 64 ShareableFileMap::iterator found = g_file_map.Get().Find(path); 65 ShareableFileReference* reference = 66 (found == g_file_map.Get().End()) ? NULL : found->second; 67 return scoped_refptr<ShareableFileReference>(reference); 68 } 69 70 // static 71 scoped_refptr<ShareableFileReference> ShareableFileReference::GetOrCreate( 72 const base::FilePath& path, 73 FinalReleasePolicy policy, 74 base::TaskRunner* file_task_runner) { 75 return GetOrCreate( 76 ScopedFile(path, static_cast<ScopedFile::ScopeOutPolicy>(policy), 77 file_task_runner)); 78 } 79 80 // static 81 scoped_refptr<ShareableFileReference> ShareableFileReference::GetOrCreate( 82 ScopedFile scoped_file) { 83 if (scoped_file.path().empty()) 84 return scoped_refptr<ShareableFileReference>(); 85 86 typedef std::pair<ShareableFileMap::iterator, bool> InsertResult; 87 // Required for VS2010: http://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair 88 webkit_blob::ShareableFileReference* null_reference = NULL; 89 InsertResult result = g_file_map.Get().Insert( 90 ShareableFileMap::value_type(scoped_file.path(), null_reference)); 91 if (result.second == false) { 92 scoped_file.Release(); 93 return scoped_refptr<ShareableFileReference>(result.first->second); 94 } 95 96 // Wasn't in the map, create a new reference and store the pointer. 97 scoped_refptr<ShareableFileReference> reference( 98 new ShareableFileReference(scoped_file.Pass())); 99 result.first->second = reference.get(); 100 return reference; 101 } 102 103 void ShareableFileReference::AddFinalReleaseCallback( 104 const FinalReleaseCallback& callback) { 105 DCHECK(g_file_map.Get().CalledOnValidThread()); 106 scoped_file_.AddScopeOutCallback(callback, NULL); 107 } 108 109 ShareableFileReference::ShareableFileReference(ScopedFile scoped_file) 110 : scoped_file_(scoped_file.Pass()) { 111 DCHECK(g_file_map.Get().Find(path())->second == NULL); 112 } 113 114 ShareableFileReference::~ShareableFileReference() { 115 DCHECK(g_file_map.Get().Find(path())->second == this); 116 g_file_map.Get().Erase(path()); 117 } 118 119 } // namespace webkit_blob 120