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
33 namespace OHOS {
34 namespace DHCP {
35 DEFINE_DHCPLOG_DHCP_LABEL("DhcpThread");
36 #if DHCP_FFRT_ENABLE
37 class DhcpThread::DhcpThreadImpl {
38 public:
DhcpThreadImpl(const std::string & threadName)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 }
~DhcpThreadImpl()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 }
PostSyncTask(Callback & callback)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 }
PostAsyncTask(Callback & callback,int64_t delayTime=0)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 }
PostAsyncTask(Callback & callback,const std::string & name,int64_t delayTime=0)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 }
RemoveAsyncTask(const std::string & name)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 }
122 private:
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
128 class DhcpThread::DhcpThreadImpl {
129 public:
DhcpThreadImpl(const std::string & threadName)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 }
~DhcpThreadImpl()136 ~DhcpThreadImpl()
137 {
138 mRunFlag = false;
139 mCondition.notify_one();
140 if (mWorkerThread.joinable()) {
141 mWorkerThread.join();
142 }
143 }
PostSyncTask(Callback & callback)144 bool PostSyncTask(Callback &callback)
145 {
146 DHCP_LOGE("DhcpThreadImpl PostSyncTask Unsupported in lite.");
147 return false;
148 }
PostAsyncTask(Callback & callback,int64_t delayTime=0)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 }
PostAsyncTask(Callback & callback,const std::string & name,int64_t delayTime=0)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 }
RemoveAsyncTask(const std::string & name)168 void RemoveAsyncTask(const std::string &name)
169 {
170 DHCP_LOGE("DhcpThreadImpl RemoveAsyncTask Unsupported in lite.");
171 }
172 private:
Run(DhcpThreadImpl & instance)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
DhcpThread(const std::string & threadName)199 DhcpThread::DhcpThread(const std::string &threadName)
200 :ptr_(new DhcpThreadImpl(threadName))
201 {}
202
~DhcpThread()203 DhcpThread::~DhcpThread()
204 {
205 ptr_.reset();
206 }
207
PostSyncTask(const Callback & callback)208 bool 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
PostAsyncTask(const Callback & callback,int64_t delayTime)217 bool 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
PostAsyncTask(const Callback & callback,const std::string & name,int64_t delayTime)226 bool 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 }
RemoveAsyncTask(const std::string & name)234 void 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
GetInstance()244 DhcpTimer *DhcpTimer::GetInstance()
245 {
246 static DhcpTimer instance;
247 return &instance;
248 }
249 #ifdef DHCP_FFRT_ENABLE
DhcpTimer()250 DhcpTimer::DhcpTimer() : timer_(std::make_unique<DhcpThread>("DhcpTimer"))
251 {
252 timerIdInit = 0;
253 }
254
~DhcpTimer()255 DhcpTimer::~DhcpTimer()
256 {
257 if (timer_) {
258 timer_.reset();
259 }
260 }
261
Register(const TimerCallback & callback,uint32_t & outTimerId,uint32_t interval,bool once)262 EnumErrCode 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
UnRegister(uint32_t timerId)280 void 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
DhcpTimer()296 DhcpTimer::DhcpTimer() : timer_(std::make_unique<Utils::Timer>("DhcpTimer"))
297 {
298 timer_->Setup();
299 }
300
~DhcpTimer()301 DhcpTimer::~DhcpTimer()
302 {
303 if (timer_) {
304 timer_->Shutdown(true);
305 }
306 }
307
Register(const TimerCallback & callback,uint32_t & outTimerId,uint32_t interval,bool once)308 EnumErrCode 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
UnRegister(uint32_t timerId)325 void 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 }