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) { |
tzik
2013/04/24 02:37:42
DCHECK(file_task_runner);?
kinuko
2013/04/24 04:15:17
Let's check it in ScopedFile's ctor together.
| |
80 DCHECK(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 | |
81 typedef std::pair<ShareableFileMap::iterator, bool> InsertResult; | 86 typedef std::pair<ShareableFileMap::iterator, bool> InsertResult; |
82 | |
83 // Required for VS2010: http://connect.microsoft.com/VisualStudio/feedback/det ails/520043/error-converting-from-null-to-a-pointer-type-in-std-pair | 87 // 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; | 88 webkit_blob::ShareableFileReference* null_reference = NULL; |
85 InsertResult result = g_file_map.Get().Insert( | 89 InsertResult result = g_file_map.Get().Insert( |
86 ShareableFileMap::value_type(path, null_reference)); | 90 ShareableFileMap::value_type(scoped_file.path(), null_reference)); |
87 if (result.second == false) | 91 if (result.second == false) { |
92 scoped_file.Release(); | |
88 return scoped_refptr<ShareableFileReference>(result.first->second); | 93 return scoped_refptr<ShareableFileReference>(result.first->second); |
94 } | |
89 | 95 |
90 // Wasn't in the map, create a new reference and store the pointer. | 96 // Wasn't in the map, create a new reference and store the pointer. |
91 scoped_refptr<ShareableFileReference> reference( | 97 scoped_refptr<ShareableFileReference> reference( |
92 new ShareableFileReference(path, policy, file_task_runner)); | 98 new ShareableFileReference(scoped_file.Pass())); |
93 result.first->second = reference.get(); | 99 result.first->second = reference.get(); |
94 return reference; | 100 return reference; |
95 } | 101 } |
96 | 102 |
97 void ShareableFileReference::AddFinalReleaseCallback( | 103 void ShareableFileReference::AddFinalReleaseCallback( |
98 const FinalReleaseCallback& callback) { | 104 const FinalReleaseCallback& callback) { |
99 DCHECK(g_file_map.Get().CalledOnValidThread()); | 105 DCHECK(g_file_map.Get().CalledOnValidThread()); |
100 final_release_callbacks_.push_back(callback); | 106 scoped_file_.AddScopeOutCallback( |
107 callback, base::MessageLoopProxy::current()); | |
tzik
2013/04/24 02:37:42
b::MLP::current() can be just NULL?
kinuko
2013/04/24 04:15:17
Done.
| |
101 } | 108 } |
102 | 109 |
103 ShareableFileReference::ShareableFileReference( | 110 ShareableFileReference::ShareableFileReference(ScopedFile scoped_file) |
104 const base::FilePath& path, FinalReleasePolicy policy, | 111 : scoped_file_(scoped_file.Pass()) { |
105 base::TaskRunner* file_task_runner) | 112 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 } | 113 } |
111 | 114 |
112 ShareableFileReference::~ShareableFileReference() { | 115 ShareableFileReference::~ShareableFileReference() { |
113 DCHECK(g_file_map.Get().Find(path_)->second == this); | 116 DCHECK(g_file_map.Get().Find(path())->second == this); |
114 g_file_map.Get().Erase(path_); | 117 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 } | 118 } |
124 | 119 |
125 } // namespace webkit_blob | 120 } // namespace webkit_blob |
OLD | NEW |