blob: 4fcc00ed2bd8b76c1fc632b21fb4e7cac0302add [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.
*/
#ifndef CAMERA_HAL_MEDIATEK_MTKCAM_PIPELINE_HWNODE_P2_P2_PROCESSOR_H_
#define CAMERA_HAL_MEDIATEK_MTKCAM_PIPELINE_HWNODE_P2_P2_PROCESSOR_H_
#include "P2_Processor_t.h"
#include "P2_LogHeaderBegin.h"
#include <mtkcam/utils/debug/P2_DebugControl.h>
#define P2_CLASS_TAG Processor
#define P2_TRACE TRACE_PROCESSOR
#include "P2_LogHeader.h"
#include <memory>
#include <string>
#define DEFAULT_THREAD_POLICY SCHED_OTHER
#define DEFAULT_THREAD_PRIORITY -2
namespace P2 {
template <typename Init_T, typename Config_T, typename Enque_T>
Processor<Init_T, Config_T, Enque_T>::Processor(const std::string& name)
: mName(name), mEnable(MTRUE), mIdleWaitMS(0), mNeedThread(MTRUE) {
TRACE_S_FUNC_ENTER(mName);
TRACE_S_FUNC_EXIT(mName);
}
template <typename Init_T, typename Config_T, typename Enque_T>
Processor<Init_T, Config_T, Enque_T>::Processor(const std::string& name,
MINT32 policy,
MINT32 priority)
: mName(name), mEnable(MTRUE), mIdleWaitMS(0), mNeedThread(MTRUE) {
TRACE_S_FUNC_ENTER(mName);
TRACE_S_FUNC_EXIT(mName);
}
template <typename Init_T, typename Config_T, typename Enque_T>
Processor<Init_T, Config_T, Enque_T>::~Processor() {
TRACE_S_FUNC_ENTER(mName);
if (mThread.get() != nullptr) {
MY_S_LOGE(mName,
"Processor::uninit() not called: Child class MUST ensure "
"uninit() in own destructor");
mThread = nullptr;
}
TRACE_S_FUNC_EXIT(mName);
}
template <typename Init_T, typename Config_T, typename Enque_T>
const char* Processor<Init_T, Config_T, Enque_T>::getName() const {
return mName.c_str();
}
template <typename Init_T, typename Config_T, typename Enque_T>
MBOOL Processor<Init_T, Config_T, Enque_T>::setEnable(MBOOL enable) {
TRACE_S_FUNC_ENTER(mName);
std::lock_guard<std::mutex> _lock(mThreadMutex);
if (mThread == nullptr) {
mEnable = enable;
}
TRACE_S_FUNC_EXIT(mName);
return mEnable;
}
template <typename Init_T, typename Config_T, typename Enque_T>
MBOOL Processor<Init_T, Config_T, Enque_T>::isEnabled() {
TRACE_S_FUNC_ENTER(mName);
std::lock_guard<std::mutex> _lock(mThreadMutex);
TRACE_S_FUNC_EXIT(mName);
return mEnable;
}
template <typename Init_T, typename Config_T, typename Enque_T>
MBOOL Processor<Init_T, Config_T, Enque_T>::setNeedThread(MBOOL isThreadNeed) {
TRACE_S_FUNC_ENTER(mName);
std::lock_guard<std::mutex> _lock(mThreadMutex);
if (mThread == nullptr) {
mNeedThread = isThreadNeed;
}
TRACE_S_FUNC_EXIT(mName);
return mNeedThread;
}
template <typename Init_T, typename Config_T, typename Enque_T>
MVOID Processor<Init_T, Config_T, Enque_T>::setIdleWaitMS(MUINT32 ms) {
TRACE_S_FUNC_ENTER(mName);
std::lock_guard<std::mutex> _lock(mThreadMutex);
if (mThread == nullptr) {
mIdleWaitMS = ms;
}
TRACE_S_FUNC_EXIT(mName);
}
template <typename Init_T, typename Config_T, typename Enque_T>
MBOOL Processor<Init_T, Config_T, Enque_T>::init(const Init_T& param) {
TRACE_S_FUNC_ENTER(mName);
std::lock_guard<std::mutex> _lock(mThreadMutex);
MBOOL ret = !mEnable;
if (mEnable && mThread == nullptr) {
if (this->onInit(param)) {
mThread = std::make_shared<ProcessThread>(this->shared_from_this(),
mNeedThread);
if (mThread == nullptr) {
MY_S_LOGE(mName, "OOM: cannot create ProcessThread");
this->onUninit();
} else {
if (mNeedThread) {
mThread->run();
} else {
this->onThreadStart();
}
ret = MTRUE;
}
}
}
TRACE_S_FUNC_EXIT(mName);
return ret;
}
template <typename Init_T, typename Config_T, typename Enque_T>
MVOID Processor<Init_T, Config_T, Enque_T>::uninit() {
TRACE_S_FUNC_ENTER(mName);
std::lock_guard<std::mutex> _lock(mThreadMutex);
if (mThread != nullptr) {
mThread->stop();
if (mThread->join() != OK) {
MY_S_LOGW(mName, "ProcessThread join failed");
}
if (!mNeedThread) {
this->onThreadStop();
}
mThread = nullptr;
this->onUninit();
}
TRACE_S_FUNC_EXIT(mName);
}
template <typename Init_T, typename Config_T, typename Enque_T>
MBOOL Processor<Init_T, Config_T, Enque_T>::config(const Config_T& param) {
TRACE_S_FUNC_ENTER(mName);
std::lock_guard<std::mutex> _lock(mThreadMutex);
MBOOL ret = !mEnable;
if (mThread != nullptr) {
ret = this->onConfig(param);
}
TRACE_S_FUNC_EXIT(mName);
return ret;
}
template <typename Init_T, typename Config_T, typename Enque_T>
MBOOL Processor<Init_T, Config_T, Enque_T>::enque(const Enque_T& param) {
TRACE_S_FUNC_ENTER(mName);
std::lock_guard<std::mutex> _lock(mThreadMutex);
MBOOL ret = MFALSE;
if (mThread != nullptr) {
mThread->enque(param);
ret = MTRUE;
}
TRACE_S_FUNC_EXIT(mName);
return ret;
}
template <typename Init_T, typename Config_T, typename Enque_T>
MVOID Processor<Init_T, Config_T, Enque_T>::flush() {
TRACE_S_FUNC_ENTER(mName);
std::lock_guard<std::mutex> _lock(mThreadMutex);
if (mThread != nullptr) {
this->onNotifyFlush();
mThread->flush();
this->onWaitFlush();
}
TRACE_S_FUNC_EXIT(mName);
}
template <typename Init_T, typename Config_T, typename Enque_T>
MVOID Processor<Init_T, Config_T, Enque_T>::notifyFlush() {
TRACE_S_FUNC_ENTER(mName);
std::lock_guard<std::mutex> _lock(mThreadMutex);
if (mThread != nullptr) {
this->onNotifyFlush();
}
TRACE_S_FUNC_EXIT(mName);
}
template <typename Init_T, typename Config_T, typename Enque_T>
MVOID Processor<Init_T, Config_T, Enque_T>::waitFlush() {
TRACE_S_FUNC_ENTER(mName);
std::lock_guard<std::mutex> _lock(mThreadMutex);
if (mThread != nullptr) {
mThread->flush();
this->onWaitFlush();
}
TRACE_S_FUNC_EXIT(mName);
}
template <typename Init_T, typename Config_T, typename Enque_T>
Processor<Init_T, Config_T, Enque_T>::ProcessThread::ProcessThread(
std::shared_ptr<Processor> parent, MBOOL needThread)
: mParent(parent),
mName(parent->mName),
mIdleWaitTime(NSCam::Utils::ms2ns(parent->mIdleWaitMS)),
mStop(MFALSE),
mIdle(MTRUE),
mNeedThread(needThread) {
TRACE_S_FUNC_ENTER(mName);
TRACE_S_FUNC_EXIT(mName);
}
template <typename Init_T, typename Config_T, typename Enque_T>
Processor<Init_T, Config_T, Enque_T>::ProcessThread::~ProcessThread() {
TRACE_S_FUNC_ENTER(mName);
TRACE_S_FUNC_EXIT(mName);
}
template <typename Init_T, typename Config_T, typename Enque_T>
status_t Processor<Init_T, Config_T, Enque_T>::ProcessThread::readyToRun() {
TRACE_S_FUNC_ENTER(mName);
TRACE_S_FUNC_EXIT(mName);
return 0;
}
template <typename Init_T, typename Config_T, typename Enque_T>
status_t Processor<Init_T, Config_T, Enque_T>::ProcessThread::run() {
TRACE_S_FUNC_ENTER(mName);
mThread = std::thread(std::bind(
&Processor<Init_T, Config_T, Enque_T>::ProcessThread::threadLoop, this));
TRACE_S_FUNC_EXIT(mName);
return 0;
}
template <typename Init_T, typename Config_T, typename Enque_T>
status_t Processor<Init_T, Config_T, Enque_T>::ProcessThread::join() {
TRACE_S_FUNC_ENTER(mName);
if (mThread.joinable()) {
mThread.join();
}
TRACE_S_FUNC_EXIT(mName);
return 0;
}
template <typename Init_T, typename Config_T, typename Enque_T>
bool Processor<Init_T, Config_T, Enque_T>::ProcessThread::threadLoop() {
while (this->_threadLoop() == true) {
}
return true;
}
template <typename Init_T, typename Config_T, typename Enque_T>
bool Processor<Init_T, Config_T, Enque_T>::ProcessThread::_threadLoop() {
TRACE_S_FUNC_ENTER(mName);
Enque_T param;
WaitResult waitResult;
mParent->onThreadStart();
do {
waitResult = waitEnqueParam(&param);
if (waitResult == WAIT_OK) {
mParent->onEnque(param);
} else if (waitResult == WAIT_IDLE) {
mParent->onIdle();
}
param = Enque_T();
} while (waitResult != WAIT_EXIT);
mParent->onThreadStop();
TRACE_S_FUNC_EXIT(mName);
return false;
}
template <typename Init_T, typename Config_T, typename Enque_T>
MVOID Processor<Init_T, Config_T, Enque_T>::ProcessThread::enque(
const Enque_T& param) {
TRACE_S_FUNC_ENTER(mName);
std::lock_guard<std::mutex> _lock(mMutex);
if (mNeedThread) {
mQueue.push(param);
mCondition.notify_all();
} else {
mParent->onEnque(param);
}
TRACE_S_FUNC_EXIT(mName);
}
template <typename Init_T, typename Config_T, typename Enque_T>
MVOID Processor<Init_T, Config_T, Enque_T>::ProcessThread::flush() {
TRACE_S_FUNC_ENTER(mName);
std::unique_lock<std::mutex> _lock(mMutex);
while (!mIdle) {
mCondition.wait(_lock);
}
TRACE_S_FUNC_EXIT(mName);
}
template <typename Init_T, typename Config_T, typename Enque_T>
MVOID Processor<Init_T, Config_T, Enque_T>::ProcessThread::stop() {
TRACE_S_FUNC_ENTER(mName);
std::lock_guard<std::mutex> _lock(mMutex);
mStop = MTRUE;
mCondition.notify_all();
TRACE_S_FUNC_EXIT(mName);
}
template <typename Init_T, typename Config_T, typename Enque_T>
typename Processor<Init_T, Config_T, Enque_T>::ProcessThread::WaitResult
Processor<Init_T, Config_T, Enque_T>::ProcessThread::waitEnqueParam(
Enque_T* param) {
TRACE_S_FUNC_ENTER(mName);
std::unique_lock<std::mutex> _lock(mMutex);
WaitResult result = WAIT_ERROR;
MBOOL needWaitIdle = MFALSE;
if (mQueue.size() == 0) {
if (!mIdle) {
mIdle = MTRUE;
needWaitIdle = MTRUE;
mCondition.notify_all();
}
if (mStop) {
result = WAIT_EXIT;
} else if (needWaitIdle && mIdleWaitTime) {
std::cv_status status =
mCondition.wait_for(_lock, std::chrono::nanoseconds(mIdleWaitTime));
if (status == std::cv_status::timeout) {
result = WAIT_IDLE;
}
} else {
mCondition.wait(_lock);
}
}
if (mQueue.size()) {
*param = mQueue.front();
mQueue.pop();
mIdle = MFALSE;
result = WAIT_OK;
}
TRACE_S_FUNC_EXIT(mName);
return result;
}
} // namespace P2
#include "P2_LogHeaderEnd.h"
#endif // CAMERA_HAL_MEDIATEK_MTKCAM_PIPELINE_HWNODE_P2_P2_PROCESSOR_H_