diff options
author | epenner@chromium.org <epenner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-15 21:13:33 +0000 |
---|---|---|
committer | epenner@chromium.org <epenner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-15 21:13:33 +0000 |
commit | a2e99f4d09f6fd48236c39665d68b155edd7465b (patch) | |
tree | 14cd586067c72820f6ed8e5134c9f473ef639cee /ui/gl | |
parent | 6df15b3fb7493528e01770a4ef66266e1229d5f9 (diff) | |
download | chromium_src-a2e99f4d09f6fd48236c39665d68b155edd7465b.zip chromium_src-a2e99f4d09f6fd48236c39665d68b155edd7465b.tar.gz chromium_src-a2e99f4d09f6fd48236c39665d68b155edd7465b.tar.bz2 |
gpu: Reduce shared memory duplication.
This uses a safe shared memory pool to prevent
duplicating the same shared memory twice.
BUG=176197
NOTRY=true
No try since it's Android only.
Review URL: https://chromiumcodereview.appspot.com/12258043
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182823 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/gl')
-rw-r--r-- | ui/gl/async_pixel_transfer_delegate_android.cc | 74 | ||||
-rw-r--r-- | ui/gl/gl.gyp | 2 | ||||
-rw-r--r-- | ui/gl/safe_shared_memory_pool.cc | 135 | ||||
-rw-r--r-- | ui/gl/safe_shared_memory_pool.h | 88 |
4 files changed, 259 insertions, 40 deletions
diff --git a/ui/gl/async_pixel_transfer_delegate_android.cc b/ui/gl/async_pixel_transfer_delegate_android.cc index be5ee6c..cd934a5 100644 --- a/ui/gl/async_pixel_transfer_delegate_android.cc +++ b/ui/gl/async_pixel_transfer_delegate_android.cc @@ -21,6 +21,7 @@ #include "ui/gl/gl_bindings.h" #include "ui/gl/gl_context.h" #include "ui/gl/gl_surface_egl.h" +#include "ui/gl/safe_shared_memory_pool.h" // TODO(epenner): Move thread priorities to base. (crbug.com/170549) #include <sys/resource.h> @@ -77,29 +78,6 @@ void DoFullTexSubImage2D(const AsyncTexImage2DParams& tex_params, void* data) { tex_params.format, tex_params.type, data); } - -// We duplicate shared memory to avoid use-after-free issues. This could also -// be solved by ref-counting something, or with a destruction callback. There -// wasn't an obvious hook or ref-counted container, so for now we dup/mmap. -SharedMemory* DuplicateSharedMemory(SharedMemory* shared_memory, uint32 size) { - // Duplicate the handle. - SharedMemoryHandle duped_shared_memory_handle; - if (!shared_memory->ShareToProcess( - base::GetCurrentProcessHandle(), - &duped_shared_memory_handle)) { - CHECK(false); // Diagnosing a crash. - return NULL; - } - scoped_ptr<SharedMemory> duped_shared_memory( - new SharedMemory(duped_shared_memory_handle, false)); - // Map the shared memory into this process. This validates the size. - if (!duped_shared_memory->Map(size)) { - CHECK(false); // Diagnosing a crash. - return NULL; - } - return duped_shared_memory.release(); -} - // Gets the address of the data from shared memory. void* GetAddress(SharedMemory* shared_memory, uint32 shm_data_offset) { // Memory bounds have already been validated, so there @@ -140,10 +118,16 @@ class TransferThread : public base::Thread { context_ = NULL; } + SafeSharedMemoryPool* safe_shared_memory_pool() { + return &safe_shared_memory_pool_; + } + private: scoped_refptr<gfx::GLContext> context_; scoped_refptr<gfx::GLSurface> surface_; + SafeSharedMemoryPool safe_shared_memory_pool_; + DISALLOW_COPY_AND_ASSIGN(TransferThread); }; @@ -154,6 +138,11 @@ base::MessageLoopProxy* transfer_message_loop_proxy() { return g_transfer_thread.Pointer()->message_loop_proxy(); } +SafeSharedMemoryPool* safe_shared_memory_pool() { + return g_transfer_thread.Pointer()->safe_shared_memory_pool(); +} + + } // namespace // Class which holds async pixel transfers state (EGLImage). @@ -352,13 +341,13 @@ class AsyncPixelTransferDelegateAndroid static void PerformAsyncTexImage2D( TransferStateInternal* state, AsyncTexImage2DParams tex_params, - base::SharedMemory* shared_memory, - uint32 shared_memory_data_offset); + AsyncMemoryParams mem_params, + ScopedSafeSharedMemory* safe_shared_memory); static void PerformAsyncTexSubImage2D( TransferStateInternal* state, AsyncTexSubImage2DParams tex_params, - base::SharedMemory* shared_memory, - uint32 shared_memory_data_offset); + AsyncMemoryParams mem_params, + ScopedSafeSharedMemory* safe_shared_memory); // Returns true if a work-around was used. bool WorkAroundAsyncTexImage2D( @@ -479,9 +468,10 @@ void AsyncPixelTransferDelegateAndroid::AsyncTexImage2D( &AsyncPixelTransferDelegateAndroid::PerformAsyncTexImage2D, base::Unretained(state.get()), // This is referenced in reply below. tex_params, - base::Owned(DuplicateSharedMemory(mem_params.shared_memory, - mem_params.shm_size)), - mem_params.shm_data_offset), + mem_params, + base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), + mem_params.shared_memory, + mem_params.shm_size))), base::Bind( &AsyncPixelTransferDelegateAndroid::AsyncTexImage2DCompleted, AsWeakPtr(), @@ -524,9 +514,10 @@ void AsyncPixelTransferDelegateAndroid::AsyncTexSubImage2D( &AsyncPixelTransferDelegateAndroid::PerformAsyncTexSubImage2D, base::Unretained(state.get()), // This is referenced in reply below. tex_params, - base::Owned(DuplicateSharedMemory(mem_params.shared_memory, - mem_params.shm_size)), - mem_params.shm_data_offset), + mem_params, + base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(), + mem_params.shared_memory, + mem_params.shm_size))), base::Bind( &AsyncPixelTransferDelegateAndroid::AsyncTexSubImage2DCompleted, AsWeakPtr(), @@ -570,8 +561,8 @@ void SetGlParametersForEglImageTexture() { void AsyncPixelTransferDelegateAndroid::PerformAsyncTexImage2D( TransferStateInternal* state, AsyncTexImage2DParams tex_params, - base::SharedMemory* shared_memory, - uint32 shared_memory_data_offset) { + AsyncMemoryParams mem_params, + ScopedSafeSharedMemory* safe_shared_memory) { TRACE_EVENT2("gpu", "PerformAsyncTexImage", "width", tex_params.width, "height", tex_params.height); @@ -580,7 +571,8 @@ void AsyncPixelTransferDelegateAndroid::PerformAsyncTexImage2D( DCHECK_EQ(0, tex_params.level); DCHECK_EQ(EGL_NO_IMAGE_KHR, state->egl_image_); - void* data = GetAddress(shared_memory, shared_memory_data_offset); + void* data = GetAddress(safe_shared_memory->shared_memory(), + mem_params.shm_data_offset); { TRACE_EVENT0("gpu", "glTexImage2D no data"); glGenTextures(1, &state->thread_texture_id_); @@ -616,8 +608,8 @@ void AsyncPixelTransferDelegateAndroid::PerformAsyncTexImage2D( void AsyncPixelTransferDelegateAndroid::PerformAsyncTexSubImage2D( TransferStateInternal* state, AsyncTexSubImage2DParams tex_params, - base::SharedMemory* shared_memory, - uint32 shared_memory_data_offset) { + AsyncMemoryParams mem_params, + ScopedSafeSharedMemory* safe_shared_memory) { TRACE_EVENT2("gpu", "PerformAsyncTexSubImage2D", "width", tex_params.width, "height", tex_params.height); @@ -626,7 +618,8 @@ void AsyncPixelTransferDelegateAndroid::PerformAsyncTexSubImage2D( DCHECK_NE(EGL_NO_IMAGE_KHR, state->egl_image_); DCHECK_EQ(0, tex_params.level); - void* data = GetAddress(shared_memory, shared_memory_data_offset); + void* data = GetAddress(safe_shared_memory->shared_memory(), + mem_params.shm_data_offset); base::TimeTicks begin_time(base::TimeTicks::HighResNow()); if (!state->thread_texture_id_) { @@ -692,7 +685,8 @@ bool AsyncPixelTransferDelegateAndroid::WorkAroundAsyncTexImage2D( // On imagination we allocate synchronously all the time, even // if the dimensions support fast uploads. This is for part a.) // above, so allocations occur on a different thread/context as uploads. - void* data = GetAddress(mem_params.shared_memory, mem_params.shm_data_offset); + void* data = GetAddress(mem_params.shared_memory, + mem_params.shm_data_offset); SetGlParametersForEglImageTexture(); { diff --git a/ui/gl/gl.gyp b/ui/gl/gl.gyp index b4e7409..81279bfb 100644 --- a/ui/gl/gl.gyp +++ b/ui/gl/gl.gyp @@ -97,6 +97,8 @@ 'gl_switches.h', 'gpu_switching_manager.cc', 'gpu_switching_manager.h', + 'safe_shared_memory_pool.h', + 'safe_shared_memory_pool.cc', 'scoped_make_current.cc', 'scoped_make_current.h', 'gl_state_restorer.cc', diff --git a/ui/gl/safe_shared_memory_pool.cc b/ui/gl/safe_shared_memory_pool.cc new file mode 100644 index 0000000..79ee4be --- /dev/null +++ b/ui/gl/safe_shared_memory_pool.cc @@ -0,0 +1,135 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/gl/safe_shared_memory_pool.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/process_util.h" +#include "build/build_config.h" + +using base::SharedMemory; +using base::SharedMemoryHandle; + +namespace gfx { + +ScopedSafeSharedMemory::ScopedSafeSharedMemory(SafeSharedMemoryPool* pool, + base::SharedMemory* memory, + size_t shm_size) { + DCHECK(pool); + DCHECK(memory); + DCHECK(memory->memory()); + pool_ = pool; + original_handle_ = memory->handle(); + safe_shared_memory_ = pool->AcquireSafeSharedMemory(memory, shm_size); + CHECK(safe_shared_memory_); +} + +ScopedSafeSharedMemory::~ScopedSafeSharedMemory() { + // Release the handle. The pool will delete the SharedMemory + // object when it is no longer referenced. + pool_->ReleaseSafeSharedMemory(original_handle_); +} + +base::SharedMemory* ScopedSafeSharedMemory::shared_memory() { + return safe_shared_memory_; +} + + +SafeSharedMemoryPool::SafeSharedMemoryPool() + : handles_consumed_(0), + address_space_consumed_(0), + max_handles_consumed_(0), + max_address_space_consumed_(0) { +} + +SafeSharedMemoryPool::~SafeSharedMemoryPool() { +} + +base::SharedMemory* SafeSharedMemoryPool:: + AcquireSafeSharedMemory(base::SharedMemory* shared_memory, + size_t shm_size) { + DCHECK(shared_memory); + DCHECK(shared_memory->memory()); + base::AutoLock scoped_lock(lock_); + + MemoryMap::iterator it = memory_.find(shared_memory->handle()); + // If we don't already have it, duplicated it. + if (it == memory_.end()) { + // Duplicate a new shared memory and track it. + TrackedMemory tracker; + tracker.safe_shared_memory = DuplicateSharedMemory(shared_memory, shm_size); + tracker.reference_count = 1; + tracker.shm_size = shm_size; + memory_[shared_memory->handle()] = tracker; + + // Adjust stats. + handles_consumed_++; + address_space_consumed_ += shm_size; + max_handles_consumed_ = std::max(max_handles_consumed_, + handles_consumed_); + max_address_space_consumed_ = std::max(max_address_space_consumed_, + address_space_consumed_); + return tracker.safe_shared_memory; + } + + // Otherwise, add a reference and return the existing one. + DCHECK(it->second.reference_count); + DCHECK(it->second.safe_shared_memory); + DCHECK(it->second.safe_shared_memory->memory()); + it->second.reference_count++; + return it->second.safe_shared_memory; +} + +void SafeSharedMemoryPool:: + ReleaseSafeSharedMemory(const base::SharedMemoryHandle& handle) { + base::AutoLock scoped_lock(lock_); + + MemoryMap::iterator it = memory_.find(handle); + CHECK(it != memory_.end()); + CHECK(it->second.reference_count); + CHECK(it->second.safe_shared_memory); + if (--it->second.reference_count == 0) { + // Adjust stats. + handles_consumed_--; + address_space_consumed_ -= it->second.shm_size; + DCHECK(handles_consumed_ >= 0); + DCHECK(address_space_consumed_ >= 0); + // Delete the safe memory and remove it. + delete it->second.safe_shared_memory; + memory_.erase(it); + } +} + +SharedMemory* SafeSharedMemoryPool::DuplicateSharedMemory( + SharedMemory* shared_memory, size_t size) { + // Duplicate the handle. + SharedMemoryHandle duped_shared_memory_handle; + if (!shared_memory->ShareToProcess( + base::GetCurrentProcessHandle(), + &duped_shared_memory_handle)) { + LOG(ERROR) << "Failed SharedMemory::ShareToProcess"; + LOG(ERROR) << "Total handles open " << handles_consumed_; + LOG(ERROR) << "Total address space " << address_space_consumed_; + LOG(ERROR) << "Max handles open " << max_handles_consumed_; + LOG(ERROR) << "Max address space " << max_address_space_consumed_; + CHECK(false); // Diagnosing a crash. + return NULL; + } + scoped_ptr<SharedMemory> duped_shared_memory( + new SharedMemory(duped_shared_memory_handle, false)); + // Map the shared memory into this process. This validates the size. + if (!duped_shared_memory->Map(size)) { + LOG(ERROR) << "Failed SharedMemory::Map"; + LOG(ERROR) << "Total handles open " << handles_consumed_; + LOG(ERROR) << "Total address space " << address_space_consumed_; + LOG(ERROR) << "Max handles open " << max_handles_consumed_; + LOG(ERROR) << "Max address space " << max_address_space_consumed_; + CHECK(false); // Diagnosing a crash. + return NULL; + } + return duped_shared_memory.release(); +} + +} // namespace gfx diff --git a/ui/gl/safe_shared_memory_pool.h b/ui/gl/safe_shared_memory_pool.h new file mode 100644 index 0000000..4d5eb9d --- /dev/null +++ b/ui/gl/safe_shared_memory_pool.h @@ -0,0 +1,88 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_GL_SAFE_SHARED_MEMORY_POOL_H_ +#define UI_GL_SAFE_SHARED_MEMORY_POOL_H_ + +#include <map> + +#include "base/basictypes.h" +#include "base/shared_memory.h" +#include "base/synchronization/lock.h" +#include "build/build_config.h" + +namespace base { +class SharedMemory; +} + +namespace gfx { +class SafeSharedMemoryPool; +class ScopedSafeSharedMemory; +} + +namespace gfx { + +// These classes exist to help protect against deletion of shared +// memory that is being used on a worker thread. It's mainly a +// security measure to prevent use-after-free in the browser, due +// to a misbehaving client. That said, this should be removed +// in favor of higher-level reference counting of an appropriate +// opaque 'memory blob' data-structure. + +class ScopedSafeSharedMemory { + public: + base::SharedMemory* shared_memory(); + ScopedSafeSharedMemory(SafeSharedMemoryPool* pool, + base::SharedMemory* memory, + size_t shm_size); + ~ScopedSafeSharedMemory(); + private: + base::SharedMemory* safe_shared_memory_; + base::SharedMemoryHandle original_handle_; + SafeSharedMemoryPool* pool_; + + DISALLOW_COPY_AND_ASSIGN(ScopedSafeSharedMemory); +}; + +class SafeSharedMemoryPool { + public: + SafeSharedMemoryPool(); + virtual ~SafeSharedMemoryPool(); + + private: + friend class ScopedSafeSharedMemory; + + // Acquires and release shared memory. The acquired shared memory + // is guaranteed to live until it is released. + base::SharedMemory* AcquireSafeSharedMemory(base::SharedMemory*, size_t size); + void ReleaseSafeSharedMemory(const base::SharedMemoryHandle&); + + // Utility function to duplicate shared memory. + base::SharedMemory* DuplicateSharedMemory(base::SharedMemory*, size_t size); + + // Track all SharedMemory's that we have already duplicated. + struct TrackedMemory { + base::SharedMemory* safe_shared_memory; + size_t shm_size; + int reference_count; + }; + + typedef std::map<base::SharedMemoryHandle, TrackedMemory> MemoryMap; + MemoryMap memory_; + + // Track usage to diagnose crashes. + int handles_consumed_; + int address_space_consumed_; + int max_handles_consumed_; + int max_address_space_consumed_; + + base::Lock lock_; + + DISALLOW_COPY_AND_ASSIGN(SafeSharedMemoryPool); +}; + +} // namespace gfx + +#endif // UI_GL_ASYNC_TASK_DELEGATE_H_ + |