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 #ifdef 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 #ifdef DHCP_FFRT_ENABLE
37 constexpr int DHCP_THREAD_TIMEOUT_LIMIT = 30 * 1000 * 1000; // 30s
38 constexpr int DHCP_THREAD_MAX_CONCURRENCY = 1;
TransferQueuePtr(std::shared_ptr<ffrt::queue> queue)39 inline ffrt_queue_t* TransferQueuePtr(std::shared_ptr<ffrt::queue> queue)
40 {
41 if (queue) {
42 return reinterpret_cast<ffrt_queue_t*>(queue.get());
43 }
44 return nullptr;
45 }
46 class DhcpThread::DhcpThreadImpl {
47 public:
DhcpThreadImpl(const std::string & threadName)48 DhcpThreadImpl(const std::string &threadName)
49 {
50 std::lock_guard<ffrt::mutex> lock(eventQurueMutex);
51 if (eventQueue != nullptr) {
52 DHCP_LOGI("DhcpThreadImpl already init.");
53 return;
54 }
55 eventQueue = std::make_shared<ffrt::queue>(ffrt::queue_concurrent, threadName.c_str(),
56 ffrt::queue_attr().max_concurrency(DHCP_THREAD_MAX_CONCURRENCY));
57 DHCP_LOGI("DhcpThreadImpl: Create a new eventQueue, threadName:%{public}s", threadName.c_str());
58 }
~DhcpThreadImpl()59 ~DhcpThreadImpl()
60 {
61 DHCP_LOGI("DhcpThread: ~DhcpThread");
62 std::lock_guard<ffrt::mutex> lock(eventQurueMutex);
63 ffrt_queue_t* queue = TransferQueuePtr(eventQueue);
64 if (queue == nullptr) {
65 DHCP_LOGE("~DhcpThread is unavailable.");
66 return;
67 }
68 ffrt_queue_cancel_all(*queue);
69 if (eventQueue != nullptr) {
70 eventQueue.reset();
71 }
72 }
73
PostSyncTask(Callback & callback)74 bool PostSyncTask(Callback &callback)
75 {
76 std::lock_guard<ffrt::mutex> lock(eventQurueMutex);
77 if (eventQueue == nullptr) {
78 DHCP_LOGE("PostSyncTask: eventQueue is nullptr!");
79 return false;
80 }
81 DHCP_LOGD("PostSyncTask Enter");
82 ffrt::task_handle handle = eventQueue->submit_h(callback);
83 if (handle == nullptr) {
84 return false;
85 }
86 eventQueue->wait(handle);
87 return true;
88 }
PostAsyncTask(Callback & callback,int64_t delayTime=0)89 bool PostAsyncTask(Callback &callback, int64_t delayTime = 0)
90 {
91 std::lock_guard<ffrt::mutex> lock(eventQurueMutex);
92 if (eventQueue == nullptr) {
93 DHCP_LOGE("PostAsyncTask: eventQueue is nullptr!");
94 return false;
95 }
96 int64_t delayTimeUs = delayTime * 1000;
97 DHCP_LOGD("PostAsyncTask Enter");
98 ffrt::task_handle handle = eventQueue->submit_h(callback, ffrt::task_attr().delay(delayTimeUs));
99 return handle != nullptr;
100 }
PostAsyncTask(Callback & callback,const std::string & name,int64_t delayTime=0,bool isHighPriority=false)101 bool PostAsyncTask(Callback &callback, const std::string &name, int64_t delayTime = 0, bool isHighPriority = false)
102 {
103 std::lock_guard<ffrt::mutex> lock(eventQurueMutex);
104 if (eventQueue == nullptr) {
105 DHCP_LOGE("PostAsyncTask: eventQueue is nullptr!");
106 return false;
107 }
108 int64_t delayTimeUs = delayTime * 1000;
109 DHCP_LOGD("PostAsyncTask Enter %{public}s", name.c_str());
110 ffrt::task_handle handle = nullptr;
111 if (isHighPriority) {
112 handle = eventQueue->submit_h(callback,
113 ffrt::task_attr().name(name.c_str()).delay(delayTimeUs).priority(ffrt_queue_priority_immediate));
114 } else {
115 handle = eventQueue->submit_h(callback, ffrt::task_attr().name(name.c_str()).delay(delayTimeUs));
116 }
117 if (handle == nullptr) {
118 return false;
119 }
120 return true;
121 }
122
PostSyncTimeOutTask(const std::function<int32_t ()> & callback,int64_t waitTime)123 bool PostSyncTimeOutTask(const std::function<int32_t()> &callback, int64_t waitTime)
124 {
125 ffrt::future<int32_t> f = ffrt::async(callback);
126 ffrt::future_status status = f.wait_for(std::chrono::milliseconds(waitTime));
127 if (status == ffrt::future_status::timeout) {
128 DHCP_LOGE("PostSyncTimeOutTask: Task timeout");
129 return false;
130 }
131 return f.get() == 0 ? true : false;
132 }
133
RemoveAsyncTask(const std::string & name)134 void RemoveAsyncTask(const std::string &name)
135 {
136 std::lock_guard<ffrt::mutex> lock(eventQurueMutex);
137 DHCP_LOGD("RemoveAsyncTask Enter %{public}s", name.c_str());
138 ffrt_queue_t* queue = TransferQueuePtr(eventQueue);
139 if (queue == nullptr) {
140 DHCP_LOGE("RemoveAsyncTask is unavailable.");
141 return;
142 }
143 int ret = ffrt_queue_cancel_by_name(*queue, name.c_str());
144 if (ret != 0) {
145 DHCP_LOGD("RemoveAsyncTask failed.");
146 }
147 }
HasAsyncTask(const std::string & name,bool & hasTask)148 int HasAsyncTask(const std::string &name, bool &hasTask)
149 {
150 std::lock_guard<ffrt::mutex> lock(eventQurueMutex);
151 ffrt_queue_t* queue = TransferQueuePtr(eventQueue);
152 if (queue == nullptr) {
153 DHCP_LOGE("HasAsyncTask is unavailable.");
154 return -1;
155 }
156 bool result = ffrt_queue_has_task(*queue, name.c_str());
157 DHCP_LOGD("HasAsyncTask Enter %{public}s %{public}d", name.c_str(), static_cast<int>(result));
158 hasTask = result;
159 return 0;
160 }
161 private:
162 std::shared_ptr<ffrt::queue> eventQueue = nullptr;
163 mutable ffrt::mutex eventQurueMutex;
164 };
165 #else
166 class DhcpThread::DhcpThreadImpl {
167 public:
DhcpThreadImpl(const std::string & threadName)168 DhcpThreadImpl(const std::string &threadName)
169 {
170 mRunFlag = true;
171 mWorkerThread = std::thread(DhcpThreadImpl::Run, std::ref(*this));
172 pthread_setname_np(mWorkerThread.native_handle(), threadName.c_str());
173 }
~DhcpThreadImpl()174 ~DhcpThreadImpl()
175 {
176 mRunFlag = false;
177 mCondition.notify_one();
178 if (mWorkerThread.joinable()) {
179 mWorkerThread.join();
180 }
181 }
PostSyncTask(Callback & callback)182 bool PostSyncTask(Callback &callback)
183 {
184 DHCP_LOGE("DhcpThreadImpl PostSyncTask Unsupported in lite.");
185 return false;
186 }
PostAsyncTask(Callback & callback,int64_t delayTime=0)187 bool PostAsyncTask(Callback &callback, int64_t delayTime = 0)
188 {
189 if (delayTime > 0) {
190 DHCP_LOGE("DhcpThreadImpl PostAsyncTask with delayTime Unsupported in lite.");
191 return false;
192 }
193 DHCP_LOGD("PostAsyncTask Enter");
194 {
195 std::unique_lock<std::mutex> lock(mMutex);
196 mEventQue.push_back(callback);
197 }
198 mCondition.notify_one();
199 return true;
200 }
PostAsyncTask(Callback & callback,const std::string & name,int64_t delayTime=0,bool isHighPriority=false)201 bool PostAsyncTask(Callback &callback, const std::string &name, int64_t delayTime = 0, bool isHighPriority = false)
202 {
203 DHCP_LOGE("DhcpThreadImpl PostAsyncTask with name Unsupported in lite.");
204 return false;
205 }
RemoveAsyncTask(const std::string & name)206 void RemoveAsyncTask(const std::string &name)
207 {
208 DHCP_LOGE("DhcpThreadImpl RemoveAsyncTask Unsupported in lite.");
209 }
HasAsyncTask(const std::string & name,bool & hasTask)210 int HasAsyncTask(const std::string &name, bool &hasTask)
211 {
212 DHCP_LOGE("DhcpThreadImpl HasAsyncTask Unsupported in lite.");
213 return -1;
214 }
215 private:
Run(DhcpThreadImpl & instance)216 static void Run(DhcpThreadImpl &instance)
217 {
218 while (instance.mRunFlag) {
219 std::unique_lock<std::mutex> lock(instance.mMutex);
220 while (instance.mEventQue.empty() && instance.mRunFlag) {
221 instance.mCondition.wait(lock);
222 }
223 if (!instance.mRunFlag) {
224 break;
225 }
226 Callback msg = instance.mEventQue.front();
227 instance.mEventQue.pop_front();
228 lock.unlock();
229 msg();
230 }
231 return;
232 }
233 std::thread mWorkerThread;
234 std::atomic<bool> mRunFlag;
235 std::mutex mMutex;
236 std::condition_variable mCondition;
237 std::deque<Callback> mEventQue;
238 };
239 #endif
240
241
DhcpThread(const std::string & threadName)242 DhcpThread::DhcpThread(const std::string &threadName)
243 :ptr_(new DhcpThreadImpl(threadName))
244 {}
245
~DhcpThread()246 DhcpThread::~DhcpThread()
247 {
248 ptr_.reset();
249 }
250
PostSyncTask(const Callback & callback)251 bool DhcpThread::PostSyncTask(const Callback &callback)
252 {
253 if (ptr_ == nullptr) {
254 DHCP_LOGE("PostSyncTask: ptr_ is nullptr!");
255 return false;
256 }
257 return ptr_->PostSyncTask(const_cast<Callback &>(callback));
258 }
259
PostAsyncTask(const Callback & callback,int64_t delayTime)260 bool DhcpThread::PostAsyncTask(const Callback &callback, int64_t delayTime)
261 {
262 if (ptr_ == nullptr) {
263 DHCP_LOGE("PostAsyncTask: ptr_ is nullptr!");
264 return false;
265 }
266 return ptr_->PostAsyncTask(const_cast<Callback &>(callback), delayTime);
267 }
268
PostAsyncTask(const Callback & callback,const std::string & name,int64_t delayTime,bool isHighPriority)269 bool DhcpThread::PostAsyncTask(const Callback &callback, const std::string &name,
270 int64_t delayTime, bool isHighPriority)
271 {
272 if (ptr_ == nullptr) {
273 DHCP_LOGE("PostAsyncTask: ptr_ is nullptr!");
274 return false;
275 }
276 return ptr_->PostAsyncTask(const_cast<Callback &>(callback), name, delayTime, isHighPriority);
277 }
278
PostSyncTimeOutTask(const std::function<int32_t ()> & callback,int32_t waitTime)279 bool DhcpThread::PostSyncTimeOutTask(const std::function<int32_t()> &callback, int32_t waitTime)
280 {
281 if (ptr_ == nullptr) {
282 DHCP_LOGE("PostSyncTimeOutTask: ptr_ is nullptr!");
283 return false;
284 }
285 if (waitTime < 0) {
286 DHCP_LOGE("waitTime %{public}d < 0!", waitTime);
287 return false;
288 }
289 return ptr_->PostSyncTimeOutTask(callback, waitTime);
290 }
291
RemoveAsyncTask(const std::string & name)292 void DhcpThread::RemoveAsyncTask(const std::string &name)
293 {
294 if (ptr_ == nullptr) {
295 DHCP_LOGE("RemoveAsyncTask: ptr_ is nullptr!");
296 return;
297 }
298 ptr_->RemoveAsyncTask(name);
299 }
300
HasAsyncTask(const std::string & name,bool & hasTask)301 int DhcpThread::HasAsyncTask(const std::string &name, bool &hasTask)
302 {
303 if (ptr_ == nullptr) {
304 DHCP_LOGE("HasAsyncTask: ptr_ is nullptr!");
305 return -1;
306 }
307 return ptr_->HasAsyncTask(name, hasTask);
308 }
309
310 #ifndef OHOS_ARCH_LITE
GetInstance()311 DhcpTimer *DhcpTimer::GetInstance()
312 {
313 static DhcpTimer instance;
314 return &instance;
315 }
316 #ifdef DHCP_FFRT_ENABLE
DhcpTimer()317 DhcpTimer::DhcpTimer() : timer_(std::make_unique<DhcpThread>("DhcpTimer"))
318 {
319 timerIdInit = 0;
320 }
321
~DhcpTimer()322 DhcpTimer::~DhcpTimer()
323 {
324 if (timer_) {
325 timer_.reset();
326 }
327 }
328
Register(const TimerCallback & callback,uint32_t & outTimerId,uint32_t interval,bool once)329 EnumErrCode DhcpTimer::Register(const TimerCallback &callback, uint32_t &outTimerId, uint32_t interval, bool once)
330 {
331 if (timer_ == nullptr) {
332 DHCP_LOGE("timer_ is nullptr");
333 return DHCP_OPT_FAILED;
334 }
335 timerIdInit++;
336 bool ret = timer_->PostAsyncTask(callback, std::to_string(timerIdInit), interval);
337 if (!ret) {
338 DHCP_LOGE("Register timer failed");
339 timerIdInit--;
340 return DHCP_OPT_FAILED;
341 }
342
343 outTimerId = timerIdInit;
344 return DHCP_OPT_SUCCESS;
345 }
346
UnRegister(uint32_t timerId)347 void DhcpTimer::UnRegister(uint32_t timerId)
348 {
349 if (timerId == 0) {
350 DHCP_LOGE("timerId is 0, no register timer");
351 return;
352 }
353
354 if (timer_ == nullptr) {
355 DHCP_LOGE("timer_ is nullptr");
356 return;
357 }
358
359 timer_->RemoveAsyncTask(std::to_string(timerId));
360 return;
361 }
362 #else
DhcpTimer()363 DhcpTimer::DhcpTimer() : timer_(std::make_unique<Utils::Timer>("DhcpTimer"))
364 {
365 timer_->Setup();
366 }
367
~DhcpTimer()368 DhcpTimer::~DhcpTimer()
369 {
370 if (timer_) {
371 timer_->Shutdown(true);
372 }
373 }
374
Register(const TimerCallback & callback,uint32_t & outTimerId,uint32_t interval,bool once)375 EnumErrCode DhcpTimer::Register(const TimerCallback &callback, uint32_t &outTimerId, uint32_t interval, bool once)
376 {
377 if (timer_ == nullptr) {
378 DHCP_LOGE("timer_ is nullptr");
379 return DHCP_OPT_FAILED;
380 }
381
382 uint32_t ret = timer_->Register(callback, interval, once);
383 if (ret == Utils::TIMER_ERR_DEAL_FAILED) {
384 DHCP_LOGE("Register timer failed");
385 return DHCP_OPT_FAILED;
386 }
387
388 outTimerId = ret;
389 return DHCP_OPT_SUCCESS;
390 }
391
UnRegister(uint32_t timerId)392 void DhcpTimer::UnRegister(uint32_t timerId)
393 {
394 if (timerId == 0) {
395 DHCP_LOGE("timerId is 0, no register timer");
396 return;
397 }
398
399 if (timer_ == nullptr) {
400 DHCP_LOGE("timer_ is nullptr");
401 return;
402 }
403
404 timer_->Unregister(timerId);
405 return;
406 }
407 #endif
408 #endif
409 }
410 }