Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "webkit/blob/shareable_file_reference.h" | 5 #include "webkit/blob/shareable_file_reference.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 | 8 |
| 9 #include "base/file_util.h" | |
| 10 #include "base/files/file_util_proxy.h" | |
| 11 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
| 10 #include "base/message_loop/message_loop_proxy.h" | |
| 12 #include "base/task_runner.h" | 11 #include "base/task_runner.h" |
| 13 #include "base/threading/thread_checker.h" | 12 #include "base/threading/non_thread_safe.h" |
| 14 | 13 |
| 15 namespace webkit_blob { | 14 namespace webkit_blob { |
| 16 | 15 |
| 17 namespace { | 16 namespace { |
| 18 | 17 |
| 19 // A shareable file map with enforcement of thread checker. | 18 // A shareable file map with enforcement of thread checker. |
| 20 // This map may get deleted on a different thread in AtExitManager at the | 19 class ShareableFileMap : public base::NonThreadSafe { |
| 21 // very end on the main thread (at the point all other threads must be | |
| 22 // terminated), so we use ThreadChecker rather than NonThreadSafe and do not | |
| 23 // check thread in the dtor. | |
| 24 class ShareableFileMap { | |
| 25 public: | 20 public: |
| 26 typedef std::map<base::FilePath, ShareableFileReference*> FileMap; | 21 typedef std::map<base::FilePath, ShareableFileReference*> FileMap; |
| 27 typedef FileMap::iterator iterator; | 22 typedef FileMap::iterator iterator; |
| 28 typedef FileMap::key_type key_type; | 23 typedef FileMap::key_type key_type; |
| 29 typedef FileMap::value_type value_type; | 24 typedef FileMap::value_type value_type; |
| 30 | 25 |
| 31 ShareableFileMap() {} | 26 ShareableFileMap() {} |
| 32 | 27 |
| 28 ~ShareableFileMap() { | |
| 29 DetachFromThread(); | |
| 30 } | |
| 31 | |
| 33 iterator Find(key_type key) { | 32 iterator Find(key_type key) { |
| 34 DCHECK(CalledOnValidThread()); | 33 DCHECK(CalledOnValidThread()); |
| 35 return file_map_.find(key); | 34 return file_map_.find(key); |
| 36 } | 35 } |
| 37 | 36 |
| 38 iterator End() { | 37 iterator End() { |
| 39 DCHECK(CalledOnValidThread()); | 38 DCHECK(CalledOnValidThread()); |
| 40 return file_map_.end(); | 39 return file_map_.end(); |
| 41 } | 40 } |
| 42 | 41 |
| 43 std::pair<iterator, bool> Insert(value_type value) { | 42 std::pair<iterator, bool> Insert(value_type value) { |
| 44 DCHECK(CalledOnValidThread()); | 43 DCHECK(CalledOnValidThread()); |
| 45 return file_map_.insert(value); | 44 return file_map_.insert(value); |
| 46 } | 45 } |
| 47 | 46 |
| 48 void Erase(key_type key) { | 47 void Erase(key_type key) { |
| 49 DCHECK(CalledOnValidThread()); | 48 DCHECK(CalledOnValidThread()); |
| 50 file_map_.erase(key); | 49 file_map_.erase(key); |
| 51 } | 50 } |
| 52 | 51 |
| 53 bool CalledOnValidThread() const { | |
| 54 return thread_checker_.CalledOnValidThread(); | |
| 55 } | |
| 56 | |
| 57 private: | 52 private: |
| 58 FileMap file_map_; | 53 FileMap file_map_; |
| 59 base::ThreadChecker thread_checker_; | |
| 60 DISALLOW_COPY_AND_ASSIGN(ShareableFileMap); | 54 DISALLOW_COPY_AND_ASSIGN(ShareableFileMap); |
| 61 }; | 55 }; |
| 62 | 56 |
| 63 base::LazyInstance<ShareableFileMap> g_file_map = LAZY_INSTANCE_INITIALIZER; | 57 base::LazyInstance<ShareableFileMap> g_file_map = LAZY_INSTANCE_INITIALIZER; |
| 64 | 58 |
| 65 } // namespace | 59 } // namespace |
| 66 | 60 |
| 67 // static | 61 // static |
| 68 scoped_refptr<ShareableFileReference> ShareableFileReference::Get( | 62 scoped_refptr<ShareableFileReference> ShareableFileReference::Get( |
| 69 const base::FilePath& path) { | 63 const base::FilePath& path) { |
| 70 ShareableFileMap::iterator found = g_file_map.Get().Find(path); | 64 ShareableFileMap::iterator found = g_file_map.Get().Find(path); |
| 71 ShareableFileReference* reference = | 65 ShareableFileReference* reference = |
| 72 (found == g_file_map.Get().End()) ? NULL : found->second; | 66 (found == g_file_map.Get().End()) ? NULL : found->second; |
| 73 return scoped_refptr<ShareableFileReference>(reference); | 67 return scoped_refptr<ShareableFileReference>(reference); |
| 74 } | 68 } |
| 75 | 69 |
| 76 // static | 70 // static |
| 77 scoped_refptr<ShareableFileReference> ShareableFileReference::GetOrCreate( | 71 scoped_refptr<ShareableFileReference> ShareableFileReference::GetOrCreate( |
| 78 const base::FilePath& path, FinalReleasePolicy policy, | 72 const base::FilePath& path, |
| 73 FinalReleasePolicy policy, | |
| 79 base::TaskRunner* file_task_runner) { | 74 base::TaskRunner* file_task_runner) { |
| 80 DCHECK(file_task_runner); | 75 ScopedFile::ScopeOutPolicy scope_out_policy = |
| 76 ScopedFile::DONT_DELETE_ON_SCOPE_OUT; | |
| 77 switch (policy) { | |
| 78 case DELETE_ON_FINAL_RELEASE: | |
| 79 scope_out_policy = ScopedFile::DELETE_ON_SCOPE_OUT; | |
| 80 break; | |
| 81 case DONT_DELETE_ON_FINAL_RELEASE: | |
| 82 scope_out_policy = ScopedFile::DONT_DELETE_ON_SCOPE_OUT; | |
| 83 break; | |
| 84 default: | |
| 85 NOTREACHED(); | |
| 86 } | |
| 87 return GetOrCreate(ScopedFile(path, scope_out_policy, file_task_runner)); | |
| 88 } | |
| 89 | |
| 90 // static | |
| 91 scoped_refptr<ShareableFileReference> ShareableFileReference::GetOrCreate( | |
| 92 ScopedFile scoped_file) { | |
| 93 if (scoped_file.empty()) | |
| 94 return NULL; | |
| 81 typedef std::pair<ShareableFileMap::iterator, bool> InsertResult; | 95 typedef std::pair<ShareableFileMap::iterator, bool> InsertResult; |
| 82 | 96 |
| 83 // Required for VS2010: http://connect.microsoft.com/VisualStudio/feedback/det ails/520043/error-converting-from-null-to-a-pointer-type-in-std-pair | 97 // Required for VS2010: http://connect.microsoft.com/VisualStudio/feedback/det ails/520043/error-converting-from-null-to-a-pointer-type-in-std-pair |
| 84 webkit_blob::ShareableFileReference* null_reference = NULL; | 98 webkit_blob::ShareableFileReference* null_reference = NULL; |
| 85 InsertResult result = g_file_map.Get().Insert( | 99 InsertResult result = g_file_map.Get().Insert( |
| 86 ShareableFileMap::value_type(path, null_reference)); | 100 ShareableFileMap::value_type(scoped_file.path(), null_reference)); |
| 87 if (result.second == false) | 101 if (result.second == false) { |
| 102 scoped_file.Release(); | |
|
michaeln
2013/04/22 21:07:03
if there are existing callbacks associated with sc
kinuko
2013/04/23 06:31:29
I have a mixed feeling about how to do in such a c
| |
| 88 return scoped_refptr<ShareableFileReference>(result.first->second); | 103 return scoped_refptr<ShareableFileReference>(result.first->second); |
| 104 } | |
| 89 | 105 |
| 90 // Wasn't in the map, create a new reference and store the pointer. | 106 // Wasn't in the map, create a new reference and store the pointer. |
| 91 scoped_refptr<ShareableFileReference> reference( | 107 scoped_refptr<ShareableFileReference> reference( |
| 92 new ShareableFileReference(path, policy, file_task_runner)); | 108 new ShareableFileReference(scoped_file.Pass())); |
| 93 result.first->second = reference.get(); | 109 result.first->second = reference.get(); |
| 94 return reference; | 110 return reference; |
| 95 } | 111 } |
| 96 | 112 |
| 97 void ShareableFileReference::AddFinalReleaseCallback( | 113 void ShareableFileReference::AddFinalReleaseCallback( |
| 98 const FinalReleaseCallback& callback) { | 114 const FinalReleaseCallback& callback) { |
| 99 DCHECK(g_file_map.Get().CalledOnValidThread()); | 115 DCHECK(g_file_map.Get().CalledOnValidThread()); |
| 100 final_release_callbacks_.push_back(callback); | 116 scoped_file_.AddScopeOutCallback( |
| 117 callback, base::MessageLoopProxy::current()); | |
| 101 } | 118 } |
| 102 | 119 |
| 103 ShareableFileReference::ShareableFileReference( | 120 ShareableFileReference::ShareableFileReference(ScopedFile scoped_file) |
| 104 const base::FilePath& path, FinalReleasePolicy policy, | 121 : scoped_file_(scoped_file.Pass()) { |
| 105 base::TaskRunner* file_task_runner) | 122 DCHECK(g_file_map.Get().Find(path())->second == NULL); |
| 106 : path_(path), | |
| 107 final_release_policy_(policy), | |
| 108 file_task_runner_(file_task_runner) { | |
| 109 DCHECK(g_file_map.Get().Find(path_)->second == NULL); | |
| 110 } | 123 } |
| 111 | 124 |
| 112 ShareableFileReference::~ShareableFileReference() { | 125 ShareableFileReference::~ShareableFileReference() { |
| 113 DCHECK(g_file_map.Get().Find(path_)->second == this); | 126 DCHECK(g_file_map.Get().Find(path())->second == this); |
| 114 g_file_map.Get().Erase(path_); | 127 g_file_map.Get().Erase(path()); |
| 115 | |
| 116 for (size_t i = 0; i < final_release_callbacks_.size(); i++) | |
| 117 final_release_callbacks_[i].Run(path_); | |
| 118 | |
| 119 if (final_release_policy_ == DELETE_ON_FINAL_RELEASE) { | |
| 120 base::FileUtilProxy::Delete(file_task_runner_, path_, false /* recursive */, | |
| 121 base::FileUtilProxy::StatusCallback()); | |
| 122 } | |
| 123 } | 128 } |
| 124 | 129 |
| 125 } // namespace webkit_blob | 130 } // namespace webkit_blob |
| OLD | NEW |