1 /*
2 * Copyright (C) 2023 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
16 #include "watchdog.h"
17 #include <mutex>
18
19 namespace {
20 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "watchdog"};
21 }
22
23 namespace OHOS {
24 namespace Media {
~WatchDog()25 WatchDog::~WatchDog()
26 {
27 DisableWatchDog();
28 }
29
EnableWatchDog()30 void WatchDog::EnableWatchDog()
31 {
32 while (true) {
33 std::unique_lock<std::mutex> lock(mutex_);
34 if (enable_) {
35 return;
36 }
37
38 if (disabling.load()) {
39 continue; // Wait for disable execution to finish.
40 }
41
42 enable_ = true;
43 thread_ = std::make_unique<std::thread>(&WatchDog::WatchDogThread, this);
44 break;
45 }
46 };
47
DisableWatchDog()48 void WatchDog::DisableWatchDog()
49 {
50 std::unique_lock<std::mutex> lock(mutex_);
51 if (disabling.load() == false) {
52 disabling.store(true);
53 enable_ = false;
54 cond_.notify_all();
55 lock.unlock(); // Make the thread acquire the lock and exit.
56 if (thread_ != nullptr && thread_->joinable()) {
57 thread_->join();
58 thread_.reset();
59 thread_ = nullptr;
60 }
61
62 // It may be changed by thread. Assign value after thread recycle.
63 pause_ = false;
64 alarmed_ = false;
65 disabling.store(false);
66 }
67 };
68
PauseWatchDog()69 void WatchDog::PauseWatchDog()
70 {
71 std::unique_lock<std::mutex> lock(mutex_);
72 if (enable_) {
73 pause_ = true;
74 paused_ = true;
75 cond_.notify_all();
76 }
77 };
78
ResumeWatchDog()79 void WatchDog::ResumeWatchDog()
80 {
81 std::unique_lock<std::mutex> lock(mutex_);
82 if (enable_) {
83 pause_ = false;
84 cond_.notify_all();
85 }
86 };
87
SetWatchDogTimeout(uint32_t timeoutMs)88 void WatchDog::SetWatchDogTimeout(uint32_t timeoutMs)
89 {
90 std::unique_lock<std::mutex> lock(mutex_);
91 timeoutMs_ = timeoutMs;
92 };
93
Notify()94 void WatchDog::Notify()
95 {
96 std::unique_lock<std::mutex> lock(mutex_);
97 if (enable_) {
98 if (alarmed_) {
99 alarmed_ = false;
100 AlarmRecovery();
101 pause_ = false;
102 cond_.notify_all();
103 }
104
105 count_++;
106 cond_.notify_all();
107 }
108 };
109
Alarm()110 void WatchDog::Alarm()
111 {
112 MEDIA_LOGI("Alarm!");
113 };
114
AlarmRecovery()115 void WatchDog::AlarmRecovery()
116 {
117 MEDIA_LOGI("AlarmRecovery!");
118 };
119
WatchDogThread()120 void WatchDog::WatchDogThread()
121 {
122 while (true) {
123 std::unique_lock<std::mutex> lock(mutex_);
124
125 // For pause/resume control, wait only when paused.
126 cond_.wait(lock, [this] {
127 return (enable_ == false) || (pause_ == false);
128 });
129
130 if (paused_) {
131 paused_ = false;
132 }
133
134 // For timeout detection.
135 cond_.wait_for(lock, std::chrono::milliseconds(timeoutMs_), [this] {
136 return (enable_ == false) || (pause_ == true) || (count_ > 0);
137 });
138
139 if (enable_ == false) {
140 break;
141 }
142
143 if (pause_ == true || paused_ == true) {
144 continue;
145 }
146
147 if (count_ == 0) {
148 MEDIA_LOGI("Watchdog timeout!");
149 if (alarmed_ == false) {
150 alarmed_ = true;
151 Alarm();
152 pause_ = true;
153 }
154 }
155
156 count_ = 0;
157 }
158 }
159 } // namespace Media
160 } // namespace OHOS
161