| // 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 "gpu/command_buffer/service/safe_shared_memory_pool.h" |
| |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/process/process_handle.h" |
| #include "build/build_config.h" |
| |
| using base::SharedMemory; |
| using base::SharedMemoryHandle; |
| |
| namespace gpu { |
| |
| 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_acquired_(0), |
| handles_consumed_(0), |
| address_space_consumed_(0), |
| max_handles_acquired_(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_); |
| |
| // Adjust stats. |
| handles_acquired_++; |
| max_handles_acquired_ = std::max(max_handles_acquired_, |
| handles_acquired_); |
| |
| 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_); |
| |
| // Adjust stats. |
| DCHECK_GT(handles_acquired_, 0); |
| handles_acquired_--; |
| |
| 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. |
| DCHECK_GT(handles_consumed_, 0); |
| handles_consumed_--; |
| DCHECK_LE(it->second.shm_size, address_space_consumed_); |
| address_space_consumed_ -= it->second.shm_size; |
| // 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)) { |
| PLOG(ERROR) << "Failed SharedMemory::ShareToProcess"; |
| LOG(ERROR) << "Total handles acquired " << handles_acquired_; |
| LOG(ERROR) << "Total handles open " << handles_consumed_; |
| LOG(ERROR) << "Total address space " << address_space_consumed_; |
| LOG(ERROR) << "Max handles acquired " << max_handles_acquired_; |
| 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)) { |
| PLOG(ERROR) << "Failed SharedMemory::Map(" << size << ")"; |
| LOG(ERROR) << "Total handles acquired " << handles_acquired_; |
| LOG(ERROR) << "Total handles open " << handles_consumed_; |
| LOG(ERROR) << "Total address space " << address_space_consumed_; |
| LOG(ERROR) << "Max handles acquired " << max_handles_acquired_; |
| 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 gpu |