summaryrefslogtreecommitdiff
path: root/chromium/content/browser/loader/resource_buffer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/loader/resource_buffer.cc')
-rw-r--r--chromium/content/browser/loader/resource_buffer.cc181
1 files changed, 181 insertions, 0 deletions
diff --git a/chromium/content/browser/loader/resource_buffer.cc b/chromium/content/browser/loader/resource_buffer.cc
new file mode 100644
index 00000000000..4364de18ba8
--- /dev/null
+++ b/chromium/content/browser/loader/resource_buffer.cc
@@ -0,0 +1,181 @@
+// 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 "content/browser/loader/resource_buffer.h"
+
+#include <math.h>
+
+#include "base/logging.h"
+
+namespace content {
+
+// A circular buffer allocator.
+//
+// We keep track of the starting offset (alloc_start_) and the ending offset
+// (alloc_end_). There are two layouts to keep in mind:
+//
+// #1:
+// ------------[XXXXXXXXXXXXXXXXXXXXXXX]----
+// ^ ^
+// start end
+//
+// #2:
+// XXXXXXXXXX]---------------------[XXXXXXXX
+// ^ ^
+// end start
+//
+// If end <= start, then we have the buffer wraparound case (depicted second).
+// If the buffer is empty, then start and end will be set to -1.
+//
+// Allocations are always contiguous.
+
+ResourceBuffer::ResourceBuffer()
+ : buf_size_(0),
+ min_alloc_size_(0),
+ max_alloc_size_(0),
+ alloc_start_(-1),
+ alloc_end_(-1) {
+}
+
+ResourceBuffer::~ResourceBuffer() {
+}
+
+bool ResourceBuffer::Initialize(int buffer_size,
+ int min_allocation_size,
+ int max_allocation_size) {
+ DCHECK(!IsInitialized());
+
+ // It would be wasteful if these are not multiples of min_allocation_size.
+ DCHECK_EQ(0, buffer_size % min_allocation_size);
+ DCHECK_EQ(0, max_allocation_size % min_allocation_size);
+
+ buf_size_ = buffer_size;
+ min_alloc_size_ = min_allocation_size;
+ max_alloc_size_ = max_allocation_size;
+
+ return shared_mem_.CreateAndMapAnonymous(buf_size_);
+}
+
+bool ResourceBuffer::IsInitialized() const {
+ return shared_mem_.memory() != NULL;
+}
+
+bool ResourceBuffer::ShareToProcess(
+ base::ProcessHandle process_handle,
+ base::SharedMemoryHandle* shared_memory_handle,
+ int* shared_memory_size) {
+ DCHECK(IsInitialized());
+
+ if (!shared_mem_.ShareToProcess(process_handle, shared_memory_handle))
+ return false;
+
+ *shared_memory_size = buf_size_;
+ return true;
+}
+
+bool ResourceBuffer::CanAllocate() const {
+ DCHECK(IsInitialized());
+
+ if (alloc_start_ == -1)
+ return true;
+
+ int diff = alloc_end_ - alloc_start_;
+ if (diff > 0)
+ return (buf_size_ - diff) >= min_alloc_size_;
+
+ return -diff >= min_alloc_size_;
+}
+
+char* ResourceBuffer::Allocate(int* size) {
+ DCHECK(CanAllocate());
+
+ int alloc_offset = 0;
+ int alloc_size;
+
+ if (alloc_start_ == -1) {
+ // This is the first allocation.
+ alloc_start_ = 0;
+ alloc_end_ = buf_size_;
+ alloc_size = buf_size_;
+ } else if (alloc_start_ < alloc_end_) {
+ // Append the next allocation if it fits. Otherwise, wraparound.
+ //
+ // NOTE: We could look to see if a larger allocation is possible by
+ // wrapping around sooner, but instead we just look to fill the space at
+ // the end of the buffer provided that meets the min_alloc_size_
+ // requirement.
+ //
+ if ((buf_size_ - alloc_end_) >= min_alloc_size_) {
+ alloc_offset = alloc_end_;
+ alloc_size = buf_size_ - alloc_end_;
+ alloc_end_ = buf_size_;
+ } else {
+ // It must be possible to allocate a least min_alloc_size_.
+ DCHECK(alloc_start_ >= min_alloc_size_);
+ alloc_size = alloc_start_;
+ alloc_end_ = alloc_start_;
+ }
+ } else {
+ // This is the wraparound case.
+ DCHECK(alloc_end_ < alloc_start_);
+ alloc_offset = alloc_end_;
+ alloc_size = alloc_start_ - alloc_end_;
+ alloc_end_ = alloc_start_;
+ }
+
+ // Make sure alloc_size does not exceed max_alloc_size_. We store the
+ // current value of alloc_size, so that we can use ShrinkLastAllocation to
+ // trim it back. This allows us to reuse the alloc_end_ adjustment logic.
+
+ alloc_sizes_.push(alloc_size);
+
+ if (alloc_size > max_alloc_size_) {
+ alloc_size = max_alloc_size_;
+ ShrinkLastAllocation(alloc_size);
+ }
+
+ *size = alloc_size;
+ return static_cast<char*>(shared_mem_.memory()) + alloc_offset;
+}
+
+int ResourceBuffer::GetLastAllocationOffset() const {
+ DCHECK(!alloc_sizes_.empty());
+ DCHECK(alloc_end_ >= alloc_sizes_.back());
+ return alloc_end_ - alloc_sizes_.back();
+}
+
+void ResourceBuffer::ShrinkLastAllocation(int new_size) {
+ DCHECK(!alloc_sizes_.empty());
+
+ int aligned_size = (new_size / min_alloc_size_) * min_alloc_size_;
+ if (aligned_size < new_size)
+ aligned_size += min_alloc_size_;
+
+ DCHECK_LE(new_size, aligned_size);
+ DCHECK_GE(alloc_sizes_.back(), aligned_size);
+
+ int* last_allocation_size = &alloc_sizes_.back();
+ alloc_end_ -= (*last_allocation_size - aligned_size);
+ *last_allocation_size = aligned_size;
+}
+
+void ResourceBuffer::RecycleLeastRecentlyAllocated() {
+ DCHECK(!alloc_sizes_.empty());
+ int allocation_size = alloc_sizes_.front();
+ alloc_sizes_.pop();
+
+ alloc_start_ += allocation_size;
+ DCHECK(alloc_start_ <= buf_size_);
+
+ if (alloc_start_ == alloc_end_) {
+ DCHECK(alloc_sizes_.empty());
+ alloc_start_ = -1;
+ alloc_end_ = -1;
+ } else if (alloc_start_ == buf_size_) {
+ DCHECK(!alloc_sizes_.empty());
+ alloc_start_ = 0;
+ }
+}
+
+} // namespace content