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 }