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#include <map> 16#include "dhcp_thread.h" 17#include "dhcp_logger.h" 18#if DHCP_FFRT_ENABLE 19#include "ffrt_inner.h" 20#else 21#include <atomic> 22#include <chrono> 23#include <condition_variable> 24#include <deque> 25#include <memory> 26#include <mutex> 27#include <thread> 28#ifndef OHOS_ARCH_LITE 29#include "common_timer_errors.h" 30#include "timer.h" 31#endif 32#endif 33namespace OHOS { 34namespace DHCP { 35DEFINE_DHCPLOG_DHCP_LABEL("DhcpThread"); 36#if DHCP_FFRT_ENABLE 37class DhcpThread::DhcpThreadImpl { 38public: 39 DhcpThreadImpl(const std::string &threadName) 40 { 41 std::lock_guard<ffrt::mutex> lock(eventQurueMutex); 42 if (eventQueue != nullptr) { 43 DHCP_LOGI("DhcpThreadImpl already init."); 44 return; 45 } 46 eventQueue = std::make_shared<ffrt::queue>(threadName.c_str()); 47 DHCP_LOGI("DhcpThreadImpl: Create a new eventQueue, threadName:%{public}s", threadName.c_str()); 48 } 49 ~DhcpThreadImpl() 50 { 51 std::lock_guard<ffrt::mutex> lock(eventQurueMutex); 52 DHCP_LOGI("DhcpThread: ~DhcpThread"); 53 if (eventQueue) { 54 eventQueue = nullptr; 55 } 56 for (auto iter = taskMap_.begin(); iter != taskMap_.end();) { 57 iter->second = nullptr; 58 iter = taskMap_.erase(iter); 59 } 60 } 61 bool PostSyncTask(Callback &callback) 62 { 63 std::lock_guard<ffrt::mutex> lock(eventQurueMutex); 64 if (eventQueue == nullptr) { 65 DHCP_LOGE("PostSyncTask: eventQueue is nullptr!"); 66 return false; 67 } 68 DHCP_LOGD("PostSyncTask Enter"); 69 ffrt::task_handle handle = eventQueue->submit_h(callback); 70 if (handle == nullptr) { 71 return false; 72 } 73 eventQueue->wait(handle); 74 return true; 75 } 76 bool PostAsyncTask(Callback &callback, int64_t delayTime = 0) 77 { 78 std::lock_guard<ffrt::mutex> lock(eventQurueMutex); 79 if (eventQueue == nullptr) { 80 DHCP_LOGE("PostAsyncTask: eventQueue is nullptr!"); 81 return false; 82 } 83 int64_t delayTimeUs = delayTime * 1000; 84 DHCP_LOGD("PostAsyncTask Enter"); 85 ffrt::task_handle handle = eventQueue->submit_h(callback, ffrt::task_attr().delay(delayTimeUs)); 86 return handle != nullptr; 87 } 88 bool PostAsyncTask(Callback &callback, const std::string &name, int64_t delayTime = 0) 89 { 90 std::lock_guard<ffrt::mutex> lock(eventQurueMutex); 91 if (eventQueue == nullptr) { 92 DHCP_LOGE("PostAsyncTask: eventQueue is nullptr!"); 93 return false; 94 } 95 int64_t delayTimeUs = delayTime * 1000; 96 DHCP_LOGD("PostAsyncTask Enter %{public}s", name.c_str()); 97 ffrt::task_handle handle = eventQueue->submit_h( 98 callback, ffrt::task_attr().name(name.c_str()).delay(delayTimeUs)); 99 if (handle == nullptr) { 100 return false; 101 } 102 taskMap_[name] = std::move(handle); 103 return true; 104 } 105 void RemoveAsyncTask(const std::string &name) 106 { 107 std::lock_guard<ffrt::mutex> lock(eventQurueMutex); 108 DHCP_LOGD("RemoveAsyncTask Enter %{public}s", name.c_str()); 109 auto item = taskMap_.find(name); 110 if (item == taskMap_.end()) { 111 DHCP_LOGD("task not found"); 112 return; 113 } 114 if (item->second != nullptr && eventQueue != nullptr) { 115 int32_t ret = eventQueue->cancel(item->second); 116 if (ret != 0) { 117 DHCP_LOGE("RemoveAsyncTask failed, error code : %{public}d", ret); 118 } 119 } 120 taskMap_.erase(name); 121 } 122private: 123 std::shared_ptr<ffrt::queue> eventQueue = nullptr; 124 mutable ffrt::mutex eventQurueMutex; 125 std::map<std::string, ffrt::task_handle> taskMap_; 126}; 127#else 128class DhcpThread::DhcpThreadImpl { 129public: 130 DhcpThreadImpl(const std::string &threadName) 131 { 132 mRunFlag = true; 133 mWorkerThread = std::thread(DhcpThreadImpl::Run, std::ref(*this)); 134 pthread_setname_np(mWorkerThread.native_handle(), threadName.c_str()); 135 } 136 ~DhcpThreadImpl() 137 { 138 mRunFlag = false; 139 mCondition.notify_one(); 140 if (mWorkerThread.joinable()) { 141 mWorkerThread.join(); 142 } 143 } 144 bool PostSyncTask(Callback &callback) 145 { 146 DHCP_LOGE("DhcpThreadImpl PostSyncTask Unsupported in lite."); 147 return false; 148 } 149 bool PostAsyncTask(Callback &callback, int64_t delayTime = 0) 150 { 151 if (delayTime > 0) { 152 DHCP_LOGE("DhcpThreadImpl PostAsyncTask with delayTime Unsupported in lite."); 153 return false; 154 } 155 DHCP_LOGD("PostAsyncTask Enter"); 156 { 157 std::unique_lock<std::mutex> lock(mMutex); 158 mEventQue.push_back(callback); 159 } 160 mCondition.notify_one(); 161 return true; 162 } 163 bool PostAsyncTask(Callback &callback, const std::string &name, int64_t delayTime = 0) 164 { 165 DHCP_LOGE("DhcpThreadImpl PostAsyncTask with name Unsupported in lite."); 166 return false; 167 } 168 void RemoveAsyncTask(const std::string &name) 169 { 170 DHCP_LOGE("DhcpThreadImpl RemoveAsyncTask Unsupported in lite."); 171 } 172private: 173 static void Run(DhcpThreadImpl &instance) 174 { 175 while (instance.mRunFlag) { 176 std::unique_lock<std::mutex> lock(instance.mMutex); 177 while (instance.mEventQue.empty() && instance.mRunFlag) { 178 instance.mCondition.wait(lock); 179 } 180 if (!instance.mRunFlag) { 181 break; 182 } 183 Callback msg = instance.mEventQue.front(); 184 instance.mEventQue.pop_front(); 185 lock.unlock(); 186 msg(); 187 } 188 return; 189 } 190 std::thread mWorkerThread; 191 std::atomic<bool> mRunFlag; 192 std::mutex mMutex; 193 std::condition_variable mCondition; 194 std::deque<Callback> mEventQue; 195}; 196#endif 197 198 199DhcpThread::DhcpThread(const std::string &threadName) 200 :ptr_(new DhcpThreadImpl(threadName)) 201{} 202 203DhcpThread::~DhcpThread() 204{ 205 ptr_.reset(); 206} 207 208bool DhcpThread::PostSyncTask(const Callback &callback) 209{ 210 if (ptr_ == nullptr) { 211 DHCP_LOGE("PostSyncTask: ptr_ is nullptr!"); 212 return false; 213 } 214 return ptr_->PostSyncTask(const_cast<Callback &>(callback)); 215} 216 217bool DhcpThread::PostAsyncTask(const Callback &callback, int64_t delayTime) 218{ 219 if (ptr_ == nullptr) { 220 DHCP_LOGE("PostAsyncTask: ptr_ is nullptr!"); 221 return false; 222 } 223 return ptr_->PostAsyncTask(const_cast<Callback &>(callback), delayTime); 224} 225 226bool DhcpThread::PostAsyncTask(const Callback &callback, const std::string &name, int64_t delayTime) 227{ 228 if (ptr_ == nullptr) { 229 DHCP_LOGE("PostAsyncTask: ptr_ is nullptr!"); 230 return false; 231 } 232 return ptr_->PostAsyncTask(const_cast<Callback &>(callback), name, delayTime); 233} 234void DhcpThread::RemoveAsyncTask(const std::string &name) 235{ 236 if (ptr_ == nullptr) { 237 DHCP_LOGE("RemoveAsyncTask: ptr_ is nullptr!"); 238 return; 239 } 240 ptr_->RemoveAsyncTask(name); 241} 242 243#ifndef OHOS_ARCH_LITE 244DhcpTimer *DhcpTimer::GetInstance() 245{ 246 static DhcpTimer instance; 247 return &instance; 248} 249#ifdef DHCP_FFRT_ENABLE 250DhcpTimer::DhcpTimer() : timer_(std::make_unique<DhcpThread>("DhcpTimer")) 251{ 252 timerIdInit = 0; 253} 254 255DhcpTimer::~DhcpTimer() 256{ 257 if (timer_) { 258 timer_.reset(); 259 } 260} 261 262EnumErrCode DhcpTimer::Register(const TimerCallback &callback, uint32_t &outTimerId, uint32_t interval, bool once) 263{ 264 if (timer_ == nullptr) { 265 DHCP_LOGE("timer_ is nullptr"); 266 return DHCP_OPT_FAILED; 267 } 268 timerIdInit++; 269 bool ret = timer_->PostAsyncTask(callback, std::to_string(timerIdInit), interval); 270 if (!ret) { 271 DHCP_LOGE("Register timer failed"); 272 timerIdInit--; 273 return DHCP_OPT_FAILED; 274 } 275 276 outTimerId = timerIdInit; 277 return DHCP_OPT_SUCCESS; 278} 279 280void DhcpTimer::UnRegister(uint32_t timerId) 281{ 282 if (timerId == 0) { 283 DHCP_LOGE("timerId is 0, no register timer"); 284 return; 285 } 286 287 if (timer_ == nullptr) { 288 DHCP_LOGE("timer_ is nullptr"); 289 return; 290 } 291 292 timer_->RemoveAsyncTask(std::to_string(timerId)); 293 return; 294} 295#else 296DhcpTimer::DhcpTimer() : timer_(std::make_unique<Utils::Timer>("DhcpTimer")) 297{ 298 timer_->Setup(); 299} 300 301DhcpTimer::~DhcpTimer() 302{ 303 if (timer_) { 304 timer_->Shutdown(true); 305 } 306} 307 308EnumErrCode DhcpTimer::Register(const TimerCallback &callback, uint32_t &outTimerId, uint32_t interval, bool once) 309{ 310 if (timer_ == nullptr) { 311 DHCP_LOGE("timer_ is nullptr"); 312 return DHCP_OPT_FAILED; 313 } 314 315 uint32_t ret = timer_->Register(callback, interval, once); 316 if (ret == Utils::TIMER_ERR_DEAL_FAILED) { 317 DHCP_LOGE("Register timer failed"); 318 return DHCP_OPT_FAILED; 319 } 320 321 outTimerId = ret; 322 return DHCP_OPT_SUCCESS; 323} 324 325void DhcpTimer::UnRegister(uint32_t timerId) 326{ 327 if (timerId == 0) { 328 DHCP_LOGE("timerId is 0, no register timer"); 329 return; 330 } 331 332 if (timer_ == nullptr) { 333 DHCP_LOGE("timer_ is nullptr"); 334 return; 335 } 336 337 timer_->Unregister(timerId); 338 return; 339} 340#endif 341#endif 342} 343}