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 "content/child/child_thread_impl.h" | 5 #include "content/child/child_thread_impl.h" |
6 | 6 |
7 #include <signal.h> | 7 #include <signal.h> |
8 | 8 |
9 #include <string> | 9 #include <string> |
10 | 10 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
52 #include "content/child/websocket_dispatcher.h" | 52 #include "content/child/websocket_dispatcher.h" |
53 #include "content/common/child_process_messages.h" | 53 #include "content/common/child_process_messages.h" |
54 #include "content/common/in_process_child_thread_params.h" | 54 #include "content/common/in_process_child_thread_params.h" |
55 #include "content/public/common/content_switches.h" | 55 #include "content/public/common/content_switches.h" |
56 #include "ipc/ipc_logging.h" | 56 #include "ipc/ipc_logging.h" |
57 #include "ipc/ipc_switches.h" | 57 #include "ipc/ipc_switches.h" |
58 #include "ipc/ipc_sync_channel.h" | 58 #include "ipc/ipc_sync_channel.h" |
59 #include "ipc/ipc_sync_message_filter.h" | 59 #include "ipc/ipc_sync_message_filter.h" |
60 #include "ipc/mojo/ipc_channel_mojo.h" | 60 #include "ipc/mojo/ipc_channel_mojo.h" |
61 | 61 |
62 #if defined(OS_ANDROID) | |
63 #include "base/thread_task_runner_handle.h" | |
64 #endif | |
65 | |
62 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) | 66 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) |
63 #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" | 67 #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" |
64 #endif | 68 #endif |
65 | 69 |
66 using tracked_objects::ThreadData; | 70 using tracked_objects::ThreadData; |
67 | 71 |
68 namespace content { | 72 namespace content { |
69 namespace { | 73 namespace { |
70 | 74 |
71 // How long to wait for a connection to the browser process before giving up. | 75 // How long to wait for a connection to the browser process before giving up. |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
154 #endif | 158 #endif |
155 } | 159 } |
156 | 160 |
157 protected: | 161 protected: |
158 ~SuicideOnChannelErrorFilter() override {} | 162 ~SuicideOnChannelErrorFilter() override {} |
159 }; | 163 }; |
160 | 164 |
161 #endif // OS(POSIX) | 165 #endif // OS(POSIX) |
162 | 166 |
163 #if defined(OS_ANDROID) | 167 #if defined(OS_ANDROID) |
164 ChildThreadImpl* g_child_thread = NULL; | 168 // A class that allows for triggering a clean shutdown from another |
165 bool g_child_thread_initialized = false; | 169 // thread through draining the main thread's msg loop. |
170 class QuitClosure { | |
171 public: | |
172 QuitClosure(); | |
173 ~QuitClosure(); | |
166 | 174 |
167 // A lock protects g_child_thread. | 175 void BindToMainThread(); |
168 base::LazyInstance<base::Lock>::Leaky g_lazy_child_thread_lock = | 176 void PostQuitFromNonMainThread(); |
169 LAZY_INSTANCE_INITIALIZER; | |
170 | 177 |
171 // base::ConditionVariable has an explicit constructor that takes | 178 private: |
172 // a base::Lock pointer as parameter. The base::DefaultLazyInstanceTraits | 179 static void PostClosure( |
173 // doesn't handle the case. Thus, we need our own class here. | 180 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
174 struct CondVarLazyInstanceTraits { | 181 base::Closure closure); |
175 static const bool kRegisterOnExit = false; | |
176 #ifndef NDEBUG | |
177 static const bool kAllowedToAccessOnNonjoinableThread = true; | |
178 #endif | |
179 | 182 |
180 static base::ConditionVariable* New(void* instance) { | 183 base::Lock lock_; |
181 return new (instance) base::ConditionVariable( | 184 base::ConditionVariable cond_var_; |
182 g_lazy_child_thread_lock.Pointer()); | 185 base::Closure closure_; |
183 } | |
184 static void Delete(base::ConditionVariable* instance) { | |
185 instance->~ConditionVariable(); | |
186 } | |
187 }; | 186 }; |
188 | 187 |
189 // A condition variable that synchronize threads initializing and waiting | 188 QuitClosure::QuitClosure() : cond_var_(&lock_) { |
190 // for g_child_thread. | |
191 base::LazyInstance<base::ConditionVariable, CondVarLazyInstanceTraits> | |
192 g_lazy_child_thread_cv = LAZY_INSTANCE_INITIALIZER; | |
193 | |
194 void QuitMainThreadMessageLoop() { | |
195 base::MessageLoop::current()->Quit(); | |
196 } | 189 } |
197 | 190 |
191 QuitClosure::~QuitClosure() { | |
192 } | |
193 | |
194 void QuitClosure::PostClosure( | |
195 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | |
196 base::Closure closure) { | |
197 task_runner->PostTask(FROM_HERE, closure); | |
198 } | |
199 | |
200 void QuitClosure::BindToMainThread() { | |
201 { | |
202 base::AutoLock lock(lock_); | |
203 scoped_refptr<base::SingleThreadTaskRunner> task_runner( | |
204 base::ThreadTaskRunnerHandle::Get()); | |
205 base::Closure quit_closure = | |
206 base::MessageLoop::current()->QuitWhenIdleClosure(); | |
207 closure_ = | |
208 base::Bind(&QuitClosure::PostClosure, task_runner, quit_closure); | |
209 } | |
210 cond_var_.Signal(); | |
piman
2015/05/19 22:36:29
nit: You can signal while the lock is taken, it's
no sievers
2015/05/19 22:41:55
Done.
| |
211 } | |
212 | |
213 void QuitClosure::PostQuitFromNonMainThread() { | |
214 base::AutoLock lock(lock_); | |
215 while (closure_.is_null()) | |
216 cond_var_.Wait(); | |
217 | |
218 closure_.Run(); | |
219 } | |
220 | |
221 base::LazyInstance<QuitClosure> g_quit_closure = LAZY_INSTANCE_INITIALIZER; | |
198 #endif | 222 #endif |
199 | 223 |
200 } // namespace | 224 } // namespace |
201 | 225 |
202 ChildThread* ChildThread::Get() { | 226 ChildThread* ChildThread::Get() { |
203 return ChildThreadImpl::current(); | 227 return ChildThreadImpl::current(); |
204 } | 228 } |
205 | 229 |
206 ChildThreadImpl::Options::Options() | 230 ChildThreadImpl::Options::Options() |
207 : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 231 : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
395 connection_timeout = temp; | 419 connection_timeout = temp; |
396 } | 420 } |
397 | 421 |
398 base::MessageLoop::current()->PostDelayedTask( | 422 base::MessageLoop::current()->PostDelayedTask( |
399 FROM_HERE, | 423 FROM_HERE, |
400 base::Bind(&ChildThreadImpl::EnsureConnected, | 424 base::Bind(&ChildThreadImpl::EnsureConnected, |
401 channel_connected_factory_.GetWeakPtr()), | 425 channel_connected_factory_.GetWeakPtr()), |
402 base::TimeDelta::FromSeconds(connection_timeout)); | 426 base::TimeDelta::FromSeconds(connection_timeout)); |
403 | 427 |
404 #if defined(OS_ANDROID) | 428 #if defined(OS_ANDROID) |
405 { | 429 g_quit_closure.Get().BindToMainThread(); |
406 base::AutoLock lock(g_lazy_child_thread_lock.Get()); | |
407 g_child_thread = this; | |
408 g_child_thread_initialized = true; | |
409 } | |
410 // Signalling without locking is fine here because only | |
411 // one thread can wait on the condition variable. | |
412 g_lazy_child_thread_cv.Get().Signal(); | |
413 #endif | 430 #endif |
414 | 431 |
415 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) | 432 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) |
416 trace_memory_controller_.reset(new base::trace_event::TraceMemoryController( | 433 trace_memory_controller_.reset(new base::trace_event::TraceMemoryController( |
417 message_loop_->message_loop_proxy(), ::HeapProfilerWithPseudoStackStart, | 434 message_loop_->message_loop_proxy(), ::HeapProfilerWithPseudoStackStart, |
418 ::HeapProfilerStop, ::GetHeapProfile)); | 435 ::HeapProfilerStop, ::GetHeapProfile)); |
419 #endif | 436 #endif |
420 | 437 |
421 base::trace_event::MemoryDumpManager::GetInstance()->Initialize(); | 438 base::trace_event::MemoryDumpManager::GetInstance()->Initialize(); |
422 | 439 |
423 shared_bitmap_manager_.reset( | 440 shared_bitmap_manager_.reset( |
424 new ChildSharedBitmapManager(thread_safe_sender())); | 441 new ChildSharedBitmapManager(thread_safe_sender())); |
425 | 442 |
426 gpu_memory_buffer_manager_.reset( | 443 gpu_memory_buffer_manager_.reset( |
427 new ChildGpuMemoryBufferManager(thread_safe_sender())); | 444 new ChildGpuMemoryBufferManager(thread_safe_sender())); |
428 | 445 |
429 discardable_shared_memory_manager_.reset( | 446 discardable_shared_memory_manager_.reset( |
430 new ChildDiscardableSharedMemoryManager(thread_safe_sender())); | 447 new ChildDiscardableSharedMemoryManager(thread_safe_sender())); |
431 } | 448 } |
432 | 449 |
433 ChildThreadImpl::~ChildThreadImpl() { | 450 ChildThreadImpl::~ChildThreadImpl() { |
434 // ChildDiscardableSharedMemoryManager has to be destroyed while | 451 // ChildDiscardableSharedMemoryManager has to be destroyed while |
435 // |thread_safe_sender_| is still valid. | 452 // |thread_safe_sender_| is still valid. |
436 discardable_shared_memory_manager_.reset(); | 453 discardable_shared_memory_manager_.reset(); |
437 | 454 |
438 #if defined(OS_ANDROID) | |
439 { | |
440 base::AutoLock lock(g_lazy_child_thread_lock.Get()); | |
441 g_child_thread = nullptr; | |
442 } | |
443 #endif | |
444 | |
445 #ifdef IPC_MESSAGE_LOG_ENABLED | 455 #ifdef IPC_MESSAGE_LOG_ENABLED |
446 IPC::Logging::GetInstance()->SetIPCSender(NULL); | 456 IPC::Logging::GetInstance()->SetIPCSender(NULL); |
447 #endif | 457 #endif |
448 | 458 |
449 channel_->RemoveFilter(histogram_message_filter_.get()); | 459 channel_->RemoveFilter(histogram_message_filter_.get()); |
450 channel_->RemoveFilter(sync_message_filter_.get()); | 460 channel_->RemoveFilter(sync_message_filter_.get()); |
451 | 461 |
452 // The ChannelProxy object caches a pointer to the IPC thread, so need to | 462 // The ChannelProxy object caches a pointer to the IPC thread, so need to |
453 // reset it as it's not guaranteed to outlive this object. | 463 // reset it as it's not guaranteed to outlive this object. |
454 // NOTE: this also has the side-effect of not closing the main IPC channel to | 464 // NOTE: this also has the side-effect of not closing the main IPC channel to |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
629 ChildThreadImpl* ChildThreadImpl::current() { | 639 ChildThreadImpl* ChildThreadImpl::current() { |
630 return g_lazy_tls.Pointer()->Get(); | 640 return g_lazy_tls.Pointer()->Get(); |
631 } | 641 } |
632 | 642 |
633 #if defined(OS_ANDROID) | 643 #if defined(OS_ANDROID) |
634 // The method must NOT be called on the child thread itself. | 644 // The method must NOT be called on the child thread itself. |
635 // It may block the child thread if so. | 645 // It may block the child thread if so. |
636 void ChildThreadImpl::ShutdownThread() { | 646 void ChildThreadImpl::ShutdownThread() { |
637 DCHECK(!ChildThreadImpl::current()) << | 647 DCHECK(!ChildThreadImpl::current()) << |
638 "this method should NOT be called from child thread itself"; | 648 "this method should NOT be called from child thread itself"; |
639 { | 649 g_quit_closure.Get().PostQuitFromNonMainThread(); |
640 base::AutoLock lock(g_lazy_child_thread_lock.Get()); | |
641 while (!g_child_thread_initialized) | |
642 g_lazy_child_thread_cv.Get().Wait(); | |
643 | |
644 // g_child_thread may already have been destructed while we didn't hold the | |
645 // lock. | |
646 if (!g_child_thread) | |
647 return; | |
648 | |
649 DCHECK_NE(base::MessageLoop::current(), g_child_thread->message_loop()); | |
650 g_child_thread->message_loop()->PostTask( | |
651 FROM_HERE, base::Bind(&QuitMainThreadMessageLoop)); | |
652 } | |
653 } | 650 } |
654 #endif | 651 #endif |
655 | 652 |
656 void ChildThreadImpl::OnProcessFinalRelease() { | 653 void ChildThreadImpl::OnProcessFinalRelease() { |
657 if (on_channel_error_called_) { | 654 if (on_channel_error_called_) { |
658 base::MessageLoop::current()->Quit(); | 655 base::MessageLoop::current()->Quit(); |
659 return; | 656 return; |
660 } | 657 } |
661 | 658 |
662 // The child process shutdown sequence is a request response based mechanism, | 659 // The child process shutdown sequence is a request response based mechanism, |
(...skipping 16 matching lines...) Expand all Loading... | |
679 | 676 |
680 void ChildThreadImpl::OnProcessBackgrounded(bool background) { | 677 void ChildThreadImpl::OnProcessBackgrounded(bool background) { |
681 // Set timer slack to maximum on main thread when in background. | 678 // Set timer slack to maximum on main thread when in background. |
682 base::TimerSlack timer_slack = base::TIMER_SLACK_NONE; | 679 base::TimerSlack timer_slack = base::TIMER_SLACK_NONE; |
683 if (background) | 680 if (background) |
684 timer_slack = base::TIMER_SLACK_MAXIMUM; | 681 timer_slack = base::TIMER_SLACK_MAXIMUM; |
685 base::MessageLoop::current()->SetTimerSlack(timer_slack); | 682 base::MessageLoop::current()->SetTimerSlack(timer_slack); |
686 } | 683 } |
687 | 684 |
688 } // namespace content | 685 } // namespace content |
OLD | NEW |