blob: 41351d94f7e5dab7e92849e7dcf20eeecfe618ac [file] [log] [blame]
/*
* Copyright (C) 2019 MediaTek Inc.
*
* 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.
*/
#define LOG_TAG "MtkCam/StreamBufferPoolImpl"
//
#include "MyUtils.h"
#include <list>
#include <mtkcam/pipeline/utils/streambuf/StreamBufferPoolImpl.h>
//
/******************************************************************************
*
******************************************************************************/
namespace NSCam {
namespace v3 {
namespace Utils {
/******************************************************************************
*
******************************************************************************/
StreamBufferPoolImpl::StreamBufferPoolImpl() {
muToAllocCnt = 0;
mName = "";
mExitPending = false;
mRunning = false;
mLogLevel = ::property_get_int32("debug.camera.log.sbpool", 0);
}
StreamBufferPoolImpl::~StreamBufferPoolImpl() {
MY_LOGD_IF(mLogLevel > 1, "destroy pool %s", mName);
}
MVOID
StreamBufferPoolImpl::finishImpl() {
mlAvailableBuf.clear();
mlInUseBuf.clear();
mWaitingList.clear();
muToAllocCnt = 0;
}
/******************************************************************************
*
******************************************************************************/
MERROR
StreamBufferPoolImpl::initPoolImpl(char const* szCallerName,
size_t maxNumberOfBuffers,
size_t minNumberOfInitialCommittedBuffers) {
MY_LOGD("initPoolImpl %s, max %zu, min %zu", szCallerName, maxNumberOfBuffers,
minNumberOfInitialCommittedBuffers);
mName = szCallerName;
if (szCallerName == nullptr || maxNumberOfBuffers == 0 ||
maxNumberOfBuffers < minNumberOfInitialCommittedBuffers) {
MY_LOGE("wrong params: %s, %zu, %zu", szCallerName, maxNumberOfBuffers,
minNumberOfInitialCommittedBuffers);
return INVALID_OPERATION;
}
{
std::lock_guard<std::mutex> _l(mLock);
for (size_t i = minNumberOfInitialCommittedBuffers; i-- > 0;) {
MUINT32 construct_result = 0;
if (do_construct(&construct_result) == NO_MEMORY) {
MY_LOGE("do_construct allocate buffer failed");
return NO_MEMORY;
}
mlAvailableBuf.push_back(construct_result);
}
muToAllocCnt = maxNumberOfBuffers - minNumberOfInitialCommittedBuffers;
////
}
return OK;
} // initPool
MVOID
StreamBufferPoolImpl::signalUserLocked() {
if (mWaitingList.size()) {
(*mWaitingList.begin())->notify_one();
}
}
/******************************************************************************
*
******************************************************************************/
MVOID
StreamBufferPoolImpl::dumpPoolImpl() const {
std::lock_guard<std::mutex> _l(mLock);
MY_LOGD("dumpPoolImpl +");
if (!mlAvailableBuf.empty()) {
typename std::list<MUINT32>::const_iterator iter = mlAvailableBuf.begin();
while (iter != mlAvailableBuf.end()) {
MY_LOGD("available buf %d", *iter);
iter++;
}
}
if (!mlInUseBuf.empty()) {
typename std::list<MUINT32>::const_iterator iter = mlInUseBuf.begin();
while (iter != mlInUseBuf.end()) {
MY_LOGD("in use buf %d", *iter);
iter++;
}
}
//
MY_LOGD("dumpPoolImpl -");
}
MVOID
StreamBufferPoolImpl::uninitPoolImpl(char const* szCallerName) {
MY_LOGD_IF(mLogLevel > 1, "caller(%s) uninit pool(%s)", szCallerName, mName);
{
std::lock_guard<std::mutex> _l(mLock);
mExitPending = true;
}
mThread.join();
{
std::lock_guard<std::mutex> _l(mLock);
mlAvailableBuf.clear();
mlInUseBuf.clear();
muToAllocCnt = 0;
}
}
/******************************************************************************
*
******************************************************************************/
MERROR
StreamBufferPoolImpl::commitPoolImpl(char const* szCallerName) {
MY_LOGD_IF(mLogLevel > 1, "caller(%s) commit pool(%s)", szCallerName, mName);
if (muToAllocCnt > 0) {
mThread = std::thread(std::bind(&StreamBufferPoolImpl::threadLoop, this));
}
return OK;
}
/******************************************************************************
*
******************************************************************************/
MERROR
StreamBufferPoolImpl::acquireFromPoolImpl(char const* szCallerName,
MUINT32* rpBufferIndex,
int64_t nsTimeout) {
std::unique_lock<std::mutex> _l(mLock);
MY_LOGD_IF(mLogLevel > 2,
"caller(%s) aquires buffer from pool(%s), available(%zu)",
szCallerName, mName, mlAvailableBuf.size());
if (!mlAvailableBuf.empty()) {
typename std::list<MUINT32>::iterator iter = mlAvailableBuf.begin();
mlInUseBuf.push_back(*iter);
*rpBufferIndex = *iter;
mlAvailableBuf.erase(iter);
//
return OK;
} else if (!mRunning && muToAllocCnt > 0) {
MUINT32 construct_result = 0;
mLock.unlock();
MERROR err = do_construct(&construct_result);
mLock.lock();
if (err == NO_MEMORY) {
MY_LOGE("do_construct allocate buffer failed");
return NO_MEMORY;
}
mlInUseBuf.push_back(construct_result);
*rpBufferIndex = construct_result;
--muToAllocCnt;
return OK;
}
std::condition_variable cond;
mWaitingList.push_back(&cond);
// wait for buffer
MY_LOGD("acquireFromPoolImpl waiting %" PRId64 " ns", nsTimeout);
cond.wait_for(_l, std::chrono::nanoseconds(nsTimeout));
std::list<std::condition_variable*>::iterator pCond = mWaitingList.begin();
while (pCond != mWaitingList.end()) {
if ((*pCond) == &cond) {
mWaitingList.erase(pCond);
break;
}
pCond++;
}
if (!mlAvailableBuf.empty()) {
typename std::list<MUINT32>::iterator iter = mlAvailableBuf.begin();
mlInUseBuf.push_back(*iter);
*rpBufferIndex = *iter;
mlAvailableBuf.erase(iter);
//
return OK;
}
MY_LOGW("mPoolName timeout: buffer available %zu, toAlloc %d",
mlAvailableBuf.size(), muToAllocCnt);
return TIMED_OUT;
}
/******************************************************************************
*
******************************************************************************/
MERROR
StreamBufferPoolImpl::releaseToPoolImpl(char const* szCallerName,
MUINT32 pBufferIndex) {
MY_LOGD_IF(mLogLevel > 2,
"caller(%s) release buffer to pool(%s), available(%zu)",
szCallerName, mName, mlAvailableBuf.size());
{
std::lock_guard<std::mutex> _l(mLock);
typename std::list<MUINT32>::iterator iter = mlInUseBuf.begin();
while (iter != mlInUseBuf.end()) {
if (*iter == pBufferIndex) {
mlAvailableBuf.push_back(*iter);
mlInUseBuf.erase(iter);
//
signalUserLocked();
return OK;
}
iter++;
}
}
MY_LOGE("cannot find buffer index %d", pBufferIndex);
dumpPoolImpl();
return INVALID_OPERATION;
}
/******************************************************************************
*
******************************************************************************/
bool StreamBufferPoolImpl::_threadLoop() {
bool next = false;
MUINT32 construct_result = 0;
if (do_construct(&construct_result) == NO_MEMORY) {
MY_LOGE("do_construct allocate buffer failed");
return NO_MEMORY;
}
{
std::lock_guard<std::mutex> _l(mLock);
mlAvailableBuf.push_back(construct_result);
next = (--muToAllocCnt) > 0;
signalUserLocked();
}
return next;
}
/******************************************************************************
*
******************************************************************************/
bool StreamBufferPoolImpl::threadLoop() {
while (this->_threadLoop()) {
std::lock_guard<std::mutex> _l(mLock);
if (mExitPending) {
mRunning = false;
break;
}
}
return true;
}
}; // namespace Utils
}; // namespace v3
}; // namespace NSCam