OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "content/browser/service_worker/service_worker_process_manager.h" | 5 #include "content/browser/service_worker/service_worker_process_manager.h" |
6 | 6 |
7 #include "content/browser/renderer_host/render_process_host_impl.h" | 7 #include "content/browser/renderer_host/render_process_host_impl.h" |
8 #include "content/browser/service_worker/service_worker_context_wrapper.h" | 8 #include "content/browser/service_worker/service_worker_context_wrapper.h" |
9 #include "content/public/browser/browser_thread.h" | 9 #include "content/public/browser/browser_thread.h" |
10 #include "content/public/browser/site_instance.h" | 10 #include "content/public/browser/site_instance.h" |
11 #include "url/gurl.h" | 11 #include "url/gurl.h" |
12 | 12 |
13 namespace content { | 13 namespace content { |
14 | 14 |
15 namespace { | |
16 | |
17 // Functor to sort by the .second element of a struct. | |
18 struct SecondGreater { | |
19 template <typename Value> | |
20 bool operator()(const Value& lhs, const Value& rhs) { | |
21 return lhs.second > rhs.second; | |
22 } | |
23 }; | |
24 | |
25 } // namespace | |
26 | |
15 static bool IncrementWorkerRefCountByPid(int process_id) { | 27 static bool IncrementWorkerRefCountByPid(int process_id) { |
16 RenderProcessHost* rph = RenderProcessHost::FromID(process_id); | 28 RenderProcessHost* rph = RenderProcessHost::FromID(process_id); |
17 if (!rph || rph->FastShutdownStarted()) | 29 if (!rph || rph->FastShutdownStarted()) |
18 return false; | 30 return false; |
19 | 31 |
20 static_cast<RenderProcessHostImpl*>(rph)->IncrementWorkerRefCount(); | 32 static_cast<RenderProcessHostImpl*>(rph)->IncrementWorkerRefCount(); |
21 return true; | 33 return true; |
22 } | 34 } |
23 | 35 |
24 ServiceWorkerProcessManager::ProcessInfo::ProcessInfo( | 36 ServiceWorkerProcessManager::ProcessInfo::ProcessInfo( |
(...skipping 29 matching lines...) Expand all Loading... | |
54 for (std::map<int, ProcessInfo>::const_iterator it = instance_info_.begin(); | 66 for (std::map<int, ProcessInfo>::const_iterator it = instance_info_.begin(); |
55 it != instance_info_.end(); | 67 it != instance_info_.end(); |
56 ++it) { | 68 ++it) { |
57 RenderProcessHost* rph = RenderProcessHost::FromID(it->second.process_id); | 69 RenderProcessHost* rph = RenderProcessHost::FromID(it->second.process_id); |
58 DCHECK(rph); | 70 DCHECK(rph); |
59 static_cast<RenderProcessHostImpl*>(rph)->DecrementWorkerRefCount(); | 71 static_cast<RenderProcessHostImpl*>(rph)->DecrementWorkerRefCount(); |
60 } | 72 } |
61 instance_info_.clear(); | 73 instance_info_.clear(); |
62 } | 74 } |
63 | 75 |
76 void ServiceWorkerProcessManager::AddScopePendingProcesses( | |
77 const GURL& scope, const std::vector<int>& pending_processes) { | |
kinuko
2014/08/12 15:27:07
Looks like these methods are called only on IO thr
kinuko
2014/08/12 15:42:48
Oops, this comment was irrelevant, please ignore t
| |
78 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
79 BrowserThread::PostTask( | |
80 BrowserThread::UI, | |
81 FROM_HERE, | |
82 base::Bind(&ServiceWorkerProcessManager::AddScopePendingProcesses, | |
83 weak_this_, | |
84 scope, | |
85 pending_processes)); | |
86 return; | |
87 } | |
88 | |
89 ProcessRefMap& process_refs = scope_processes_[scope]; | |
90 for (std::vector<int>::const_iterator it = pending_processes.begin(); | |
91 it != pending_processes.end(); | |
92 ++it) { | |
93 if (process_refs.find(*it) != process_refs.end()) | |
94 continue; | |
95 RenderProcessHost* host = RenderProcessHost::FromID(*it); | |
96 if (!host && *it != process_id_for_test_) | |
97 continue; | |
98 if (host) { | |
99 // FIXME: the pending process maybe contained by multiple scopes, as | |
Jeffrey Yasskin
2014/08/19 23:42:24
s/maybe/may be/
| |
100 // RPH doesn't have "HasObserver" method, let's remove it first. | |
Jeffrey Yasskin
2014/08/19 23:42:24
s/method, let's/method. Let's/
xiang
2014/08/29 07:49:39
this method is removed.
| |
101 host->RemoveObserver(this); | |
102 host->AddObserver(this); | |
103 } | |
104 process_refs.insert(std::make_pair(*it, 0)); | |
105 } | |
106 } | |
107 | |
108 void ServiceWorkerProcessManager::AddScopeProcessReference( | |
109 const GURL& scope, int process_id) { | |
110 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
111 BrowserThread::PostTask( | |
112 BrowserThread::UI, | |
113 FROM_HERE, | |
114 base::Bind(&ServiceWorkerProcessManager::AddScopeProcessReference, | |
115 weak_this_, | |
116 scope, | |
117 process_id)); | |
118 return; | |
119 } | |
120 | |
121 ProcessRefMap& process_refs = scope_processes_[scope]; | |
122 ProcessRefMap::iterator found = process_refs.find(process_id); | |
Jeffrey Yasskin
2014/08/19 23:42:24
You can write these 4 lines as:
++process_refs[pr
xiang
2014/08/29 07:49:39
Done.
| |
123 if (found == process_refs.end()) | |
124 found = process_refs.insert(std::make_pair(process_id, 0)).first; | |
125 ++found->second; | |
126 } | |
127 | |
128 void ServiceWorkerProcessManager::RemoveScopeProcessReference( | |
129 const GURL& scope, int process_id) { | |
130 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
131 BrowserThread::PostTask( | |
132 BrowserThread::UI, | |
133 FROM_HERE, | |
134 base::Bind(&ServiceWorkerProcessManager::RemoveScopeProcessReference, | |
135 weak_this_, | |
136 scope, | |
137 process_id)); | |
138 return; | |
139 } | |
140 | |
141 ScopeProcessRefMap::iterator it = scope_processes_.find(scope); | |
142 if (it == scope_processes_.end()) { | |
143 NOTREACHED() << "Scope process refrences not found: " << scope; | |
144 return; | |
145 } | |
146 ProcessRefMap& process_refs = it->second; | |
147 ProcessRefMap::iterator found = process_refs.find(process_id); | |
148 if (found == process_refs.end()) { | |
149 NOTREACHED() << "Releasing unknown process ref " << process_id; | |
150 return; | |
151 } | |
152 if (--found->second == 0) { | |
Jeffrey Yasskin
2014/08/19 23:42:23
You're not guarding against releasing a pending pr
xiang
2014/08/29 07:49:39
we don't have pending process now.
| |
153 process_refs.erase(found); | |
154 if (process_refs.empty()) | |
155 scope_processes_.erase(it); | |
156 } | |
157 } | |
158 | |
159 bool ServiceWorkerProcessManager::ScopeHasProcessToRun( | |
160 const GURL& scope) const { | |
161 ScopeProcessRefMap::const_iterator it = scope_processes_.find(scope); | |
162 if (it == scope_processes_.end()) | |
163 return false; | |
164 return !it->second.empty(); | |
165 } | |
166 | |
167 void ServiceWorkerProcessManager::RenderProcessHostDestroyed( | |
168 RenderProcessHost* host) { | |
169 ScopeProcessRefMap::iterator it = scope_processes_.begin(); | |
170 while (it != scope_processes_.end()) { | |
171 ProcessRefMap& process_refs = it->second; | |
172 ProcessRefMap::iterator found = process_refs.find(host->GetID()); | |
173 if (found != process_refs.end()) { | |
174 process_refs.erase(found); | |
175 if (process_refs.empty()) { | |
176 scope_processes_.erase(it++); | |
177 continue; | |
178 } | |
179 } | |
180 ++it; | |
181 } | |
182 } | |
183 | |
64 void ServiceWorkerProcessManager::AllocateWorkerProcess( | 184 void ServiceWorkerProcessManager::AllocateWorkerProcess( |
65 int embedded_worker_id, | 185 int embedded_worker_id, |
66 const std::vector<int>& process_ids, | 186 const GURL& scope, |
67 const GURL& script_url, | 187 const GURL& script_url, |
68 const base::Callback<void(ServiceWorkerStatusCode, int process_id)>& | 188 const base::Callback<void(ServiceWorkerStatusCode, int process_id)>& |
69 callback) { | 189 callback) { |
70 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 190 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
71 BrowserThread::PostTask( | 191 BrowserThread::PostTask( |
72 BrowserThread::UI, | 192 BrowserThread::UI, |
73 FROM_HERE, | 193 FROM_HERE, |
74 base::Bind(&ServiceWorkerProcessManager::AllocateWorkerProcess, | 194 base::Bind(&ServiceWorkerProcessManager::AllocateWorkerProcess, |
75 weak_this_, | 195 weak_this_, |
76 embedded_worker_id, | 196 embedded_worker_id, |
77 process_ids, | 197 scope, |
78 script_url, | 198 script_url, |
79 callback)); | 199 callback)); |
80 return; | 200 return; |
81 } | 201 } |
82 | 202 |
83 if (process_id_for_test_ != -1) { | 203 if (process_id_for_test_ != -1) { |
84 // Let tests specify the returned process ID. Note: We may need to be able | 204 // Let tests specify the returned process ID. Note: We may need to be able |
85 // to specify the error code too. | 205 // to specify the error code too. |
86 BrowserThread::PostTask( | 206 BrowserThread::PostTask( |
87 BrowserThread::IO, | 207 BrowserThread::IO, |
88 FROM_HERE, | 208 FROM_HERE, |
89 base::Bind(callback, SERVICE_WORKER_OK, process_id_for_test_)); | 209 base::Bind(callback, SERVICE_WORKER_OK, process_id_for_test_)); |
90 return; | 210 return; |
91 } | 211 } |
92 | 212 |
93 DCHECK(!ContainsKey(instance_info_, embedded_worker_id)) | 213 DCHECK(!ContainsKey(instance_info_, embedded_worker_id)) |
94 << embedded_worker_id << " already has a process allocated"; | 214 << embedded_worker_id << " already has a process allocated"; |
95 | 215 |
96 for (std::vector<int>::const_iterator it = process_ids.begin(); | 216 std::vector<int> sorted_candidates = SortProcessesForScope(scope); |
97 it != process_ids.end(); | 217 if (!sorted_candidates.empty()) { |
Jeffrey Yasskin
2014/08/19 23:42:23
You don't need to check this. If sorted_candidates
xiang
2014/08/29 07:49:39
Done.
| |
98 ++it) { | 218 for (std::vector<int>::const_iterator it = sorted_candidates.begin(); |
99 if (IncrementWorkerRefCountByPid(*it)) { | 219 it != sorted_candidates.end(); |
220 ++it) { | |
221 if (!IncrementWorkerRefCountByPid(*it)) | |
222 continue; | |
100 instance_info_.insert( | 223 instance_info_.insert( |
101 std::make_pair(embedded_worker_id, ProcessInfo(*it))); | 224 std::make_pair(embedded_worker_id, ProcessInfo(*it))); |
102 BrowserThread::PostTask(BrowserThread::IO, | 225 BrowserThread::PostTask(BrowserThread::IO, |
103 FROM_HERE, | 226 FROM_HERE, |
104 base::Bind(callback, SERVICE_WORKER_OK, *it)); | 227 base::Bind(callback, SERVICE_WORKER_OK, *it)); |
105 return; | 228 return; |
106 } | 229 } |
107 } | 230 } |
108 | 231 |
109 if (!browser_context_) { | 232 if (!browser_context_) { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
172 } else { | 295 } else { |
173 rph = RenderProcessHost::FromID(info->second.process_id); | 296 rph = RenderProcessHost::FromID(info->second.process_id); |
174 DCHECK(rph) | 297 DCHECK(rph) |
175 << "Process " << info->second.process_id | 298 << "Process " << info->second.process_id |
176 << " was destroyed unexpectedly. Did we actually hold a reference?"; | 299 << " was destroyed unexpectedly. Did we actually hold a reference?"; |
177 } | 300 } |
178 static_cast<RenderProcessHostImpl*>(rph)->DecrementWorkerRefCount(); | 301 static_cast<RenderProcessHostImpl*>(rph)->DecrementWorkerRefCount(); |
179 instance_info_.erase(info); | 302 instance_info_.erase(info); |
180 } | 303 } |
181 | 304 |
305 std::vector<int> ServiceWorkerProcessManager::SortProcessesForScope( | |
306 const GURL& scope) const { | |
307 ScopeProcessRefMap::const_iterator it = scope_processes_.find(scope); | |
308 if (it == scope_processes_.end()) | |
309 return std::vector<int>(); | |
310 | |
311 std::vector<std::pair<int, int> > counted( | |
312 it->second.begin(), it->second.end()); | |
313 std::sort(counted.begin(), counted.end(), SecondGreater()); | |
314 | |
315 std::vector<int> result(counted.size()); | |
316 for (size_t i = 0; i < counted.size(); ++i) | |
317 result[i] = counted[i].first; | |
318 return result; | |
319 } | |
320 | |
182 } // namespace content | 321 } // namespace content |
183 | 322 |
184 namespace base { | 323 namespace base { |
185 // Destroying ServiceWorkerProcessManagers only on the UI thread allows the | 324 // Destroying ServiceWorkerProcessManagers only on the UI thread allows the |
186 // member WeakPtr to safely guard the object's lifetime when used on that | 325 // member WeakPtr to safely guard the object's lifetime when used on that |
187 // thread. | 326 // thread. |
188 void DefaultDeleter<content::ServiceWorkerProcessManager>::operator()( | 327 void DefaultDeleter<content::ServiceWorkerProcessManager>::operator()( |
189 content::ServiceWorkerProcessManager* ptr) const { | 328 content::ServiceWorkerProcessManager* ptr) const { |
190 content::BrowserThread::DeleteSoon( | 329 content::BrowserThread::DeleteSoon( |
191 content::BrowserThread::UI, FROM_HERE, ptr); | 330 content::BrowserThread::UI, FROM_HERE, ptr); |
192 } | 331 } |
193 } // namespace base | 332 } // namespace base |
OLD | NEW |