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 return ptr->PostSyncTask(const_cast<Callback &>(callback));
211 }
212
PostAsyncTask(const Callback & callback,int64_t delayTime)213 bool DhcpThread::PostAsyncTask(const Callback &callback, int64_t delayTime)
214 {
215 return ptr->PostAsyncTask(const_cast<Callback &>(callback), delayTime);
216 }
217
PostAsyncTask(const Callback & callback,const std::string & name,int64_t delayTime)218 bool DhcpThread::PostAsyncTask(const Callback &callback, const std::string &name, int64_t delayTime)
219 {
220 return ptr->PostAsyncTask(const_cast<Callback &>(callback), name, delayTime);
221 }
RemoveAsyncTask(const std::string & name)222 void DhcpThread::RemoveAsyncTask(const std::string &name)
223 {
224 ptr->RemoveAsyncTask(name);
225 }
226
227 #ifndef OHOS_ARCH_LITE
GetInstance()228 DhcpTimer *DhcpTimer::GetInstance()
229 {
230 static DhcpTimer instance;
231 return &instance;
232 }
233 #ifdef DHCP_FFRT_ENABLE
DhcpTimer()234 DhcpTimer::DhcpTimer() : timer_(std::make_unique<DhcpThread>("DhcpTimer"))
235 {
236 timerIdInit = 0;
237 }
238
~DhcpTimer()239 DhcpTimer::~DhcpTimer()
240 {
241 if (timer_) {
242 timer_.reset();
243 }
244 }
245
Register(const TimerCallback & callback,uint32_t & outTimerId,uint32_t interval,bool once)246 EnumErrCode DhcpTimer::Register(const TimerCallback &callback, uint32_t &outTimerId, uint32_t interval, bool once)
247 {
248 if (timer_ == nullptr) {
249 DHCP_LOGE("timer_ is nullptr");
250 return DHCP_OPT_FAILED;
251 }
252 timerIdInit++;
253 bool ret = timer_->PostAsyncTask(callback, std::to_string(timerIdInit), interval);
254 if (!ret) {
255 DHCP_LOGE("Register timer failed");
256 timerIdInit--;
257 return DHCP_OPT_FAILED;
258 }
259
260 outTimerId = timerIdInit;
261 return DHCP_OPT_SUCCESS;
262 }
263
UnRegister(uint32_t timerId)264 void DhcpTimer::UnRegister(uint32_t timerId)
265 {
266 if (timerId == 0) {
267 DHCP_LOGE("timerId is 0, no register timer");
268 return;
269 }
270
271 if (timer_ == nullptr) {
272 DHCP_LOGE("timer_ is nullptr");
273 return;
274 }
275
276 timer_->RemoveAsyncTask(std::to_string(timerId));
277 return;
278 }
279 #else
DhcpTimer()280 DhcpTimer::DhcpTimer() : timer_(std::make_unique<Utils::Timer>("DhcpTimer"))
281 {
282 timer_->Setup();
283 }
284
~DhcpTimer()285 DhcpTimer::~DhcpTimer()
286 {
287 if (timer_) {
288 timer_->Shutdown(true);
289 }
290 }
291
Register(const TimerCallback & callback,uint32_t & outTimerId,uint32_t interval,bool once)292 EnumErrCode DhcpTimer::Register(const TimerCallback &callback, uint32_t &outTimerId, uint32_t interval, bool once)
293 {
294 if (timer_ == nullptr) {
295 DHCP_LOGE("timer_ is nullptr");
296 return DHCP_OPT_FAILED;
297 }
298
299 uint32_t ret = timer_->Register(callback, interval, once);
300 if (ret == Utils::TIMER_ERR_DEAL_FAILED) {
301 DHCP_LOGE("Register timer failed");
302 return DHCP_OPT_FAILED;
303 }
304
305 outTimerId = ret;
306 return DHCP_OPT_SUCCESS;
307 }
308
UnRegister(uint32_t timerId)309 void DhcpTimer::UnRegister(uint32_t timerId)
310 {
311 if (timerId == 0) {
312 DHCP_LOGE("timerId is 0, no register timer");
313 return;
314 }
315
316 if (timer_ == nullptr) {
317 DHCP_LOGE("timer_ is nullptr");
318 return;
319 }
320
321 timer_->Unregister(timerId);
322 return;
323 }
324 #endif
325 #endif
326 }
327 }