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 |