blob: 9ba5390d2001ee59909c515d6757494f842860a4 [file] [log] [blame]
// 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