1cb7eb8c9Sopenharmony_ci/*
2cb7eb8c9Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
3cb7eb8c9Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4cb7eb8c9Sopenharmony_ci * you may not use this file except in compliance with the License.
5cb7eb8c9Sopenharmony_ci * You may obtain a copy of the License at
6cb7eb8c9Sopenharmony_ci *
7cb7eb8c9Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8cb7eb8c9Sopenharmony_ci *
9cb7eb8c9Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10cb7eb8c9Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11cb7eb8c9Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12cb7eb8c9Sopenharmony_ci * See the License for the specific language governing permissions and
13cb7eb8c9Sopenharmony_ci * limitations under the License.
14cb7eb8c9Sopenharmony_ci */
15cb7eb8c9Sopenharmony_ci#ifndef DFSU_THREAD_H
16cb7eb8c9Sopenharmony_ci#define DFSU_THREAD_H
17cb7eb8c9Sopenharmony_ci
18cb7eb8c9Sopenharmony_ci#include <atomic>
19cb7eb8c9Sopenharmony_ci#include <condition_variable>
20cb7eb8c9Sopenharmony_ci#include <functional>
21cb7eb8c9Sopenharmony_ci#include <mutex>
22cb7eb8c9Sopenharmony_ci#include <thread>
23cb7eb8c9Sopenharmony_ci#include "utils_log.h"
24cb7eb8c9Sopenharmony_ci
25cb7eb8c9Sopenharmony_cinamespace OHOS {
26cb7eb8c9Sopenharmony_cinamespace Storage {
27cb7eb8c9Sopenharmony_cinamespace DistributedFile {
28cb7eb8c9Sopenharmony_cinamespace Utils {
29cb7eb8c9Sopenharmony_ciclass DfsuThread {
30cb7eb8c9Sopenharmony_cipublic:
31cb7eb8c9Sopenharmony_ci    DfsuThread() = default;
32cb7eb8c9Sopenharmony_ci    DfsuThread(const DfsuThread &) = delete;
33cb7eb8c9Sopenharmony_ci    DfsuThread &operator=(const DfsuThread &) = delete;
34cb7eb8c9Sopenharmony_ci
35cb7eb8c9Sopenharmony_ci    ~DfsuThread()
36cb7eb8c9Sopenharmony_ci    {
37cb7eb8c9Sopenharmony_ci        Stop();
38cb7eb8c9Sopenharmony_ci    }
39cb7eb8c9Sopenharmony_ci
40cb7eb8c9Sopenharmony_ci    template<class Fn, class... Args>
41cb7eb8c9Sopenharmony_ci    bool Run(Fn &&Fx, Args &&...Ax)
42cb7eb8c9Sopenharmony_ci    {
43cb7eb8c9Sopenharmony_ci        std::unique_lock<std::mutex> lock(threadMutex_);
44cb7eb8c9Sopenharmony_ci        if (thread_ != nullptr) {
45cb7eb8c9Sopenharmony_ci            return false;
46cb7eb8c9Sopenharmony_ci        }
47cb7eb8c9Sopenharmony_ci        running_ = true;
48cb7eb8c9Sopenharmony_ci        thread_ = std::make_unique<std::thread>(std::forward<Fn>(Fx), std::forward<Args>(Ax)...);
49cb7eb8c9Sopenharmony_ci        return true;
50cb7eb8c9Sopenharmony_ci    }
51cb7eb8c9Sopenharmony_ci
52cb7eb8c9Sopenharmony_ci    bool RunLoop(std::function<bool()> task, uint64_t interval, uint32_t retryTimes = UINT32_MAX)
53cb7eb8c9Sopenharmony_ci    {
54cb7eb8c9Sopenharmony_ci        std::unique_lock<std::mutex> lock(threadMutex_);
55cb7eb8c9Sopenharmony_ci        if (thread_ != nullptr) {
56cb7eb8c9Sopenharmony_ci            return false;
57cb7eb8c9Sopenharmony_ci        }
58cb7eb8c9Sopenharmony_ci        running_ = true;
59cb7eb8c9Sopenharmony_ci        thread_ = std::make_unique<std::thread>([this, task, interval, retryTimes] {
60cb7eb8c9Sopenharmony_ci            uint32_t times = retryTimes;
61cb7eb8c9Sopenharmony_ci            LOGD("DfsThread: entering loop");
62cb7eb8c9Sopenharmony_ci            while ((!task()) && (times > 0)) {
63cb7eb8c9Sopenharmony_ci                times--;
64cb7eb8c9Sopenharmony_ci                std::unique_lock<std::mutex> lock(sleepMutex_);
65cb7eb8c9Sopenharmony_ci                bool stop =
66cb7eb8c9Sopenharmony_ci                    sleepCv_.wait_for(lock, std::chrono::milliseconds(interval), [this]() { return !this->running_; });
67cb7eb8c9Sopenharmony_ci                if (stop) { // is stopped
68cb7eb8c9Sopenharmony_ci                    break;
69cb7eb8c9Sopenharmony_ci                }
70cb7eb8c9Sopenharmony_ci            }
71cb7eb8c9Sopenharmony_ci            LOGD("DfsThread: leaving loop");
72cb7eb8c9Sopenharmony_ci        });
73cb7eb8c9Sopenharmony_ci        return true;
74cb7eb8c9Sopenharmony_ci    }
75cb7eb8c9Sopenharmony_ci
76cb7eb8c9Sopenharmony_ci    bool RunLoopFlexible(std::function<bool(uint64_t &)> task, uint64_t interval, uint32_t retryTimes = UINT32_MAX)
77cb7eb8c9Sopenharmony_ci    {
78cb7eb8c9Sopenharmony_ci        std::unique_lock<std::mutex> lock(threadMutex_);
79cb7eb8c9Sopenharmony_ci        if (thread_ != nullptr) {
80cb7eb8c9Sopenharmony_ci            return false;
81cb7eb8c9Sopenharmony_ci        }
82cb7eb8c9Sopenharmony_ci        running_ = true;
83cb7eb8c9Sopenharmony_ci        thread_ = std::make_unique<std::thread>([this, task, interval, retryTimes] {
84cb7eb8c9Sopenharmony_ci            uint32_t times = retryTimes;
85cb7eb8c9Sopenharmony_ci            uint64_t duration = interval;
86cb7eb8c9Sopenharmony_ci            LOGD("DfsThread: entering flexible loop");
87cb7eb8c9Sopenharmony_ci            while ((!task(duration)) && (times > 0)) {
88cb7eb8c9Sopenharmony_ci                times--;
89cb7eb8c9Sopenharmony_ci                std::unique_lock<std::mutex> lock(sleepMutex_);
90cb7eb8c9Sopenharmony_ci                bool stop =
91cb7eb8c9Sopenharmony_ci                    sleepCv_.wait_for(lock, std::chrono::milliseconds(duration), [this]() { return !this->running_; });
92cb7eb8c9Sopenharmony_ci                if (stop) { // is stopped
93cb7eb8c9Sopenharmony_ci                    break;
94cb7eb8c9Sopenharmony_ci                }
95cb7eb8c9Sopenharmony_ci            }
96cb7eb8c9Sopenharmony_ci            LOGD("DfsThread: leaving flexible loop");
97cb7eb8c9Sopenharmony_ci        });
98cb7eb8c9Sopenharmony_ci        return true;
99cb7eb8c9Sopenharmony_ci    }
100cb7eb8c9Sopenharmony_ci
101cb7eb8c9Sopenharmony_ci    bool Stop()
102cb7eb8c9Sopenharmony_ci    {
103cb7eb8c9Sopenharmony_ci        std::unique_lock<std::mutex> lockThread(threadMutex_);
104cb7eb8c9Sopenharmony_ci        if (thread_ == nullptr) {
105cb7eb8c9Sopenharmony_ci            return true;
106cb7eb8c9Sopenharmony_ci        }
107cb7eb8c9Sopenharmony_ci        {
108cb7eb8c9Sopenharmony_ci            std::unique_lock<std::mutex> lockSleep(sleepMutex_);
109cb7eb8c9Sopenharmony_ci            running_ = false;
110cb7eb8c9Sopenharmony_ci            sleepCv_.notify_one();
111cb7eb8c9Sopenharmony_ci        }
112cb7eb8c9Sopenharmony_ci        LOGD("wait thread to stop");
113cb7eb8c9Sopenharmony_ci        if (thread_->joinable()) {
114cb7eb8c9Sopenharmony_ci            thread_->join();
115cb7eb8c9Sopenharmony_ci        }
116cb7eb8c9Sopenharmony_ci        thread_ = nullptr;
117cb7eb8c9Sopenharmony_ci        return true;
118cb7eb8c9Sopenharmony_ci    }
119cb7eb8c9Sopenharmony_ci
120cb7eb8c9Sopenharmony_ci    bool operator==(std::thread::id id)
121cb7eb8c9Sopenharmony_ci    {
122cb7eb8c9Sopenharmony_ci        if (thread_ == nullptr) {
123cb7eb8c9Sopenharmony_ci            return false;
124cb7eb8c9Sopenharmony_ci        }
125cb7eb8c9Sopenharmony_ci        return thread_->get_id() == id;
126cb7eb8c9Sopenharmony_ci    }
127cb7eb8c9Sopenharmony_ci
128cb7eb8c9Sopenharmony_ciprivate:
129cb7eb8c9Sopenharmony_ci    std::atomic_bool running_ {false};
130cb7eb8c9Sopenharmony_ci    std::mutex threadMutex_ {};
131cb7eb8c9Sopenharmony_ci    std::unique_ptr<std::thread> thread_ {nullptr};
132cb7eb8c9Sopenharmony_ci    std::mutex sleepMutex_ {};
133cb7eb8c9Sopenharmony_ci    std::condition_variable sleepCv_ {};
134cb7eb8c9Sopenharmony_ci};
135cb7eb8c9Sopenharmony_ci} // namespace Utils
136cb7eb8c9Sopenharmony_ci} // namespace DistributedFile
137cb7eb8c9Sopenharmony_ci} // namespace Storage
138cb7eb8c9Sopenharmony_ci} // namespace OHOS
139cb7eb8c9Sopenharmony_ci#endif // DFSU_THREAD_H