blob: 0908edbc0833ca7bf93f10eeebaea458d21540a9 [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 <queue>
#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/shared_memory.h"
#include "content/common/content_export.h"
namespace content {
// ResourceBuffer implements a simple "circular buffer" allocation strategy.
// Allocations are recycled in FIFO order.
// You can think of the ResourceBuffer as a FIFO. The Allocate method reserves
// space in the buffer. Allocate may be called multiple times until the buffer
// is fully reserved (at which point CanAllocate returns false). Allocations
// are freed in FIFO order via a call to RecycleLeastRecentlyAllocated.
// ResourceBuffer is reference-counted for the benefit of consumers, who need
// to ensure that ResourceBuffer stays alive while they are using its memory.
// // Writes data into the ResourceBuffer, and returns the location (byte
// // offset and count) of the bytes written into the ResourceBuffer's shared
// // memory buffer.
// void WriteToBuffer(ResourceBuffer* buf, int* offset, int* count) {
// DCHECK(buf->CanAllocate());
// *offset = -1;
// *count = 0;
// int size;
// char* ptr = buf->Allocate(&size);
// if (!ptr) { /* handle error */ }
// int bytes_read = static_cast<int>(fread(ptr, 1, size, file_pointer_));
// if (!bytes_read) { /* handle error */ }
// if (bytes_read < size)
// buf->ShrinkLastAllocation(bytes_read);
// *offset = buf->GetLastAllocationOffset();
// *count = bytes_read;
// }
// NOTE: As the above example illustrates, the ResourceBuffer keeps track of
// the last allocation made. Calling ShrinkLastAllocation is optional, as it
// just helps the ResourceBuffer optimize storage and be more aggressive about
// returning larger allocations from the Allocate method.
class CONTENT_EXPORT ResourceBuffer
: public base::RefCountedThreadSafe<ResourceBuffer> {
// Initialize the shared memory buffer. It will be buffer_size bytes in
// length. The min/max_allocation_size parameters control the behavior of
// the Allocate method. It will prefer to return segments that are
// max_allocation_size in length, but will return segments less than that if
// space is limited. It will not return allocations smaller than
// min_allocation_size.
bool Initialize(int buffer_size,
int min_allocation_size,
int max_allocation_size);
bool IsInitialized() const;
// Returns a shared memory handle that can be passed to the given process.
// The shared memory handle is only intended to be interpretted by code
// running in the specified process. NOTE: The caller should ensure that
// this memory eventually be returned to the operating system.
bool ShareToProcess(base::ProcessHandle process_handle,
base::SharedMemoryHandle* shared_memory_handle,
int* shared_memory_size);
// Returns true if Allocate will succeed.
bool CanAllocate() const;
// Returns a pointer into the shared memory buffer or NULL if the buffer is
// already fully allocated. The returned size will be max_allocation_size
// unless the buffer is close to being full.
char* Allocate(int* size);
// Returns the offset into the shared memory buffer where the last allocation
// returned by Allocate can be found.
int GetLastAllocationOffset() const;
// Called to reduce the size of the last allocation returned by Allocate. It
// is OK for new_size to match the current size of the last allocation.
void ShrinkLastAllocation(int new_size);
// Called to allow reuse of memory that was previously allocated. See notes
// above the class for more details about this method.
void RecycleLeastRecentlyAllocated();
friend class base::RefCountedThreadSafe<ResourceBuffer>;
base::SharedMemory shared_mem_;
int buf_size_;
int min_alloc_size_;
int max_alloc_size_;
// These point to the range of the shared memory that is currently allocated.
// If alloc_start_ is -1, then the range is empty and nothing is allocated.
// Otherwise, alloc_start_ points to the start of the allocated range, and
// alloc_end_ points just beyond the end of the previous allocation. In the
// wraparound case, alloc_end_ <= alloc_start_. See for
// more details about these members.
int alloc_start_;
int alloc_end_;
std::queue<int> alloc_sizes_;
} // namespace content