1518678f8Sopenharmony_ci/*
2518678f8Sopenharmony_ci * Copyright (C) 2024 Huawei Device Co., Ltd.
3518678f8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4518678f8Sopenharmony_ci * you may not use this file except in compliance with the License.
5518678f8Sopenharmony_ci * You may obtain a copy of the License at
6518678f8Sopenharmony_ci *
7518678f8Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8518678f8Sopenharmony_ci *
9518678f8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10518678f8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11518678f8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12518678f8Sopenharmony_ci * See the License for the specific language governing permissions and
13518678f8Sopenharmony_ci * limitations under the License.
14518678f8Sopenharmony_ci */
15518678f8Sopenharmony_ci#include <map>
16518678f8Sopenharmony_ci#include "dhcp_thread.h"
17518678f8Sopenharmony_ci#include "dhcp_logger.h"
18518678f8Sopenharmony_ci#if DHCP_FFRT_ENABLE
19518678f8Sopenharmony_ci#include "ffrt_inner.h"
20518678f8Sopenharmony_ci#else
21518678f8Sopenharmony_ci#include <atomic>
22518678f8Sopenharmony_ci#include <chrono>
23518678f8Sopenharmony_ci#include <condition_variable>
24518678f8Sopenharmony_ci#include <deque>
25518678f8Sopenharmony_ci#include <memory>
26518678f8Sopenharmony_ci#include <mutex>
27518678f8Sopenharmony_ci#include <thread>
28518678f8Sopenharmony_ci#ifndef OHOS_ARCH_LITE
29518678f8Sopenharmony_ci#include "common_timer_errors.h"
30518678f8Sopenharmony_ci#include "timer.h"
31518678f8Sopenharmony_ci#endif
32518678f8Sopenharmony_ci#endif
33518678f8Sopenharmony_cinamespace OHOS {
34518678f8Sopenharmony_cinamespace DHCP {
35518678f8Sopenharmony_ciDEFINE_DHCPLOG_DHCP_LABEL("DhcpThread");
36518678f8Sopenharmony_ci#if DHCP_FFRT_ENABLE
37518678f8Sopenharmony_ciclass DhcpThread::DhcpThreadImpl {
38518678f8Sopenharmony_cipublic:
39518678f8Sopenharmony_ci    DhcpThreadImpl(const std::string &threadName)
40518678f8Sopenharmony_ci    {
41518678f8Sopenharmony_ci        std::lock_guard<ffrt::mutex> lock(eventQurueMutex);
42518678f8Sopenharmony_ci        if (eventQueue != nullptr) {
43518678f8Sopenharmony_ci            DHCP_LOGI("DhcpThreadImpl already init.");
44518678f8Sopenharmony_ci            return;
45518678f8Sopenharmony_ci        }
46518678f8Sopenharmony_ci        eventQueue = std::make_shared<ffrt::queue>(threadName.c_str());
47518678f8Sopenharmony_ci        DHCP_LOGI("DhcpThreadImpl: Create a new eventQueue, threadName:%{public}s", threadName.c_str());
48518678f8Sopenharmony_ci    }
49518678f8Sopenharmony_ci    ~DhcpThreadImpl()
50518678f8Sopenharmony_ci    {
51518678f8Sopenharmony_ci        std::lock_guard<ffrt::mutex> lock(eventQurueMutex);
52518678f8Sopenharmony_ci        DHCP_LOGI("DhcpThread: ~DhcpThread");
53518678f8Sopenharmony_ci        if (eventQueue) {
54518678f8Sopenharmony_ci            eventQueue = nullptr;
55518678f8Sopenharmony_ci        }
56518678f8Sopenharmony_ci        for (auto iter = taskMap_.begin(); iter != taskMap_.end();) {
57518678f8Sopenharmony_ci            iter->second = nullptr;
58518678f8Sopenharmony_ci            iter = taskMap_.erase(iter);
59518678f8Sopenharmony_ci        }
60518678f8Sopenharmony_ci    }
61518678f8Sopenharmony_ci    bool PostSyncTask(Callback &callback)
62518678f8Sopenharmony_ci    {
63518678f8Sopenharmony_ci        std::lock_guard<ffrt::mutex> lock(eventQurueMutex);
64518678f8Sopenharmony_ci        if (eventQueue == nullptr) {
65518678f8Sopenharmony_ci            DHCP_LOGE("PostSyncTask: eventQueue is nullptr!");
66518678f8Sopenharmony_ci            return false;
67518678f8Sopenharmony_ci        }
68518678f8Sopenharmony_ci        DHCP_LOGD("PostSyncTask Enter");
69518678f8Sopenharmony_ci        ffrt::task_handle handle = eventQueue->submit_h(callback);
70518678f8Sopenharmony_ci        if (handle == nullptr) {
71518678f8Sopenharmony_ci            return false;
72518678f8Sopenharmony_ci        }
73518678f8Sopenharmony_ci        eventQueue->wait(handle);
74518678f8Sopenharmony_ci        return true;
75518678f8Sopenharmony_ci    }
76518678f8Sopenharmony_ci    bool PostAsyncTask(Callback &callback, int64_t delayTime = 0)
77518678f8Sopenharmony_ci    {
78518678f8Sopenharmony_ci        std::lock_guard<ffrt::mutex> lock(eventQurueMutex);
79518678f8Sopenharmony_ci        if (eventQueue == nullptr) {
80518678f8Sopenharmony_ci            DHCP_LOGE("PostAsyncTask: eventQueue is nullptr!");
81518678f8Sopenharmony_ci            return false;
82518678f8Sopenharmony_ci        }
83518678f8Sopenharmony_ci        int64_t delayTimeUs = delayTime * 1000;
84518678f8Sopenharmony_ci        DHCP_LOGD("PostAsyncTask Enter");
85518678f8Sopenharmony_ci        ffrt::task_handle handle = eventQueue->submit_h(callback, ffrt::task_attr().delay(delayTimeUs));
86518678f8Sopenharmony_ci        return handle != nullptr;
87518678f8Sopenharmony_ci    }
88518678f8Sopenharmony_ci    bool PostAsyncTask(Callback &callback, const std::string &name, int64_t delayTime = 0)
89518678f8Sopenharmony_ci    {
90518678f8Sopenharmony_ci        std::lock_guard<ffrt::mutex> lock(eventQurueMutex);
91518678f8Sopenharmony_ci        if (eventQueue == nullptr) {
92518678f8Sopenharmony_ci            DHCP_LOGE("PostAsyncTask: eventQueue is nullptr!");
93518678f8Sopenharmony_ci            return false;
94518678f8Sopenharmony_ci        }
95518678f8Sopenharmony_ci        int64_t delayTimeUs = delayTime * 1000;
96518678f8Sopenharmony_ci        DHCP_LOGD("PostAsyncTask Enter %{public}s", name.c_str());
97518678f8Sopenharmony_ci        ffrt::task_handle handle = eventQueue->submit_h(
98518678f8Sopenharmony_ci            callback, ffrt::task_attr().name(name.c_str()).delay(delayTimeUs));
99518678f8Sopenharmony_ci        if (handle == nullptr) {
100518678f8Sopenharmony_ci            return false;
101518678f8Sopenharmony_ci        }
102518678f8Sopenharmony_ci        taskMap_[name] = std::move(handle);
103518678f8Sopenharmony_ci        return true;
104518678f8Sopenharmony_ci    }
105518678f8Sopenharmony_ci    void RemoveAsyncTask(const std::string &name)
106518678f8Sopenharmony_ci    {
107518678f8Sopenharmony_ci        std::lock_guard<ffrt::mutex> lock(eventQurueMutex);
108518678f8Sopenharmony_ci        DHCP_LOGD("RemoveAsyncTask Enter %{public}s", name.c_str());
109518678f8Sopenharmony_ci        auto item = taskMap_.find(name);
110518678f8Sopenharmony_ci        if (item == taskMap_.end()) {
111518678f8Sopenharmony_ci            DHCP_LOGD("task not found");
112518678f8Sopenharmony_ci            return;
113518678f8Sopenharmony_ci        }
114518678f8Sopenharmony_ci        if (item->second != nullptr && eventQueue != nullptr) {
115518678f8Sopenharmony_ci            int32_t ret = eventQueue->cancel(item->second);
116518678f8Sopenharmony_ci            if (ret != 0) {
117518678f8Sopenharmony_ci                DHCP_LOGE("RemoveAsyncTask failed, error code : %{public}d", ret);
118518678f8Sopenharmony_ci            }
119518678f8Sopenharmony_ci        }
120518678f8Sopenharmony_ci        taskMap_.erase(name);
121518678f8Sopenharmony_ci    }
122518678f8Sopenharmony_ciprivate:
123518678f8Sopenharmony_ci    std::shared_ptr<ffrt::queue> eventQueue = nullptr;
124518678f8Sopenharmony_ci    mutable ffrt::mutex eventQurueMutex;
125518678f8Sopenharmony_ci    std::map<std::string, ffrt::task_handle> taskMap_;
126518678f8Sopenharmony_ci};
127518678f8Sopenharmony_ci#else
128518678f8Sopenharmony_ciclass DhcpThread::DhcpThreadImpl {
129518678f8Sopenharmony_cipublic:
130518678f8Sopenharmony_ci    DhcpThreadImpl(const std::string &threadName)
131518678f8Sopenharmony_ci    {
132518678f8Sopenharmony_ci        mRunFlag = true;
133518678f8Sopenharmony_ci        mWorkerThread = std::thread(DhcpThreadImpl::Run, std::ref(*this));
134518678f8Sopenharmony_ci        pthread_setname_np(mWorkerThread.native_handle(), threadName.c_str());
135518678f8Sopenharmony_ci    }
136518678f8Sopenharmony_ci    ~DhcpThreadImpl()
137518678f8Sopenharmony_ci    {
138518678f8Sopenharmony_ci        mRunFlag = false;
139518678f8Sopenharmony_ci        mCondition.notify_one();
140518678f8Sopenharmony_ci        if (mWorkerThread.joinable()) {
141518678f8Sopenharmony_ci            mWorkerThread.join();
142518678f8Sopenharmony_ci        }
143518678f8Sopenharmony_ci    }
144518678f8Sopenharmony_ci    bool PostSyncTask(Callback &callback)
145518678f8Sopenharmony_ci    {
146518678f8Sopenharmony_ci        DHCP_LOGE("DhcpThreadImpl PostSyncTask Unsupported in lite.");
147518678f8Sopenharmony_ci        return false;
148518678f8Sopenharmony_ci    }
149518678f8Sopenharmony_ci    bool PostAsyncTask(Callback &callback, int64_t delayTime = 0)
150518678f8Sopenharmony_ci    {
151518678f8Sopenharmony_ci        if (delayTime > 0) {
152518678f8Sopenharmony_ci            DHCP_LOGE("DhcpThreadImpl PostAsyncTask with delayTime Unsupported in lite.");
153518678f8Sopenharmony_ci            return false;
154518678f8Sopenharmony_ci        }
155518678f8Sopenharmony_ci        DHCP_LOGD("PostAsyncTask Enter");
156518678f8Sopenharmony_ci        {
157518678f8Sopenharmony_ci            std::unique_lock<std::mutex> lock(mMutex);
158518678f8Sopenharmony_ci            mEventQue.push_back(callback);
159518678f8Sopenharmony_ci        }
160518678f8Sopenharmony_ci        mCondition.notify_one();
161518678f8Sopenharmony_ci        return true;
162518678f8Sopenharmony_ci    }
163518678f8Sopenharmony_ci    bool PostAsyncTask(Callback &callback, const std::string &name, int64_t delayTime = 0)
164518678f8Sopenharmony_ci    {
165518678f8Sopenharmony_ci        DHCP_LOGE("DhcpThreadImpl PostAsyncTask with name Unsupported in lite.");
166518678f8Sopenharmony_ci        return false;
167518678f8Sopenharmony_ci    }
168518678f8Sopenharmony_ci    void RemoveAsyncTask(const std::string &name)
169518678f8Sopenharmony_ci    {
170518678f8Sopenharmony_ci        DHCP_LOGE("DhcpThreadImpl RemoveAsyncTask Unsupported in lite.");
171518678f8Sopenharmony_ci    }
172518678f8Sopenharmony_ciprivate:
173518678f8Sopenharmony_ci    static  void Run(DhcpThreadImpl &instance)
174518678f8Sopenharmony_ci    {
175518678f8Sopenharmony_ci        while (instance.mRunFlag) {
176518678f8Sopenharmony_ci            std::unique_lock<std::mutex> lock(instance.mMutex);
177518678f8Sopenharmony_ci            while (instance.mEventQue.empty() && instance.mRunFlag) {
178518678f8Sopenharmony_ci                instance.mCondition.wait(lock);
179518678f8Sopenharmony_ci            }
180518678f8Sopenharmony_ci            if (!instance.mRunFlag) {
181518678f8Sopenharmony_ci                break;
182518678f8Sopenharmony_ci            }
183518678f8Sopenharmony_ci            Callback msg = instance.mEventQue.front();
184518678f8Sopenharmony_ci            instance.mEventQue.pop_front();
185518678f8Sopenharmony_ci            lock.unlock();
186518678f8Sopenharmony_ci            msg();
187518678f8Sopenharmony_ci        }
188518678f8Sopenharmony_ci        return;
189518678f8Sopenharmony_ci    }
190518678f8Sopenharmony_ci    std::thread mWorkerThread;
191518678f8Sopenharmony_ci    std::atomic<bool> mRunFlag;
192518678f8Sopenharmony_ci    std::mutex mMutex;
193518678f8Sopenharmony_ci    std::condition_variable mCondition;
194518678f8Sopenharmony_ci    std::deque<Callback> mEventQue;
195518678f8Sopenharmony_ci};
196518678f8Sopenharmony_ci#endif
197518678f8Sopenharmony_ci
198518678f8Sopenharmony_ci
199518678f8Sopenharmony_ciDhcpThread::DhcpThread(const std::string &threadName)
200518678f8Sopenharmony_ci    :ptr_(new DhcpThreadImpl(threadName))
201518678f8Sopenharmony_ci{}
202518678f8Sopenharmony_ci
203518678f8Sopenharmony_ciDhcpThread::~DhcpThread()
204518678f8Sopenharmony_ci{
205518678f8Sopenharmony_ci    ptr_.reset();
206518678f8Sopenharmony_ci}
207518678f8Sopenharmony_ci
208518678f8Sopenharmony_cibool DhcpThread::PostSyncTask(const Callback &callback)
209518678f8Sopenharmony_ci{
210518678f8Sopenharmony_ci    if (ptr_ == nullptr) {
211518678f8Sopenharmony_ci        DHCP_LOGE("PostSyncTask: ptr_ is nullptr!");
212518678f8Sopenharmony_ci        return false;
213518678f8Sopenharmony_ci    }
214518678f8Sopenharmony_ci    return ptr_->PostSyncTask(const_cast<Callback &>(callback));
215518678f8Sopenharmony_ci}
216518678f8Sopenharmony_ci
217518678f8Sopenharmony_cibool DhcpThread::PostAsyncTask(const Callback &callback, int64_t delayTime)
218518678f8Sopenharmony_ci{
219518678f8Sopenharmony_ci    if (ptr_ == nullptr) {
220518678f8Sopenharmony_ci        DHCP_LOGE("PostAsyncTask: ptr_ is nullptr!");
221518678f8Sopenharmony_ci        return false;
222518678f8Sopenharmony_ci    }
223518678f8Sopenharmony_ci    return ptr_->PostAsyncTask(const_cast<Callback &>(callback), delayTime);
224518678f8Sopenharmony_ci}
225518678f8Sopenharmony_ci
226518678f8Sopenharmony_cibool DhcpThread::PostAsyncTask(const Callback &callback, const std::string &name, int64_t delayTime)
227518678f8Sopenharmony_ci{
228518678f8Sopenharmony_ci    if (ptr_ == nullptr) {
229518678f8Sopenharmony_ci        DHCP_LOGE("PostAsyncTask: ptr_ is nullptr!");
230518678f8Sopenharmony_ci        return false;
231518678f8Sopenharmony_ci    }
232518678f8Sopenharmony_ci    return ptr_->PostAsyncTask(const_cast<Callback &>(callback), name, delayTime);
233518678f8Sopenharmony_ci}
234518678f8Sopenharmony_civoid DhcpThread::RemoveAsyncTask(const std::string &name)
235518678f8Sopenharmony_ci{
236518678f8Sopenharmony_ci    if (ptr_ == nullptr) {
237518678f8Sopenharmony_ci        DHCP_LOGE("RemoveAsyncTask: ptr_ is nullptr!");
238518678f8Sopenharmony_ci        return;
239518678f8Sopenharmony_ci    }
240518678f8Sopenharmony_ci    ptr_->RemoveAsyncTask(name);
241518678f8Sopenharmony_ci}
242518678f8Sopenharmony_ci
243518678f8Sopenharmony_ci#ifndef OHOS_ARCH_LITE
244518678f8Sopenharmony_ciDhcpTimer *DhcpTimer::GetInstance()
245518678f8Sopenharmony_ci{
246518678f8Sopenharmony_ci    static DhcpTimer instance;
247518678f8Sopenharmony_ci    return &instance;
248518678f8Sopenharmony_ci}
249518678f8Sopenharmony_ci#ifdef DHCP_FFRT_ENABLE
250518678f8Sopenharmony_ciDhcpTimer::DhcpTimer() : timer_(std::make_unique<DhcpThread>("DhcpTimer"))
251518678f8Sopenharmony_ci{
252518678f8Sopenharmony_ci    timerIdInit = 0;
253518678f8Sopenharmony_ci}
254518678f8Sopenharmony_ci
255518678f8Sopenharmony_ciDhcpTimer::~DhcpTimer()
256518678f8Sopenharmony_ci{
257518678f8Sopenharmony_ci    if (timer_) {
258518678f8Sopenharmony_ci        timer_.reset();
259518678f8Sopenharmony_ci    }
260518678f8Sopenharmony_ci}
261518678f8Sopenharmony_ci
262518678f8Sopenharmony_ciEnumErrCode DhcpTimer::Register(const TimerCallback &callback, uint32_t &outTimerId, uint32_t interval, bool once)
263518678f8Sopenharmony_ci{
264518678f8Sopenharmony_ci    if (timer_ == nullptr) {
265518678f8Sopenharmony_ci        DHCP_LOGE("timer_ is nullptr");
266518678f8Sopenharmony_ci        return DHCP_OPT_FAILED;
267518678f8Sopenharmony_ci    }
268518678f8Sopenharmony_ci    timerIdInit++;
269518678f8Sopenharmony_ci    bool ret = timer_->PostAsyncTask(callback, std::to_string(timerIdInit), interval);
270518678f8Sopenharmony_ci    if (!ret) {
271518678f8Sopenharmony_ci        DHCP_LOGE("Register timer failed");
272518678f8Sopenharmony_ci        timerIdInit--;
273518678f8Sopenharmony_ci        return DHCP_OPT_FAILED;
274518678f8Sopenharmony_ci    }
275518678f8Sopenharmony_ci
276518678f8Sopenharmony_ci    outTimerId = timerIdInit;
277518678f8Sopenharmony_ci    return DHCP_OPT_SUCCESS;
278518678f8Sopenharmony_ci}
279518678f8Sopenharmony_ci
280518678f8Sopenharmony_civoid DhcpTimer::UnRegister(uint32_t timerId)
281518678f8Sopenharmony_ci{
282518678f8Sopenharmony_ci    if (timerId == 0) {
283518678f8Sopenharmony_ci        DHCP_LOGE("timerId is 0, no register timer");
284518678f8Sopenharmony_ci        return;
285518678f8Sopenharmony_ci    }
286518678f8Sopenharmony_ci
287518678f8Sopenharmony_ci    if (timer_ == nullptr) {
288518678f8Sopenharmony_ci        DHCP_LOGE("timer_ is nullptr");
289518678f8Sopenharmony_ci        return;
290518678f8Sopenharmony_ci    }
291518678f8Sopenharmony_ci
292518678f8Sopenharmony_ci    timer_->RemoveAsyncTask(std::to_string(timerId));
293518678f8Sopenharmony_ci    return;
294518678f8Sopenharmony_ci}
295518678f8Sopenharmony_ci#else
296518678f8Sopenharmony_ciDhcpTimer::DhcpTimer() : timer_(std::make_unique<Utils::Timer>("DhcpTimer"))
297518678f8Sopenharmony_ci{
298518678f8Sopenharmony_ci    timer_->Setup();
299518678f8Sopenharmony_ci}
300518678f8Sopenharmony_ci
301518678f8Sopenharmony_ciDhcpTimer::~DhcpTimer()
302518678f8Sopenharmony_ci{
303518678f8Sopenharmony_ci    if (timer_) {
304518678f8Sopenharmony_ci        timer_->Shutdown(true);
305518678f8Sopenharmony_ci    }
306518678f8Sopenharmony_ci}
307518678f8Sopenharmony_ci
308518678f8Sopenharmony_ciEnumErrCode DhcpTimer::Register(const TimerCallback &callback, uint32_t &outTimerId, uint32_t interval, bool once)
309518678f8Sopenharmony_ci{
310518678f8Sopenharmony_ci    if (timer_ == nullptr) {
311518678f8Sopenharmony_ci        DHCP_LOGE("timer_ is nullptr");
312518678f8Sopenharmony_ci        return DHCP_OPT_FAILED;
313518678f8Sopenharmony_ci    }
314518678f8Sopenharmony_ci
315518678f8Sopenharmony_ci    uint32_t ret = timer_->Register(callback, interval, once);
316518678f8Sopenharmony_ci    if (ret == Utils::TIMER_ERR_DEAL_FAILED) {
317518678f8Sopenharmony_ci        DHCP_LOGE("Register timer failed");
318518678f8Sopenharmony_ci        return DHCP_OPT_FAILED;
319518678f8Sopenharmony_ci    }
320518678f8Sopenharmony_ci
321518678f8Sopenharmony_ci    outTimerId = ret;
322518678f8Sopenharmony_ci    return DHCP_OPT_SUCCESS;
323518678f8Sopenharmony_ci}
324518678f8Sopenharmony_ci
325518678f8Sopenharmony_civoid DhcpTimer::UnRegister(uint32_t timerId)
326518678f8Sopenharmony_ci{
327518678f8Sopenharmony_ci    if (timerId == 0) {
328518678f8Sopenharmony_ci        DHCP_LOGE("timerId is 0, no register timer");
329518678f8Sopenharmony_ci        return;
330518678f8Sopenharmony_ci    }
331518678f8Sopenharmony_ci
332518678f8Sopenharmony_ci    if (timer_ == nullptr) {
333518678f8Sopenharmony_ci        DHCP_LOGE("timer_ is nullptr");
334518678f8Sopenharmony_ci        return;
335518678f8Sopenharmony_ci    }
336518678f8Sopenharmony_ci
337518678f8Sopenharmony_ci    timer_->Unregister(timerId);
338518678f8Sopenharmony_ci    return;
339518678f8Sopenharmony_ci}
340518678f8Sopenharmony_ci#endif
341518678f8Sopenharmony_ci#endif
342518678f8Sopenharmony_ci}
343518678f8Sopenharmony_ci}