From 8930d471c128ed74b11beaa78ea1b171c1ac7157 Mon Sep 17 00:00:00 2001 From: "jam@chromium.org" Date: Sat, 21 Feb 2009 08:05:28 +0000 Subject: Refactor code from RenderThread and PluginThread and move it to ChildThread. ChildProcess now owns the ChildThread, which removes duplicate code and simplifies things. Clean up ChildProcess, there really was no need for all the templates and statics in it and its subclasses. Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=10080 Review URL: http://codereview.chromium.org/21502 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10144 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/renderer/chrome_plugin_host.cc | 8 +- chrome/renderer/mock_render_process.h | 12 +-- chrome/renderer/net/render_dns_master.cc | 8 +- chrome/renderer/render_process.cc | 80 +++++++++--------- chrome/renderer/render_process.h | 46 +++++----- chrome/renderer/render_process_unittest.cc | 9 +- chrome/renderer/render_thread.cc | 126 +++++++++------------------- chrome/renderer/render_thread.h | 70 +++++++--------- chrome/renderer/render_thread_unittest.cc | 29 ++++--- chrome/renderer/render_view.cc | 17 ++-- chrome/renderer/render_view_unittest.cc | 10 +-- chrome/renderer/render_widget.cc | 16 ++-- chrome/renderer/render_widget.h | 2 +- chrome/renderer/render_widget_unittest.cc | 11 +-- chrome/renderer/renderer_glue.cc | 48 +++++------ chrome/renderer/renderer_main.cc | 7 +- chrome/renderer/webplugin_delegate_proxy.cc | 4 +- 17 files changed, 209 insertions(+), 294 deletions(-) (limited to 'chrome/renderer') diff --git a/chrome/renderer/chrome_plugin_host.cc b/chrome/renderer/chrome_plugin_host.cc index 6f793b7..9d437c0 100644 --- a/chrome/renderer/chrome_plugin_host.cc +++ b/chrome/renderer/chrome_plugin_host.cc @@ -320,7 +320,7 @@ int STDCALL CPB_GetBrowsingContextInfo( return sizeof(char*); std::wstring wretval; - if (!g_render_thread->Send(new ViewHostMsg_GetDataDir(&wretval))) + if (!RenderThread::current()->Send(new ViewHostMsg_GetDataDir(&wretval))) return CPERR_FAILURE; file_util::AppendToPath(&wretval, chrome::kChromePluginDataDirname); *static_cast(buf) = CPB_StringDup(CPB_Alloc, WideToUTF8(wretval)); @@ -491,8 +491,8 @@ CPError STDCALL CPB_SendMessage(CPID id, const void *data, uint32 data_len) { const uint8* data_ptr = static_cast(data); std::vector v(data_ptr, data_ptr + data_len); - if (!g_render_thread->Send(new ViewHostMsg_PluginMessage(plugin->filename(), - v))) { + if (!RenderThread::current()->Send( + new ViewHostMsg_PluginMessage(plugin->filename(), v))) { return CPERR_FAILURE; } return CPERR_SUCCESS; @@ -507,7 +507,7 @@ CPError STDCALL CPB_SendSyncMessage(CPID id, const void *data, uint32 data_len, const uint8* data_ptr = static_cast(data); std::vector v(data_ptr, data_ptr + data_len); std::vector r; - if (!g_render_thread->Send(new ViewHostMsg_PluginSyncMessage( + if (!RenderThread::current()->Send(new ViewHostMsg_PluginSyncMessage( plugin->filename(), v, &r))) { return CPERR_FAILURE; } diff --git a/chrome/renderer/mock_render_process.h b/chrome/renderer/mock_render_process.h index d7bd178..629967f 100644 --- a/chrome/renderer/mock_render_process.h +++ b/chrome/renderer/mock_render_process.h @@ -5,21 +5,17 @@ #ifndef CHROME_RENDERER_MOCK_RENDER_PROCESS_H_ #define CHROME_RENDERER_MOCK_RENDER_PROCESS_H_ -#include - #include "chrome/common/child_process.h" +class ChildThread; + // This class is a trivial mock of the child process singleton. It is necessary // so we don't trip DCHECKs in ChildProcess::ReleaseProcess() when destroying // a render widget instance. class MockProcess : public ChildProcess { public: - explicit MockProcess(const std::wstring& channel_name) {} - static void GlobalInit() { - ChildProcessFactory factory; - ChildProcess::GlobalInit(L"dummy", &factory); - } + explicit MockProcess() : ChildProcess(NULL) {} + explicit MockProcess(ChildThread* thread) : ChildProcess(thread) {} }; #endif // CHROME_RENDERER_MOCK_RENDER_PROCESS_H_ - diff --git a/chrome/renderer/net/render_dns_master.cc b/chrome/renderer/net/render_dns_master.cc index beacec6..b62b6ca 100644 --- a/chrome/renderer/net/render_dns_master.cc +++ b/chrome/renderer/net/render_dns_master.cc @@ -19,7 +19,7 @@ // This API is used in the render process by renderer_glue.cc. // IF you are in the render process, you MUST be on the renderer thread to call. void DnsPrefetchCString(const char* hostname, size_t length) { - g_render_thread->Resolve(hostname, length); + RenderThread::current()->Resolve(hostname, length); } // The number of hostnames submitted to Browser DNS resolver per call to @@ -55,7 +55,7 @@ void RenderDnsMaster::Resolve(const char* name, size_t length) { if (0 != old_size) return; // Overkill safety net: Don't send too many InvokeLater's. render_dns_factory_.RevokeAll(); - g_render_thread->message_loop()->PostDelayedTask(FROM_HERE, + RenderThread::current()->message_loop()->PostDelayedTask(FROM_HERE, render_dns_factory_.NewRunnableMethod( &RenderDnsMaster::SubmitHostnames), 10); } @@ -89,7 +89,7 @@ void RenderDnsMaster::SubmitHostnames() { DnsPrefetchNames(kMAX_SUBMISSION_PER_TASK); if (new_name_count_ > 0 || 0 < c_string_queue_.Size()) { render_dns_factory_.RevokeAll(); - g_render_thread->message_loop()->PostDelayedTask(FROM_HERE, + RenderThread::current()->message_loop()->PostDelayedTask(FROM_HERE, render_dns_factory_.NewRunnableMethod( &RenderDnsMaster::SubmitHostnames), 10); } else { @@ -145,7 +145,7 @@ void RenderDnsMaster::DnsPrefetchNames(size_t max_count) { new_name_count_ -= names.size(); DCHECK(new_name_count_ >= 0); - g_render_thread->Send(new ViewHostMsg_DnsPrefetch(names)); + RenderThread::current()->Send(new ViewHostMsg_DnsPrefetch(names)); } // is_numeric_ip() checks to see if all characters in name are either numeric, diff --git a/chrome/renderer/render_process.cc b/chrome/renderer/render_process.cc index 198f854f..8cec986 100644 --- a/chrome/renderer/render_process.cc +++ b/chrome/renderer/render_process.cc @@ -29,34 +29,50 @@ #include "chrome/renderer/render_view.h" #include "webkit/glue/webkit_glue.h" -//----------------------------------------------------------------------------- -bool RenderProcess::load_plugins_in_process_ = false; - -//----------------------------------------------------------------------------- +RenderProcess::RenderProcess() + : ChildProcess(new RenderThread()), + ALLOW_THIS_IN_INITIALIZER_LIST(shared_mem_cache_cleaner_( + base::TimeDelta::FromSeconds(5), + this, &RenderProcess::ClearTransportDIBCache)), + sequence_number_(0) { + Init(); +} RenderProcess::RenderProcess(const std::wstring& channel_name) - : render_thread_(channel_name), + : ChildProcess(new RenderThread(channel_name)), ALLOW_THIS_IN_INITIALIZER_LIST(shared_mem_cache_cleaner_( base::TimeDelta::FromSeconds(5), this, &RenderProcess::ClearTransportDIBCache)), sequence_number_(0) { - for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) - shared_mem_cache_[i] = NULL; + Init(); } RenderProcess::~RenderProcess() { + // TODO(port) + // Try and limit what we pull in for our non-Win unit test bundle +#ifndef NDEBUG + // log important leaked objects + webkit_glue::CheckForLeaks(); +#endif + + GetShutDownEvent()->Signal(); + // We need to stop the RenderThread as the clearer_factory_ // member could be in use while the object itself is destroyed, // as a result of the containing RenderProcess object being destroyed. // This race condition causes a crash when the renderer process is shutting // down. - render_thread_.Stop(); + child_thread()->Stop(); ClearTransportDIBCache(); } -// static -bool RenderProcess::GlobalInit(const std::wstring &channel_name) { +void RenderProcess::Init() { + in_process_plugins_ = InProcessPlugins(); + in_process_gears_ = false; + for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) + shared_mem_cache_[i] = NULL; + #if defined(OS_WIN) // HACK: See http://b/issue?id=1024307 for rationale. if (GetModuleHandle(L"LPK.DLL") == NULL) { @@ -84,10 +100,6 @@ bool RenderProcess::GlobalInit(const std::wstring &channel_name) { webkit_glue::SetRecordPlaybackMode(true); } - if (command_line.HasSwitch(switches::kInProcessPlugins) || - command_line.HasSwitch(switches::kSingleProcess)) - load_plugins_in_process_ = true; - if (command_line.HasSwitch(switches::kEnableWatchdog)) { // TODO(JAR): Need to implement renderer IO msgloop watchdog. } @@ -98,6 +110,7 @@ bool RenderProcess::GlobalInit(const std::wstring &channel_name) { if (command_line.HasSwitch(switches::kGearsInRenderer)) { #if defined(OS_WIN) + in_process_gears_ = true; // Load gears.dll on startup so we can access it before the sandbox // blocks us. std::wstring path; @@ -113,19 +126,12 @@ bool RenderProcess::GlobalInit(const std::wstring &channel_name) { // TODO(scherkus): check for any DLL dependencies. webkit_glue::SetMediaPlayerAvailable(true); } - - ChildProcessFactory factory; - return ChildProcess::GlobalInit(channel_name, &factory); -} - -// static -void RenderProcess::GlobalCleanup() { - ChildProcess::GlobalCleanup(); } -// static -bool RenderProcess::ShouldLoadPluginsInProcess() { - return load_plugins_in_process_; +bool RenderProcess::InProcessPlugins() { + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + return command_line.HasSwitch(switches::kInProcessPlugins) || + command_line.HasSwitch(switches::kSingleProcess); } // ----------------------------------------------------------------------------- @@ -155,7 +161,7 @@ TransportDIB* RenderProcess::CreateTransportDIB(size_t size) { // get one. IPC::Maybe mhandle; IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, &mhandle); - if (!render_thread_.Send(msg)) + if (!child_thread()->Send(msg)) return NULL; if (!mhandle.valid) return NULL; @@ -171,7 +177,7 @@ void RenderProcess::FreeTransportDIB(TransportDIB* dib) { // On Mac we need to tell the browser that it can drop a reference to the // shared memory. IPC::Message* msg = new ViewHostMsg_FreeTransportDIB(dib->id()); - render_thread_.Send(msg); + child_thread()->Send(msg); #endif delete dib; @@ -180,14 +186,13 @@ void RenderProcess::FreeTransportDIB(TransportDIB* dib) { // ----------------------------------------------------------------------------- -// static skia::PlatformCanvas* RenderProcess::GetDrawingCanvas( TransportDIB** memory, const gfx::Rect& rect) { const size_t stride = skia::PlatformCanvas::StrideForWidth(rect.width()); const size_t size = stride * rect.height(); - if (!self()->GetTransportDIBFromCache(memory, size)) { - *memory = self()->CreateTransportDIB(size); + if (!GetTransportDIBFromCache(memory, size)) { + *memory = CreateTransportDIB(size); if (!*memory) return false; } @@ -195,14 +200,13 @@ skia::PlatformCanvas* RenderProcess::GetDrawingCanvas( return CanvasFromTransportDIB(*memory, rect); } -// static void RenderProcess::ReleaseTransportDIB(TransportDIB* mem) { - if (self()->PutSharedMemInCache(mem)) { - self()->shared_mem_cache_cleaner_.Reset(); + if (PutSharedMemInCache(mem)) { + shared_mem_cache_cleaner_.Reset(); return; } - self()->FreeTransportDIB(mem); + FreeTransportDIB(mem); } bool RenderProcess::GetTransportDIBFromCache(TransportDIB** mem, @@ -266,11 +270,3 @@ void RenderProcess::ClearTransportDIBCache() { } } -void RenderProcess::Cleanup() { - // TODO(port) - // Try and limit what we pull in for our non-Win unit test bundle -#ifndef NDEBUG - // log important leaked objects - webkit_glue::CheckForLeaks(); -#endif -} diff --git a/chrome/renderer/render_process.h b/chrome/renderer/render_process.h index 9c4cabe..a4bc0ff5 100644 --- a/chrome/renderer/render_process.h +++ b/chrome/renderer/render_process.h @@ -21,11 +21,12 @@ class TransportDIB; // each renderer. class RenderProcess : public ChildProcess { public: - static bool GlobalInit(const std::wstring& channel_name); - static void GlobalCleanup(); + // This constructor grabs the channel name from the command line arguments. + RenderProcess(); + // This constructor uses the given channel name. + RenderProcess(const std::wstring& channel_name); - // Returns true if plugins should be loaded in-process. - static bool ShouldLoadPluginsInProcess(); + ~RenderProcess(); // Get a canvas suitable for drawing and transporting to the browser // memory: (output) the transport DIB memory @@ -34,25 +35,31 @@ class RenderProcess : public ChildProcess { // // When no longer needed, you should pass the TransportDIB to // ReleaseTransportDIB so that it can be recycled. - static skia::PlatformCanvas* GetDrawingCanvas( + skia::PlatformCanvas* GetDrawingCanvas( TransportDIB** memory, const gfx::Rect& rect); // Frees shared memory allocated by AllocSharedMemory. You should only use // this function to free the SharedMemory object. - static void ReleaseTransportDIB(TransportDIB* memory); + void ReleaseTransportDIB(TransportDIB* memory); - private: - friend class ChildProcessFactory; - explicit RenderProcess(const std::wstring& channel_name); - ~RenderProcess(); + // Returns true if plugins should be loaded in-process. + bool in_process_plugins() const { return in_process_plugins_; } - // Returns a pointer to the RenderProcess singleton instance. This is - // guaranteed to be non-NULL between calls to GlobalInit and GlobalCleanup. - static RenderProcess* self() { - return static_cast(child_process_); + // Returns true if Gears should be loaded in-process. + bool in_process_gears() const { return in_process_gears_; } + + // Returns a pointer to the RenderProcess singleton instance. + static RenderProcess* current() { + return static_cast(ChildProcess::current()); } - static ChildProcess* ClassFactory(const std::wstring& channel_name); + protected: + friend class RenderThread; + // Just like in_process_plugins(), but called before RenderProcess is created. + static bool InProcessPlugins(); + + private: + void Init(); // Look in the shared memory cache for a suitable object to reuse. // result: (output) the memory found @@ -77,12 +84,6 @@ class RenderProcess : public ChildProcess { TransportDIB* CreateTransportDIB(size_t size); void FreeTransportDIB(TransportDIB*); - // ChildProcess implementation - virtual void Cleanup(); - - // The one render thread (to be replaced with a set of render threads). - RenderThread render_thread_; - // A very simplistic and small cache. If an entry in this array is non-null, // then it points to a SharedMemory object that is available for reuse. TransportDIB* shared_mem_cache_[2]; @@ -93,7 +94,8 @@ class RenderProcess : public ChildProcess { // TransportDIB sequence number uint32 sequence_number_; - static bool load_plugins_in_process_; + bool in_process_plugins_; + bool in_process_gears_; DISALLOW_COPY_AND_ASSIGN(RenderProcess); }; diff --git a/chrome/renderer/render_process_unittest.cc b/chrome/renderer/render_process_unittest.cc index 4f77d5d..7859d8f 100644 --- a/chrome/renderer/render_process_unittest.cc +++ b/chrome/renderer/render_process_unittest.cc @@ -13,15 +13,16 @@ namespace { class RenderProcessTest : public testing::Test { public: virtual void SetUp() { - RenderProcess::GlobalInit(L"render_process_unittest"); + render_process_.reset(new RenderProcess(L"render_process_unittest")); } virtual void TearDown() { - RenderProcess::GlobalCleanup(); + render_process_.reset(); } private: MessageLoopForIO message_loop_; + scoped_ptr render_process_; }; @@ -30,10 +31,10 @@ TEST_F(RenderProcessTest, TestTransportDIBAllocation) { #if !defined(OS_MACOSX) const gfx::Rect rect(0, 0, 100, 100); TransportDIB* dib; - skia::PlatformCanvas* canvas = RenderProcess::GetDrawingCanvas(&dib, rect); + skia::PlatformCanvas* canvas = RenderProcess::current()->GetDrawingCanvas(&dib, rect); ASSERT_TRUE(dib); ASSERT_TRUE(canvas); - RenderProcess::ReleaseTransportDIB(dib); + RenderProcess::current()->ReleaseTransportDIB(dib); delete canvas; #endif } diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc index 2937935..58de4ef 100644 --- a/chrome/renderer/render_thread.cc +++ b/chrome/renderer/render_thread.cc @@ -14,9 +14,9 @@ #include "base/shared_memory.h" #include "chrome/common/chrome_plugin_lib.h" -#include "chrome/common/ipc_logging.h" #include "chrome/common/render_messages.h" #include "chrome/common/notification_service.h" +#include "chrome/plugin/npobject_util.h" // TODO(port) #if defined(OS_WIN) #include "chrome/plugin/plugin_channel.h" @@ -34,8 +34,6 @@ #include "webkit/glue/cache_manager.h" -RenderThread* g_render_thread; - static const unsigned int kCacheStatsDelayMS = 2000 /* milliseconds */; // V8 needs a 1MB stack size. @@ -44,78 +42,53 @@ static const size_t kStackSize = 1024 * 1024; //----------------------------------------------------------------------------- // Methods below are only called on the owner's thread: -RenderThread::RenderThread(const std::wstring& channel_name) - : Thread("Chrome_RenderThread"), - owner_loop_(MessageLoop::current()), - channel_name_(channel_name), +// When we run plugins in process, we actually run them on the render thread, +// which means that we need to make the render thread pump UI events. +RenderThread::RenderThread() + : ChildThread( + base::Thread::Options(RenderProcess::InProcessPlugins() ? + MessageLoop::TYPE_UI : MessageLoop::TYPE_DEFAULT, kStackSize)), visited_link_slave_(NULL), user_script_slave_(NULL), - render_dns_master_(NULL), - in_send_(0) { - DCHECK(owner_loop_); - base::Thread::Options options; - options.stack_size = kStackSize; - // When we run plugins in process, we actually run them on the render thread, - // which means that we need to make the render thread pump UI events. - if (RenderProcess::ShouldLoadPluginsInProcess()) - options.message_loop_type = MessageLoop::TYPE_UI; - StartWithOptions(options); + render_dns_master_(NULL) { } -RenderThread::~RenderThread() { - Stop(); +RenderThread::RenderThread(const std::wstring& channel_name) + : ChildThread( + base::Thread::Options(RenderProcess::InProcessPlugins() ? + MessageLoop::TYPE_UI : MessageLoop::TYPE_DEFAULT, kStackSize)), + visited_link_slave_(NULL), + user_script_slave_(NULL), + render_dns_master_(NULL) { + SetChannelName(channel_name); } -void RenderThread::OnChannelError() { - owner_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); +RenderThread::~RenderThread() { } -bool RenderThread::Send(IPC::Message* msg) { - in_send_++; - bool rv = channel_->Send(msg); - in_send_--; - return rv; +RenderThread* RenderThread::current() { + DCHECK(!IsPluginProcess()); + return static_cast(ChildThread::current()); } void RenderThread::AddFilter(IPC::ChannelProxy::MessageFilter* filter) { - channel_->AddFilter(filter); + channel()->AddFilter(filter); } void RenderThread::RemoveFilter(IPC::ChannelProxy::MessageFilter* filter) { - channel_->RemoveFilter(filter); + channel()->RemoveFilter(filter); } void RenderThread::Resolve(const char* name, size_t length) { return render_dns_master_->Resolve(name, length); } -void RenderThread::AddRoute(int32 routing_id, - IPC::Channel::Listener* listener) { - DCHECK(MessageLoop::current() == message_loop()); - - // This corresponds to the AddRoute call done in CreateView. - router_.AddRoute(routing_id, listener); -} - -void RenderThread::RemoveRoute(int32 routing_id) { - DCHECK(MessageLoop::current() == message_loop()); - - router_.RemoveRoute(routing_id); -} - void RenderThread::Init() { - DCHECK(!g_render_thread); - g_render_thread = this; - + ChildThread::Init(); notification_service_.reset(new NotificationService); - cache_stats_factory_.reset( new ScopedRunnableMethodFactory(this)); - channel_.reset(new IPC::SyncChannel(channel_name_, - IPC::Channel::MODE_CLIENT, this, NULL, owner_loop_, true, - RenderProcess::GetShutDownEvent())); - #if defined(OS_WIN) // The renderer thread should wind-up COM. CoInitialize(0); @@ -124,19 +97,10 @@ void RenderThread::Init() { visited_link_slave_ = new VisitedLinkSlave(); user_script_slave_ = new UserScriptSlave(); render_dns_master_.reset(new RenderDnsMaster()); - -#ifdef IPC_MESSAGE_LOG_ENABLED - IPC::Logging::current()->SetIPCSender(this); -#endif } void RenderThread::CleanUp() { - DCHECK(g_render_thread == this); - g_render_thread = NULL; - - // Need to destruct the SyncChannel to the browser before we go away because - // it caches a pointer to this thread. - channel_.reset(); + ChildThread::CleanUp(); // TODO(port) #if defined(OS_WIN) @@ -144,10 +108,6 @@ void RenderThread::CleanUp() { PluginChannelBase::CleanupChannels(); #endif -#ifdef IPC_MESSAGE_LOG_ENABLED - IPC::Logging::current()->SetIPCSender(NULL); -#endif - notification_service_.reset(); delete visited_link_slave_; @@ -172,30 +132,20 @@ void RenderThread::OnUpdateUserScripts( user_script_slave_->UpdateScripts(scripts); } -void RenderThread::OnMessageReceived(const IPC::Message& msg) { - // NOTE: We could subclass router_ to intercept OnControlMessageReceived, but - // it seems simpler to just process any control messages that we care about - // up-front and then send the rest of the messages onto router_. - - if (msg.routing_id() == MSG_ROUTING_CONTROL) { - IPC_BEGIN_MESSAGE_MAP(RenderThread, msg) - IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_NewTable, OnUpdateVisitedLinks) - IPC_MESSAGE_HANDLER(ViewMsg_SetNextPageID, OnSetNextPageID) - // TODO(port): removed from render_messages_internal.h; - // is there a new non-windows message I should add here? - IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView) - IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities, OnSetCacheCapacities) - IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats, - OnGetCacheResourceStats) - IPC_MESSAGE_HANDLER(ViewMsg_PluginMessage, OnPluginMessage) - IPC_MESSAGE_HANDLER(ViewMsg_UserScripts_NewScripts, - OnUpdateUserScripts) - // send the rest to the router - IPC_MESSAGE_UNHANDLED(router_.OnMessageReceived(msg)) - IPC_END_MESSAGE_MAP() - } else { - router_.OnMessageReceived(msg); - } +void RenderThread::OnControlMessageReceived(const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(RenderThread, msg) + IPC_MESSAGE_HANDLER(ViewMsg_VisitedLink_NewTable, OnUpdateVisitedLinks) + IPC_MESSAGE_HANDLER(ViewMsg_SetNextPageID, OnSetNextPageID) + // TODO(port): removed from render_messages_internal.h; + // is there a new non-windows message I should add here? + IPC_MESSAGE_HANDLER(ViewMsg_New, OnCreateNewView) + IPC_MESSAGE_HANDLER(ViewMsg_SetCacheCapacities, OnSetCacheCapacities) + IPC_MESSAGE_HANDLER(ViewMsg_GetCacheResourceStats, + OnGetCacheResourceStats) + IPC_MESSAGE_HANDLER(ViewMsg_PluginMessage, OnPluginMessage) + IPC_MESSAGE_HANDLER(ViewMsg_UserScripts_NewScripts, + OnUpdateUserScripts) + IPC_END_MESSAGE_MAP() } void RenderThread::OnPluginMessage(const FilePath& plugin_path, diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h index 44dd548..a3bd534 100644 --- a/chrome/renderer/render_thread.h +++ b/chrome/renderer/render_thread.h @@ -10,10 +10,8 @@ #include "base/gfx/native_widget_types.h" #include "base/shared_memory.h" #include "base/task.h" -#include "base/thread.h" #include "build/build_config.h" -#include "chrome/common/ipc_sync_channel.h" -#include "chrome/common/message_router.h" +#include "chrome/common/child_thread.h" class FilePath; class NotificationService; @@ -27,10 +25,12 @@ struct WebPreferences; // The RenderThreadBase is the minimal interface that a RenderView/Widget // expects from a render thread. The interface basically abstracts a way to send // and receive messages. -class RenderThreadBase : public IPC::Message::Sender { +class RenderThreadBase { public: virtual ~RenderThreadBase() {} + virtual bool Send(IPC::Message* msg) = 0; + // True if currently sending a message. virtual bool InSend() const = 0; @@ -52,21 +52,35 @@ class RenderThreadBase : public IPC::Message::Sender { // Most of the communication occurs in the form of IPC messages. They are // routed to the RenderThread according to the routing IDs of the messages. // The routing IDs correspond to RenderView instances. -class RenderThread : public IPC::Channel::Listener, - public RenderThreadBase, - public base::Thread { +class RenderThread : public RenderThreadBase, + public ChildThread { public: - explicit RenderThread(const std::wstring& channel_name); + // Grabs the IPC channel name from the command line. + RenderThread(); + // Constructor that's used when running in single process mode. + RenderThread(const std::wstring& channel_name); virtual ~RenderThread(); - // IPC::Channel::Listener implementation: - virtual void OnMessageReceived(const IPC::Message& msg); - virtual void OnChannelError(); - - // IPC::Message::Sender implementation: - virtual bool Send(IPC::Message* msg); + // Returns the one render thread for this process. Note that this should only + // be accessed when running on the render thread itself + static RenderThread* current(); // Overridded from RenderThreadBase. + virtual bool Send(IPC::Message* msg) { + return ChildThread::Send(msg); + } + + virtual bool InSend() const { + return ChildThread::InSend(); + } + + virtual void AddRoute(int32 routing_id, IPC::Channel::Listener* listener) { + return ChildThread::AddRoute(routing_id, listener); + } + virtual void RemoveRoute(int32 routing_id) { + return ChildThread::RemoveRoute(routing_id); + } + virtual void AddFilter(IPC::ChannelProxy::MessageFilter* filter); virtual void RemoveFilter(IPC::ChannelProxy::MessageFilter* filter); @@ -79,25 +93,17 @@ class RenderThread : public IPC::Channel::Listener, // Do DNS prefetch resolution of a hostname. void Resolve(const char* name, size_t length); - // See documentation on MessageRouter for AddRoute and RemoveRoute - virtual void AddRoute(int32 routing_id, IPC::Channel::Listener* listener); - virtual void RemoveRoute(int32 routing_id); - // Invokes InformHostOfCacheStats after a short delay. Used to move this // bookkeeping operation off the critical latency path. void InformHostOfCacheStatsLater(); - MessageLoop* owner_loop() { return owner_loop_; } - - // Indicates if RenderThread::Send() is on the call stack. - virtual bool InSend() const { return in_send_ != 0; } + private: + virtual void OnControlMessageReceived(const IPC::Message& msg); - protected: // Called by the thread base class virtual void Init(); virtual void CleanUp(); - private: void OnUpdateVisitedLinks(base::SharedMemoryHandle table); void OnUpdateUserScripts(base::SharedMemoryHandle table); @@ -119,16 +125,6 @@ class RenderThread : public IPC::Channel::Listener, // decisions about how to allocation resources using current information. void InformHostOfCacheStats(); - // The message loop used to run tasks on the thread that started this thread. - MessageLoop* owner_loop_; - - // Used only on the background render thread to implement message routing - // functionality to the consumers of the RenderThread. - MessageRouter router_; - - std::wstring channel_name_; - scoped_ptr channel_; - // These objects live solely on the render thread. VisitedLinkSlave* visited_link_slave_; UserScriptSlave* user_script_slave_; @@ -139,13 +135,7 @@ class RenderThread : public IPC::Channel::Listener, scoped_ptr notification_service_; - int in_send_; - DISALLOW_COPY_AND_ASSIGN(RenderThread); }; -// The global RenderThread object for this process. Note that this should only -// be accessed when running on the render thread itself. -extern RenderThread* g_render_thread; - #endif // CHROME_RENDERER_RENDER_THREAD_H_ diff --git a/chrome/renderer/render_thread_unittest.cc b/chrome/renderer/render_thread_unittest.cc index 12e6941..3d09c51 100644 --- a/chrome/renderer/render_thread_unittest.cc +++ b/chrome/renderer/render_thread_unittest.cc @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/string_util.h" #include "base/waitable_event.h" #include "chrome/common/ipc_sync_channel.h" #include "chrome/common/render_messages.h" @@ -12,39 +11,39 @@ namespace { -const char kThreadName[] = "render_thread_unittest"; +const wchar_t kThreadName[] = L"render_thread_unittest"; class RenderThreadTest : public testing::Test { public: virtual void SetUp() { - MockProcess::GlobalInit(); // Need a MODE_SERVER to make MODE_CLIENTs (like a RenderThread) happy. - channel_ = new IPC::Channel(ASCIIToWide(kThreadName), - IPC::Channel::MODE_SERVER, NULL); + channel_ = new IPC::Channel(kThreadName, IPC::Channel::MODE_SERVER, NULL); + mock_process_.reset(new MockProcess(new RenderThread(kThreadName))); } virtual void TearDown() { message_loop_.RunAllPending(); + mock_process_.reset(); + // Delete the server channel after the RenderThread so that + // IPC::SyncChannel's OnChannelError doesn't fire on the context and attempt + // to use the listener thread which is now gone. delete channel_; - MockProcess::GlobalCleanup(); + // Need to fully destruct IPC::SyncChannel before the message loop goes + // away. + message_loop_.RunAllPending(); } - private: + protected: MessageLoopForIO message_loop_; + scoped_ptr mock_process_; IPC::Channel *channel_; }; TEST_F(RenderThreadTest, TestGlobal) { - ASSERT_FALSE(g_render_thread); - { - RenderThread thread(ASCIIToWide(kThreadName)); - ASSERT_TRUE(g_render_thread); - } - ASSERT_FALSE(g_render_thread); + ASSERT_TRUE(RenderThread::current()); } TEST_F(RenderThreadTest, TestVisitedMsg) { - RenderThread thread(ASCIIToWide(kThreadName)); #if defined(OS_WIN) IPC::Message* msg = new ViewMsg_VisitedLink_NewTable(NULL); #elif defined(OS_POSIX) @@ -54,7 +53,7 @@ TEST_F(RenderThreadTest, TestVisitedMsg) { ASSERT_TRUE(msg); // Message goes nowhere, but this confirms Init() has happened. // Unusually (?), RenderThread() Start()s itself in it's constructor. - thread.Send(msg); + mock_process_->child_thread()->Send(msg); // No need to delete msg; per Message::Send() documentation, "The // implementor takes ownership of the given Message regardless of diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 9528187..d87b327 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -1461,8 +1461,8 @@ void RenderView::DidFinishDocumentLoadForFrame(WebView* webview, // Check whether we have new encoding name. UpdateEncoding(frame, webview->GetMainFrameEncodingName()); - if (g_render_thread) // Will be NULL during unit tests. - g_render_thread->user_script_slave()->InjectScripts( + if (RenderThread::current()) // Will be NULL during unit tests. + RenderThread::current()->user_script_slave()->InjectScripts( frame, UserScript::DOCUMENT_END); } @@ -1532,8 +1532,8 @@ void RenderView::WindowObjectCleared(WebFrame* webframe) { } void RenderView::DocumentElementAvailable(WebFrame* frame) { - if (g_render_thread) // Will be NULL during unit tests. - g_render_thread->user_script_slave()->InjectScripts( + if (RenderThread::current()) // Will be NULL during unit tests. + RenderThread::current()->user_script_slave()->InjectScripts( frame, UserScript::DOCUMENT_START); } @@ -1863,13 +1863,12 @@ WebWidget* RenderView::CreatePopupWidget(WebView* webview, static bool ShouldLoadPluginInProcess(const std::string& mime_type, bool* is_gears) { - if (RenderProcess::ShouldLoadPluginsInProcess()) + if (RenderProcess::current()->in_process_plugins()) return true; if (mime_type == "application/x-googlegears") { *is_gears = true; - return CommandLine::ForCurrentProcess()->HasSwitch( - switches::kGearsInRenderer); + return RenderProcess::current()->in_process_gears(); } return false; @@ -2866,8 +2865,8 @@ std::string RenderView::GetAltHTMLForTemplate( MessageLoop* RenderView::GetMessageLoopForIO() { // Assume that we have only one RenderThread in the process and the owner loop // of RenderThread is an IO message loop. - if (g_render_thread) - return g_render_thread->owner_loop(); + if (RenderThread::current()) + return RenderThread::current()->owner_loop(); return NULL; } diff --git a/chrome/renderer/render_view_unittest.cc b/chrome/renderer/render_view_unittest.cc index 82aff43..6778eb9 100644 --- a/chrome/renderer/render_view_unittest.cc +++ b/chrome/renderer/render_view_unittest.cc @@ -60,7 +60,7 @@ class RenderViewTest : public testing::Test { // testing::Test virtual void SetUp() { - MockProcess::GlobalInit(); + mock_process_.reset(new MockProcess()); render_thread_.set_routing_id(kRouteId); @@ -77,15 +77,13 @@ class RenderViewTest : public testing::Test { view_ = NULL; - // There is a delayed task that the child process posts to terminate the - // message loop so we need to spin the message loop to delete the task. - MockProcess::GlobalCleanup(); - msg_loop_.Run(); + mock_process_.reset(); + msg_loop_.RunAllPending(); } MessageLoop msg_loop_; MockRenderThread render_thread_; - + scoped_ptr mock_process_; scoped_refptr view_; }; diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc index b42ff18..c24e83f 100644 --- a/chrome/renderer/render_widget.cc +++ b/chrome/renderer/render_widget.cc @@ -98,21 +98,21 @@ RenderWidget::RenderWidget(RenderThreadBase* render_thread, bool activatable) ime_control_updated_(false), ime_control_busy_(false), activatable_(activatable) { - RenderProcess::AddRefProcess(); + RenderProcess::current()->AddRefProcess(); DCHECK(render_thread_); } RenderWidget::~RenderWidget() { DCHECK(!webwidget_) << "Leaking our WebWidget!"; if (current_paint_buf_) { - RenderProcess::ReleaseTransportDIB(current_paint_buf_); + RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_); current_paint_buf_ = NULL; } if (current_scroll_buf_) { - RenderProcess::ReleaseTransportDIB(current_scroll_buf_); + RenderProcess::current()->ReleaseTransportDIB(current_scroll_buf_); current_scroll_buf_ = NULL; } - RenderProcess::ReleaseProcess(); + RenderProcess::current()->ReleaseProcess(); } /*static*/ @@ -298,7 +298,7 @@ void RenderWidget::OnPaintRectAck() { // If we sent a PaintRect message with a zero-sized bitmap, then // we should have no current paint buf. if (current_paint_buf_) { - RenderProcess::ReleaseTransportDIB(current_paint_buf_); + RenderProcess::current()->ReleaseTransportDIB(current_paint_buf_); current_paint_buf_ = NULL; } @@ -310,7 +310,7 @@ void RenderWidget::OnScrollRectAck() { DCHECK(scroll_reply_pending()); if (current_scroll_buf_) { - RenderProcess::ReleaseTransportDIB(current_scroll_buf_); + RenderProcess::current()->ReleaseTransportDIB(current_scroll_buf_); current_scroll_buf_ = NULL; } @@ -403,7 +403,7 @@ void RenderWidget::DoDeferredPaint() { // Compute a buffer for painting and cache it. skia::PlatformCanvas* canvas = - RenderProcess::GetDrawingCanvas(¤t_paint_buf_, damaged_rect); + RenderProcess::current()->GetDrawingCanvas(¤t_paint_buf_, damaged_rect); if (!canvas) { NOTREACHED(); return; @@ -480,7 +480,7 @@ void RenderWidget::DoDeferredScroll() { damaged_rect = scroll_rect_.Intersect(damaged_rect); skia::PlatformCanvas* canvas = - RenderProcess::GetDrawingCanvas(¤t_scroll_buf_, damaged_rect); + RenderProcess::current()->GetDrawingCanvas(¤t_scroll_buf_, damaged_rect); if (!canvas) { NOTREACHED(); return; diff --git a/chrome/renderer/render_widget.h b/chrome/renderer/render_widget.h index b0c4b11..edcc5af 100644 --- a/chrome/renderer/render_widget.h +++ b/chrome/renderer/render_widget.h @@ -32,7 +32,7 @@ class RenderWidget : public IPC::Channel::Listener, public: // Creates a new RenderWidget. The opener_id is the routing ID of the // RenderView that this widget lives inside. The render_thread is any - // RenderThreadBase implementation, mostly commonly g_render_thread. + // RenderThreadBase implementation, mostly commonly RenderThread::current(). static RenderWidget* Create(int32 opener_id, RenderThreadBase* render_thread, bool activatable); diff --git a/chrome/renderer/render_widget_unittest.cc b/chrome/renderer/render_widget_unittest.cc index 6c2b24f..6937a64 100644 --- a/chrome/renderer/render_widget_unittest.cc +++ b/chrome/renderer/render_widget_unittest.cc @@ -28,20 +28,17 @@ class RenderWidgetTest : public testing::Test { private: // testing::Test virtual void SetUp() { - MockProcess::GlobalInit(); - + mock_process_.reset(new MockProcess()); render_thread_.set_routing_id(kRouteId); widget_ = RenderWidget::Create(kOpenerId, &render_thread_, true); ASSERT_TRUE(widget_); } virtual void TearDown() { widget_ = NULL; - - // There is a delayed task that the child process posts to terminate the - // message loop so we need to spin the message loop to delete the task. - MockProcess::GlobalCleanup(); - msg_loop_.Run(); + mock_process_.reset(); } + + scoped_ptr mock_process_; }; } // namespace diff --git a/chrome/renderer/renderer_glue.cc b/chrome/renderer/renderer_glue.cc index a65f326..7ccf018 100644 --- a/chrome/renderer/renderer_glue.cc +++ b/chrome/renderer/renderer_glue.cc @@ -134,14 +134,14 @@ ScopedClipboardWriterGlue::~ScopedClipboardWriterGlue() { #if defined(OS_WIN) if (shared_buf_) { - g_render_thread->Send( + RenderThread::current()->Send( new ViewHostMsg_ClipboardWriteObjectsSync(objects_)); delete shared_buf_; return; } #endif - g_render_thread->Send( + RenderThread::current()->Send( new ViewHostMsg_ClipboardWriteObjectsAsync(objects_)); } @@ -183,7 +183,7 @@ bool GetMimeTypeFromExtension(const FilePath::StringType &ext, // The sandbox restricts our access to the registry, so we need to proxy // these calls over to the browser process. DCHECK(mime_type->empty()); - g_render_thread->Send( + RenderThread::current()->Send( new ViewHostMsg_GetMimeTypeFromExtension(ext, mime_type)); return !mime_type->empty(); } @@ -196,7 +196,7 @@ bool GetMimeTypeFromFile(const FilePath &file_path, // The sandbox restricts our access to the registry, so we need to proxy // these calls over to the browser process. DCHECK(mime_type->empty()); - g_render_thread->Send( + RenderThread::current()->Send( new ViewHostMsg_GetMimeTypeFromFile(file_path, mime_type)); return !mime_type->empty(); } @@ -209,7 +209,7 @@ bool GetPreferredExtensionForMimeType(const std::string& mime_type, // The sandbox restricts our access to the registry, so we need to proxy // these calls over to the browser process. DCHECK(ext->empty()); - g_render_thread->Send( + RenderThread::current()->Send( new ViewHostMsg_GetPreferredExtensionForMimeType(mime_type, ext)); return !ext->empty(); } @@ -246,21 +246,21 @@ bool ClipboardIsFormatAvailable(Clipboard::FormatType format) { bool ClipboardIsFormatAvailable(unsigned int format) { bool result; - g_render_thread->Send( + RenderThread::current()->Send( new ViewHostMsg_ClipboardIsFormatAvailable(format, &result)); return result; } void ClipboardReadText(std::wstring* result) { - g_render_thread->Send(new ViewHostMsg_ClipboardReadText(result)); + RenderThread::current()->Send(new ViewHostMsg_ClipboardReadText(result)); } void ClipboardReadAsciiText(std::string* result) { - g_render_thread->Send(new ViewHostMsg_ClipboardReadAsciiText(result)); + RenderThread::current()->Send(new ViewHostMsg_ClipboardReadAsciiText(result)); } void ClipboardReadHTML(std::wstring* markup, GURL* url) { - g_render_thread->Send(new ViewHostMsg_ClipboardReadHTML(markup, url)); + RenderThread::current()->Send(new ViewHostMsg_ClipboardReadHTML(markup, url)); } GURL GetInspectorURL() { @@ -271,9 +271,8 @@ std::string GetUIResourceProtocol() { return "chrome"; } -bool GetPlugins(bool refresh, - std::vector* plugins) { - return g_render_thread->Send( +bool GetPlugins(bool refresh, std::vector* plugins) { + return RenderThread::current()->Send( new ViewHostMsg_GetPlugins(refresh, plugins)); } @@ -281,33 +280,24 @@ bool GetPlugins(bool refresh, bool EnsureFontLoaded(HFONT font) { LOGFONT logfont; GetObject(font, sizeof(LOGFONT), &logfont); - return g_render_thread->Send(new ViewHostMsg_LoadFont(logfont)); + return RenderThread::current()->Send(new ViewHostMsg_LoadFont(logfont)); } #endif webkit_glue::ScreenInfo GetScreenInfo(gfx::NativeViewId window) { webkit_glue::ScreenInfo results; - g_render_thread->Send( + RenderThread::current()->Send( new ViewHostMsg_GetScreenInfo(window, &results)); return results; } uint64 VisitedLinkHash(const char* canonical_url, size_t length) { - return g_render_thread->visited_link_slave()->ComputeURLFingerprint( + return RenderThread::current()->visited_link_slave()->ComputeURLFingerprint( canonical_url, length); } bool IsLinkVisited(uint64 link_hash) { - return g_render_thread->visited_link_slave()->IsVisited(link_hash); -} - -int ResolveProxyFromRenderThread(const GURL& url, std::string* proxy_result) { - // Send a synchronous IPC from renderer process to the browser process to - // resolve the proxy. (includes --single-process case). - int net_error; - bool ipc_ok = g_render_thread->Send( - new ViewHostMsg_ResolveProxy(url, &net_error, proxy_result)); - return ipc_ok ? net_error : net::ERR_UNEXPECTED; + return RenderThread::current()->visited_link_slave()->IsVisited(link_hash); } #ifndef USING_SIMPLE_RESOURCE_LOADER_BRIDGE @@ -354,12 +344,12 @@ ResourceLoaderBridge* ResourceLoaderBridge::Create( void SetCookie(const GURL& url, const GURL& policy_url, const std::string& cookie) { - g_render_thread->Send(new ViewHostMsg_SetCookie(url, policy_url, cookie)); + RenderThread::current()->Send(new ViewHostMsg_SetCookie(url, policy_url, cookie)); } std::string GetCookies(const GURL& url, const GURL& policy_url) { std::string cookies; - g_render_thread->Send(new ViewHostMsg_GetCookies(url, policy_url, &cookies)); + RenderThread::current()->Send(new ViewHostMsg_GetCookies(url, policy_url, &cookies)); return cookies; } @@ -367,8 +357,8 @@ void NotifyCacheStats() { // Update the browser about our cache // NOTE: Since this can be called from the plugin process, we might not have // a RenderThread. Do nothing in that case. - if (g_render_thread) - g_render_thread->InformHostOfCacheStatsLater(); + if (!IsPluginProcess()) + RenderThread::current()->InformHostOfCacheStatsLater(); } #endif // !USING_SIMPLE_RESOURCE_LOADER_BRIDGE diff --git a/chrome/renderer/renderer_main.cc b/chrome/renderer/renderer_main.cc index c376486..8ca5346 100644 --- a/chrome/renderer/renderer_main.cc +++ b/chrome/renderer/renderer_main.cc @@ -90,9 +90,8 @@ int RendererMain(const MainFunctionParams& parameters) { HandleRendererErrorTestParameters(parsed_command_line); - std::wstring channel_name = - parsed_command_line.GetSwitchValue(switches::kProcessChannelID); - if (RenderProcess::GlobalInit(channel_name)) { + { + RenderProcess render_process; bool run_loop = true; if (!no_sandbox) { run_loop = platform.EnableSandbox(); @@ -108,8 +107,6 @@ int RendererMain(const MainFunctionParams& parameters) { if (pool) pool->Recycle(); MessageLoop::current()->Run(); } - - RenderProcess::GlobalCleanup(); } platform.PlatformUninitialize(); return 0; diff --git a/chrome/renderer/webplugin_delegate_proxy.cc b/chrome/renderer/webplugin_delegate_proxy.cc index 155c19a..bc0754e 100644 --- a/chrome/renderer/webplugin_delegate_proxy.cc +++ b/chrome/renderer/webplugin_delegate_proxy.cc @@ -209,12 +209,12 @@ bool WebPluginDelegateProxy::Initialize(const GURL& url, char** argn, bool load_manually) { std::wstring channel_name; FilePath plugin_path; - if (!g_render_thread->Send(new ViewHostMsg_OpenChannelToPlugin( + if (!RenderThread::current()->Send(new ViewHostMsg_OpenChannelToPlugin( url, mime_type_, clsid_, webkit_glue::GetWebKitLocale(), &channel_name, &plugin_path))) return false; - MessageLoop* ipc_message_loop = g_render_thread->owner_loop(); + MessageLoop* ipc_message_loop = RenderThread::current()->owner_loop(); scoped_refptr channel_host = PluginChannelHost::GetPluginChannelHost(channel_name, ipc_message_loop); if (!channel_host.get()) -- cgit v1.1