1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <fbl/array.h>
8 #include <fbl/intrusive_single_list.h>
9 #include <fbl/unique_ptr.h>
10 #include <fbl/vector.h>
11 #include <lib/fzl/vmo-mapper.h>
12 #include <lib/zx/vmo.h>
13 #include <limits>
14 #include <zircon/types.h>
15 
16 namespace fzl {
17 
18 // This class is not thread safe.
19 // VMO Pools are collections of VMOs that are used together
20 // and share similiar properties.  The VMO pool is intended to be used
21 // by a content producer, as all VMOs in the pool are automatically
22 // mapped to a VMAR.  The VMO Pool adds lifecyle management as well,
23 // by keeping track of which vmos are 'locked'.  Although this class
24 // does not maintain any vmo handles, mapping the vmos into vmars retains
25 // ownership.
26 //
27 // VMO Pools are intended to act as one backing for BufferCollections.
28 class VmoPool {
29 
30 public:
31     // Initializes a VmoPool with a set of vmos. You can pass a vector of vmos,
32     // or a vmo pointer and the number of vmos it should grab.
33     // If successful, returns ZX_OK.
34     zx_status_t Init(const fbl::Vector<zx::vmo>& vmos);
35     zx_status_t Init(const zx::vmo* vmos, size_t num_vmos);
36 
37     // Resets the buffer locks and the 'in process' indicator.
38     void Reset();
39 
40     // Finds the next available buffer, and sets that buffer as currently in progress.
41     // Returns ZX_OK if successful, and, if buffer_index != nullptr, stores the
42     // buffer index into buffer_index.
43     // Returns ZX_ERR_NOT_FOUND if no buffers were available or ZX_ERR_BAD_STATE
44     // if a buffer is in the currently in progress state.
45     zx_status_t GetNewBuffer(uint32_t* buffer_index = nullptr);
46 
47     // Sets the currently in progress buffer as completed and ready to consume.
48     // The buffer will be locked for CPU reads until BufferRelease is called
49     // with its index.  'Locked' in this context means that GetNewBuffer will
50     // not set this buffer to the current buffer.
51     // Returns ZX_OK if successful, or ZX_ERR_BAD_STATE if no buffer is
52     // currently in progress.
53     // If buffer_index != nullptr, the currently in progress buffer index
54     // will be returned here.
55     zx_status_t BufferCompleted(uint32_t* buffer_index = nullptr);
56 
57     // Unlocks the buffer with the specified index and sets it as ready to be
58     // reused.  It is permissible to call BufferRelease instead of
59     // BufferCompleted, effectively cancelling use of the current buffer.
60     // Returns ZX_OK if successful, or ZX_ERR_NOT_FOUND if no locked buffer
61     // was found with the given index. If the index is out of bounds,
62     // ZX_ERROR_INVALID_ARGS will be returned.
63     zx_status_t BufferRelease(uint32_t buffer_index);
64 
HasBufferInProgress()65     inline bool HasBufferInProgress() const {
66         return current_buffer_ != kInvalidCurBuffer;
67     }
68 
69     // Return the size of the current buffer.  Returns 0 if no current buffer.
70     uint64_t CurrentBufferSize() const;
71 
72     // Return the start address of the current buffer.
73     // Returns nullptr if no current buffer.
74     void* CurrentBufferAddress() const;
75 
76     ~VmoPool();
77 
78 private:
79     struct ListableBuffer : public fbl::SinglyLinkedListable<ListableBuffer*> {
80         VmoMapper buffer;
81     };
82 
83     // The sentinel value for no in-progress buffer:
84     static constexpr uint32_t kInvalidCurBuffer = std::numeric_limits<uint32_t>::max();
85     // The buffer to which we are currently writing.
86     uint32_t current_buffer_ = kInvalidCurBuffer;
87     // VMO backing the buffer.
88     fbl::Array<ListableBuffer> buffers_;
89     // The list of free buffers.
90     fbl::SinglyLinkedList<ListableBuffer*> free_buffers_;
91 };
92 
93 } // namespace fzl
94