| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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 "build/build_config.h" | 5 #include "build/build_config.h" |
| 6 | 6 |
| 7 #if defined(OS_WIN) | 7 #if defined(OS_WIN) |
| 8 #include <windows.h> | 8 #include <windows.h> |
| 9 #include <objidl.h> | 9 #include <objidl.h> |
| 10 #include <mlang.h> | 10 #include <mlang.h> |
| 11 #endif | 11 #endif |
| 12 | 12 |
| 13 #include "chrome/renderer/render_process.h" | 13 #include "chrome/renderer/render_process.h" |
| 14 | 14 |
| 15 #include "base/basictypes.h" | 15 #include "base/basictypes.h" |
| 16 #include "base/command_line.h" | 16 #include "base/command_line.h" |
| 17 #include "base/compiler_specific.h" | 17 #include "base/compiler_specific.h" |
| 18 #include "base/message_loop.h" | 18 #include "base/message_loop.h" |
| 19 #include "base/histogram.h" | 19 #include "base/histogram.h" |
| 20 #include "base/path_service.h" | 20 #include "base/path_service.h" |
| 21 #include "base/sys_info.h" | 21 #include "base/sys_info.h" |
| 22 #include "chrome/browser/net/dns_global.h" // TODO(jar): DNS calls should be re
nderer specific, not including browser. | 22 #include "chrome/browser/net/dns_global.h" // TODO(jar): DNS calls should be re
nderer specific, not including browser. |
| 23 #include "chrome/common/chrome_switches.h" | 23 #include "chrome/common/chrome_switches.h" |
| 24 #include "chrome/common/chrome_paths.h" | 24 #include "chrome/common/chrome_paths.h" |
| 25 #include "chrome/common/ipc_channel.h" | 25 #include "chrome/common/ipc_channel.h" |
| 26 #include "chrome/common/ipc_message_utils.h" | 26 #include "chrome/common/ipc_message_utils.h" |
| 27 #include "chrome/common/render_messages.h" | 27 #include "chrome/common/render_messages.h" |
| 28 #include "chrome/common/transport_dib.h" |
| 28 #include "chrome/renderer/render_view.h" | 29 #include "chrome/renderer/render_view.h" |
| 29 #include "webkit/glue/webkit_glue.h" | 30 #include "webkit/glue/webkit_glue.h" |
| 30 | 31 |
| 31 //----------------------------------------------------------------------------- | 32 //----------------------------------------------------------------------------- |
| 32 | 33 |
| 33 bool RenderProcess::load_plugins_in_process_ = false; | 34 bool RenderProcess::load_plugins_in_process_ = false; |
| 34 | 35 |
| 35 //----------------------------------------------------------------------------- | 36 //----------------------------------------------------------------------------- |
| 36 | 37 |
| 37 RenderProcess::RenderProcess(const std::wstring& channel_name) | 38 RenderProcess::RenderProcess(const std::wstring& channel_name) |
| 38 : render_thread_(channel_name), | 39 : render_thread_(channel_name), |
| 39 ALLOW_THIS_IN_INITIALIZER_LIST(clearer_factory_(this)) { | 40 ALLOW_THIS_IN_INITIALIZER_LIST(shared_mem_cache_cleaner_( |
| 41 base::TimeDelta::FromSeconds(5), |
| 42 this, &RenderProcess::ClearTransportDIBCache)), |
| 43 sequence_number_(0) { |
| 40 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) | 44 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) |
| 41 shared_mem_cache_[i] = NULL; | 45 shared_mem_cache_[i] = NULL; |
| 42 } | 46 } |
| 43 | 47 |
| 44 RenderProcess::~RenderProcess() { | 48 RenderProcess::~RenderProcess() { |
| 45 // We need to stop the RenderThread as the clearer_factory_ | 49 // We need to stop the RenderThread as the clearer_factory_ |
| 46 // member could be in use while the object itself is destroyed, | 50 // member could be in use while the object itself is destroyed, |
| 47 // as a result of the containing RenderProcess object being destroyed. | 51 // as a result of the containing RenderProcess object being destroyed. |
| 48 // This race condition causes a crash when the renderer process is shutting | 52 // This race condition causes a crash when the renderer process is shutting |
| 49 // down. | 53 // down. |
| 50 render_thread_.Stop(); | 54 render_thread_.Stop(); |
| 51 ClearSharedMemCache(); | 55 ClearTransportDIBCache(); |
| 52 } | 56 } |
| 53 | 57 |
| 54 // static | 58 // static |
| 55 bool RenderProcess::GlobalInit(const std::wstring &channel_name) { | 59 bool RenderProcess::GlobalInit(const std::wstring &channel_name) { |
| 56 #if defined(OS_WIN) | 60 #if defined(OS_WIN) |
| 57 // HACK: See http://b/issue?id=1024307 for rationale. | 61 // HACK: See http://b/issue?id=1024307 for rationale. |
| 58 if (GetModuleHandle(L"LPK.DLL") == NULL) { | 62 if (GetModuleHandle(L"LPK.DLL") == NULL) { |
| 59 // Makes sure lpk.dll is loaded by gdi32 to make sure ExtTextOut() works | 63 // Makes sure lpk.dll is loaded by gdi32 to make sure ExtTextOut() works |
| 60 // when buffering into a EMF buffer for printing. | 64 // when buffering into a EMF buffer for printing. |
| 61 typedef BOOL (__stdcall *GdiInitializeLanguagePack)(int LoadedShapingDLLs); | 65 typedef BOOL (__stdcall *GdiInitializeLanguagePack)(int LoadedShapingDLLs); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 // static | 121 // static |
| 118 void RenderProcess::GlobalCleanup() { | 122 void RenderProcess::GlobalCleanup() { |
| 119 ChildProcess::GlobalCleanup(); | 123 ChildProcess::GlobalCleanup(); |
| 120 } | 124 } |
| 121 | 125 |
| 122 // static | 126 // static |
| 123 bool RenderProcess::ShouldLoadPluginsInProcess() { | 127 bool RenderProcess::ShouldLoadPluginsInProcess() { |
| 124 return load_plugins_in_process_; | 128 return load_plugins_in_process_; |
| 125 } | 129 } |
| 126 | 130 |
| 131 // ----------------------------------------------------------------------------- |
| 132 // Platform specific code for dealing with bitmap transport... |
| 133 |
| 134 // ----------------------------------------------------------------------------- |
| 135 // Create a platform canvas object which renders into the given transport |
| 136 // memory. |
| 137 // ----------------------------------------------------------------------------- |
| 138 static skia::PlatformCanvas* CanvasFromTransportDIB( |
| 139 TransportDIB* dib, const gfx::Rect& rect) { |
| 140 #if defined(OS_WIN) |
| 141 return new skia::PlatformCanvas(rect.width(), rect.height(), true, |
| 142 dib->handle()); |
| 143 #elif defined(OS_LINUX) || defined(OS_MACOSX) |
| 144 return new skia::PlatformCanvas(rect.width(), rect.height(), true, |
| 145 reinterpret_cast<uint8_t*>(dib->memory())); |
| 146 #endif |
| 147 } |
| 148 |
| 149 TransportDIB* RenderProcess::CreateTransportDIB(size_t size) { |
| 150 #if defined(OS_WIN) || defined(OS_LINUX) |
| 151 // Windows and Linux create transport DIBs inside the renderer |
| 152 return TransportDIB::Create(size, sequence_number_++); |
| 153 #elif defined(OS_MACOSX) // defined(OS_WIN) || defined(OS_LINUX) |
| 154 // Mac creates transport DIBs in the browser, so we need to do a sync IPC to |
| 155 // get one. |
| 156 IPC::Maybe<TransportDIB::Handle> mhandle; |
| 157 IPC::Message* msg = new ViewHostMsg_AllocTransportDIB(size, &mhandle); |
| 158 if (!render_thread_.Send(msg)) |
| 159 return NULL; |
| 160 if (!mhandle.valid) |
| 161 return NULL; |
| 162 return TransportDIB::Map(mhandle.value); |
| 163 #endif // defined(OS_MACOSX) |
| 164 } |
| 165 |
| 166 void RenderProcess::FreeTransportDIB(TransportDIB* dib) { |
| 167 if (!dib) |
| 168 return; |
| 169 |
| 170 #if defined(OS_MACOSX) |
| 171 // On Mac we need to tell the browser that it can drop a reference to the |
| 172 // shared memory. |
| 173 IPC::Message* msg = new ViewHostMsg_FreeTransportDIB(dib->id()); |
| 174 render_thread_.Send(msg); |
| 175 #endif |
| 176 |
| 177 delete dib; |
| 178 } |
| 179 |
| 180 // ----------------------------------------------------------------------------- |
| 181 |
| 182 |
| 127 // static | 183 // static |
| 128 base::SharedMemory* RenderProcess::AllocSharedMemory(size_t size) { | 184 skia::PlatformCanvas* RenderProcess::GetDrawingCanvas( |
| 129 self()->clearer_factory_.RevokeAll(); | 185 TransportDIB** memory, const gfx::Rect& rect) { |
| 186 const size_t stride = skia::PlatformCanvas::StrideForWidth(rect.width()); |
| 187 const size_t size = stride * rect.height(); |
| 130 | 188 |
| 131 base::SharedMemory* mem = self()->GetSharedMemFromCache(size); | 189 if (!self()->GetTransportDIBFromCache(memory, size)) { |
| 132 if (mem) | 190 *memory = self()->CreateTransportDIB(size); |
| 133 return mem; | 191 if (!*memory) |
| 134 | 192 return false; |
| 135 // Round-up size to allocation granularity | |
| 136 size_t allocation_granularity = base::SysInfo::VMAllocationGranularity(); | |
| 137 size = size / allocation_granularity + 1; | |
| 138 size = size * allocation_granularity; | |
| 139 | |
| 140 mem = new base::SharedMemory(); | |
| 141 if (!mem) | |
| 142 return NULL; | |
| 143 if (!mem->Create(L"", false, true, size)) { | |
| 144 delete mem; | |
| 145 return NULL; | |
| 146 } | 193 } |
| 147 | 194 |
| 148 return mem; | 195 return CanvasFromTransportDIB(*memory, rect); |
| 149 } | 196 } |
| 150 | 197 |
| 151 // static | 198 // static |
| 152 void RenderProcess::FreeSharedMemory(base::SharedMemory* mem) { | 199 void RenderProcess::ReleaseTransportDIB(TransportDIB* mem) { |
| 153 if (self()->PutSharedMemInCache(mem)) { | 200 if (self()->PutSharedMemInCache(mem)) { |
| 154 self()->ScheduleCacheClearer(); | 201 self()->shared_mem_cache_cleaner_.Reset(); |
| 155 return; | 202 return; |
| 156 } | 203 } |
| 157 DeleteSharedMem(mem); | 204 |
| 205 self()->FreeTransportDIB(mem); |
| 158 } | 206 } |
| 159 | 207 |
| 160 // static | 208 bool RenderProcess::GetTransportDIBFromCache(TransportDIB** mem, |
| 161 void RenderProcess::DeleteSharedMem(base::SharedMemory* mem) { | 209 size_t size) { |
| 162 delete mem; | |
| 163 } | |
| 164 | |
| 165 base::SharedMemory* RenderProcess::GetSharedMemFromCache(size_t size) { | |
| 166 // look for a cached object that is suitable for the requested size. | 210 // look for a cached object that is suitable for the requested size. |
| 167 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | 211 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { |
| 168 base::SharedMemory* mem = shared_mem_cache_[i]; | 212 if (shared_mem_cache_[i] && |
| 169 if (mem && mem->max_size() >= size) { | 213 size <= shared_mem_cache_[i]->size()) { |
| 214 *mem = shared_mem_cache_[i]; |
| 170 shared_mem_cache_[i] = NULL; | 215 shared_mem_cache_[i] = NULL; |
| 171 return mem; | |
| 172 } | |
| 173 } | |
| 174 return NULL; | |
| 175 } | |
| 176 | |
| 177 bool RenderProcess::PutSharedMemInCache(base::SharedMemory* mem) { | |
| 178 // simple algorithm: | |
| 179 // - look for an empty slot to store mem, or | |
| 180 // - if full, then replace any existing cache entry that is smaller than the | |
| 181 // given shared memory object. | |
| 182 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | |
| 183 if (!shared_mem_cache_[i]) { | |
| 184 shared_mem_cache_[i] = mem; | |
| 185 return true; | 216 return true; |
| 186 } | 217 } |
| 187 } | 218 } |
| 188 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | 219 |
| 189 base::SharedMemory* cached_mem = shared_mem_cache_[i]; | |
| 190 if (cached_mem->max_size() < mem->max_size()) { | |
| 191 shared_mem_cache_[i] = mem; | |
| 192 DeleteSharedMem(cached_mem); | |
| 193 return true; | |
| 194 } | |
| 195 } | |
| 196 return false; | 220 return false; |
| 197 } | 221 } |
| 198 | 222 |
| 199 void RenderProcess::ClearSharedMemCache() { | 223 int RenderProcess::FindFreeCacheSlot(size_t size) { |
| 224 // simple algorithm: |
| 225 // - look for an empty slot to store mem, or |
| 226 // - if full, then replace smallest entry which is smaller than |size| |
| 227 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { |
| 228 if (shared_mem_cache_[i] == NULL) |
| 229 return i; |
| 230 } |
| 231 |
| 232 size_t smallest_size = size; |
| 233 int smallest_index = -1; |
| 234 |
| 235 for (size_t i = 1; i < arraysize(shared_mem_cache_); ++i) { |
| 236 const size_t entry_size = shared_mem_cache_[i]->size(); |
| 237 if (entry_size < smallest_size) { |
| 238 smallest_size = entry_size; |
| 239 smallest_index = i; |
| 240 } |
| 241 } |
| 242 |
| 243 if (smallest_index != -1) { |
| 244 FreeTransportDIB(shared_mem_cache_[smallest_index]); |
| 245 shared_mem_cache_[smallest_index] = NULL; |
| 246 } |
| 247 |
| 248 return smallest_index; |
| 249 } |
| 250 |
| 251 bool RenderProcess::PutSharedMemInCache(TransportDIB* mem) { |
| 252 const int slot = FindFreeCacheSlot(mem->size()); |
| 253 if (slot == -1) |
| 254 return false; |
| 255 |
| 256 shared_mem_cache_[slot] = mem; |
| 257 return true; |
| 258 } |
| 259 |
| 260 void RenderProcess::ClearTransportDIBCache() { |
| 200 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { | 261 for (size_t i = 0; i < arraysize(shared_mem_cache_); ++i) { |
| 201 if (shared_mem_cache_[i]) { | 262 if (shared_mem_cache_[i]) { |
| 202 DeleteSharedMem(shared_mem_cache_[i]); | 263 FreeTransportDIB(shared_mem_cache_[i]); |
| 203 shared_mem_cache_[i] = NULL; | 264 shared_mem_cache_[i] = NULL; |
| 204 } | 265 } |
| 205 } | 266 } |
| 206 } | 267 } |
| 207 | 268 |
| 208 void RenderProcess::ScheduleCacheClearer() { | |
| 209 // If we already have a deferred clearer, then revoke it so we effectively | |
| 210 // delay cache clearing until idle for our desired interval. | |
| 211 clearer_factory_.RevokeAll(); | |
| 212 | |
| 213 MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
| 214 clearer_factory_.NewRunnableMethod(&RenderProcess::ClearSharedMemCache), | |
| 215 5000 /* 5 seconds */); | |
| 216 } | |
| 217 | |
| 218 void RenderProcess::Cleanup() { | 269 void RenderProcess::Cleanup() { |
| 219 // TODO(port) | 270 // TODO(port) |
| 220 // Try and limit what we pull in for our non-Win unit test bundle | 271 // Try and limit what we pull in for our non-Win unit test bundle |
| 221 #ifndef NDEBUG | 272 #ifndef NDEBUG |
| 222 // log important leaked objects | 273 // log important leaked objects |
| 223 webkit_glue::CheckForLeaks(); | 274 webkit_glue::CheckForLeaks(); |
| 224 #endif | 275 #endif |
| 225 } | 276 } |
| OLD | NEW |