/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ReadBuffer.h" #include "host-common/logging.h" #include #include #include #include namespace gfxstream { ReadBuffer::ReadBuffer(size_t bufsize) { m_size = bufsize; m_buf = (unsigned char*)malloc(m_size); m_validData = 0; m_readPtr = m_buf; } ReadBuffer::~ReadBuffer() { free(m_buf); } void ReadBuffer::setNeededFreeTailSize(size_t size) { m_neededFreeTailSize = size; } int ReadBuffer::getData(IOStream* stream, size_t minSize) { assert(stream); assert(minSize > m_validData); const size_t minSizeToRead = minSize - m_validData; const size_t neededFreeTailThisTime = std::max(minSizeToRead, m_neededFreeTailSize); size_t maxSizeToRead; const size_t freeTailSize = m_buf + m_size - (m_readPtr + m_validData); if (freeTailSize >= neededFreeTailThisTime) { maxSizeToRead = freeTailSize; } else { if (freeTailSize + (m_readPtr - m_buf) >= neededFreeTailThisTime) { // There's some gap in the beginning, if we move the data over it // that's going to be enough. memmove(m_buf, m_readPtr, m_validData); } else { // Not enough space even with moving, reallocate. // Note: make sure we can fit at least two of the requested packets // into the new buffer to minimize the reallocations and // memmove()-ing stuff around. size_t new_size = std::max(2 * minSizeToRead + m_validData, 2 * m_size); if (new_size < m_size) { // overflow check new_size = INT_MAX; } const auto new_buf = (unsigned char*)malloc(new_size); if (!new_buf) { ERR("Failed to alloc %zu bytes for ReadBuffer\n", new_size); return -1; } memcpy(new_buf, m_readPtr, m_validData); free(m_buf); m_buf = new_buf; m_size = new_size; } // We can read more now, let's request it in case all data is ready // for reading. maxSizeToRead = m_size - m_validData; m_readPtr = m_buf; } // get fresh data into the buffer; int readTotal = 0; do { const size_t readNow = stream->read(m_readPtr + m_validData, maxSizeToRead - readTotal); if (!readNow) { if (readTotal > 0) { return readTotal; } else { return -1; } } readTotal += readNow; m_validData += readNow; } while (readTotal < minSizeToRead); return readTotal; } void ReadBuffer::consume(size_t amount) { assert(amount <= m_validData); m_validData -= amount; m_readPtr += amount; } void ReadBuffer::onSave(android::base::Stream* stream) { stream->putBe32(m_size); stream->putBe32(m_validData); stream->write(m_readPtr, m_validData); } void ReadBuffer::onLoad(android::base::Stream* stream) { const auto size = stream->getBe32(); if (size > m_size) { m_size = size; free(m_buf); m_buf = (unsigned char*)malloc(m_size); } m_readPtr = m_buf; m_validData = stream->getBe32(); assert(m_validData <= m_size); stream->read(m_readPtr, m_validData); } void ReadBuffer::printStats() { printf("ReadBuffer::%s: tail move time %f ms\n", __func__, (float)m_tailMoveTimeUs / 1000.0f); m_tailMoveTimeUs = 0; } } // namespace gfxstream