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
3 // found in the LICENSE file.
5 #include "content/browser/shared_worker/shared_worker_service_impl.h"
12 #include "base/callback.h"
13 #include "base/memory/ref_counted.h"
14 #include "content/browser/devtools/embedded_worker_devtools_manager.h"
15 #include "content/browser/renderer_host/render_process_host_impl.h"
16 #include "content/browser/shared_worker/shared_worker_host.h"
17 #include "content/browser/shared_worker/shared_worker_instance.h"
18 #include "content/browser/shared_worker/shared_worker_message_filter.h"
19 #include "content/browser/shared_worker/worker_document_set.h"
20 #include "content/common/view_messages.h"
21 #include "content/common/worker_messages.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/worker_service_observer.h"
27 WorkerService
* WorkerService::GetInstance() {
28 return SharedWorkerServiceImpl::GetInstance();
33 class ScopedWorkerDependencyChecker
{
35 explicit ScopedWorkerDependencyChecker(SharedWorkerServiceImpl
* service
)
36 : service_(service
) {}
37 ScopedWorkerDependencyChecker(SharedWorkerServiceImpl
* service
,
38 base::Closure done_closure
)
39 : service_(service
), done_closure_(done_closure
) {}
40 ~ScopedWorkerDependencyChecker() {
41 service_
->CheckWorkerDependency();
42 if (!done_closure_
.is_null())
47 SharedWorkerServiceImpl
* service_
;
48 base::Closure done_closure_
;
49 DISALLOW_COPY_AND_ASSIGN(ScopedWorkerDependencyChecker
);
52 void UpdateWorkerDependencyOnUI(const std::vector
<int>& added_ids
,
53 const std::vector
<int>& removed_ids
) {
54 for (size_t i
= 0; i
< added_ids
.size(); ++i
) {
55 RenderProcessHostImpl
* render_process_host_impl
=
56 static_cast<RenderProcessHostImpl
*>(
57 RenderProcessHost::FromID(added_ids
[i
]));
58 if (!render_process_host_impl
)
60 render_process_host_impl
->IncrementWorkerRefCount();
62 for (size_t i
= 0; i
< removed_ids
.size(); ++i
) {
63 RenderProcessHostImpl
* render_process_host_impl
=
64 static_cast<RenderProcessHostImpl
*>(
65 RenderProcessHost::FromID(removed_ids
[i
]));
66 if (!render_process_host_impl
)
68 render_process_host_impl
->DecrementWorkerRefCount();
72 void UpdateWorkerDependency(const std::vector
<int>& added_ids
,
73 const std::vector
<int>& removed_ids
) {
74 BrowserThread::PostTask(
77 base::Bind(&UpdateWorkerDependencyOnUI
, added_ids
, removed_ids
));
80 void DecrementWorkerRefCount(int process_id
) {
81 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
82 BrowserThread::PostTask(BrowserThread::UI
,
84 base::Bind(&DecrementWorkerRefCount
, process_id
));
87 RenderProcessHostImpl
* render_process_host_impl
=
88 static_cast<RenderProcessHostImpl
*>(
89 RenderProcessHost::FromID(process_id
));
90 if (render_process_host_impl
)
91 render_process_host_impl
->DecrementWorkerRefCount();
94 bool TryIncrementWorkerRefCount(int worker_process_id
) {
95 RenderProcessHostImpl
* render_process
= static_cast<RenderProcessHostImpl
*>(
96 RenderProcessHost::FromID(worker_process_id
));
97 if (!render_process
|| render_process
->FastShutdownStarted()) {
100 render_process
->IncrementWorkerRefCount();
106 class SharedWorkerServiceImpl::SharedWorkerPendingInstance
{
108 struct SharedWorkerPendingRequest
{
109 SharedWorkerPendingRequest(SharedWorkerMessageFilter
* filter
,
111 unsigned long long document_id
,
112 int render_process_id
,
113 int render_frame_route_id
)
116 document_id(document_id
),
117 render_process_id(render_process_id
),
118 render_frame_route_id(render_frame_route_id
) {}
119 SharedWorkerMessageFilter
* const filter
;
121 const unsigned long long document_id
;
122 const int render_process_id
;
123 const int render_frame_route_id
;
126 typedef ScopedVector
<SharedWorkerPendingRequest
> SharedWorkerPendingRequests
;
128 explicit SharedWorkerPendingInstance(
129 scoped_ptr
<SharedWorkerInstance
> instance
)
130 : instance_(instance
.Pass()) {}
131 ~SharedWorkerPendingInstance() {}
132 SharedWorkerInstance
* instance() { return instance_
.get(); }
133 SharedWorkerInstance
* release_instance() { return instance_
.release(); }
134 SharedWorkerPendingRequests
* requests() { return &requests_
; }
135 SharedWorkerMessageFilter
* FindFilter(int process_id
) {
136 for (size_t i
= 0; i
< requests_
.size(); ++i
) {
137 if (requests_
[i
]->render_process_id
== process_id
)
138 return requests_
[i
]->filter
;
142 void AddRequest(scoped_ptr
<SharedWorkerPendingRequest
> request_info
) {
143 requests_
.push_back(request_info
.release());
145 void RemoveRequest(int process_id
) {
146 for (SharedWorkerPendingRequests::iterator request_itr
= requests_
.begin();
147 request_itr
!= requests_
.end();) {
148 if ((*request_itr
)->render_process_id
== process_id
)
149 request_itr
= requests_
.erase(request_itr
);
154 void RegisterToSharedWorkerHost(SharedWorkerHost
* host
) {
155 for (size_t i
= 0; i
< requests_
.size(); ++i
) {
156 SharedWorkerPendingRequest
* request
= requests_
[i
];
157 host
->AddFilter(request
->filter
, request
->route_id
);
158 host
->worker_document_set()->Add(request
->filter
,
159 request
->document_id
,
160 request
->render_process_id
,
161 request
->render_frame_route_id
);
164 void SendWorkerCreatedMessages() {
165 for (size_t i
= 0; i
< requests_
.size(); ++i
) {
166 SharedWorkerPendingRequest
* request
= requests_
[i
];
167 request
->filter
->Send(new ViewMsg_WorkerCreated(request
->route_id
));
172 scoped_ptr
<SharedWorkerInstance
> instance_
;
173 SharedWorkerPendingRequests requests_
;
174 DISALLOW_COPY_AND_ASSIGN(SharedWorkerPendingInstance
);
177 class SharedWorkerServiceImpl::SharedWorkerReserver
178 : public base::RefCountedThreadSafe
<SharedWorkerReserver
> {
180 SharedWorkerReserver(int pending_instance_id
,
181 int worker_process_id
,
184 const SharedWorkerInstance
& instance
)
185 : worker_process_id_(worker_process_id
),
186 worker_route_id_(worker_route_id
),
187 is_new_worker_(is_new_worker
),
188 instance_(instance
) {}
190 void TryReserve(const base::Callback
<void(bool)>& success_cb
,
191 const base::Closure
& failure_cb
,
192 bool (*try_increment_worker_ref_count
)(int)) {
193 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
194 if (!try_increment_worker_ref_count(worker_process_id_
)) {
195 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
, failure_cb
);
198 bool pause_on_start
= false;
199 if (is_new_worker_
) {
201 EmbeddedWorkerDevToolsManager::GetInstance()->SharedWorkerCreated(
202 worker_process_id_
, worker_route_id_
, instance_
);
204 BrowserThread::PostTask(
205 BrowserThread::IO
, FROM_HERE
, base::Bind(success_cb
, pause_on_start
));
209 friend class base::RefCountedThreadSafe
<SharedWorkerReserver
>;
210 ~SharedWorkerReserver() {}
212 const int worker_process_id_
;
213 const int worker_route_id_
;
214 const bool is_new_worker_
;
215 const SharedWorkerInstance instance_
;
219 bool (*SharedWorkerServiceImpl::s_try_increment_worker_ref_count_
)(int) =
220 TryIncrementWorkerRefCount
;
222 SharedWorkerServiceImpl
* SharedWorkerServiceImpl::GetInstance() {
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
224 return Singleton
<SharedWorkerServiceImpl
>::get();
227 SharedWorkerServiceImpl::SharedWorkerServiceImpl()
228 : update_worker_dependency_(UpdateWorkerDependency
),
229 next_pending_instance_id_(0) {
232 SharedWorkerServiceImpl::~SharedWorkerServiceImpl() {}
234 void SharedWorkerServiceImpl::ResetForTesting() {
235 last_worker_depended_renderers_
.clear();
236 worker_hosts_
.clear();
238 update_worker_dependency_
= UpdateWorkerDependency
;
239 s_try_increment_worker_ref_count_
= TryIncrementWorkerRefCount
;
242 bool SharedWorkerServiceImpl::TerminateWorker(int process_id
, int route_id
) {
243 SharedWorkerHost
* host
=
244 worker_hosts_
.get(std::make_pair(process_id
, route_id
));
245 if (!host
|| !host
->instance())
247 host
->TerminateWorker();
251 std::vector
<WorkerService::WorkerInfo
> SharedWorkerServiceImpl::GetWorkers() {
252 std::vector
<WorkerService::WorkerInfo
> results
;
253 for (WorkerHostMap::const_iterator iter
= worker_hosts_
.begin();
254 iter
!= worker_hosts_
.end();
256 SharedWorkerHost
* host
= iter
->second
;
257 const SharedWorkerInstance
* instance
= host
->instance();
259 WorkerService::WorkerInfo info
;
260 info
.url
= instance
->url();
261 info
.name
= instance
->name();
262 info
.route_id
= host
->worker_route_id();
263 info
.process_id
= host
->process_id();
264 info
.handle
= host
->container_render_filter()->PeerHandle();
265 results
.push_back(info
);
271 void SharedWorkerServiceImpl::AddObserver(WorkerServiceObserver
* observer
) {
272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
273 observers_
.AddObserver(observer
);
276 void SharedWorkerServiceImpl::RemoveObserver(WorkerServiceObserver
* observer
) {
277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
278 observers_
.RemoveObserver(observer
);
281 void SharedWorkerServiceImpl::CreateWorker(
282 const ViewHostMsg_CreateWorker_Params
& params
,
284 SharedWorkerMessageFilter
* filter
,
285 ResourceContext
* resource_context
,
286 const WorkerStoragePartitionId
& partition_id
,
287 bool* url_mismatch
) {
288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
289 *url_mismatch
= false;
290 scoped_ptr
<SharedWorkerInstance
> instance(
291 new SharedWorkerInstance(params
.url
,
293 params
.content_security_policy
,
294 params
.security_policy_type
,
297 scoped_ptr
<SharedWorkerPendingInstance::SharedWorkerPendingRequest
> request(
298 new SharedWorkerPendingInstance::SharedWorkerPendingRequest(
302 filter
->render_process_id(),
303 params
.render_frame_route_id
));
304 if (SharedWorkerPendingInstance
* pending
= FindPendingInstance(*instance
)) {
305 if (params
.url
!= pending
->instance()->url()) {
306 *url_mismatch
= true;
309 pending
->AddRequest(request
.Pass());
312 scoped_ptr
<SharedWorkerPendingInstance
> pending_instance(
313 new SharedWorkerPendingInstance(instance
.Pass()));
314 pending_instance
->AddRequest(request
.Pass());
315 ReserveRenderProcessToCreateWorker(pending_instance
.Pass(), url_mismatch
);
318 void SharedWorkerServiceImpl::ForwardToWorker(
319 const IPC::Message
& message
,
320 SharedWorkerMessageFilter
* filter
) {
321 for (WorkerHostMap::const_iterator iter
= worker_hosts_
.begin();
322 iter
!= worker_hosts_
.end();
324 if (iter
->second
->FilterMessage(message
, filter
))
329 void SharedWorkerServiceImpl::DocumentDetached(
330 unsigned long long document_id
,
331 SharedWorkerMessageFilter
* filter
) {
332 ScopedWorkerDependencyChecker
checker(this);
333 for (WorkerHostMap::const_iterator iter
= worker_hosts_
.begin();
334 iter
!= worker_hosts_
.end();
336 iter
->second
->DocumentDetached(filter
, document_id
);
340 void SharedWorkerServiceImpl::WorkerContextClosed(
342 SharedWorkerMessageFilter
* filter
) {
343 ScopedWorkerDependencyChecker
checker(this);
344 if (SharedWorkerHost
* host
= FindSharedWorkerHost(filter
, worker_route_id
))
345 host
->WorkerContextClosed();
348 void SharedWorkerServiceImpl::WorkerContextDestroyed(
350 SharedWorkerMessageFilter
* filter
) {
351 ScopedWorkerDependencyChecker
checker(this);
352 scoped_ptr
<SharedWorkerHost
> host
=
353 worker_hosts_
.take_and_erase(std::make_pair(filter
->render_process_id(),
357 host
->WorkerContextDestroyed();
360 void SharedWorkerServiceImpl::WorkerReadyForInspection(
362 SharedWorkerMessageFilter
* filter
) {
363 if (SharedWorkerHost
* host
= FindSharedWorkerHost(filter
, worker_route_id
))
364 host
->WorkerReadyForInspection();
367 void SharedWorkerServiceImpl::WorkerScriptLoaded(
369 SharedWorkerMessageFilter
* filter
) {
370 if (SharedWorkerHost
* host
= FindSharedWorkerHost(filter
, worker_route_id
))
371 host
->WorkerScriptLoaded();
374 void SharedWorkerServiceImpl::WorkerScriptLoadFailed(
376 SharedWorkerMessageFilter
* filter
) {
377 ScopedWorkerDependencyChecker
checker(this);
378 scoped_ptr
<SharedWorkerHost
> host
=
379 worker_hosts_
.take_and_erase(std::make_pair(filter
->render_process_id(),
383 host
->WorkerScriptLoadFailed();
386 void SharedWorkerServiceImpl::WorkerConnected(
389 SharedWorkerMessageFilter
* filter
) {
390 if (SharedWorkerHost
* host
= FindSharedWorkerHost(filter
, worker_route_id
))
391 host
->WorkerConnected(message_port_id
);
394 void SharedWorkerServiceImpl::AllowDatabase(
397 const base::string16
& name
,
398 const base::string16
& display_name
,
399 unsigned long estimated_size
,
401 SharedWorkerMessageFilter
* filter
) {
402 if (SharedWorkerHost
* host
= FindSharedWorkerHost(filter
, worker_route_id
))
403 host
->AllowDatabase(url
, name
, display_name
, estimated_size
, result
);
406 void SharedWorkerServiceImpl::AllowFileSystem(
409 IPC::Message
* reply_msg
,
410 SharedWorkerMessageFilter
* filter
) {
411 if (SharedWorkerHost
* host
= FindSharedWorkerHost(filter
, worker_route_id
)) {
412 host
->AllowFileSystem(url
, make_scoped_ptr(reply_msg
));
414 filter
->Send(reply_msg
);
419 void SharedWorkerServiceImpl::AllowIndexedDB(
422 const base::string16
& name
,
424 SharedWorkerMessageFilter
* filter
) {
425 if (SharedWorkerHost
* host
= FindSharedWorkerHost(filter
, worker_route_id
))
426 host
->AllowIndexedDB(url
, name
, result
);
429 void SharedWorkerServiceImpl::OnSharedWorkerMessageFilterClosing(
430 SharedWorkerMessageFilter
* filter
) {
431 ScopedWorkerDependencyChecker
checker(this);
432 std::vector
<ProcessRouteIdPair
> remove_list
;
433 for (WorkerHostMap::iterator iter
= worker_hosts_
.begin();
434 iter
!= worker_hosts_
.end();
436 iter
->second
->FilterShutdown(filter
);
437 if (iter
->first
.first
== filter
->render_process_id())
438 remove_list
.push_back(iter
->first
);
440 for (size_t i
= 0; i
< remove_list
.size(); ++i
) {
441 scoped_ptr
<SharedWorkerHost
> host
=
442 worker_hosts_
.take_and_erase(remove_list
[i
]);
445 std::vector
<int> remove_pending_instance_list
;
446 for (PendingInstaneMap::iterator iter
= pending_instances_
.begin();
447 iter
!= pending_instances_
.end();
449 iter
->second
->RemoveRequest(filter
->render_process_id());
450 if (!iter
->second
->requests()->size())
451 remove_pending_instance_list
.push_back(iter
->first
);
453 for (size_t i
= 0; i
< remove_pending_instance_list
.size(); ++i
)
454 pending_instances_
.take_and_erase(remove_pending_instance_list
[i
]);
457 void SharedWorkerServiceImpl::NotifyWorkerDestroyed(int worker_process_id
,
458 int worker_route_id
) {
459 FOR_EACH_OBSERVER(WorkerServiceObserver
,
461 WorkerDestroyed(worker_process_id
, worker_route_id
));
464 void SharedWorkerServiceImpl::ReserveRenderProcessToCreateWorker(
465 scoped_ptr
<SharedWorkerPendingInstance
> pending_instance
,
466 bool* url_mismatch
) {
467 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
468 DCHECK(!FindPendingInstance(*pending_instance
->instance()));
470 *url_mismatch
= false;
471 if (!pending_instance
->requests()->size())
473 int worker_process_id
= -1;
474 int worker_route_id
= MSG_ROUTING_NONE
;
475 bool is_new_worker
= true;
476 SharedWorkerHost
* host
= FindSharedWorkerHost(*pending_instance
->instance());
478 if (pending_instance
->instance()->url() != host
->instance()->url()) {
480 *url_mismatch
= true;
483 worker_process_id
= host
->process_id();
484 worker_route_id
= host
->worker_route_id();
485 is_new_worker
= false;
487 SharedWorkerMessageFilter
* first_filter
=
488 (*pending_instance
->requests()->begin())->filter
;
489 worker_process_id
= first_filter
->render_process_id();
490 worker_route_id
= first_filter
->GetNextRoutingID();
492 const int pending_instance_id
= next_pending_instance_id_
++;
493 scoped_refptr
<SharedWorkerReserver
> reserver(
494 new SharedWorkerReserver(pending_instance_id
,
498 *pending_instance
->instance()));
499 BrowserThread::PostTask(
503 &SharedWorkerReserver::TryReserve
,
505 base::Bind(&SharedWorkerServiceImpl::RenderProcessReservedCallback
,
506 base::Unretained(this),
512 &SharedWorkerServiceImpl::RenderProcessReserveFailedCallback
,
513 base::Unretained(this),
518 s_try_increment_worker_ref_count_
));
519 pending_instances_
.set(pending_instance_id
, pending_instance
.Pass());
522 void SharedWorkerServiceImpl::RenderProcessReservedCallback(
523 int pending_instance_id
,
524 int worker_process_id
,
527 bool pause_on_start
) {
528 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
529 // To offset the TryIncrementWorkerRefCount called for the reservation,
530 // calls DecrementWorkerRefCount after CheckWorkerDependency in
531 // ScopeWorkerDependencyChecker's destructor.
532 ScopedWorkerDependencyChecker
checker(
533 this, base::Bind(&DecrementWorkerRefCount
, worker_process_id
));
534 scoped_ptr
<SharedWorkerPendingInstance
> pending_instance
=
535 pending_instances_
.take_and_erase(pending_instance_id
);
536 if (!pending_instance
)
538 if (!is_new_worker
) {
539 SharedWorkerHost
* existing_host
=
540 worker_hosts_
.get(std::make_pair(worker_process_id
, worker_route_id
));
541 if (!existing_host
) {
542 // Retry reserving a renderer process if the existed Shared Worker was
543 // destroyed on IO thread while reserving the renderer process on UI
545 ReserveRenderProcessToCreateWorker(pending_instance
.Pass(), NULL
);
548 pending_instance
->RegisterToSharedWorkerHost(existing_host
);
549 pending_instance
->SendWorkerCreatedMessages();
552 SharedWorkerMessageFilter
* filter
=
553 pending_instance
->FindFilter(worker_process_id
);
555 pending_instance
->RemoveRequest(worker_process_id
);
556 // Retry reserving a renderer process if the requested renderer process was
557 // destroyed on IO thread while reserving the renderer process on UI thread.
558 ReserveRenderProcessToCreateWorker(pending_instance
.Pass(), NULL
);
561 scoped_ptr
<SharedWorkerHost
> host(new SharedWorkerHost(
562 pending_instance
->release_instance(), filter
, worker_route_id
));
563 pending_instance
->RegisterToSharedWorkerHost(host
.get());
564 const GURL url
= host
->instance()->url();
565 const base::string16 name
= host
->instance()->name();
566 host
->Start(pause_on_start
);
567 worker_hosts_
.set(std::make_pair(worker_process_id
, worker_route_id
),
570 WorkerServiceObserver
,
572 WorkerCreated(url
, name
, worker_process_id
, worker_route_id
));
575 void SharedWorkerServiceImpl::RenderProcessReserveFailedCallback(
576 int pending_instance_id
,
577 int worker_process_id
,
579 bool is_new_worker
) {
580 worker_hosts_
.take_and_erase(
581 std::make_pair(worker_process_id
, worker_route_id
));
582 scoped_ptr
<SharedWorkerPendingInstance
> pending_instance
=
583 pending_instances_
.take_and_erase(pending_instance_id
);
584 if (!pending_instance
)
586 pending_instance
->RemoveRequest(worker_process_id
);
587 // Retry reserving a renderer process.
588 ReserveRenderProcessToCreateWorker(pending_instance
.Pass(), NULL
);
591 SharedWorkerHost
* SharedWorkerServiceImpl::FindSharedWorkerHost(
592 SharedWorkerMessageFilter
* filter
,
593 int worker_route_id
) {
594 return worker_hosts_
.get(std::make_pair(filter
->render_process_id(),
598 SharedWorkerHost
* SharedWorkerServiceImpl::FindSharedWorkerHost(
599 const SharedWorkerInstance
& instance
) {
600 for (WorkerHostMap::const_iterator iter
= worker_hosts_
.begin();
601 iter
!= worker_hosts_
.end();
603 SharedWorkerHost
* host
= iter
->second
;
604 if (host
->instance() && !host
->closed() &&
605 host
->instance()->Matches(instance
)) {
612 SharedWorkerServiceImpl::SharedWorkerPendingInstance
*
613 SharedWorkerServiceImpl::FindPendingInstance(
614 const SharedWorkerInstance
& instance
) {
615 for (PendingInstaneMap::iterator iter
= pending_instances_
.begin();
616 iter
!= pending_instances_
.end();
618 if (iter
->second
->instance()->Matches(instance
))
625 SharedWorkerServiceImpl::GetRenderersWithWorkerDependency() {
626 std::set
<int> dependent_renderers
;
627 for (WorkerHostMap::iterator host_iter
= worker_hosts_
.begin();
628 host_iter
!= worker_hosts_
.end();
630 const int process_id
= host_iter
->first
.first
;
631 if (dependent_renderers
.count(process_id
))
633 if (host_iter
->second
->instance() &&
634 host_iter
->second
->worker_document_set()->ContainsExternalRenderer(
636 dependent_renderers
.insert(process_id
);
639 return dependent_renderers
;
642 void SharedWorkerServiceImpl::CheckWorkerDependency() {
643 const std::set
<int> current_worker_depended_renderers
=
644 GetRenderersWithWorkerDependency();
645 std::vector
<int> added_items
= base::STLSetDifference
<std::vector
<int> >(
646 current_worker_depended_renderers
, last_worker_depended_renderers_
);
647 std::vector
<int> removed_items
= base::STLSetDifference
<std::vector
<int> >(
648 last_worker_depended_renderers_
, current_worker_depended_renderers
);
649 if (!added_items
.empty() || !removed_items
.empty()) {
650 last_worker_depended_renderers_
= current_worker_depended_renderers
;
651 update_worker_dependency_(added_items
, removed_items
);
655 void SharedWorkerServiceImpl::ChangeUpdateWorkerDependencyFuncForTesting(
656 UpdateWorkerDependencyFunc new_func
) {
657 update_worker_dependency_
= new_func
;
660 void SharedWorkerServiceImpl::ChangeTryIncrementWorkerRefCountFuncForTesting(
661 bool (*new_func
)(int)) {
662 s_try_increment_worker_ref_count_
= new_func
;
665 } // namespace content