OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
agl
2013/11/14 16:20:37
2013
agl
2013/11/14 16:20:37
Note, this file name is very generic. See comments
alcutter
2013/11/14 16:51:59
Ack.
alcutter
2013/11/14 16:51:59
Done.
| |
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 <map> | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/stl_util.h" | |
9 #include "base/synchronization/lock.h" | |
10 #include "content/browser/renderer_host/render_process_host_impl.h" | |
11 #include "content/browser/renderer_host/render_view_host_impl.h" | |
12 #include "content/public/browser/browser_thread.h" | |
13 #include "content/public/browser/notification_observer.h" | |
14 #include "content/public/browser/notification_registrar.h" | |
15 #include "content/public/browser/notification_service.h" | |
16 #include "content/public/browser/notification_types.h" | |
17 | |
18 template <typename T> | |
agl
2013/11/14 16:20:37
This pollutes the global name space here. I think
alcutter
2013/11/14 16:51:59
Done.
| |
19 struct MatchSecond { | |
20 explicit MatchSecond(const T& t) : value(t) {} | |
21 | |
22 template <typename Pair> | |
23 bool operator()(const Pair& p) const { | |
24 return (value == p.second); | |
25 } | |
26 T value; | |
27 }; | |
28 | |
29 namespace content { | |
30 | |
31 template <typename T> | |
32 class ItemStore : public NotificationObserver { | |
agl
2013/11/14 16:20:37
ItemStore is an incredibly generic name.
Renderer
agl
2013/11/14 16:20:37
This needs a fairly large comment explaining it:
alcutter
2013/11/14 16:51:59
Ok, I'll rename once you're happy with everything
alcutter
2013/11/14 16:51:59
Fair point - this file is really just the old cont
| |
33 protected: | |
agl
2013/11/14 16:20:37
You are inheriting from this object. Are you sure
alcutter
2013/11/14 16:51:59
I don't really mind either way, I'm happy to chang
| |
34 ItemStore() : next_item_id_(1) { | |
35 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
36 RegisterForNotification(); | |
37 } else { | |
38 BrowserThread::PostTask(BrowserThread::UI, | |
39 FROM_HERE, | |
40 base::Bind(&ItemStore::RegisterForNotification, | |
41 base::Unretained(this))); | |
42 } | |
43 } | |
44 | |
45 virtual ~ItemStore() {} | |
46 | |
47 void RegisterForNotification() { | |
48 // We watch for RenderProcess termination, as this is how we clear | |
49 // items for now. | |
50 // TODO(jcampan): we should be listening to events such as resource cached/ | |
51 // removed from cache, and remove the item when we know it | |
52 // is not used anymore. | |
53 | |
54 registrar_.Add(this, | |
55 NOTIFICATION_RENDERER_PROCESS_TERMINATED, | |
56 NotificationService::AllBrowserContextsAndSources()); | |
57 registrar_.Add(this, | |
58 NOTIFICATION_RENDERER_PROCESS_CLOSED, | |
59 NotificationService::AllBrowserContextsAndSources()); | |
60 } | |
61 | |
62 int Store(T* item, int process_id) { | |
agl
2013/11/14 16:20:37
// Store adds |item| to this collection, associate
alcutter
2013/11/14 16:51:59
Done.
| |
63 DCHECK(item); | |
64 base::AutoLock auto_lock(lock_); | |
65 | |
66 int item_id; | |
67 | |
68 // Do we already know this item? | |
69 typename ReverseItemMap::iterator item_iter = item_to_id_.find(item); | |
70 if (item_iter == item_to_id_.end()) { | |
71 item_id = next_item_id_++; | |
72 // We use 0 as an invalid item_id value. In the unlikely event that | |
73 // next_item_id_ wraps around, we reset it to 1. | |
74 if (next_item_id_ == 0) | |
75 next_item_id_ = 1; | |
76 item->AddRef(); | |
77 id_to_item_[item_id] = item; | |
78 item_to_id_[item] = item_id; | |
79 } else { | |
80 item_id = item_iter->second; | |
81 } | |
82 | |
83 // Let's update process_id_to_item_id_. | |
84 std::pair<IDMap::iterator, IDMap::iterator> process_ids = | |
85 process_id_to_item_id_.equal_range(process_id); | |
86 if (std::find_if(process_ids.first, | |
87 process_ids.second, | |
88 MatchSecond<int>(item_id)) == process_ids.second) { | |
89 process_id_to_item_id_.insert(std::make_pair(process_id, item_id)); | |
90 } | |
91 | |
92 // And item_id_to_process_id_. | |
93 std::pair<IDMap::iterator, IDMap::iterator> item_ids = | |
94 item_id_to_process_id_.equal_range(item_id); | |
95 if (std::find_if(item_ids.first, | |
96 item_ids.second, | |
97 MatchSecond<int>(process_id)) == item_ids.second) { | |
98 item_id_to_process_id_.insert(std::make_pair(item_id, process_id)); | |
99 } | |
100 | |
101 return item_id; | |
102 } | |
103 | |
104 bool Retrieve(int item_id, scoped_refptr<T>* item) { | |
agl
2013/11/14 16:20:37
// Retrieve ...
alcutter
2013/11/14 16:51:59
Done.
| |
105 base::AutoLock auto_lock(lock_); | |
106 | |
107 typename ItemMap::iterator iter = id_to_item_.find(item_id); | |
108 if (iter == id_to_item_.end()) | |
109 return false; | |
110 if (item) | |
111 *item = iter->second; | |
112 return true; | |
113 } | |
114 | |
115 void RemoveInternal(int item_id) { | |
116 typename ItemMap::iterator item_iter = id_to_item_.find(item_id); | |
117 DCHECK(item_iter != id_to_item_.end()); | |
118 | |
119 typename ReverseItemMap::iterator id_iter = | |
120 item_to_id_.find(item_iter->second.get()); | |
121 DCHECK(id_iter != item_to_id_.end()); | |
122 item_to_id_.erase(id_iter); | |
123 | |
124 item_iter->second->Release(); | |
125 id_to_item_.erase(item_iter); | |
126 } | |
127 | |
128 void RemoveForRenderProcessHost(int process_id) { | |
129 base::AutoLock auto_lock(lock_); | |
130 | |
131 // We iterate through all the item ids for that process. | |
132 std::pair<IDMap::iterator, IDMap::iterator> process_ids = | |
133 process_id_to_item_id_.equal_range(process_id); | |
134 for (IDMap::iterator ids_iter = process_ids.first; | |
135 ids_iter != process_ids.second; | |
136 ++ids_iter) { | |
137 int item_id = ids_iter->second; | |
138 // Find all the processes referring to this item id in | |
139 // item_id_to_process_id_, then locate the process being removed within | |
140 // that range. | |
141 std::pair<IDMap::iterator, IDMap::iterator> item_ids = | |
142 item_id_to_process_id_.equal_range(item_id); | |
143 IDMap::iterator proc_iter = std::find_if( | |
144 item_ids.first, item_ids.second, MatchSecond<int>(process_id)); | |
145 DCHECK(proc_iter != item_ids.second); | |
146 | |
147 // Before removing, determine if no other processes refer to the current | |
148 // item id. If |proc_iter| (the current process) is the lower bound of | |
149 // processes containing the current item id and if |next_proc_iter| is the | |
150 // upper bound (the first process that does not), then only one process, | |
151 // the one being removed, refers to the item id. | |
152 IDMap::iterator next_proc_iter = proc_iter; | |
153 ++next_proc_iter; | |
154 bool last_process_for_item_id = | |
155 (proc_iter == item_ids.first && next_proc_iter == item_ids.second); | |
156 item_id_to_process_id_.erase(proc_iter); | |
157 | |
158 if (last_process_for_item_id) { | |
159 // The current item id is not referenced by any other processes, so | |
160 // remove it from id_to_item_ and item_to_id_. | |
161 RemoveInternal(item_id); | |
162 } | |
163 } | |
164 if (process_ids.first != process_ids.second) | |
165 process_id_to_item_id_.erase(process_ids.first, process_ids.second); | |
166 } | |
167 | |
168 void Observe(int type, | |
169 const NotificationSource& source, | |
170 const NotificationDetails& details) { | |
171 DCHECK(type == NOTIFICATION_RENDERER_PROCESS_TERMINATED || | |
172 type == NOTIFICATION_RENDERER_PROCESS_CLOSED); | |
173 RenderProcessHost* rph = Source<RenderProcessHost>(source).ptr(); | |
174 DCHECK(rph); | |
175 RemoveForRenderProcessHost(rph->GetID()); | |
176 } | |
177 | |
178 protected: | |
179 typedef std::multimap<int, int> IDMap; | |
180 typedef std::map<int, scoped_refptr<T> > ItemMap; | |
181 typedef std::map<T*, int, typename T::LessThan> ReverseItemMap; | |
182 | |
183 // Is only used on the UI Thread. | |
184 NotificationRegistrar registrar_; | |
185 | |
186 IDMap process_id_to_item_id_; | |
187 IDMap item_id_to_process_id_; | |
188 ItemMap id_to_item_; | |
189 ReverseItemMap item_to_id_; | |
190 | |
191 int next_item_id_; | |
192 | |
193 // This lock protects: process_to_item_id_, item_id_to_process_id_, | |
194 // id_to_item_, and item_to_id_. | |
195 base::Lock lock_; | |
196 }; | |
197 | |
198 } // namespace content | |
OLD | NEW |