Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
|
agl
2013/11/14 16:20:37
2013
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> | |
| 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 { | |
| 33 protected: | |
| 34 | |
| 35 ItemStore() : next_item_id_(1) { | |
|
agl
2013/11/14 16:20:37
this should be indented two spaces and then the bo
alcutter
2013/11/14 16:51:59
I think this should've already been done with the
| |
| 36 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
| 37 RegisterForNotification(); | |
| 38 } else { | |
| 39 BrowserThread::PostTask( | |
| 40 BrowserThread::UI, FROM_HERE, | |
| 41 base::Bind(&ItemStore::RegisterForNotification, | |
| 42 base::Unretained(this))); | |
| 43 } | |
| 44 } | |
| 45 | |
| 46 virtual ~ItemStore() { | |
| 47 } | |
| 48 | |
| 49 void RegisterForNotification() { | |
| 50 // We watch for RenderProcess termination, as this is how we clear | |
| 51 // items for now. | |
| 52 // TODO(jcampan): we should be listening to events such as resource cached/ | |
| 53 // removed from cache, and remove the item when we know it | |
| 54 // is not used anymore. | |
| 55 | |
| 56 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED, | |
| 57 NotificationService::AllBrowserContextsAndSources()); | |
| 58 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED, | |
| 59 NotificationService::AllBrowserContextsAndSources()); | |
| 60 } | |
| 61 | |
| 62 int Store(T* item, int process_id) { | |
| 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, process_ids.second, | |
| 87 MatchSecond<int>(item_id)) == process_ids.second) { | |
| 88 process_id_to_item_id_.insert(std::make_pair(process_id, item_id)); | |
| 89 } | |
| 90 | |
| 91 // And item_id_to_process_id_. | |
| 92 std::pair<IDMap::iterator, IDMap::iterator> item_ids = | |
| 93 item_id_to_process_id_.equal_range(item_id); | |
| 94 if (std::find_if(item_ids.first, item_ids.second, | |
| 95 MatchSecond<int>(process_id)) == item_ids.second) { | |
| 96 item_id_to_process_id_.insert(std::make_pair(item_id, process_id)); | |
| 97 } | |
| 98 | |
| 99 return item_id; | |
| 100 } | |
| 101 | |
| 102 bool Retrieve(int item_id, scoped_refptr<T>* item) { | |
| 103 base::AutoLock auto_lock(lock_); | |
| 104 | |
| 105 typename ItemMap::iterator iter = id_to_item_.find(item_id); | |
| 106 if (iter == id_to_item_.end()) | |
| 107 return false; | |
| 108 if (item) | |
| 109 *item = iter->second; | |
| 110 return true; | |
| 111 } | |
| 112 | |
| 113 void RemoveInternal(int item_id) { | |
| 114 typename ItemMap::iterator item_iter = id_to_item_.find(item_id); | |
| 115 DCHECK(item_iter != id_to_item_.end()); | |
| 116 | |
| 117 typename ReverseItemMap::iterator id_iter = | |
| 118 item_to_id_.find(item_iter->second.get()); | |
| 119 DCHECK(id_iter != item_to_id_.end()); | |
| 120 item_to_id_.erase(id_iter); | |
| 121 | |
| 122 item_iter->second->Release(); | |
| 123 id_to_item_.erase(item_iter); | |
| 124 } | |
| 125 | |
| 126 void RemoveForRenderProcessHost(int process_id) { | |
| 127 base::AutoLock auto_lock(lock_); | |
| 128 | |
| 129 // We iterate through all the item ids for that process. | |
| 130 std::pair<IDMap::iterator, IDMap::iterator> process_ids = | |
| 131 process_id_to_item_id_.equal_range(process_id); | |
| 132 for (IDMap::iterator ids_iter = process_ids.first; | |
| 133 ids_iter != process_ids.second; ++ids_iter) { | |
| 134 int item_id = ids_iter->second; | |
| 135 // Find all the processes referring to this item id in | |
| 136 // item_id_to_process_id_, then locate the process being removed within | |
| 137 // that range. | |
| 138 std::pair<IDMap::iterator, IDMap::iterator> item_ids = | |
| 139 item_id_to_process_id_.equal_range(item_id); | |
| 140 IDMap::iterator proc_iter = | |
| 141 std::find_if(item_ids.first, item_ids.second, | |
| 142 MatchSecond<int>(process_id)); | |
| 143 DCHECK(proc_iter != item_ids.second); | |
| 144 | |
| 145 // Before removing, determine if no other processes refer to the current | |
| 146 // item id. If |proc_iter| (the current process) is the lower bound of | |
| 147 // processes containing the current item id and if |next_proc_iter| is the | |
| 148 // upper bound (the first process that does not), then only one process, | |
| 149 // the one being removed, refers to the item id. | |
| 150 IDMap::iterator next_proc_iter = proc_iter; | |
| 151 ++next_proc_iter; | |
| 152 bool last_process_for_item_id = | |
| 153 (proc_iter == item_ids.first && next_proc_iter == item_ids.second); | |
| 154 item_id_to_process_id_.erase(proc_iter); | |
| 155 | |
| 156 if (last_process_for_item_id) { | |
| 157 // The current item id is not referenced by any other processes, so | |
| 158 // remove it from id_to_item_ and item_to_id_. | |
| 159 RemoveInternal(item_id); | |
| 160 } | |
| 161 } | |
| 162 if (process_ids.first != process_ids.second) | |
| 163 process_id_to_item_id_.erase(process_ids.first, process_ids.second); | |
| 164 } | |
| 165 | |
| 166 void Observe(int type, | |
| 167 const NotificationSource& source, | |
| 168 const NotificationDetails& details) { | |
| 169 DCHECK(type == NOTIFICATION_RENDERER_PROCESS_TERMINATED || | |
| 170 type == NOTIFICATION_RENDERER_PROCESS_CLOSED); | |
| 171 RenderProcessHost* rph = Source<RenderProcessHost>(source).ptr(); | |
| 172 DCHECK(rph); | |
| 173 RemoveForRenderProcessHost(rph->GetID()); | |
| 174 } | |
| 175 | |
| 176 protected: | |
| 177 typedef std::multimap<int, int> IDMap; | |
| 178 typedef std::map<int, scoped_refptr<T> > ItemMap; | |
| 179 typedef std::map<T*, int, typename T::LessThan> ReverseItemMap; | |
| 180 | |
| 181 // Is only used on the UI Thread. | |
| 182 NotificationRegistrar registrar_; | |
| 183 | |
| 184 IDMap process_id_to_item_id_; | |
| 185 IDMap item_id_to_process_id_; | |
| 186 ItemMap id_to_item_; | |
| 187 ReverseItemMap item_to_id_; | |
| 188 | |
| 189 int next_item_id_; | |
| 190 | |
| 191 // This lock protects: process_to_item_id_, item_id_to_process_id_, | |
| 192 // id_to_item_, and item_to_id_. | |
| 193 base::Lock lock_; | |
| 194 }; | |
| 195 | |
| 196 } // namespace content | |
| OLD | NEW |