| #include <deque> | |
| #include <iterator> | |
| #include <memory> | |
| #include <utility> | |
| #include <vector> | |
| #include "event.h" | |
| #include "event_queue.h" | |
| #include "absl/base/thread_annotations.h" | |
| #include "absl/log/log.h" | |
| #include "absl/status/status.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/synchronization/mutex.h" | |
| #include "absl/time/time.h" | |
| namespace safepower_agent { | |
| struct EventQueue::Impl { | |
| absl::Mutex mutex; | |
| std::deque<Event> queue ABSL_GUARDED_BY(mutex); | |
| bool closed ABSL_GUARDED_BY(mutex) = false; | |
| bool NotEmptyOrClosed() const ABSL_SHARED_LOCKS_REQUIRED(mutex) { | |
| return !queue.empty() || closed; | |
| } | |
| }; | |
| EventQueue::EventQueue() : impl_(std::make_unique<Impl>()) {} | |
| EventQueue::~EventQueue() = default; | |
| void EventQueue::Push(Event event) { | |
| absl::MutexLock lock(impl_->mutex); | |
| if (impl_->closed) { | |
| LOG(DFATAL) << "Attempted to push to a closed EventQueue."; | |
| return; | |
| } | |
| impl_->queue.push_back(std::move(event)); | |
| } | |
| void EventQueue::Close() { | |
| absl::MutexLock lock(impl_->mutex); | |
| impl_->closed = true; | |
| } | |
| absl::StatusOr<std::vector<Event>> EventQueue::PopAllWithTimeout( | |
| absl::Duration timeout) { | |
| absl::MutexLock lock(impl_->mutex); | |
| if (impl_->queue.empty() && !impl_->closed && | |
| timeout > absl::ZeroDuration()) { | |
| impl_->mutex.AwaitWithTimeout( | |
| absl::Condition(impl_.get(), &Impl::NotEmptyOrClosed), timeout); | |
| } | |
| if (impl_->queue.empty() && impl_->closed) { | |
| return absl::AbortedError("Event queue closed"); | |
| } | |
| std::vector<Event> events(std::make_move_iterator(impl_->queue.begin()), | |
| std::make_move_iterator(impl_->queue.end())); | |
| impl_->queue.clear(); | |
| return events; | |
| } | |
| } // namespace safepower_agent |