diff options
Diffstat (limited to 'chromium/content/child/child_thread.cc')
-rw-r--r-- | chromium/content/child/child_thread.cc | 192 |
1 files changed, 145 insertions, 47 deletions
diff --git a/chromium/content/child/child_thread.cc b/chromium/content/child/child_thread.cc index 5b54ee041f9..3222b4167a1 100644 --- a/chromium/content/child/child_thread.cc +++ b/chromium/content/child/child_thread.cc @@ -4,16 +4,22 @@ #include "content/child/child_thread.h" +#include <signal.h> + #include <string> #include "base/allocator/allocator_extension.h" #include "base/base_switches.h" +#include "base/basictypes.h" #include "base/command_line.h" #include "base/debug/leak_annotations.h" #include "base/lazy_instance.h" +#include "base/logging.h" #include "base/message_loop/message_loop.h" +#include "base/message_loop/timer_slack.h" #include "base/process/kill.h" #include "base/process/process_handle.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/synchronization/condition_variable.h" #include "base/synchronization/lock.h" @@ -23,7 +29,10 @@ #include "content/child/child_histogram_message_filter.h" #include "content/child/child_process.h" #include "content/child/child_resource_message_filter.h" +#include "content/child/child_shared_bitmap_manager.h" #include "content/child/fileapi/file_system_dispatcher.h" +#include "content/child/fileapi/webfilesystem_impl.h" +#include "content/child/mojo/mojo_application.h" #include "content/child/power_monitor_broadcast_source.h" #include "content/child/quota_dispatcher.h" #include "content/child/quota_message_filter.h" @@ -64,16 +73,55 @@ base::LazyInstance<base::ThreadLocalPointer<ChildThread> > g_lazy_tls = // plugins), PluginThread has EnsureTerminateMessageFilter. #if defined(OS_POSIX) -class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter { +// TODO(earthdok): Re-enable on CrOS http://crbug.com/360622 +#if (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \ + defined(THREAD_SANITIZER)) && !defined(OS_CHROMEOS) +// A thread delegate that waits for |duration| and then exits the process with +// _exit(0). +class WaitAndExitDelegate : public base::PlatformThread::Delegate { + public: + explicit WaitAndExitDelegate(base::TimeDelta duration) + : duration_(duration) {} + virtual ~WaitAndExitDelegate() OVERRIDE {} + + virtual void ThreadMain() OVERRIDE { + base::PlatformThread::Sleep(duration_); + _exit(0); + } + + private: + const base::TimeDelta duration_; + DISALLOW_COPY_AND_ASSIGN(WaitAndExitDelegate); +}; + +bool CreateWaitAndExitThread(base::TimeDelta duration) { + scoped_ptr<WaitAndExitDelegate> delegate(new WaitAndExitDelegate(duration)); + + const bool thread_created = + base::PlatformThread::CreateNonJoinable(0, delegate.get()); + if (!thread_created) + return false; + + // A non joinable thread has been created. The thread will either terminate + // the process or will be terminated by the process. Therefore, keep the + // delegate object alive for the lifetime of the process. + WaitAndExitDelegate* leaking_delegate = delegate.release(); + ANNOTATE_LEAKING_OBJECT_PTR(leaking_delegate); + ignore_result(leaking_delegate); + return true; +} +#endif + +class SuicideOnChannelErrorFilter : public IPC::MessageFilter { public: - // IPC::ChannelProxy::MessageFilter + // IPC::MessageFilter virtual void OnChannelError() OVERRIDE { // For renderer/worker processes: // On POSIX, at least, one can install an unload handler which loops // forever and leave behind a renderer process which eats 100% CPU forever. // // This is because the terminate signals (ViewMsg_ShouldClose and the error - // from the IPC channel) are routed to the main message loop but never + // from the IPC sender) are routed to the main message loop but never // processed (because that message loop is stuck in V8). // // One could make the browser SIGKILL the renderers, but that leaves open a @@ -81,23 +129,23 @@ class SuicideOnChannelErrorFilter : public IPC::ChannelProxy::MessageFilter { // the browser because "it's stuck") will leave behind a process eating all // the CPU. // - // So, we install a filter on the channel so that we can process this event + // So, we install a filter on the sender so that we can process this event // here and kill the process. - if (CommandLine::ForCurrentProcess()-> - HasSwitch(switches::kChildCleanExit)) { - // If clean exit is requested, we want to kill this process after giving - // it 60 seconds to run exit handlers. Exit handlers may including ones - // that write profile data to disk (which happens under profile collection - // mode). - alarm(60); + // TODO(earthdok): Re-enable on CrOS http://crbug.com/360622 +#if (defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \ + defined(THREAD_SANITIZER)) && !defined(OS_CHROMEOS) + // Some sanitizer tools rely on exit handlers (e.g. to run leak detection, + // or dump code coverage data to disk). Instead of exiting the process + // immediately, we give it 60 seconds to run exit handlers. + CHECK(CreateWaitAndExitThread(base::TimeDelta::FromSeconds(60))); #if defined(LEAK_SANITIZER) - // Invoke LeakSanitizer early to avoid detecting shutdown-only leaks. If - // leaks are found, the process will exit here. - __lsan_do_leak_check(); + // Invoke LeakSanitizer early to avoid detecting shutdown-only leaks. If + // leaks are found, the process will exit here. + __lsan_do_leak_check(); +#endif +#else + _exit(0); #endif - } else { - _exit(0); - } } protected: @@ -118,7 +166,10 @@ base::LazyInstance<base::Lock> g_lazy_child_thread_lock = // doesn't handle the case. Thus, we need our own class here. struct CondVarLazyInstanceTraits { static const bool kRegisterOnExit = true; - static const bool kAllowedToAccessOnNonjoinableThread ALLOW_UNUSED = false; +#ifndef NDEBUG + static const bool kAllowedToAccessOnNonjoinableThread = false; +#endif + static base::ConditionVariable* New(void* instance) { return new (instance) base::ConditionVariable( g_lazy_child_thread_lock.Pointer()); @@ -141,8 +192,17 @@ void QuitMainThreadMessageLoop() { } // namespace +ChildThread::ChildThreadMessageRouter::ChildThreadMessageRouter( + IPC::Sender* sender) + : sender_(sender) {} + +bool ChildThread::ChildThreadMessageRouter::Send(IPC::Message* msg) { + return sender_->Send(msg); +} + ChildThread::ChildThread() - : channel_connected_factory_(this), + : router_(this), + channel_connected_factory_(this), in_browser_process_(false) { channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( switches::kProcessChannelID); @@ -151,6 +211,7 @@ ChildThread::ChildThread() ChildThread::ChildThread(const std::string& channel_name) : channel_name_(channel_name), + router_(this), channel_connected_factory_(this), in_browser_process_(true) { Init(); @@ -166,18 +227,20 @@ void ChildThread::Init() { // the logger, and the logger does not like being created on the IO thread. IPC::Logging::GetInstance(); #endif - channel_.reset( - new IPC::SyncChannel(channel_name_, - IPC::Channel::MODE_CLIENT, - this, - ChildProcess::current()->io_message_loop_proxy(), - true, - ChildProcess::current()->GetShutDownEvent())); + channel_ = + IPC::SyncChannel::Create(channel_name_, + IPC::Channel::MODE_CLIENT, + this, + ChildProcess::current()->io_message_loop_proxy(), + true, + ChildProcess::current()->GetShutDownEvent()); #ifdef IPC_MESSAGE_LOG_ENABLED if (!in_browser_process_) IPC::Logging::GetInstance()->SetIPCSender(this); #endif + mojo_application_.reset(new MojoApplication(this)); + sync_message_filter_ = new IPC::SyncMessageFilter(ChildProcess::current()->GetShutDownEvent()); thread_safe_sender_ = new ThreadSafeSender( @@ -204,12 +267,17 @@ void ChildThread::Init() { channel_->AddFilter(histogram_message_filter_.get()); channel_->AddFilter(sync_message_filter_.get()); - channel_->AddFilter(new tracing::ChildTraceMessageFilter( - ChildProcess::current()->io_message_loop_proxy())); channel_->AddFilter(resource_message_filter_.get()); channel_->AddFilter(quota_message_filter_->GetFilter()); channel_->AddFilter(service_worker_message_filter_->GetFilter()); + if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess)) { + // In single process mode, browser-side tracing will cover the whole + // process including renderers. + channel_->AddFilter(new tracing::ChildTraceMessageFilter( + ChildProcess::current()->io_message_loop_proxy())); + } + // In single process mode we may already have a power monitor if (!base::PowerMonitor::Get()) { scoped_ptr<PowerMonitorBroadcastSource> power_monitor_source( @@ -227,11 +295,21 @@ void ChildThread::Init() { channel_->AddFilter(new SuicideOnChannelErrorFilter()); #endif + int connection_timeout = kConnectionTimeoutS; + std::string connection_override = + CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kIPCConnectionTimeout); + if (!connection_override.empty()) { + int temp; + if (base::StringToInt(connection_override, &temp)) + connection_timeout = temp; + } + base::MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&ChildThread::EnsureConnected, channel_connected_factory_.GetWeakPtr()), - base::TimeDelta::FromSeconds(kConnectionTimeoutS)); + base::TimeDelta::FromSeconds(connection_timeout)); #if defined(OS_ANDROID) { @@ -250,6 +328,9 @@ void ChildThread::Init() { ::HeapProfilerStop, ::GetHeapProfile)); #endif + + shared_bitmap_manager_.reset( + new ChildSharedBitmapManager(thread_safe_sender())); } ChildThread::~ChildThread() { @@ -277,6 +358,7 @@ void ChildThread::Shutdown() { // safely shutdown blink in their Shutdown implementation. file_system_dispatcher_.reset(); quota_dispatcher_.reset(); + WebFileSystemImpl::DeleteThreadSpecificInstance(); } void ChildThread::OnChannelConnected(int32 peer_pid) { @@ -288,6 +370,15 @@ void ChildThread::OnChannelError() { base::MessageLoop::current()->Quit(); } +void ChildThread::ConnectToService( + const mojo::String& service_url, + const mojo::String& service_name, + mojo::ScopedMessagePipeHandle message_pipe, + const mojo::String& requestor_url) { + // By default, we don't expect incoming connections. + NOTREACHED(); +} + bool ChildThread::Send(IPC::Message* msg) { DCHECK(base::MessageLoop::current() == message_loop()); if (!channel_) { @@ -298,21 +389,9 @@ bool ChildThread::Send(IPC::Message* msg) { return channel_->Send(msg); } -void ChildThread::AddRoute(int32 routing_id, IPC::Listener* listener) { - DCHECK(base::MessageLoop::current() == message_loop()); - - router_.AddRoute(routing_id, listener); -} - -void ChildThread::RemoveRoute(int32 routing_id) { +MessageRouter* ChildThread::GetRouter() { DCHECK(base::MessageLoop::current() == message_loop()); - - router_.RemoveRoute(routing_id); -} - -webkit_glue::ResourceLoaderBridge* ChildThread::CreateBridge( - const webkit_glue::ResourceLoaderBridge::RequestInfo& request_info) { - return resource_dispatcher()->CreateBridge(request_info); + return &router_; } base::SharedMemory* ChildThread::AllocateSharedMemory(size_t buf_size) { @@ -355,6 +434,9 @@ base::SharedMemory* ChildThread::AllocateSharedMemory( } bool ChildThread::OnMessageReceived(const IPC::Message& msg) { + if (mojo_application_->OnMessageReceived(msg)) + return true; + // Resource responses are sent to the resource dispatcher. if (resource_dispatcher_->OnMessageReceived(msg)) return true; @@ -377,6 +459,8 @@ bool ChildThread::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ChildProcessMsg_GetChildProfilerData, OnGetChildProfilerData) IPC_MESSAGE_HANDLER(ChildProcessMsg_DumpHandles, OnDumpHandles) + IPC_MESSAGE_HANDLER(ChildProcessMsg_SetProcessBackgrounded, + OnProcessBackgrounded) #if defined(USE_TCMALLOC) IPC_MESSAGE_HANDLER(ChildProcessMsg_GetTcmallocStats, OnGetTcmallocStats) #endif @@ -429,10 +513,9 @@ void ChildThread::OnDumpHandles() { switches::kAuditAllHandles))); handle_enum->EnumerateHandles(); Send(new ChildProcessHostMsg_DumpHandlesDone); - return; -#endif - +#else NOTIMPLEMENTED(); +#endif } #if defined(USE_TCMALLOC) @@ -464,7 +547,6 @@ void ChildThread::ShutdownThread() { g_child_thread->message_loop()->PostTask( FROM_HERE, base::Bind(&QuitMainThreadMessageLoop)); } - #endif void ChildThread::OnProcessFinalRelease() { @@ -487,4 +569,20 @@ void ChildThread::EnsureConnected() { base::KillProcess(base::GetCurrentProcessHandle(), 0, false); } +void ChildThread::OnProcessBackgrounded(bool background) { + // Set timer slack to maximum on main thread when in background. + base::TimerSlack timer_slack = base::TIMER_SLACK_NONE; + if (background) + timer_slack = base::TIMER_SLACK_MAXIMUM; + base::MessageLoop::current()->SetTimerSlack(timer_slack); + +#ifdef OS_WIN + // Windows Vista+ has a fancy process backgrounding mode that can only be set + // from within the process. + // TODO(wfh) Do not set background from within process until the issue with + // white tabs is resolved. See http://crbug.com/398103. + // base::Process::Current().SetProcessBackgrounded(background); +#endif // OS_WIN +} + } // namespace content |