| #include "polling_state_monitor.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "daemon_context.h" |
| #include "safepower_agent.pb.h" |
| #include "state_updater.h" |
| #include "absl/functional/bind_front.h" |
| #include "absl/log/log.h" |
| #include "absl/status/status.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/synchronization/mutex.h" |
| #include "absl/time/time.h" |
| |
| namespace safepower_agent { |
| |
| PollingStateMonitor::PollingStateMonitor( |
| std::string entity_tag, absl::Duration interval, |
| std::shared_ptr<StateUpdater<safepower_agent_proto::SystemState>> |
| system_state_updater, |
| std::string monitor_name) |
| : monitor_name_(std::move(monitor_name)), |
| entity_tag_(std::move(entity_tag)), |
| interval_(interval), |
| system_state_updater_(std::move(system_state_updater)) {} |
| |
| void PollingStateMonitor::StopTimer() { |
| if (task_name_.empty()) { |
| return; |
| } |
| LOG(INFO) << "Stopping " << task_name_; |
| absl::Status status = DaemonContext::Get().scheduler().CancelCall(task_name_); |
| if (!status.ok()) { |
| LOG(WARNING) << "Failed to cancel polling state monitor: " << status; |
| } |
| task_name_.clear(); |
| } |
| |
| void PollingStateMonitor::StartTimer(absl::Duration interval) { |
| LOG(INFO) << "Starting " << monitor_name_ << " for " << entity_tag_ |
| << " with interval " << interval; |
| std::string task_name = absl::StrCat(monitor_name_, "_", entity_tag_); |
| absl::Status status = DaemonContext::Get().scheduler().PeriodicCall( |
| absl::bind_front(&PollingStateMonitor::Check, this), interval, task_name); |
| if (!status.ok()) { |
| LOG(DFATAL) << "Failed to start " << monitor_name_ << ": " << status; |
| return; |
| } |
| task_name_ = std::move(task_name); |
| } |
| |
| void PollingStateMonitor::Pause() { |
| { |
| absl::MutexLock lock(task_mutex_); |
| if (task_name_.empty()) { |
| LOG(DFATAL) << "PollingStateMonitor paused while task not started"; |
| } |
| StopTimer(); |
| OnPause(); |
| } |
| activate_callback_handle_ = system_state_updater_->OnActive( |
| absl::bind_front(&PollingStateMonitor::Resume, this)); |
| } |
| |
| void PollingStateMonitor::Resume() { |
| { |
| absl::MutexLock lock(task_mutex_); |
| if (!task_name_.empty()) { |
| LOG(DFATAL) << "PollingStateMonitor resumed while task started"; |
| return; |
| } |
| StartTimer(interval_); |
| } |
| idle_callback_handle_ = system_state_updater_->OnIdle( |
| absl::bind_front(&PollingStateMonitor::Pause, this)); |
| } |
| |
| absl::Status PollingStateMonitor::Start() { |
| // Will start immediately if the state updater is idle. |
| activate_callback_handle_ = system_state_updater_->OnActive( |
| absl::bind_front(&PollingStateMonitor::Resume, this)); |
| return absl::OkStatus(); |
| } |
| |
| PollingStateMonitor::~PollingStateMonitor() { |
| idle_callback_handle_.TryCancel(); |
| idle_callback_handle_.Wait(); |
| activate_callback_handle_.TryCancel(); |
| activate_callback_handle_.Wait(); |
| if (!task_mutex_.try_lock()) { |
| LOG(DFATAL) << "PollingStateMonitor destroyed while mutex was held"; |
| task_mutex_.lock(); |
| } |
| StopTimer(); |
| task_mutex_.unlock(); |
| } |
| |
| } // namespace safepower_agent |