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