| #include "callback_manager.h" |
| |
| #include <iterator> |
| #include <list> |
| #include <utility> |
| #include <vector> |
| |
| #include "absl/functional/any_invocable.h" |
| #include "absl/log/check.h" |
| #include "absl/log/log.h" |
| #include "absl/synchronization/mutex.h" |
| |
| namespace safepower_agent { |
| |
| CallbackManager::Handle::Handle(PrivateToken, CallbackManager& manager, |
| std::list<Callback>::iterator it) |
| : manager_(&manager), it_(it) {} |
| |
| CallbackManager::Handle::~Handle() { |
| if (manager_ == nullptr) return; |
| absl::MutexLock lock(manager_->mutex_); |
| manager_->callbacks_.erase(it_); |
| } |
| |
| CallbackManager::Handle::Handle(Handle&& other) { |
| manager_ = other.manager_; |
| it_ = other.it_; |
| other.manager_ = nullptr; |
| } |
| |
| CallbackManager::Handle& CallbackManager::Handle::operator=(Handle&& other) { |
| if (manager_ != nullptr) { |
| absl::MutexLock lock(manager_->mutex_); |
| manager_->callbacks_.erase(it_); |
| } |
| manager_ = other.manager_; |
| it_ = other.it_; |
| other.manager_ = nullptr; |
| return *this; |
| } |
| |
| bool CallbackManager::Handle::pending() const { |
| if (manager_ == nullptr) return false; |
| absl::MutexLock lock_running(manager_->running_mutex_); |
| absl::MutexLock lock(manager_->mutex_); |
| return *it_ != nullptr; |
| } |
| |
| bool CallbackManager::Handle::TryCancel() { |
| if (manager_ == nullptr) return false; |
| absl::MutexLock lock_running(manager_->running_mutex_); |
| absl::MutexLock lock(manager_->mutex_); |
| if (*it_ == nullptr) return false; |
| *it_ = nullptr; |
| return true; |
| } |
| |
| CallbackManager::~CallbackManager() { |
| if (!mutex_.try_lock()) { |
| LOG(DFATAL) << "CallbackManager destroyed while mutex was held"; |
| return; |
| } |
| for (Callback& callback : callbacks_) { |
| if (callback) { |
| LOG(DFATAL) << "CallbackManager destroyed with pending callbacks"; |
| break; |
| } |
| } |
| mutex_.unlock(); |
| } |
| |
| CallbackManager::Handle CallbackManager::RunFirst(Callback callback) { |
| absl::MutexLock lock(mutex_); |
| callbacks_.push_front(std::move(callback)); |
| return Handle({}, *this, callbacks_.begin()); |
| } |
| |
| CallbackManager::Handle CallbackManager::RunLast(Callback callback) { |
| absl::MutexLock lock(mutex_); |
| callbacks_.push_back(std::move(callback)); |
| return Handle({}, *this, std::prev(callbacks_.end())); |
| } |
| |
| void CallbackManager::RunCallbacks() { |
| // We need to move the callbacks out of the list because we will run them |
| // outside of the lock. This allows the callback to install / remove other |
| // callbacks. |
| std::vector<Callback> callbacks_to_run; |
| { |
| absl::MutexLock lock(mutex_); |
| for (auto& callback : callbacks_) { |
| if (callback) { |
| callbacks_to_run.push_back(std::move(callback)); |
| } |
| } |
| } |
| absl::MutexLock lock(running_mutex_); |
| for (auto& callback : callbacks_to_run) { |
| std::move(callback)(); |
| } |
| } |
| |
| } // namespace safepower_agent |