blob: 072706da3358315075dc77ab1c7c3389fb2bed19 [file] [log] [blame]
/*
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Changes from Qualcomm Innovation Center, Inc. are provided under the following license:
*
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#ifdef LINUX_ENABLED
#include <algorithm>
#endif
#include "PalRingBuffer.h"
#include "PalCommon.h"
#define LOG_TAG "PAL: PalRingBuffer"
int32_t PalRingBuffer::removeReader(PalRingBufferReader *reader)
{
auto iter = std::find(readOffsets_.begin(), readOffsets_.end(), reader);
if (iter != readOffsets_.end())
readOffsets_.erase(iter);
return 0;
}
size_t PalRingBuffer::read(std::shared_ptr<PalRingBufferReader>reader __unused,
void* readBuffer __unused, size_t readSize __unused)
{
return 0;
}
size_t PalRingBuffer::getFreeSize()
{
size_t freeSize = bufferEnd_;
std::vector<PalRingBufferReader*>::iterator it;
for (it = readOffsets_.begin(); it != readOffsets_.end(); it++) {
if ((*(it))->state_ == READER_ENABLED)
freeSize = std::min(freeSize, bufferEnd_ - (*(it))->unreadSize_);
}
return freeSize;
}
void PalRingBuffer::updateUnReadSize(size_t writtenSize)
{
int32_t i = 0;
std::vector<PalRingBufferReader*>::iterator it;
for (it = readOffsets_.begin(); it != readOffsets_.end(); it++, i++) {
(*(it))->unreadSize_ += writtenSize;
PAL_VERBOSE(LOG_TAG, "Reader (%d), unreadSize(%zu)", i, (*(it))->unreadSize_);
if ((*(it))->requestedSize_ > 0 &&
(*(it))->unreadSize_ >= (*(it))->requestedSize_) {
(*(it))->cv_.notify_one();
}
}
}
void PalRingBuffer::updateIndices(uint32_t startIndice, uint32_t endIndice)
{
startIndex = startIndice;
endIndex = endIndice;
PAL_VERBOSE(LOG_TAG, "start index = %u, end index = %u", startIndex, endIndex);
}
size_t PalRingBuffer::write(void* writeBuffer, size_t writeSize)
{
/* update the unread size for each reader*/
mutex_.lock();
size_t freeSize = getFreeSize();
size_t writtenSize = 0;
int32_t i = 0;
size_t sizeToCopy = 0;
PAL_DBG(LOG_TAG, "Enter. freeSize(%zu), writeOffset(%zu)", freeSize, writeOffset_);
if (writeSize <= freeSize)
sizeToCopy = writeSize;
else
sizeToCopy = freeSize;
if (sizeToCopy) {
//buffer wrapped around
if (writeOffset_ + sizeToCopy > bufferEnd_) {
i = bufferEnd_ - writeOffset_;
ar_mem_cpy(buffer_ + writeOffset_, i, writeBuffer, i);
writtenSize += i;
sizeToCopy -= writtenSize;
ar_mem_cpy(buffer_, sizeToCopy, (char*)writeBuffer + writtenSize,
sizeToCopy);
writtenSize += sizeToCopy;
writeOffset_ = sizeToCopy;
} else {
ar_mem_cpy(buffer_ + writeOffset_, sizeToCopy, writeBuffer,
sizeToCopy);
writeOffset_ += sizeToCopy;
writtenSize = sizeToCopy;
}
}
updateUnReadSize(writtenSize);
writeOffset_ = writeOffset_ % bufferEnd_;
PAL_DBG(LOG_TAG, "Exit. writeOffset(%zu)", writeOffset_);
mutex_.unlock();
return writtenSize;
}
void PalRingBuffer::reset()
{
std::vector<PalRingBufferReader*>::iterator it;
mutex_.lock();
startIndex = 0;
endIndex = 0;
writeOffset_ = 0;
mutex_.unlock();
/* Reset all the associated readers */
for (it = readOffsets_.begin(); it != readOffsets_.end(); it++)
(*(it))->reset();
}
void PalRingBuffer::resizeRingBuffer(size_t bufferSize)
{
if (buffer_) {
delete[] buffer_;
buffer_ = nullptr;
}
buffer_ = (char *)new char[bufferSize];
bufferEnd_ = bufferSize;
}
bool PalRingBufferReader::waitForBuffers(uint32_t buffer_size)
{
std::unique_lock<std::mutex> lck(mutex_);
if (state_ == READER_ENABLED) {
if (unreadSize_ >= buffer_size)
goto exit;
requestedSize_ = buffer_size;
cv_.wait_for(lck, std::chrono::milliseconds(3000));
}
exit:
requestedSize_ = 0;
return unreadSize_ >= buffer_size;
}
int32_t PalRingBufferReader::read(void* readBuffer, size_t bufferSize)
{
int32_t readSize = 0;
if (state_ == READER_DISABLED)
return -EINVAL;
// Return 0 when no data can be read for current reader
if (unreadSize_ == 0)
return 0;
ringBuffer_->mutex_.lock();
// when writeOffset leads readOffset
if (ringBuffer_->writeOffset_ > readOffset_) {
unreadSize_ = ringBuffer_->writeOffset_ - readOffset_;
if (bufferSize >= unreadSize_) {
ar_mem_cpy(readBuffer, unreadSize_, ringBuffer_->buffer_ +
readOffset_, unreadSize_);
readOffset_ += unreadSize_;
readSize = unreadSize_;
unreadSize_ = 0;
} else {
ar_mem_cpy(readBuffer, unreadSize_, ringBuffer_->buffer_ +
readOffset_, bufferSize);
readOffset_ += bufferSize;
readSize = bufferSize;
unreadSize_ = ringBuffer_->writeOffset_ - readOffset_;
}
} else {
//When readOffset leads WriteOffset
int32_t freeClientSize = bufferSize;
int32_t i = ringBuffer_->bufferEnd_ - readOffset_;
if (bufferSize >= i) {
ar_mem_cpy(readBuffer, i, (char*)(ringBuffer_->buffer_ +
readOffset_), i);
readSize = i;
freeClientSize -= readSize;
unreadSize_ = ringBuffer_->writeOffset_;
readOffset_ = 0;
//copy remaining unread buffer
if (freeClientSize > unreadSize_) {
ar_mem_cpy((char *)readBuffer + readSize, unreadSize_,
ringBuffer_->buffer_, unreadSize_);
readSize += unreadSize_;
readOffset_ = unreadSize_;
unreadSize_ = 0;
} else {
//copy whatever we can
ar_mem_cpy((char *)readBuffer + readSize, freeClientSize,
ringBuffer_->buffer_, freeClientSize);
readSize += freeClientSize;
readOffset_ = freeClientSize;
unreadSize_ = ringBuffer_->writeOffset_ - readOffset_;
}
} else {
ar_mem_cpy(readBuffer, bufferSize, ringBuffer_->buffer_ +
readOffset_, bufferSize);
readSize = bufferSize;
readOffset_ += bufferSize;
unreadSize_ = ringBuffer_->bufferEnd_ - readOffset_ +
ringBuffer_->writeOffset_;
}
}
ringBuffer_->mutex_.unlock();
return readSize;
}
size_t PalRingBufferReader::advanceReadOffset(size_t advanceSize)
{
size_t size_advanced = 0;
std::lock_guard<std::mutex> lock(ringBuffer_->mutex_);
/* add code to advance the offset here*/
if (unreadSize_ < advanceSize) {
PAL_ERR(LOG_TAG, "Cannot advance read offset %zu greater than unread size %zu",
advanceSize, unreadSize_);
return size_advanced;
}
unreadSize_ -= advanceSize;
if (readOffset_ + advanceSize < ringBuffer_->bufferEnd_) {
readOffset_ += advanceSize;
} else {
readOffset_ = readOffset_ + advanceSize - ringBuffer_->bufferEnd_;
}
size_advanced += advanceSize;
return size_advanced;
}
void PalRingBufferReader::updateState(pal_ring_buffer_reader_state state)
{
PAL_DBG(LOG_TAG, "update reader state to %d", state);
std::lock_guard<std::mutex> lock(ringBuffer_->mutex_);
if (state_ == READER_DISABLED && state == READER_ENABLED) {
if (unreadSize_ > ringBuffer_->bufferEnd_)
unreadSize_ = ringBuffer_->bufferEnd_;
if (unreadSize_ <= ringBuffer_->writeOffset_) {
readOffset_ = ringBuffer_->writeOffset_ - unreadSize_;
} else {
readOffset_ = ringBuffer_->writeOffset_ +
ringBuffer_->bufferEnd_ - unreadSize_;
}
}
state_ = state;
}
void PalRingBufferReader::getIndices(uint32_t *startIndice, uint32_t *endIndice)
{
*startIndice = ringBuffer_->startIndex;
*endIndice = ringBuffer_->endIndex;
PAL_VERBOSE(LOG_TAG, "start index = %u, end index = %u",
ringBuffer_->startIndex, ringBuffer_->endIndex);
}
size_t PalRingBufferReader::getUnreadSize()
{
PAL_VERBOSE(LOG_TAG, "unread size %zu", unreadSize_);
return unreadSize_;
}
void PalRingBufferReader::reset()
{
ringBuffer_->mutex_.lock();
readOffset_ = 0;
unreadSize_ = 0;
state_ = READER_DISABLED;
ringBuffer_->mutex_.unlock();
requestedSize_ = 0;
cv_.notify_all();
}
PalRingBufferReader* PalRingBuffer::newReader()
{
PalRingBufferReader* readOffset =
new PalRingBufferReader(this);
readOffsets_.push_back(readOffset);
return readOffset;
}