Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(458)

Side by Side Diff: content/child/child_thread_impl.cc

Issue 1140633005: Android: Fix ChildThreadImpl::ShutdownThread() (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address comment Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698