summaryrefslogtreecommitdiffstats
path: root/ui/gl
diff options
context:
space:
mode:
authorepenner@chromium.org <epenner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-15 21:13:33 +0000
committerepenner@chromium.org <epenner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-15 21:13:33 +0000
commita2e99f4d09f6fd48236c39665d68b155edd7465b (patch)
tree14cd586067c72820f6ed8e5134c9f473ef639cee /ui/gl
parent6df15b3fb7493528e01770a4ef66266e1229d5f9 (diff)
downloadchromium_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.cc74
-rw-r--r--ui/gl/gl.gyp2
-rw-r--r--ui/gl/safe_shared_memory_pool.cc135
-rw-r--r--ui/gl/safe_shared_memory_pool.h88
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_
+