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 base::AutoLock lock(lock_); |
| 202 scoped_refptr<base::SingleThreadTaskRunner> task_runner( |
| 203 base::ThreadTaskRunnerHandle::Get()); |
| 204 base::Closure quit_closure = |
| 205 base::MessageLoop::current()->QuitWhenIdleClosure(); |
| 206 closure_ = base::Bind(&QuitClosure::PostClosure, task_runner, quit_closure); |
| 207 cond_var_.Signal(); |
| 208 } |
| 209 |
| 210 void QuitClosure::PostQuitFromNonMainThread() { |
| 211 base::AutoLock lock(lock_); |
| 212 while (closure_.is_null()) |
| 213 cond_var_.Wait(); |
| 214 |
| 215 closure_.Run(); |
| 216 } |
| 217 |
| 218 base::LazyInstance<QuitClosure> g_quit_closure = LAZY_INSTANCE_INITIALIZER; |
198 #endif | 219 #endif |
199 | 220 |
200 } // namespace | 221 } // namespace |
201 | 222 |
202 ChildThread* ChildThread::Get() { | 223 ChildThread* ChildThread::Get() { |
203 return ChildThreadImpl::current(); | 224 return ChildThreadImpl::current(); |
204 } | 225 } |
205 | 226 |
206 ChildThreadImpl::Options::Options() | 227 ChildThreadImpl::Options::Options() |
207 : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 228 : channel_name(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 connection_timeout = temp; | 416 connection_timeout = temp; |
396 } | 417 } |
397 | 418 |
398 base::MessageLoop::current()->PostDelayedTask( | 419 base::MessageLoop::current()->PostDelayedTask( |
399 FROM_HERE, | 420 FROM_HERE, |
400 base::Bind(&ChildThreadImpl::EnsureConnected, | 421 base::Bind(&ChildThreadImpl::EnsureConnected, |
401 channel_connected_factory_.GetWeakPtr()), | 422 channel_connected_factory_.GetWeakPtr()), |
402 base::TimeDelta::FromSeconds(connection_timeout)); | 423 base::TimeDelta::FromSeconds(connection_timeout)); |
403 | 424 |
404 #if defined(OS_ANDROID) | 425 #if defined(OS_ANDROID) |
405 { | 426 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 | 427 #endif |
414 | 428 |
415 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) | 429 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) |
416 trace_memory_controller_.reset(new base::trace_event::TraceMemoryController( | 430 trace_memory_controller_.reset(new base::trace_event::TraceMemoryController( |
417 message_loop_->message_loop_proxy(), ::HeapProfilerWithPseudoStackStart, | 431 message_loop_->message_loop_proxy(), ::HeapProfilerWithPseudoStackStart, |
418 ::HeapProfilerStop, ::GetHeapProfile)); | 432 ::HeapProfilerStop, ::GetHeapProfile)); |
419 #endif | 433 #endif |
420 | 434 |
421 base::trace_event::MemoryDumpManager::GetInstance()->Initialize(); | 435 base::trace_event::MemoryDumpManager::GetInstance()->Initialize(); |
422 | 436 |
423 shared_bitmap_manager_.reset( | 437 shared_bitmap_manager_.reset( |
424 new ChildSharedBitmapManager(thread_safe_sender())); | 438 new ChildSharedBitmapManager(thread_safe_sender())); |
425 | 439 |
426 gpu_memory_buffer_manager_.reset( | 440 gpu_memory_buffer_manager_.reset( |
427 new ChildGpuMemoryBufferManager(thread_safe_sender())); | 441 new ChildGpuMemoryBufferManager(thread_safe_sender())); |
428 | 442 |
429 discardable_shared_memory_manager_.reset( | 443 discardable_shared_memory_manager_.reset( |
430 new ChildDiscardableSharedMemoryManager(thread_safe_sender())); | 444 new ChildDiscardableSharedMemoryManager(thread_safe_sender())); |
431 } | 445 } |
432 | 446 |
433 ChildThreadImpl::~ChildThreadImpl() { | 447 ChildThreadImpl::~ChildThreadImpl() { |
434 // ChildDiscardableSharedMemoryManager has to be destroyed while | 448 // ChildDiscardableSharedMemoryManager has to be destroyed while |
435 // |thread_safe_sender_| is still valid. | 449 // |thread_safe_sender_| is still valid. |
436 discardable_shared_memory_manager_.reset(); | 450 discardable_shared_memory_manager_.reset(); |
437 | 451 |
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 | 452 #ifdef IPC_MESSAGE_LOG_ENABLED |
446 IPC::Logging::GetInstance()->SetIPCSender(NULL); | 453 IPC::Logging::GetInstance()->SetIPCSender(NULL); |
447 #endif | 454 #endif |
448 | 455 |
449 channel_->RemoveFilter(histogram_message_filter_.get()); | 456 channel_->RemoveFilter(histogram_message_filter_.get()); |
450 channel_->RemoveFilter(sync_message_filter_.get()); | 457 channel_->RemoveFilter(sync_message_filter_.get()); |
451 | 458 |
452 // The ChannelProxy object caches a pointer to the IPC thread, so need to | 459 // 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. | 460 // 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 | 461 // 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() { | 636 ChildThreadImpl* ChildThreadImpl::current() { |
630 return g_lazy_tls.Pointer()->Get(); | 637 return g_lazy_tls.Pointer()->Get(); |
631 } | 638 } |
632 | 639 |
633 #if defined(OS_ANDROID) | 640 #if defined(OS_ANDROID) |
634 // The method must NOT be called on the child thread itself. | 641 // The method must NOT be called on the child thread itself. |
635 // It may block the child thread if so. | 642 // It may block the child thread if so. |
636 void ChildThreadImpl::ShutdownThread() { | 643 void ChildThreadImpl::ShutdownThread() { |
637 DCHECK(!ChildThreadImpl::current()) << | 644 DCHECK(!ChildThreadImpl::current()) << |
638 "this method should NOT be called from child thread itself"; | 645 "this method should NOT be called from child thread itself"; |
639 { | 646 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 } | 647 } |
654 #endif | 648 #endif |
655 | 649 |
656 void ChildThreadImpl::OnProcessFinalRelease() { | 650 void ChildThreadImpl::OnProcessFinalRelease() { |
657 if (on_channel_error_called_) { | 651 if (on_channel_error_called_) { |
658 base::MessageLoop::current()->Quit(); | 652 base::MessageLoop::current()->Quit(); |
659 return; | 653 return; |
660 } | 654 } |
661 | 655 |
662 // The child process shutdown sequence is a request response based mechanism, | 656 // The child process shutdown sequence is a request response based mechanism, |
(...skipping 16 matching lines...) Expand all Loading... |
679 | 673 |
680 void ChildThreadImpl::OnProcessBackgrounded(bool background) { | 674 void ChildThreadImpl::OnProcessBackgrounded(bool background) { |
681 // Set timer slack to maximum on main thread when in background. | 675 // Set timer slack to maximum on main thread when in background. |
682 base::TimerSlack timer_slack = base::TIMER_SLACK_NONE; | 676 base::TimerSlack timer_slack = base::TIMER_SLACK_NONE; |
683 if (background) | 677 if (background) |
684 timer_slack = base::TIMER_SLACK_MAXIMUM; | 678 timer_slack = base::TIMER_SLACK_MAXIMUM; |
685 base::MessageLoop::current()->SetTimerSlack(timer_slack); | 679 base::MessageLoop::current()->SetTimerSlack(timer_slack); |
686 } | 680 } |
687 | 681 |
688 } // namespace content | 682 } // namespace content |
OLD | NEW |