/* * Copyright (c) 2024 Huawei Device Co., Ltd. * 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 HOS_TIMEOUTEXECUTOR_H #define HOS_TIMEOUTEXECUTOR_H #include #include #include // std::thread #include // std::mutex, std::unique_lock #include // std::condition_variable #include #include #include namespace OHOS::TIMEOUTEXECUTOR { template struct check_all_parameters; template <> struct check_all_parameters<> { static const bool value = true; }; template struct check_all_parameters : private check_all_parameters { using Mybase = check_all_parameters; static const bool value = \ std::is_scalar::value && !std::is_pointer::value && Mybase::value; }; template using TypesCheck = check_all_parameters; template class BaseExecutor { template using TC = TypesCheck; public: template> struct FunctionImpl; // function requires parameters pass by value, no reference, no pointer template struct FunctionImpl::value>> { using ResultType = Ret; using CALLABLE = Ret(Args...); CALLABLE *ptr; FunctionImpl(CALLABLE& callable) : ptr(&callable) {} ResultType invoke(Args... args) { return ((CALLABLE *)ptr)(args...); } }; // only for class inherit from std::enable_shared_from_this template struct FunctionImpl::value>> { using ResultType = Ret; using CALLABLE = Ret(Ct::*)(Args...); using SHAREPOINTER = std::shared_ptr; using Derived = std::enable_if_t, Ct>::value>; CALLABLE ptr; FunctionImpl(CALLABLE& callable) : ptr(callable) {} ResultType invoke(SHAREPOINTER cls, Args... args) { return (cls.get()->*ptr)(args...); } }; typedef FunctionImpl Function; typedef std::shared_ptr FunctionPointer; protected: FunctionPointer _fx; public: BaseExecutor(FunctionType& fx) : _fx(new Function(fx)) {} }; template class TimeOutExecutor : public BaseExecutor { uint32_t _timeout = 2000; //milliseconds using Mybase = BaseExecutor; using Result = typename BaseExecutor::Function::ResultType; public: enum ExecuteResult { SUCCESS, TIMEOUT }; TimeOutExecutor(FunctionType&& ft) : Mybase(ft) {} template ExecuteResult Execute(Result &result, Args... args) { // add ref count auto funcImpl = this->_fx; std::shared_ptr cv = std::make_shared(); std::shared_ptr is_detach = std::make_shared(false); std::shared_ptr mtxPointer = std::make_shared(); std::unique_lock lck(*mtxPointer); std::thread workThread([=, &result]() { { std::unique_lock lck(*mtxPointer); } #ifndef NOLOG std::chrono::system_clock::time_point begin = std::chrono::system_clock::now(); #endif Result r = funcImpl->invoke(args...); #ifndef NOLOG std::chrono::system_clock::time_point end = std::chrono::system_clock::now(); std::cout << "Actually execute time: " << \ std::chrono::duration_cast(end - begin).count() << " ms" << std::endl; #endif { std::unique_lock lck(*mtxPointer); if (false == (*is_detach)) { result = r; cv->notify_one(); //notify join thread completion } } }); if (cv->wait_for(lck, std::chrono::milliseconds(_timeout)) == std::cv_status::timeout) { *is_detach = true; workThread.detach(); //detach work thread and return timeout return TimeOutExecutor::TIMEOUT; } workThread.join(); return TimeOutExecutor::SUCCESS; } void SetTimeOut(uint32_t ms) { _timeout = ms; } uint32_t GetTimeOut() const { return _timeout; } }; } #endif //HOS_TIMEOUTEXECUTOR_H