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

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: 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 {
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
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
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
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
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