1 /* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef HOS_TIMEOUTEXECUTOR_H 17 #define HOS_TIMEOUTEXECUTOR_H 18 #include <chrono> 19 #include <memory> 20 #include <thread> // std::thread 21 #include <mutex> // std::mutex, std::unique_lock 22 #include <condition_variable> // std::condition_variable 23 #include <type_traits> 24 #include <atomic> 25 #include <functional> 26 27 namespace OHOS::TIMEOUTEXECUTOR { 28 29 template<class... Params> 30 struct check_all_parameters; 31 32 template <> 33 struct check_all_parameters<> { 34 static const bool value = true; 35 }; 36 37 template <class T, class... Others> 38 struct check_all_parameters<T, Others...> : 39 private check_all_parameters<Others...> { 40 using Mybase = check_all_parameters<Others...>; 41 static const bool value = \ 42 std::is_scalar<T>::value && !std::is_pointer<T>::value && Mybase::value; 43 }; 44 45 template <class... Params> 46 using TypesCheck = check_all_parameters<Params...>; 47 48 template <class FunctionType> 49 class BaseExecutor { 50 template<class... Params> 51 using TC = TypesCheck<Params...>; 52 public: 53 template<class _Fx, class Params = std::enable_if_t<true>> 54 struct FunctionImpl; 55 56 // function requires parameters pass by value, no reference, no pointer 57 template<class Ret, class... Args> 58 struct FunctionImpl<Ret(Args...), std::enable_if_t<TC<Ret, Args...>::value>> { 59 using ResultType = Ret; 60 using CALLABLE = Ret(Args...); 61 62 CALLABLE *ptr; 63 FunctionImpl(CALLABLE& callable) : ptr(&callable) {} 64 65 ResultType invoke(Args... args) 66 { 67 return ((CALLABLE *)ptr)(args...); 68 } 69 }; 70 71 // only for class inherit from std::enable_shared_from_this<T> 72 template<class Ret, class Ct, class... Args> 73 struct FunctionImpl<Ret(Ct::*)(Args...), std::enable_if_t<TC<Ret, Args...>::value>> { 74 using ResultType = Ret; 75 using CALLABLE = Ret(Ct::*)(Args...); 76 using SHAREPOINTER = std::shared_ptr<Ct>; 77 using Derived = std::enable_if_t<std::is_base_of<std::enable_shared_from_this<Ct>, Ct>::value>; 78 79 CALLABLE ptr; 80 FunctionImpl(CALLABLE& callable) : ptr(callable) {} 81 82 ResultType invoke(SHAREPOINTER cls, Args... args) 83 { 84 return (cls.get()->*ptr)(args...); 85 } 86 }; 87 88 typedef FunctionImpl<FunctionType> Function; 89 typedef std::shared_ptr<Function> FunctionPointer; 90 91 protected: 92 FunctionPointer _fx; 93 94 public: 95 BaseExecutor(FunctionType& fx) : _fx(new Function(fx)) {} 96 }; 97 98 template <class FunctionType> 99 class TimeOutExecutor : public BaseExecutor<FunctionType> { 100 uint32_t _timeout = 2000; //milliseconds 101 using Mybase = BaseExecutor<FunctionType>; 102 using Result = typename BaseExecutor<FunctionType>::Function::ResultType; 103 104 public: 105 enum ExecuteResult { 106 SUCCESS, 107 TIMEOUT 108 }; 109 110 TimeOutExecutor(FunctionType&& ft) : Mybase(ft) {} 111 112 template<class... Args> 113 ExecuteResult Execute(Result &result, Args... args) 114 { 115 // add ref count 116 auto funcImpl = this->_fx; 117 118 std::shared_ptr<std::condition_variable> cv = 119 std::make_shared<std::condition_variable>(); 120 121 std::shared_ptr<bool> is_detach = 122 std::make_shared<bool>(false); 123 124 std::shared_ptr <std::mutex> mtxPointer = std::make_shared<std::mutex>(); 125 std::unique_lock<std::mutex> lck(*mtxPointer); 126 127 std::thread workThread([=, &result]() { 128 { 129 std::unique_lock<std::mutex> lck(*mtxPointer); 130 } 131 132 #ifndef NOLOG 133 std::chrono::system_clock::time_point begin = std::chrono::system_clock::now(); 134 #endif 135 Result r = funcImpl->invoke(args...); 136 #ifndef NOLOG 137 std::chrono::system_clock::time_point end = std::chrono::system_clock::now(); 138 std::cout << "Actually execute time: " << \ 139 std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << " ms" << std::endl; 140 #endif 141 { 142 std::unique_lock<std::mutex> lck(*mtxPointer); 143 144 if (false == (*is_detach)) { 145 result = r; 146 cv->notify_one(); //notify join thread completion 147 } 148 } 149 }); 150 151 if (cv->wait_for(lck, std::chrono::milliseconds(_timeout)) == 152 std::cv_status::timeout) { 153 *is_detach = true; 154 workThread.detach(); //detach work thread and return timeout 155 return TimeOutExecutor::TIMEOUT; 156 } 157 158 workThread.join(); 159 return TimeOutExecutor::SUCCESS; 160 } 161 162 void SetTimeOut(uint32_t ms) 163 { 164 _timeout = ms; 165 } 166 167 uint32_t GetTimeOut() const 168 { 169 return _timeout; 170 } 171 }; 172 } 173 174 #endif //HOS_TIMEOUTEXECUTOR_H