// Copyright (C) 2016 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "anbox/graphics/buffer_queue.h" namespace anbox { namespace graphics { BufferQueue::BufferQueue(size_t capacity) : capacity_(capacity), buffers_(new Buffer[capacity]) {} int BufferQueue::try_push_locked(Buffer &&buffer) { if (closed_) return -EIO; if (count_ >= capacity_) return -EAGAIN; size_t pos = pos_ + count_; if (pos >= capacity_) pos -= capacity_; buffers_[pos] = std::move(buffer); if (count_++ == 0) can_pop_.notify_one(); return 0; } int BufferQueue::push_locked( Buffer &&buffer, std::unique_lock &lock) { while (count_ == capacity_) { if (closed_) return -EIO; can_push_.wait(lock); } return try_push_locked(std::move(buffer)); } int BufferQueue::wait_until_not_empty_locked(std::unique_lock &lock) { while (count_ == 0) { if (closed_) // Closed queue is empty. return -EIO; can_pop_.wait(lock); } return 0; } int BufferQueue::try_pop_locked(Buffer *buffer) { if (count_ == 0) return closed_ ? -EIO : -EAGAIN; *buffer = std::move(buffers_[pos_]); size_t pos = pos_ + 1; if (pos >= capacity_) pos -= capacity_; pos_ = pos; if (count_-- == capacity_) can_push_.notify_one(); return 0; } int BufferQueue::pop_locked( Buffer *buffer, std::unique_lock &lock) { while (count_ == 0) { if (closed_) // Closed queue is empty. return -EIO; can_pop_.wait(lock); } return try_pop_locked(buffer); } // Close the queue, it is no longer possible to push new items // to it (i.e. push() will always return Result::Error), or to // read from an empty queue (i.e. pop() will always return // Result::Error once the queue becomes empty). void BufferQueue::close_locked() { closed_ = true; // Wake any potential waiters. if (count_ == capacity_) { can_push_.notify_all(); } if (count_ == 0) { can_pop_.notify_all(); } } } // namespace graphics } // namespace anbox