blob: f5c0a6979a28e16a00398221a16682df094532a7 [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 "storage/buffer/blocking_ring_buffer.h"
#include <lib/fzl/owned-vmo-mapper.h>
#include <fbl/auto_lock.h>
namespace storage {
namespace internal {
BlockingRingBufferImpl::BlockingRingBufferImpl(std::unique_ptr<RingBuffer> buffer)
: buffer_(std::move(buffer)) {}
zx_status_t BlockingRingBufferImpl::Reserve(uint64_t blocks, BlockingRingBufferReservation* out) {
// First, ensure that it is possible for us to eventually get space.
if (blocks > buffer_->capacity()) {
return ZX_ERR_NO_SPACE;
}
RingBufferReservation reservation;
{
zx_status_t status = ZX_ERR_NO_SPACE;
fbl::AutoLock lock(&lock_);
do {
status = buffer_->Reserve(blocks, &reservation);
if (status == ZX_ERR_NO_SPACE) {
// Case 1: We cannot reserve space. Block until it is available.
cvar_.Wait(&lock_);
} else if (status != ZX_OK) {
// Case 2: We cannot reserve space, but don't expect it to become available.
return status;
}
// Case 3: We reserved space successfully. Fallthrough.
} while (status == ZX_ERR_NO_SPACE);
}
*out = BlockingRingBufferReservation(this, std::move(reservation));
return ZX_OK;
}
void BlockingRingBufferImpl::Wake() {
fbl::AutoLock lock(&lock_);
cvar_.Broadcast();
}
} // namespace internal
BlockingRingBuffer::BlockingRingBuffer(std::unique_ptr<RingBuffer> buffer)
: buffer_(internal::BlockingRingBufferImpl(std::move(buffer))) {}
zx_status_t BlockingRingBuffer::Create(storage::VmoidRegistry* vmoid_registry,
const size_t blocks,
uint32_t block_size, const char* label,
std::unique_ptr<BlockingRingBuffer>* out) {
std::unique_ptr<RingBuffer> buffer;
zx_status_t status = RingBuffer::Create(vmoid_registry, blocks, block_size, label, &buffer);
if (status != ZX_OK) {
return status;
}
*out = std::unique_ptr<BlockingRingBuffer>(new BlockingRingBuffer(std::move(buffer)));
return ZX_OK;
}
BlockingRingBufferReservation::~BlockingRingBufferReservation() {
if (!Reserved()) {
return;
}
Reset();
buffer_->Wake();
}
} // namespace storage