• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }