xref: /aosp_15_r20/system/libfmq/include/fmq/MessageQueueBase.h (revision be431cd81a9a2349eaea34eb56fcf6d1608da596)
1*be431cd8SAndroid Build Coastguard Worker /*
2*be431cd8SAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*be431cd8SAndroid Build Coastguard Worker  *
4*be431cd8SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*be431cd8SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*be431cd8SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*be431cd8SAndroid Build Coastguard Worker  *
8*be431cd8SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*be431cd8SAndroid Build Coastguard Worker  *
10*be431cd8SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*be431cd8SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*be431cd8SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*be431cd8SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*be431cd8SAndroid Build Coastguard Worker  * limitations under the License.
15*be431cd8SAndroid Build Coastguard Worker  */
16*be431cd8SAndroid Build Coastguard Worker 
17*be431cd8SAndroid Build Coastguard Worker #pragma once
18*be431cd8SAndroid Build Coastguard Worker 
19*be431cd8SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
20*be431cd8SAndroid Build Coastguard Worker #include <cutils/ashmem.h>
21*be431cd8SAndroid Build Coastguard Worker #include <fmq/EventFlag.h>
22*be431cd8SAndroid Build Coastguard Worker #include <sys/mman.h>
23*be431cd8SAndroid Build Coastguard Worker #include <sys/user.h>
24*be431cd8SAndroid Build Coastguard Worker #include <utils/Log.h>
25*be431cd8SAndroid Build Coastguard Worker #include <utils/SystemClock.h>
26*be431cd8SAndroid Build Coastguard Worker #include <atomic>
27*be431cd8SAndroid Build Coastguard Worker #include <functional>
28*be431cd8SAndroid Build Coastguard Worker 
29*be431cd8SAndroid Build Coastguard Worker using android::hardware::kSynchronizedReadWrite;
30*be431cd8SAndroid Build Coastguard Worker using android::hardware::kUnsynchronizedWrite;
31*be431cd8SAndroid Build Coastguard Worker using android::hardware::MQFlavor;
32*be431cd8SAndroid Build Coastguard Worker 
33*be431cd8SAndroid Build Coastguard Worker namespace android {
34*be431cd8SAndroid Build Coastguard Worker 
35*be431cd8SAndroid Build Coastguard Worker /* sentinel payload type that indicates the MQ will be used with a mismatching
36*be431cd8SAndroid Build Coastguard Worker MQDescriptor type, where type safety must be enforced elsewhere because the real
37*be431cd8SAndroid Build Coastguard Worker element type T is not statically known. This is used to instantiate
38*be431cd8SAndroid Build Coastguard Worker MessageQueueBase instances for Rust where we cannot generate additional template
39*be431cd8SAndroid Build Coastguard Worker instantiations across the language boundary. */
40*be431cd8SAndroid Build Coastguard Worker enum MQErased {};
41*be431cd8SAndroid Build Coastguard Worker 
42*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> class MQDescriptorType, typename T, MQFlavor flavor>
43*be431cd8SAndroid Build Coastguard Worker struct MessageQueueBase {
44*be431cd8SAndroid Build Coastguard Worker     typedef MQDescriptorType<T, flavor> Descriptor;
45*be431cd8SAndroid Build Coastguard Worker     enum Error : int {
46*be431cd8SAndroid Build Coastguard Worker         NONE,
47*be431cd8SAndroid Build Coastguard Worker         POINTER_CORRUPTION, /** Read/write pointers mismatch */
48*be431cd8SAndroid Build Coastguard Worker     };
49*be431cd8SAndroid Build Coastguard Worker     using ErrorHandler = std::function<void(Error, std::string&&)>;
50*be431cd8SAndroid Build Coastguard Worker 
51*be431cd8SAndroid Build Coastguard Worker     /**
52*be431cd8SAndroid Build Coastguard Worker      * @param Desc MQDescriptor describing the FMQ.
53*be431cd8SAndroid Build Coastguard Worker      * @param resetPointers bool indicating whether the read/write pointers
54*be431cd8SAndroid Build Coastguard Worker      * should be reset or not.
55*be431cd8SAndroid Build Coastguard Worker      */
56*be431cd8SAndroid Build Coastguard Worker     MessageQueueBase(const Descriptor& Desc, bool resetPointers = true);
57*be431cd8SAndroid Build Coastguard Worker 
58*be431cd8SAndroid Build Coastguard Worker     ~MessageQueueBase();
59*be431cd8SAndroid Build Coastguard Worker 
60*be431cd8SAndroid Build Coastguard Worker     /**
61*be431cd8SAndroid Build Coastguard Worker      * This constructor uses Ashmem shared memory to create an FMQ
62*be431cd8SAndroid Build Coastguard Worker      * that can contain a maximum of 'numElementsInQueue' elements of type T.
63*be431cd8SAndroid Build Coastguard Worker      *
64*be431cd8SAndroid Build Coastguard Worker      * @param numElementsInQueue Capacity of the MessageQueue in terms of T.
65*be431cd8SAndroid Build Coastguard Worker      * @param configureEventFlagWord Boolean that specifies if memory should
66*be431cd8SAndroid Build Coastguard Worker      * also be allocated and mapped for an EventFlag word.
67*be431cd8SAndroid Build Coastguard Worker      * @param bufferFd User-supplied file descriptor to map the memory for the ringbuffer
68*be431cd8SAndroid Build Coastguard Worker      * By default, bufferFd=-1 means library will allocate ashmem region for ringbuffer.
69*be431cd8SAndroid Build Coastguard Worker      * MessageQueue takes ownership of the file descriptor.
70*be431cd8SAndroid Build Coastguard Worker      * @param bufferSize size of buffer in bytes that bufferFd represents. This
71*be431cd8SAndroid Build Coastguard Worker      * size must be larger than or equal to (numElementsInQueue * sizeof(T)).
72*be431cd8SAndroid Build Coastguard Worker      * Otherwise, operations will cause out-of-bounds memory access.
73*be431cd8SAndroid Build Coastguard Worker      */
74*be431cd8SAndroid Build Coastguard Worker 
MessageQueueBaseMessageQueueBase75*be431cd8SAndroid Build Coastguard Worker     MessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord,
76*be431cd8SAndroid Build Coastguard Worker                      android::base::unique_fd bufferFd, size_t bufferSize)
77*be431cd8SAndroid Build Coastguard Worker         : MessageQueueBase(numElementsInQueue, configureEventFlagWord, std::move(bufferFd),
78*be431cd8SAndroid Build Coastguard Worker                            bufferSize, sizeof(T)) {
79*be431cd8SAndroid Build Coastguard Worker         /* We must not pass sizeof(T) as quantum for MQErased element type. */
80*be431cd8SAndroid Build Coastguard Worker         static_assert(!std::is_same_v<T, MQErased>,
81*be431cd8SAndroid Build Coastguard Worker                       "MessageQueueBase<..., MQErased, ...> must be constructed via a"
82*be431cd8SAndroid Build Coastguard Worker                       " constructor that accepts a descriptor or a quantum size");
83*be431cd8SAndroid Build Coastguard Worker     };
84*be431cd8SAndroid Build Coastguard Worker 
85*be431cd8SAndroid Build Coastguard Worker     MessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord = false)
86*be431cd8SAndroid Build Coastguard Worker         : MessageQueueBase(numElementsInQueue, configureEventFlagWord, android::base::unique_fd(),
87*be431cd8SAndroid Build Coastguard Worker                            0) {}
88*be431cd8SAndroid Build Coastguard Worker 
89*be431cd8SAndroid Build Coastguard Worker     /**
90*be431cd8SAndroid Build Coastguard Worker      * Set a client side error handler function which will be invoked when the FMQ detects
91*be431cd8SAndroid Build Coastguard Worker      * one of the error situations defined by the 'Error' type.
92*be431cd8SAndroid Build Coastguard Worker      */
setErrorHandlerMessageQueueBase93*be431cd8SAndroid Build Coastguard Worker     void setErrorHandler(ErrorHandler&& handler) { mErrorHandler.swap(handler); }
94*be431cd8SAndroid Build Coastguard Worker 
95*be431cd8SAndroid Build Coastguard Worker     /**
96*be431cd8SAndroid Build Coastguard Worker      * @return Number of items of type T that can be written into the FMQ
97*be431cd8SAndroid Build Coastguard Worker      * without a read.
98*be431cd8SAndroid Build Coastguard Worker      */
99*be431cd8SAndroid Build Coastguard Worker     size_t availableToWrite() const;
100*be431cd8SAndroid Build Coastguard Worker 
101*be431cd8SAndroid Build Coastguard Worker     /**
102*be431cd8SAndroid Build Coastguard Worker      * @return Number of items of type T that are waiting to be read from the
103*be431cd8SAndroid Build Coastguard Worker      * FMQ.
104*be431cd8SAndroid Build Coastguard Worker      */
105*be431cd8SAndroid Build Coastguard Worker     size_t availableToRead() const;
106*be431cd8SAndroid Build Coastguard Worker 
107*be431cd8SAndroid Build Coastguard Worker     /**
108*be431cd8SAndroid Build Coastguard Worker      * Returns the size of type T in bytes.
109*be431cd8SAndroid Build Coastguard Worker      *
110*be431cd8SAndroid Build Coastguard Worker      * @return Size of T.
111*be431cd8SAndroid Build Coastguard Worker      */
112*be431cd8SAndroid Build Coastguard Worker     size_t getQuantumSize() const;
113*be431cd8SAndroid Build Coastguard Worker 
114*be431cd8SAndroid Build Coastguard Worker     /**
115*be431cd8SAndroid Build Coastguard Worker      * Returns the size of the FMQ in terms of the size of type T.
116*be431cd8SAndroid Build Coastguard Worker      *
117*be431cd8SAndroid Build Coastguard Worker      * @return Number of items of type T that will fit in the FMQ.
118*be431cd8SAndroid Build Coastguard Worker      */
119*be431cd8SAndroid Build Coastguard Worker     size_t getQuantumCount() const;
120*be431cd8SAndroid Build Coastguard Worker 
121*be431cd8SAndroid Build Coastguard Worker     /**
122*be431cd8SAndroid Build Coastguard Worker      * @return Whether the FMQ is configured correctly.
123*be431cd8SAndroid Build Coastguard Worker      */
124*be431cd8SAndroid Build Coastguard Worker     bool isValid() const;
125*be431cd8SAndroid Build Coastguard Worker 
126*be431cd8SAndroid Build Coastguard Worker     /**
127*be431cd8SAndroid Build Coastguard Worker      * Non-blocking write to FMQ.
128*be431cd8SAndroid Build Coastguard Worker      *
129*be431cd8SAndroid Build Coastguard Worker      * @param data Pointer to the object of type T to be written into the FMQ.
130*be431cd8SAndroid Build Coastguard Worker      *
131*be431cd8SAndroid Build Coastguard Worker      * @return Whether the write was successful.
132*be431cd8SAndroid Build Coastguard Worker      */
133*be431cd8SAndroid Build Coastguard Worker     bool write(const T* data);
134*be431cd8SAndroid Build Coastguard Worker 
135*be431cd8SAndroid Build Coastguard Worker     /**
136*be431cd8SAndroid Build Coastguard Worker      * Non-blocking read from FMQ.
137*be431cd8SAndroid Build Coastguard Worker      *
138*be431cd8SAndroid Build Coastguard Worker      * @param data Pointer to the memory where the object read from the FMQ is
139*be431cd8SAndroid Build Coastguard Worker      * copied to.
140*be431cd8SAndroid Build Coastguard Worker      *
141*be431cd8SAndroid Build Coastguard Worker      * @return Whether the read was successful.
142*be431cd8SAndroid Build Coastguard Worker      */
143*be431cd8SAndroid Build Coastguard Worker     bool read(T* data);
144*be431cd8SAndroid Build Coastguard Worker 
145*be431cd8SAndroid Build Coastguard Worker     /**
146*be431cd8SAndroid Build Coastguard Worker      * Write some data into the FMQ without blocking.
147*be431cd8SAndroid Build Coastguard Worker      *
148*be431cd8SAndroid Build Coastguard Worker      * @param data Pointer to the array of items of type T.
149*be431cd8SAndroid Build Coastguard Worker      * @param count Number of items in array.
150*be431cd8SAndroid Build Coastguard Worker      *
151*be431cd8SAndroid Build Coastguard Worker      * @return Whether the write was successful.
152*be431cd8SAndroid Build Coastguard Worker      */
153*be431cd8SAndroid Build Coastguard Worker     bool write(const T* data, size_t count);
154*be431cd8SAndroid Build Coastguard Worker 
155*be431cd8SAndroid Build Coastguard Worker     /**
156*be431cd8SAndroid Build Coastguard Worker      * Perform a blocking write of 'count' items into the FMQ using EventFlags.
157*be431cd8SAndroid Build Coastguard Worker      * Does not support partial writes.
158*be431cd8SAndroid Build Coastguard Worker      *
159*be431cd8SAndroid Build Coastguard Worker      * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
160*be431cd8SAndroid Build Coastguard Worker      * associated with the FMQ and it is used in that case.
161*be431cd8SAndroid Build Coastguard Worker      *
162*be431cd8SAndroid Build Coastguard Worker      * The application code must ensure that 'evFlag' used by the
163*be431cd8SAndroid Build Coastguard Worker      * reader(s)/writer is based upon the same EventFlag word.
164*be431cd8SAndroid Build Coastguard Worker      *
165*be431cd8SAndroid Build Coastguard Worker      * The method will return false without blocking if any of the following
166*be431cd8SAndroid Build Coastguard Worker      * conditions are true:
167*be431cd8SAndroid Build Coastguard Worker      * - If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
168*be431cd8SAndroid Build Coastguard Worker      * - If the 'readNotification' bit mask is zero.
169*be431cd8SAndroid Build Coastguard Worker      * - If 'count' is greater than the FMQ size.
170*be431cd8SAndroid Build Coastguard Worker      *
171*be431cd8SAndroid Build Coastguard Worker      * If the there is insufficient space available to write into it, the
172*be431cd8SAndroid Build Coastguard Worker      * EventFlag bit mask 'readNotification' is is waited upon.
173*be431cd8SAndroid Build Coastguard Worker      *
174*be431cd8SAndroid Build Coastguard Worker      * This method should only be used with a MessageQueue of the flavor
175*be431cd8SAndroid Build Coastguard Worker      * 'kSynchronizedReadWrite'.
176*be431cd8SAndroid Build Coastguard Worker      *
177*be431cd8SAndroid Build Coastguard Worker      * Upon a successful write, wake is called on 'writeNotification' (if
178*be431cd8SAndroid Build Coastguard Worker      * non-zero).
179*be431cd8SAndroid Build Coastguard Worker      *
180*be431cd8SAndroid Build Coastguard Worker      * @param data Pointer to the array of items of type T.
181*be431cd8SAndroid Build Coastguard Worker      * @param count Number of items in array.
182*be431cd8SAndroid Build Coastguard Worker      * @param readNotification The EventFlag bit mask to wait on if there is not
183*be431cd8SAndroid Build Coastguard Worker      * enough space in FMQ to write 'count' items.
184*be431cd8SAndroid Build Coastguard Worker      * @param writeNotification The EventFlag bit mask to call wake on
185*be431cd8SAndroid Build Coastguard Worker      * a successful write. No wake is called if 'writeNotification' is zero.
186*be431cd8SAndroid Build Coastguard Worker      * @param timeOutNanos Number of nanoseconds after which the blocking
187*be431cd8SAndroid Build Coastguard Worker      * write attempt is aborted.
188*be431cd8SAndroid Build Coastguard Worker      * @param evFlag The EventFlag object to be used for blocking. If nullptr,
189*be431cd8SAndroid Build Coastguard Worker      * it is checked whether the FMQ owns an EventFlag object and that is used
190*be431cd8SAndroid Build Coastguard Worker      * for blocking instead.
191*be431cd8SAndroid Build Coastguard Worker      *
192*be431cd8SAndroid Build Coastguard Worker      * @return Whether the write was successful.
193*be431cd8SAndroid Build Coastguard Worker      */
194*be431cd8SAndroid Build Coastguard Worker     bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
195*be431cd8SAndroid Build Coastguard Worker                        uint32_t writeNotification, int64_t timeOutNanos = 0,
196*be431cd8SAndroid Build Coastguard Worker                        android::hardware::EventFlag* evFlag = nullptr);
197*be431cd8SAndroid Build Coastguard Worker 
198*be431cd8SAndroid Build Coastguard Worker     bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
199*be431cd8SAndroid Build Coastguard Worker 
200*be431cd8SAndroid Build Coastguard Worker     /**
201*be431cd8SAndroid Build Coastguard Worker      * Read some data from the FMQ without blocking.
202*be431cd8SAndroid Build Coastguard Worker      *
203*be431cd8SAndroid Build Coastguard Worker      * @param data Pointer to the array to which read data is to be written.
204*be431cd8SAndroid Build Coastguard Worker      * @param count Number of items to be read.
205*be431cd8SAndroid Build Coastguard Worker      *
206*be431cd8SAndroid Build Coastguard Worker      * @return Whether the read was successful.
207*be431cd8SAndroid Build Coastguard Worker      */
208*be431cd8SAndroid Build Coastguard Worker     bool read(T* data, size_t count);
209*be431cd8SAndroid Build Coastguard Worker 
210*be431cd8SAndroid Build Coastguard Worker     /**
211*be431cd8SAndroid Build Coastguard Worker      * Perform a blocking read operation of 'count' items from the FMQ. Does not
212*be431cd8SAndroid Build Coastguard Worker      * perform a partial read.
213*be431cd8SAndroid Build Coastguard Worker      *
214*be431cd8SAndroid Build Coastguard Worker      * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
215*be431cd8SAndroid Build Coastguard Worker      * associated with the FMQ and it is used in that case.
216*be431cd8SAndroid Build Coastguard Worker      *
217*be431cd8SAndroid Build Coastguard Worker      * The application code must ensure that 'evFlag' used by the
218*be431cd8SAndroid Build Coastguard Worker      * reader(s)/writer is based upon the same EventFlag word.
219*be431cd8SAndroid Build Coastguard Worker      *
220*be431cd8SAndroid Build Coastguard Worker      * The method will return false without blocking if any of the following
221*be431cd8SAndroid Build Coastguard Worker      * conditions are true:
222*be431cd8SAndroid Build Coastguard Worker      * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
223*be431cd8SAndroid Build Coastguard Worker      * -If the 'writeNotification' bit mask is zero.
224*be431cd8SAndroid Build Coastguard Worker      * -If 'count' is greater than the FMQ size.
225*be431cd8SAndroid Build Coastguard Worker      *
226*be431cd8SAndroid Build Coastguard Worker      * This method should only be used with a MessageQueue of the flavor
227*be431cd8SAndroid Build Coastguard Worker      * 'kSynchronizedReadWrite'.
228*be431cd8SAndroid Build Coastguard Worker 
229*be431cd8SAndroid Build Coastguard Worker      * If FMQ does not contain 'count' items, the eventFlag bit mask
230*be431cd8SAndroid Build Coastguard Worker      * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
231*be431cd8SAndroid Build Coastguard Worker      * wake is called on 'readNotification' (if non-zero).
232*be431cd8SAndroid Build Coastguard Worker      *
233*be431cd8SAndroid Build Coastguard Worker      * @param data Pointer to the array to which read data is to be written.
234*be431cd8SAndroid Build Coastguard Worker      * @param count Number of items to be read.
235*be431cd8SAndroid Build Coastguard Worker      * @param readNotification The EventFlag bit mask to call wake on after
236*be431cd8SAndroid Build Coastguard Worker      * a successful read. No wake is called if 'readNotification' is zero.
237*be431cd8SAndroid Build Coastguard Worker      * @param writeNotification The EventFlag bit mask to call a wait on
238*be431cd8SAndroid Build Coastguard Worker      * if there is insufficient data in the FMQ to be read.
239*be431cd8SAndroid Build Coastguard Worker      * @param timeOutNanos Number of nanoseconds after which the blocking
240*be431cd8SAndroid Build Coastguard Worker      * read attempt is aborted.
241*be431cd8SAndroid Build Coastguard Worker      * @param evFlag The EventFlag object to be used for blocking.
242*be431cd8SAndroid Build Coastguard Worker      *
243*be431cd8SAndroid Build Coastguard Worker      * @return Whether the read was successful.
244*be431cd8SAndroid Build Coastguard Worker      */
245*be431cd8SAndroid Build Coastguard Worker     bool readBlocking(T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
246*be431cd8SAndroid Build Coastguard Worker                       int64_t timeOutNanos = 0, android::hardware::EventFlag* evFlag = nullptr);
247*be431cd8SAndroid Build Coastguard Worker 
248*be431cd8SAndroid Build Coastguard Worker     bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);
249*be431cd8SAndroid Build Coastguard Worker 
250*be431cd8SAndroid Build Coastguard Worker     /**
251*be431cd8SAndroid Build Coastguard Worker      * Get a pointer to the MQDescriptor object that describes this FMQ.
252*be431cd8SAndroid Build Coastguard Worker      *
253*be431cd8SAndroid Build Coastguard Worker      * @return Pointer to the MQDescriptor associated with the FMQ.
254*be431cd8SAndroid Build Coastguard Worker      */
getDescMessageQueueBase255*be431cd8SAndroid Build Coastguard Worker     const Descriptor* getDesc() const { return mDesc.get(); }
256*be431cd8SAndroid Build Coastguard Worker 
257*be431cd8SAndroid Build Coastguard Worker     /**
258*be431cd8SAndroid Build Coastguard Worker      * Get a pointer to the EventFlag word if there is one associated with this FMQ.
259*be431cd8SAndroid Build Coastguard Worker      *
260*be431cd8SAndroid Build Coastguard Worker      * @return Pointer to an EventFlag word, will return nullptr if not
261*be431cd8SAndroid Build Coastguard Worker      * configured. This method does not transfer ownership. The EventFlag
262*be431cd8SAndroid Build Coastguard Worker      * word will be unmapped by the MessageQueue destructor.
263*be431cd8SAndroid Build Coastguard Worker      */
getEventFlagWordMessageQueueBase264*be431cd8SAndroid Build Coastguard Worker     std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
265*be431cd8SAndroid Build Coastguard Worker 
266*be431cd8SAndroid Build Coastguard Worker     /**
267*be431cd8SAndroid Build Coastguard Worker      * Describes a memory region in the FMQ.
268*be431cd8SAndroid Build Coastguard Worker      */
269*be431cd8SAndroid Build Coastguard Worker     struct MemRegion {
MemRegionMessageQueueBase::MemRegion270*be431cd8SAndroid Build Coastguard Worker         MemRegion() : MemRegion(nullptr, 0) {}
271*be431cd8SAndroid Build Coastguard Worker 
MemRegionMessageQueueBase::MemRegion272*be431cd8SAndroid Build Coastguard Worker         MemRegion(T* base, size_t size) : address(base), length(size) {}
273*be431cd8SAndroid Build Coastguard Worker 
274*be431cd8SAndroid Build Coastguard Worker         MemRegion& operator=(const MemRegion& other) {
275*be431cd8SAndroid Build Coastguard Worker             address = other.address;
276*be431cd8SAndroid Build Coastguard Worker             length = other.length;
277*be431cd8SAndroid Build Coastguard Worker             return *this;
278*be431cd8SAndroid Build Coastguard Worker         }
279*be431cd8SAndroid Build Coastguard Worker 
280*be431cd8SAndroid Build Coastguard Worker         /**
281*be431cd8SAndroid Build Coastguard Worker          * Gets a pointer to the base address of the MemRegion.
282*be431cd8SAndroid Build Coastguard Worker          */
getAddressMessageQueueBase::MemRegion283*be431cd8SAndroid Build Coastguard Worker         inline T* getAddress() const { return address; }
284*be431cd8SAndroid Build Coastguard Worker 
285*be431cd8SAndroid Build Coastguard Worker         /**
286*be431cd8SAndroid Build Coastguard Worker          * Gets the length of the MemRegion. This would equal to the number
287*be431cd8SAndroid Build Coastguard Worker          * of items of type T that can be read from/written into the MemRegion.
288*be431cd8SAndroid Build Coastguard Worker          */
getLengthMessageQueueBase::MemRegion289*be431cd8SAndroid Build Coastguard Worker         inline size_t getLength() const { return length; }
290*be431cd8SAndroid Build Coastguard Worker 
291*be431cd8SAndroid Build Coastguard Worker         /**
292*be431cd8SAndroid Build Coastguard Worker          * Gets the length of the MemRegion in bytes.
293*be431cd8SAndroid Build Coastguard Worker          */
294*be431cd8SAndroid Build Coastguard Worker         template <class U = T>
getLengthInBytesMessageQueueBase::MemRegion295*be431cd8SAndroid Build Coastguard Worker         inline std::enable_if_t<!std::is_same_v<U, MQErased>, size_t> getLengthInBytes() const {
296*be431cd8SAndroid Build Coastguard Worker             return length * kQuantumValue<U>;
297*be431cd8SAndroid Build Coastguard Worker         }
298*be431cd8SAndroid Build Coastguard Worker 
299*be431cd8SAndroid Build Coastguard Worker       private:
300*be431cd8SAndroid Build Coastguard Worker         /* Base address */
301*be431cd8SAndroid Build Coastguard Worker         T* address;
302*be431cd8SAndroid Build Coastguard Worker 
303*be431cd8SAndroid Build Coastguard Worker         /*
304*be431cd8SAndroid Build Coastguard Worker          * Number of items of type T that can be written to/read from the base
305*be431cd8SAndroid Build Coastguard Worker          * address.
306*be431cd8SAndroid Build Coastguard Worker          */
307*be431cd8SAndroid Build Coastguard Worker         size_t length;
308*be431cd8SAndroid Build Coastguard Worker     };
309*be431cd8SAndroid Build Coastguard Worker 
310*be431cd8SAndroid Build Coastguard Worker     /**
311*be431cd8SAndroid Build Coastguard Worker      * Describes the memory regions to be used for a read or write.
312*be431cd8SAndroid Build Coastguard Worker      * The struct contains two MemRegion objects since the FMQ is a ring
313*be431cd8SAndroid Build Coastguard Worker      * buffer and a read or write operation can wrap around. A single message
314*be431cd8SAndroid Build Coastguard Worker      * of type T will never be broken between the two MemRegions.
315*be431cd8SAndroid Build Coastguard Worker      */
316*be431cd8SAndroid Build Coastguard Worker     struct MemTransaction {
MemTransactionMessageQueueBase::MemTransaction317*be431cd8SAndroid Build Coastguard Worker         MemTransaction() : MemTransaction(MemRegion(), MemRegion()) {}
318*be431cd8SAndroid Build Coastguard Worker 
MemTransactionMessageQueueBase::MemTransaction319*be431cd8SAndroid Build Coastguard Worker         MemTransaction(const MemRegion& regionFirst, const MemRegion& regionSecond)
320*be431cd8SAndroid Build Coastguard Worker             : first(regionFirst), second(regionSecond) {}
321*be431cd8SAndroid Build Coastguard Worker 
322*be431cd8SAndroid Build Coastguard Worker         MemTransaction& operator=(const MemTransaction& other) {
323*be431cd8SAndroid Build Coastguard Worker             first = other.first;
324*be431cd8SAndroid Build Coastguard Worker             second = other.second;
325*be431cd8SAndroid Build Coastguard Worker             return *this;
326*be431cd8SAndroid Build Coastguard Worker         }
327*be431cd8SAndroid Build Coastguard Worker 
328*be431cd8SAndroid Build Coastguard Worker         /**
329*be431cd8SAndroid Build Coastguard Worker          * Helper method to calculate the address for a particular index for
330*be431cd8SAndroid Build Coastguard Worker          * the MemTransaction object.
331*be431cd8SAndroid Build Coastguard Worker          *
332*be431cd8SAndroid Build Coastguard Worker          * @param idx Index of the slot to be read/written. If the
333*be431cd8SAndroid Build Coastguard Worker          * MemTransaction object is representing the memory region to read/write
334*be431cd8SAndroid Build Coastguard Worker          * N items of type T, the valid range of idx is between 0 and N-1.
335*be431cd8SAndroid Build Coastguard Worker          *
336*be431cd8SAndroid Build Coastguard Worker          * @return Pointer to the slot idx. Will be nullptr for an invalid idx.
337*be431cd8SAndroid Build Coastguard Worker          */
338*be431cd8SAndroid Build Coastguard Worker         T* getSlot(size_t idx);
339*be431cd8SAndroid Build Coastguard Worker 
340*be431cd8SAndroid Build Coastguard Worker         /**
341*be431cd8SAndroid Build Coastguard Worker          * Helper method to write 'nMessages' items of type T into the memory
342*be431cd8SAndroid Build Coastguard Worker          * regions described by the object starting from 'startIdx'. This method
343*be431cd8SAndroid Build Coastguard Worker          * uses memcpy() and is not to meant to be used for a zero copy operation.
344*be431cd8SAndroid Build Coastguard Worker          * Partial writes are not supported.
345*be431cd8SAndroid Build Coastguard Worker          *
346*be431cd8SAndroid Build Coastguard Worker          * @param data Pointer to the source buffer.
347*be431cd8SAndroid Build Coastguard Worker          * @param nMessages Number of items of type T.
348*be431cd8SAndroid Build Coastguard Worker          * @param startIdx The slot number to begin the write from. If the
349*be431cd8SAndroid Build Coastguard Worker          * MemTransaction object is representing the memory region to read/write
350*be431cd8SAndroid Build Coastguard Worker          * N items of type T, the valid range of startIdx is between 0 and N-1;
351*be431cd8SAndroid Build Coastguard Worker          *
352*be431cd8SAndroid Build Coastguard Worker          * @return Whether the write operation of size 'nMessages' succeeded.
353*be431cd8SAndroid Build Coastguard Worker          */
354*be431cd8SAndroid Build Coastguard Worker         bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
355*be431cd8SAndroid Build Coastguard Worker 
356*be431cd8SAndroid Build Coastguard Worker         /*
357*be431cd8SAndroid Build Coastguard Worker          * Helper method to read 'nMessages' items of type T from the memory
358*be431cd8SAndroid Build Coastguard Worker          * regions described by the object starting from 'startIdx'. This method uses
359*be431cd8SAndroid Build Coastguard Worker          * memcpy() and is not meant to be used for a zero copy operation. Partial reads
360*be431cd8SAndroid Build Coastguard Worker          * are not supported.
361*be431cd8SAndroid Build Coastguard Worker          *
362*be431cd8SAndroid Build Coastguard Worker          * @param data Pointer to the destination buffer.
363*be431cd8SAndroid Build Coastguard Worker          * @param nMessages Number of items of type T.
364*be431cd8SAndroid Build Coastguard Worker          * @param startIdx The slot number to begin the read from. If the
365*be431cd8SAndroid Build Coastguard Worker          * MemTransaction object is representing the memory region to read/write
366*be431cd8SAndroid Build Coastguard Worker          * N items of type T, the valid range of startIdx is between 0 and N-1.
367*be431cd8SAndroid Build Coastguard Worker          *
368*be431cd8SAndroid Build Coastguard Worker          * @return Whether the read operation of size 'nMessages' succeeded.
369*be431cd8SAndroid Build Coastguard Worker          */
370*be431cd8SAndroid Build Coastguard Worker         bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
371*be431cd8SAndroid Build Coastguard Worker 
372*be431cd8SAndroid Build Coastguard Worker         /**
373*be431cd8SAndroid Build Coastguard Worker          * Returns a const reference to the first MemRegion in the
374*be431cd8SAndroid Build Coastguard Worker          * MemTransaction object.
375*be431cd8SAndroid Build Coastguard Worker          */
getFirstRegionMessageQueueBase::MemTransaction376*be431cd8SAndroid Build Coastguard Worker         inline const MemRegion& getFirstRegion() const { return first; }
377*be431cd8SAndroid Build Coastguard Worker 
378*be431cd8SAndroid Build Coastguard Worker         /**
379*be431cd8SAndroid Build Coastguard Worker          * Returns a const reference to the second MemRegion in the
380*be431cd8SAndroid Build Coastguard Worker          * MemTransaction object.
381*be431cd8SAndroid Build Coastguard Worker          */
getSecondRegionMessageQueueBase::MemTransaction382*be431cd8SAndroid Build Coastguard Worker         inline const MemRegion& getSecondRegion() const { return second; }
383*be431cd8SAndroid Build Coastguard Worker 
384*be431cd8SAndroid Build Coastguard Worker       private:
385*be431cd8SAndroid Build Coastguard Worker         friend MessageQueueBase<MQDescriptorType, T, flavor>;
386*be431cd8SAndroid Build Coastguard Worker 
387*be431cd8SAndroid Build Coastguard Worker         bool copyToSized(const T* data, size_t startIdx, size_t nMessages, size_t messageSize);
388*be431cd8SAndroid Build Coastguard Worker         bool copyFromSized(T* data, size_t startIdx, size_t nMessages, size_t messageSize);
389*be431cd8SAndroid Build Coastguard Worker 
390*be431cd8SAndroid Build Coastguard Worker         /*
391*be431cd8SAndroid Build Coastguard Worker          * Given a start index and the number of messages to be
392*be431cd8SAndroid Build Coastguard Worker          * read/written, this helper method calculates the
393*be431cd8SAndroid Build Coastguard Worker          * number of messages that should should be written to both the first
394*be431cd8SAndroid Build Coastguard Worker          * and second MemRegions and the base addresses to be used for
395*be431cd8SAndroid Build Coastguard Worker          * the read/write operation.
396*be431cd8SAndroid Build Coastguard Worker          *
397*be431cd8SAndroid Build Coastguard Worker          * Returns false if the 'startIdx' and 'nMessages' is
398*be431cd8SAndroid Build Coastguard Worker          * invalid for the MemTransaction object.
399*be431cd8SAndroid Build Coastguard Worker          */
400*be431cd8SAndroid Build Coastguard Worker         bool inline getMemRegionInfo(size_t idx, size_t nMessages, size_t& firstCount,
401*be431cd8SAndroid Build Coastguard Worker                                      size_t& secondCount, T** firstBaseAddress,
402*be431cd8SAndroid Build Coastguard Worker                                      T** secondBaseAddress);
403*be431cd8SAndroid Build Coastguard Worker         MemRegion first;
404*be431cd8SAndroid Build Coastguard Worker         MemRegion second;
405*be431cd8SAndroid Build Coastguard Worker     };
406*be431cd8SAndroid Build Coastguard Worker 
407*be431cd8SAndroid Build Coastguard Worker     /**
408*be431cd8SAndroid Build Coastguard Worker      * Get a MemTransaction object to write 'nMessages' items of type T.
409*be431cd8SAndroid Build Coastguard Worker      * Once the write is performed using the information from MemTransaction,
410*be431cd8SAndroid Build Coastguard Worker      * the write operation is to be committed using a call to commitWrite().
411*be431cd8SAndroid Build Coastguard Worker      *
412*be431cd8SAndroid Build Coastguard Worker      * @param nMessages Number of messages of type T.
413*be431cd8SAndroid Build Coastguard Worker      * @param Pointer to MemTransaction struct that describes memory to write 'nMessages'
414*be431cd8SAndroid Build Coastguard Worker      * items of type T. If a write of size 'nMessages' is not possible, the base
415*be431cd8SAndroid Build Coastguard Worker      * addresses in the MemTransaction object would be set to nullptr.
416*be431cd8SAndroid Build Coastguard Worker      *
417*be431cd8SAndroid Build Coastguard Worker      * @return Whether it is possible to write 'nMessages' items of type T
418*be431cd8SAndroid Build Coastguard Worker      * into the FMQ.
419*be431cd8SAndroid Build Coastguard Worker      */
420*be431cd8SAndroid Build Coastguard Worker     bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
421*be431cd8SAndroid Build Coastguard Worker 
422*be431cd8SAndroid Build Coastguard Worker     /**
423*be431cd8SAndroid Build Coastguard Worker      * Commit a write of size 'nMessages'. To be only used after a call to beginWrite().
424*be431cd8SAndroid Build Coastguard Worker      *
425*be431cd8SAndroid Build Coastguard Worker      * @param nMessages number of messages of type T to be written.
426*be431cd8SAndroid Build Coastguard Worker      *
427*be431cd8SAndroid Build Coastguard Worker      * @return Whether the write operation of size 'nMessages' succeeded.
428*be431cd8SAndroid Build Coastguard Worker      */
429*be431cd8SAndroid Build Coastguard Worker     bool commitWrite(size_t nMessages);
430*be431cd8SAndroid Build Coastguard Worker 
431*be431cd8SAndroid Build Coastguard Worker     /**
432*be431cd8SAndroid Build Coastguard Worker      * Get a MemTransaction object to read 'nMessages' items of type T.
433*be431cd8SAndroid Build Coastguard Worker      * Once the read is performed using the information from MemTransaction,
434*be431cd8SAndroid Build Coastguard Worker      * the read operation is to be committed using a call to commitRead().
435*be431cd8SAndroid Build Coastguard Worker      *
436*be431cd8SAndroid Build Coastguard Worker      * @param nMessages Number of messages of type T.
437*be431cd8SAndroid Build Coastguard Worker      * @param pointer to MemTransaction struct that describes memory to read 'nMessages'
438*be431cd8SAndroid Build Coastguard Worker      * items of type T. If a read of size 'nMessages' is not possible, the base
439*be431cd8SAndroid Build Coastguard Worker      * pointers in the MemTransaction object returned will be set to nullptr.
440*be431cd8SAndroid Build Coastguard Worker      *
441*be431cd8SAndroid Build Coastguard Worker      * @return bool Whether it is possible to read 'nMessages' items of type T
442*be431cd8SAndroid Build Coastguard Worker      * from the FMQ.
443*be431cd8SAndroid Build Coastguard Worker      */
444*be431cd8SAndroid Build Coastguard Worker     bool beginRead(size_t nMessages, MemTransaction* memTx) const;
445*be431cd8SAndroid Build Coastguard Worker 
446*be431cd8SAndroid Build Coastguard Worker     /**
447*be431cd8SAndroid Build Coastguard Worker      * Commit a read of size 'nMessages'. To be only used after a call to beginRead().
448*be431cd8SAndroid Build Coastguard Worker      * For the unsynchronized flavor of FMQ, this method will return a failure
449*be431cd8SAndroid Build Coastguard Worker      * if a write overflow happened after beginRead() was invoked.
450*be431cd8SAndroid Build Coastguard Worker      *
451*be431cd8SAndroid Build Coastguard Worker      * @param nMessages number of messages of type T to be read.
452*be431cd8SAndroid Build Coastguard Worker      *
453*be431cd8SAndroid Build Coastguard Worker      * @return bool Whether the read operation of size 'nMessages' succeeded.
454*be431cd8SAndroid Build Coastguard Worker      */
455*be431cd8SAndroid Build Coastguard Worker     bool commitRead(size_t nMessages);
456*be431cd8SAndroid Build Coastguard Worker 
457*be431cd8SAndroid Build Coastguard Worker     /**
458*be431cd8SAndroid Build Coastguard Worker      * Get the pointer to the ring buffer. Useful for debugging and fuzzing.
459*be431cd8SAndroid Build Coastguard Worker      */
getRingBufferPtrMessageQueueBase460*be431cd8SAndroid Build Coastguard Worker     uint8_t* getRingBufferPtr() const { return mRing; }
461*be431cd8SAndroid Build Coastguard Worker 
462*be431cd8SAndroid Build Coastguard Worker   protected:
463*be431cd8SAndroid Build Coastguard Worker     /**
464*be431cd8SAndroid Build Coastguard Worker      * Protected constructor that can manually specify the quantum to use.
465*be431cd8SAndroid Build Coastguard Worker      * The only external consumer of this ctor is ErasedMessageQueue, but the
466*be431cd8SAndroid Build Coastguard Worker      * constructor cannot be private because this is a base class.
467*be431cd8SAndroid Build Coastguard Worker      *
468*be431cd8SAndroid Build Coastguard Worker      * @param quantum Size of the element type, in bytes.
469*be431cd8SAndroid Build Coastguard Worker      * Other parameters have semantics given in the corresponding public ctor.
470*be431cd8SAndroid Build Coastguard Worker      */
471*be431cd8SAndroid Build Coastguard Worker 
472*be431cd8SAndroid Build Coastguard Worker     MessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord,
473*be431cd8SAndroid Build Coastguard Worker                      android::base::unique_fd bufferFd, size_t bufferSize, size_t quantum);
474*be431cd8SAndroid Build Coastguard Worker 
475*be431cd8SAndroid Build Coastguard Worker   private:
476*be431cd8SAndroid Build Coastguard Worker     template <class U = T,
477*be431cd8SAndroid Build Coastguard Worker               typename std::enable_if<!std::is_same<U, MQErased>::value, bool>::type = true>
478*be431cd8SAndroid Build Coastguard Worker     static constexpr size_t kQuantumValue = sizeof(T);
479*be431cd8SAndroid Build Coastguard Worker     inline size_t quantum() const;
480*be431cd8SAndroid Build Coastguard Worker     size_t availableToWriteBytes() const;
481*be431cd8SAndroid Build Coastguard Worker     size_t availableToReadBytes() const;
482*be431cd8SAndroid Build Coastguard Worker 
483*be431cd8SAndroid Build Coastguard Worker     MessageQueueBase(const MessageQueueBase& other) = delete;
484*be431cd8SAndroid Build Coastguard Worker     MessageQueueBase& operator=(const MessageQueueBase& other) = delete;
485*be431cd8SAndroid Build Coastguard Worker 
486*be431cd8SAndroid Build Coastguard Worker     void* mapGrantorDescr(uint32_t grantorIdx);
487*be431cd8SAndroid Build Coastguard Worker     void unmapGrantorDescr(void* address, uint32_t grantorIdx);
488*be431cd8SAndroid Build Coastguard Worker     void initMemory(bool resetPointers);
489*be431cd8SAndroid Build Coastguard Worker     bool processOverflow(uint64_t readPtr, uint64_t writePtr) const;
490*be431cd8SAndroid Build Coastguard Worker 
491*be431cd8SAndroid Build Coastguard Worker     enum DefaultEventNotification : uint32_t {
492*be431cd8SAndroid Build Coastguard Worker         /*
493*be431cd8SAndroid Build Coastguard Worker          * These are only used internally by the readBlocking()/writeBlocking()
494*be431cd8SAndroid Build Coastguard Worker          * methods and hence once other bit combinations are not required.
495*be431cd8SAndroid Build Coastguard Worker          */
496*be431cd8SAndroid Build Coastguard Worker         FMQ_NOT_FULL = 0x01,
497*be431cd8SAndroid Build Coastguard Worker         FMQ_NOT_EMPTY = 0x02
498*be431cd8SAndroid Build Coastguard Worker     };
499*be431cd8SAndroid Build Coastguard Worker     std::unique_ptr<Descriptor> mDesc;
500*be431cd8SAndroid Build Coastguard Worker     uint8_t* mRing = nullptr;
501*be431cd8SAndroid Build Coastguard Worker     /*
502*be431cd8SAndroid Build Coastguard Worker      * TODO(b/31550092): Change to 32 bit read and write pointer counters.
503*be431cd8SAndroid Build Coastguard Worker      */
504*be431cd8SAndroid Build Coastguard Worker     std::atomic<uint64_t>* mReadPtr = nullptr;
505*be431cd8SAndroid Build Coastguard Worker     std::atomic<uint64_t>* mWritePtr = nullptr;
506*be431cd8SAndroid Build Coastguard Worker 
507*be431cd8SAndroid Build Coastguard Worker     std::atomic<uint32_t>* mEvFlagWord = nullptr;
508*be431cd8SAndroid Build Coastguard Worker 
509*be431cd8SAndroid Build Coastguard Worker     /*
510*be431cd8SAndroid Build Coastguard Worker      * This EventFlag object will be owned by the FMQ and will have the same
511*be431cd8SAndroid Build Coastguard Worker      * lifetime.
512*be431cd8SAndroid Build Coastguard Worker      */
513*be431cd8SAndroid Build Coastguard Worker     android::hardware::EventFlag* mEventFlag = nullptr;
514*be431cd8SAndroid Build Coastguard Worker 
515*be431cd8SAndroid Build Coastguard Worker     ErrorHandler mErrorHandler;
516*be431cd8SAndroid Build Coastguard Worker 
517*be431cd8SAndroid Build Coastguard Worker     const size_t kPageSize = getpagesize();
518*be431cd8SAndroid Build Coastguard Worker };
519*be431cd8SAndroid Build Coastguard Worker 
520*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
getSlot(size_t idx)521*be431cd8SAndroid Build Coastguard Worker T* MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getSlot(size_t idx) {
522*be431cd8SAndroid Build Coastguard Worker     size_t firstRegionLength = first.getLength();
523*be431cd8SAndroid Build Coastguard Worker     size_t secondRegionLength = second.getLength();
524*be431cd8SAndroid Build Coastguard Worker 
525*be431cd8SAndroid Build Coastguard Worker     if (idx > firstRegionLength + secondRegionLength) {
526*be431cd8SAndroid Build Coastguard Worker         return nullptr;
527*be431cd8SAndroid Build Coastguard Worker     }
528*be431cd8SAndroid Build Coastguard Worker 
529*be431cd8SAndroid Build Coastguard Worker     if (idx < firstRegionLength) {
530*be431cd8SAndroid Build Coastguard Worker         return first.getAddress() + idx;
531*be431cd8SAndroid Build Coastguard Worker     }
532*be431cd8SAndroid Build Coastguard Worker 
533*be431cd8SAndroid Build Coastguard Worker     return second.getAddress() + idx - firstRegionLength;
534*be431cd8SAndroid Build Coastguard Worker }
535*be431cd8SAndroid Build Coastguard Worker 
536*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
getMemRegionInfo(size_t startIdx,size_t nMessages,size_t & firstCount,size_t & secondCount,T ** firstBaseAddress,T ** secondBaseAddress)537*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getMemRegionInfo(
538*be431cd8SAndroid Build Coastguard Worker         size_t startIdx, size_t nMessages, size_t& firstCount, size_t& secondCount,
539*be431cd8SAndroid Build Coastguard Worker         T** firstBaseAddress, T** secondBaseAddress) {
540*be431cd8SAndroid Build Coastguard Worker     size_t firstRegionLength = first.getLength();
541*be431cd8SAndroid Build Coastguard Worker     size_t secondRegionLength = second.getLength();
542*be431cd8SAndroid Build Coastguard Worker 
543*be431cd8SAndroid Build Coastguard Worker     if (startIdx + nMessages > firstRegionLength + secondRegionLength) {
544*be431cd8SAndroid Build Coastguard Worker         /*
545*be431cd8SAndroid Build Coastguard Worker          * Return false if 'nMessages' starting at 'startIdx' cannot be
546*be431cd8SAndroid Build Coastguard Worker          * accommodated by the MemTransaction object.
547*be431cd8SAndroid Build Coastguard Worker          */
548*be431cd8SAndroid Build Coastguard Worker         return false;
549*be431cd8SAndroid Build Coastguard Worker     }
550*be431cd8SAndroid Build Coastguard Worker 
551*be431cd8SAndroid Build Coastguard Worker     /* Number of messages to be read/written to the first MemRegion. */
552*be431cd8SAndroid Build Coastguard Worker     firstCount =
553*be431cd8SAndroid Build Coastguard Worker             startIdx < firstRegionLength ? std::min(nMessages, firstRegionLength - startIdx) : 0;
554*be431cd8SAndroid Build Coastguard Worker 
555*be431cd8SAndroid Build Coastguard Worker     /* Number of messages to be read/written to the second MemRegion. */
556*be431cd8SAndroid Build Coastguard Worker     secondCount = nMessages - firstCount;
557*be431cd8SAndroid Build Coastguard Worker 
558*be431cd8SAndroid Build Coastguard Worker     if (firstCount != 0) {
559*be431cd8SAndroid Build Coastguard Worker         *firstBaseAddress = first.getAddress() + startIdx;
560*be431cd8SAndroid Build Coastguard Worker     }
561*be431cd8SAndroid Build Coastguard Worker 
562*be431cd8SAndroid Build Coastguard Worker     if (secondCount != 0) {
563*be431cd8SAndroid Build Coastguard Worker         size_t secondStartIdx = startIdx > firstRegionLength ? startIdx - firstRegionLength : 0;
564*be431cd8SAndroid Build Coastguard Worker         *secondBaseAddress = second.getAddress() + secondStartIdx;
565*be431cd8SAndroid Build Coastguard Worker     }
566*be431cd8SAndroid Build Coastguard Worker 
567*be431cd8SAndroid Build Coastguard Worker     return true;
568*be431cd8SAndroid Build Coastguard Worker }
569*be431cd8SAndroid Build Coastguard Worker 
570*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
copyFrom(T * data,size_t startIdx,size_t nMessages)571*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyFrom(T* data,
572*be431cd8SAndroid Build Coastguard Worker                                                                              size_t startIdx,
573*be431cd8SAndroid Build Coastguard Worker                                                                              size_t nMessages) {
574*be431cd8SAndroid Build Coastguard Worker     if constexpr (!std::is_same<T, MQErased>::value) {
575*be431cd8SAndroid Build Coastguard Worker         return copyFromSized(data, startIdx, nMessages, kQuantumValue<T>);
576*be431cd8SAndroid Build Coastguard Worker     } else {
577*be431cd8SAndroid Build Coastguard Worker         /* Compile error. */
578*be431cd8SAndroid Build Coastguard Worker         static_assert(!std::is_same<T, MQErased>::value,
579*be431cd8SAndroid Build Coastguard Worker                       "copyFrom without messageSize argument cannot be used with MQErased (use "
580*be431cd8SAndroid Build Coastguard Worker                       "copyFromSized)");
581*be431cd8SAndroid Build Coastguard Worker     }
582*be431cd8SAndroid Build Coastguard Worker }
583*be431cd8SAndroid Build Coastguard Worker 
584*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
copyFromSized(T * data,size_t startIdx,size_t nMessages,size_t messageSize)585*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyFromSized(
586*be431cd8SAndroid Build Coastguard Worker         T* data, size_t startIdx, size_t nMessages, size_t messageSize) {
587*be431cd8SAndroid Build Coastguard Worker     if (data == nullptr) {
588*be431cd8SAndroid Build Coastguard Worker         return false;
589*be431cd8SAndroid Build Coastguard Worker     }
590*be431cd8SAndroid Build Coastguard Worker 
591*be431cd8SAndroid Build Coastguard Worker     size_t firstReadCount = 0, secondReadCount = 0;
592*be431cd8SAndroid Build Coastguard Worker     T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
593*be431cd8SAndroid Build Coastguard Worker 
594*be431cd8SAndroid Build Coastguard Worker     if (getMemRegionInfo(startIdx, nMessages, firstReadCount, secondReadCount, &firstBaseAddress,
595*be431cd8SAndroid Build Coastguard Worker                          &secondBaseAddress) == false) {
596*be431cd8SAndroid Build Coastguard Worker         /*
597*be431cd8SAndroid Build Coastguard Worker          * Returns false if 'startIdx' and 'nMessages' are invalid for this
598*be431cd8SAndroid Build Coastguard Worker          * MemTransaction object.
599*be431cd8SAndroid Build Coastguard Worker          */
600*be431cd8SAndroid Build Coastguard Worker         return false;
601*be431cd8SAndroid Build Coastguard Worker     }
602*be431cd8SAndroid Build Coastguard Worker 
603*be431cd8SAndroid Build Coastguard Worker     if (firstReadCount != 0) {
604*be431cd8SAndroid Build Coastguard Worker         memcpy(data, firstBaseAddress, firstReadCount * messageSize);
605*be431cd8SAndroid Build Coastguard Worker     }
606*be431cd8SAndroid Build Coastguard Worker 
607*be431cd8SAndroid Build Coastguard Worker     if (secondReadCount != 0) {
608*be431cd8SAndroid Build Coastguard Worker         memcpy(data + firstReadCount, secondBaseAddress, secondReadCount * messageSize);
609*be431cd8SAndroid Build Coastguard Worker     }
610*be431cd8SAndroid Build Coastguard Worker 
611*be431cd8SAndroid Build Coastguard Worker     return true;
612*be431cd8SAndroid Build Coastguard Worker }
613*be431cd8SAndroid Build Coastguard Worker 
614*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
copyTo(const T * data,size_t startIdx,size_t nMessages)615*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyTo(const T* data,
616*be431cd8SAndroid Build Coastguard Worker                                                                            size_t startIdx,
617*be431cd8SAndroid Build Coastguard Worker                                                                            size_t nMessages) {
618*be431cd8SAndroid Build Coastguard Worker     if constexpr (!std::is_same<T, MQErased>::value) {
619*be431cd8SAndroid Build Coastguard Worker         return copyToSized(data, startIdx, nMessages, kQuantumValue<T>);
620*be431cd8SAndroid Build Coastguard Worker     } else {
621*be431cd8SAndroid Build Coastguard Worker         /* Compile error. */
622*be431cd8SAndroid Build Coastguard Worker         static_assert(!std::is_same<T, MQErased>::value,
623*be431cd8SAndroid Build Coastguard Worker                       "copyTo without messageSize argument cannot be used with MQErased (use "
624*be431cd8SAndroid Build Coastguard Worker                       "copyToSized)");
625*be431cd8SAndroid Build Coastguard Worker     }
626*be431cd8SAndroid Build Coastguard Worker }
627*be431cd8SAndroid Build Coastguard Worker 
628*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
copyToSized(const T * data,size_t startIdx,size_t nMessages,size_t messageSize)629*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyToSized(
630*be431cd8SAndroid Build Coastguard Worker         const T* data, size_t startIdx, size_t nMessages, size_t messageSize) {
631*be431cd8SAndroid Build Coastguard Worker     if (data == nullptr) {
632*be431cd8SAndroid Build Coastguard Worker         return false;
633*be431cd8SAndroid Build Coastguard Worker     }
634*be431cd8SAndroid Build Coastguard Worker 
635*be431cd8SAndroid Build Coastguard Worker     size_t firstWriteCount = 0, secondWriteCount = 0;
636*be431cd8SAndroid Build Coastguard Worker     T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
637*be431cd8SAndroid Build Coastguard Worker 
638*be431cd8SAndroid Build Coastguard Worker     if (getMemRegionInfo(startIdx, nMessages, firstWriteCount, secondWriteCount, &firstBaseAddress,
639*be431cd8SAndroid Build Coastguard Worker                          &secondBaseAddress) == false) {
640*be431cd8SAndroid Build Coastguard Worker         /*
641*be431cd8SAndroid Build Coastguard Worker          * Returns false if 'startIdx' and 'nMessages' are invalid for this
642*be431cd8SAndroid Build Coastguard Worker          * MemTransaction object.
643*be431cd8SAndroid Build Coastguard Worker          */
644*be431cd8SAndroid Build Coastguard Worker         return false;
645*be431cd8SAndroid Build Coastguard Worker     }
646*be431cd8SAndroid Build Coastguard Worker 
647*be431cd8SAndroid Build Coastguard Worker     if (firstWriteCount != 0) {
648*be431cd8SAndroid Build Coastguard Worker         memcpy(firstBaseAddress, data, firstWriteCount * messageSize);
649*be431cd8SAndroid Build Coastguard Worker     }
650*be431cd8SAndroid Build Coastguard Worker 
651*be431cd8SAndroid Build Coastguard Worker     if (secondWriteCount != 0) {
652*be431cd8SAndroid Build Coastguard Worker         memcpy(secondBaseAddress, data + firstWriteCount, secondWriteCount * messageSize);
653*be431cd8SAndroid Build Coastguard Worker     }
654*be431cd8SAndroid Build Coastguard Worker 
655*be431cd8SAndroid Build Coastguard Worker     return true;
656*be431cd8SAndroid Build Coastguard Worker }
657*be431cd8SAndroid Build Coastguard Worker 
658*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
initMemory(bool resetPointers)659*be431cd8SAndroid Build Coastguard Worker void MessageQueueBase<MQDescriptorType, T, flavor>::initMemory(bool resetPointers) {
660*be431cd8SAndroid Build Coastguard Worker     /*
661*be431cd8SAndroid Build Coastguard Worker      * Verify that the Descriptor contains the minimum number of grantors
662*be431cd8SAndroid Build Coastguard Worker      * the native_handle is valid and T matches quantum size.
663*be431cd8SAndroid Build Coastguard Worker      */
664*be431cd8SAndroid Build Coastguard Worker     if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
665*be431cd8SAndroid Build Coastguard Worker         (mDesc->countGrantors() < hardware::details::kMinGrantorCount)) {
666*be431cd8SAndroid Build Coastguard Worker         return;
667*be431cd8SAndroid Build Coastguard Worker     }
668*be431cd8SAndroid Build Coastguard Worker     if (mDesc->getQuantum() != quantum()) {
669*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError(
670*be431cd8SAndroid Build Coastguard Worker                 "Payload size differs between the queue instantiation and the "
671*be431cd8SAndroid Build Coastguard Worker                 "MQDescriptor.");
672*be431cd8SAndroid Build Coastguard Worker         return;
673*be431cd8SAndroid Build Coastguard Worker     }
674*be431cd8SAndroid Build Coastguard Worker 
675*be431cd8SAndroid Build Coastguard Worker     if (flavor == kSynchronizedReadWrite) {
676*be431cd8SAndroid Build Coastguard Worker         mReadPtr = reinterpret_cast<std::atomic<uint64_t>*>(
677*be431cd8SAndroid Build Coastguard Worker                 mapGrantorDescr(hardware::details::READPTRPOS));
678*be431cd8SAndroid Build Coastguard Worker     } else {
679*be431cd8SAndroid Build Coastguard Worker         /*
680*be431cd8SAndroid Build Coastguard Worker          * The unsynchronized write flavor of the FMQ may have multiple readers
681*be431cd8SAndroid Build Coastguard Worker          * and each reader would have their own read pointer counter.
682*be431cd8SAndroid Build Coastguard Worker          */
683*be431cd8SAndroid Build Coastguard Worker         mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
684*be431cd8SAndroid Build Coastguard Worker     }
685*be431cd8SAndroid Build Coastguard Worker     if (mReadPtr == nullptr) goto error;
686*be431cd8SAndroid Build Coastguard Worker 
687*be431cd8SAndroid Build Coastguard Worker     mWritePtr = reinterpret_cast<std::atomic<uint64_t>*>(
688*be431cd8SAndroid Build Coastguard Worker             mapGrantorDescr(hardware::details::WRITEPTRPOS));
689*be431cd8SAndroid Build Coastguard Worker     if (mWritePtr == nullptr) goto error;
690*be431cd8SAndroid Build Coastguard Worker 
691*be431cd8SAndroid Build Coastguard Worker     if (resetPointers) {
692*be431cd8SAndroid Build Coastguard Worker         mReadPtr->store(0, std::memory_order_release);
693*be431cd8SAndroid Build Coastguard Worker         mWritePtr->store(0, std::memory_order_release);
694*be431cd8SAndroid Build Coastguard Worker     } else if (flavor != kSynchronizedReadWrite) {
695*be431cd8SAndroid Build Coastguard Worker         // Always reset the read pointer.
696*be431cd8SAndroid Build Coastguard Worker         mReadPtr->store(0, std::memory_order_release);
697*be431cd8SAndroid Build Coastguard Worker     }
698*be431cd8SAndroid Build Coastguard Worker 
699*be431cd8SAndroid Build Coastguard Worker     mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(hardware::details::DATAPTRPOS));
700*be431cd8SAndroid Build Coastguard Worker     if (mRing == nullptr) goto error;
701*be431cd8SAndroid Build Coastguard Worker 
702*be431cd8SAndroid Build Coastguard Worker     if (mDesc->countGrantors() > hardware::details::EVFLAGWORDPOS) {
703*be431cd8SAndroid Build Coastguard Worker         mEvFlagWord = static_cast<std::atomic<uint32_t>*>(
704*be431cd8SAndroid Build Coastguard Worker                 mapGrantorDescr(hardware::details::EVFLAGWORDPOS));
705*be431cd8SAndroid Build Coastguard Worker         if (mEvFlagWord == nullptr) goto error;
706*be431cd8SAndroid Build Coastguard Worker         android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
707*be431cd8SAndroid Build Coastguard Worker     }
708*be431cd8SAndroid Build Coastguard Worker     return;
709*be431cd8SAndroid Build Coastguard Worker error:
710*be431cd8SAndroid Build Coastguard Worker     if (mReadPtr) {
711*be431cd8SAndroid Build Coastguard Worker         if (flavor == kSynchronizedReadWrite) {
712*be431cd8SAndroid Build Coastguard Worker             unmapGrantorDescr(mReadPtr, hardware::details::READPTRPOS);
713*be431cd8SAndroid Build Coastguard Worker         } else {
714*be431cd8SAndroid Build Coastguard Worker             delete mReadPtr;
715*be431cd8SAndroid Build Coastguard Worker         }
716*be431cd8SAndroid Build Coastguard Worker         mReadPtr = nullptr;
717*be431cd8SAndroid Build Coastguard Worker     }
718*be431cd8SAndroid Build Coastguard Worker     if (mWritePtr) {
719*be431cd8SAndroid Build Coastguard Worker         unmapGrantorDescr(mWritePtr, hardware::details::WRITEPTRPOS);
720*be431cd8SAndroid Build Coastguard Worker         mWritePtr = nullptr;
721*be431cd8SAndroid Build Coastguard Worker     }
722*be431cd8SAndroid Build Coastguard Worker     if (mRing) {
723*be431cd8SAndroid Build Coastguard Worker         unmapGrantorDescr(mRing, hardware::details::EVFLAGWORDPOS);
724*be431cd8SAndroid Build Coastguard Worker         mRing = nullptr;
725*be431cd8SAndroid Build Coastguard Worker     }
726*be431cd8SAndroid Build Coastguard Worker }
727*be431cd8SAndroid Build Coastguard Worker 
728*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
MessageQueueBase(const Descriptor & Desc,bool resetPointers)729*be431cd8SAndroid Build Coastguard Worker MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(const Descriptor& Desc,
730*be431cd8SAndroid Build Coastguard Worker                                                                 bool resetPointers) {
731*be431cd8SAndroid Build Coastguard Worker     mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
732*be431cd8SAndroid Build Coastguard Worker     if (mDesc == nullptr || mDesc->getSize() == 0) {
733*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError("MQDescriptor is invalid or queue size is 0.");
734*be431cd8SAndroid Build Coastguard Worker         return;
735*be431cd8SAndroid Build Coastguard Worker     }
736*be431cd8SAndroid Build Coastguard Worker 
737*be431cd8SAndroid Build Coastguard Worker     initMemory(resetPointers);
738*be431cd8SAndroid Build Coastguard Worker }
739*be431cd8SAndroid Build Coastguard Worker 
740*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
MessageQueueBase(size_t numElementsInQueue,bool configureEventFlagWord,android::base::unique_fd bufferFd,size_t bufferSize,size_t quantum)741*be431cd8SAndroid Build Coastguard Worker MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(size_t numElementsInQueue,
742*be431cd8SAndroid Build Coastguard Worker                                                                 bool configureEventFlagWord,
743*be431cd8SAndroid Build Coastguard Worker                                                                 android::base::unique_fd bufferFd,
744*be431cd8SAndroid Build Coastguard Worker                                                                 size_t bufferSize, size_t quantum) {
745*be431cd8SAndroid Build Coastguard Worker     // Check if the buffer size would not overflow size_t
746*be431cd8SAndroid Build Coastguard Worker     if (numElementsInQueue > SIZE_MAX / quantum) {
747*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError("Requested message queue size too large. Size of elements: " +
748*be431cd8SAndroid Build Coastguard Worker                                     std::to_string(quantum) +
749*be431cd8SAndroid Build Coastguard Worker                                     ". Number of elements: " + std::to_string(numElementsInQueue));
750*be431cd8SAndroid Build Coastguard Worker         return;
751*be431cd8SAndroid Build Coastguard Worker     }
752*be431cd8SAndroid Build Coastguard Worker     if (numElementsInQueue == 0) {
753*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError("Requested queue size of 0.");
754*be431cd8SAndroid Build Coastguard Worker         return;
755*be431cd8SAndroid Build Coastguard Worker     }
756*be431cd8SAndroid Build Coastguard Worker     if (bufferFd != -1 && numElementsInQueue * quantum > bufferSize) {
757*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError("The supplied buffer size(" + std::to_string(bufferSize) +
758*be431cd8SAndroid Build Coastguard Worker                                     ") is smaller than the required size(" +
759*be431cd8SAndroid Build Coastguard Worker                                     std::to_string(numElementsInQueue * quantum) + ").");
760*be431cd8SAndroid Build Coastguard Worker         return;
761*be431cd8SAndroid Build Coastguard Worker     }
762*be431cd8SAndroid Build Coastguard Worker     /*
763*be431cd8SAndroid Build Coastguard Worker      * The FMQ needs to allocate memory for the ringbuffer as well as for the
764*be431cd8SAndroid Build Coastguard Worker      * read and write pointer counters. If an EventFlag word is to be configured,
765*be431cd8SAndroid Build Coastguard Worker      * we also need to allocate memory for the same/
766*be431cd8SAndroid Build Coastguard Worker      */
767*be431cd8SAndroid Build Coastguard Worker     size_t kQueueSizeBytes = numElementsInQueue * quantum;
768*be431cd8SAndroid Build Coastguard Worker     size_t kMetaDataSize = 2 * sizeof(android::hardware::details::RingBufferPosition);
769*be431cd8SAndroid Build Coastguard Worker 
770*be431cd8SAndroid Build Coastguard Worker     if (configureEventFlagWord) {
771*be431cd8SAndroid Build Coastguard Worker         kMetaDataSize += sizeof(std::atomic<uint32_t>);
772*be431cd8SAndroid Build Coastguard Worker     }
773*be431cd8SAndroid Build Coastguard Worker 
774*be431cd8SAndroid Build Coastguard Worker     /*
775*be431cd8SAndroid Build Coastguard Worker      * Ashmem memory region size needs to be specified in page-aligned bytes.
776*be431cd8SAndroid Build Coastguard Worker      * kQueueSizeBytes needs to be aligned to word boundary so that all offsets
777*be431cd8SAndroid Build Coastguard Worker      * in the grantorDescriptor will be word aligned.
778*be431cd8SAndroid Build Coastguard Worker      */
779*be431cd8SAndroid Build Coastguard Worker     size_t kAshmemSizePageAligned;
780*be431cd8SAndroid Build Coastguard Worker     if (bufferFd != -1) {
781*be431cd8SAndroid Build Coastguard Worker         // Allocate read counter and write counter only. User-supplied memory will be used for the
782*be431cd8SAndroid Build Coastguard Worker         // ringbuffer.
783*be431cd8SAndroid Build Coastguard Worker         kAshmemSizePageAligned = (kMetaDataSize + kPageSize - 1) & ~(kPageSize - 1);
784*be431cd8SAndroid Build Coastguard Worker     } else {
785*be431cd8SAndroid Build Coastguard Worker         // Allocate ringbuffer, read counter and write counter.
786*be431cd8SAndroid Build Coastguard Worker         kAshmemSizePageAligned = (hardware::details::alignToWordBoundary(kQueueSizeBytes) +
787*be431cd8SAndroid Build Coastguard Worker                                   kMetaDataSize + kPageSize - 1) &
788*be431cd8SAndroid Build Coastguard Worker                                  ~(kPageSize - 1);
789*be431cd8SAndroid Build Coastguard Worker     }
790*be431cd8SAndroid Build Coastguard Worker 
791*be431cd8SAndroid Build Coastguard Worker     /*
792*be431cd8SAndroid Build Coastguard Worker      * The native handle will contain the fds to be mapped.
793*be431cd8SAndroid Build Coastguard Worker      */
794*be431cd8SAndroid Build Coastguard Worker     int numFds = (bufferFd != -1) ? 2 : 1;
795*be431cd8SAndroid Build Coastguard Worker     native_handle_t* mqHandle = native_handle_create(numFds, 0 /* numInts */);
796*be431cd8SAndroid Build Coastguard Worker     if (mqHandle == nullptr) {
797*be431cd8SAndroid Build Coastguard Worker         return;
798*be431cd8SAndroid Build Coastguard Worker     }
799*be431cd8SAndroid Build Coastguard Worker 
800*be431cd8SAndroid Build Coastguard Worker     /*
801*be431cd8SAndroid Build Coastguard Worker      * Create an ashmem region to map the memory.
802*be431cd8SAndroid Build Coastguard Worker      */
803*be431cd8SAndroid Build Coastguard Worker     int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
804*be431cd8SAndroid Build Coastguard Worker     ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
805*be431cd8SAndroid Build Coastguard Worker     mqHandle->data[0] = ashmemFd;
806*be431cd8SAndroid Build Coastguard Worker 
807*be431cd8SAndroid Build Coastguard Worker     if (bufferFd != -1) {
808*be431cd8SAndroid Build Coastguard Worker         // Use user-supplied file descriptor for fdIndex 1
809*be431cd8SAndroid Build Coastguard Worker         mqHandle->data[1] = bufferFd.get();
810*be431cd8SAndroid Build Coastguard Worker         // release ownership of fd. mqHandle owns it now.
811*be431cd8SAndroid Build Coastguard Worker         if (bufferFd.release() < 0) {
812*be431cd8SAndroid Build Coastguard Worker             hardware::details::logError("Error releasing supplied bufferFd");
813*be431cd8SAndroid Build Coastguard Worker         }
814*be431cd8SAndroid Build Coastguard Worker 
815*be431cd8SAndroid Build Coastguard Worker         std::vector<android::hardware::GrantorDescriptor> grantors;
816*be431cd8SAndroid Build Coastguard Worker         grantors.resize(configureEventFlagWord ? hardware::details::kMinGrantorCountForEvFlagSupport
817*be431cd8SAndroid Build Coastguard Worker                                                : hardware::details::kMinGrantorCount);
818*be431cd8SAndroid Build Coastguard Worker 
819*be431cd8SAndroid Build Coastguard Worker         size_t memSize[] = {
820*be431cd8SAndroid Build Coastguard Worker                 sizeof(hardware::details::RingBufferPosition), /* memory to be allocated for read
821*be431cd8SAndroid Build Coastguard Worker                                                                   pointer counter */
822*be431cd8SAndroid Build Coastguard Worker                 sizeof(hardware::details::RingBufferPosition), /* memory to be allocated for write
823*be431cd8SAndroid Build Coastguard Worker                                                                   pointer counter */
824*be431cd8SAndroid Build Coastguard Worker                 kQueueSizeBytes,              /* memory to be allocated for data buffer */
825*be431cd8SAndroid Build Coastguard Worker                 sizeof(std::atomic<uint32_t>) /* memory to be allocated for EventFlag word */
826*be431cd8SAndroid Build Coastguard Worker         };
827*be431cd8SAndroid Build Coastguard Worker 
828*be431cd8SAndroid Build Coastguard Worker         for (size_t grantorPos = 0, offset = 0; grantorPos < grantors.size(); grantorPos++) {
829*be431cd8SAndroid Build Coastguard Worker             uint32_t grantorFdIndex;
830*be431cd8SAndroid Build Coastguard Worker             size_t grantorOffset;
831*be431cd8SAndroid Build Coastguard Worker             if (grantorPos == hardware::details::DATAPTRPOS) {
832*be431cd8SAndroid Build Coastguard Worker                 grantorFdIndex = 1;
833*be431cd8SAndroid Build Coastguard Worker                 grantorOffset = 0;
834*be431cd8SAndroid Build Coastguard Worker             } else {
835*be431cd8SAndroid Build Coastguard Worker                 grantorFdIndex = 0;
836*be431cd8SAndroid Build Coastguard Worker                 grantorOffset = offset;
837*be431cd8SAndroid Build Coastguard Worker                 offset += memSize[grantorPos];
838*be431cd8SAndroid Build Coastguard Worker             }
839*be431cd8SAndroid Build Coastguard Worker             grantors[grantorPos] = {
840*be431cd8SAndroid Build Coastguard Worker                     0 /* grantor flags */, grantorFdIndex,
841*be431cd8SAndroid Build Coastguard Worker                     static_cast<uint32_t>(hardware::details::alignToWordBoundary(grantorOffset)),
842*be431cd8SAndroid Build Coastguard Worker                     memSize[grantorPos]};
843*be431cd8SAndroid Build Coastguard Worker         }
844*be431cd8SAndroid Build Coastguard Worker 
845*be431cd8SAndroid Build Coastguard Worker         mDesc = std::unique_ptr<Descriptor>(new (std::nothrow)
846*be431cd8SAndroid Build Coastguard Worker                                                     Descriptor(grantors, mqHandle, quantum));
847*be431cd8SAndroid Build Coastguard Worker     } else {
848*be431cd8SAndroid Build Coastguard Worker         mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(
849*be431cd8SAndroid Build Coastguard Worker                 kQueueSizeBytes, mqHandle, quantum, configureEventFlagWord));
850*be431cd8SAndroid Build Coastguard Worker     }
851*be431cd8SAndroid Build Coastguard Worker     if (mDesc == nullptr) {
852*be431cd8SAndroid Build Coastguard Worker         native_handle_close(mqHandle);
853*be431cd8SAndroid Build Coastguard Worker         native_handle_delete(mqHandle);
854*be431cd8SAndroid Build Coastguard Worker         return;
855*be431cd8SAndroid Build Coastguard Worker     }
856*be431cd8SAndroid Build Coastguard Worker     initMemory(true);
857*be431cd8SAndroid Build Coastguard Worker }
858*be431cd8SAndroid Build Coastguard Worker 
859*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
~MessageQueueBase()860*be431cd8SAndroid Build Coastguard Worker MessageQueueBase<MQDescriptorType, T, flavor>::~MessageQueueBase() {
861*be431cd8SAndroid Build Coastguard Worker     if (flavor == kSynchronizedReadWrite && mReadPtr != nullptr) {
862*be431cd8SAndroid Build Coastguard Worker         unmapGrantorDescr(mReadPtr, hardware::details::READPTRPOS);
863*be431cd8SAndroid Build Coastguard Worker     } else if (mReadPtr != nullptr) {
864*be431cd8SAndroid Build Coastguard Worker         delete mReadPtr;
865*be431cd8SAndroid Build Coastguard Worker     }
866*be431cd8SAndroid Build Coastguard Worker     if (mWritePtr != nullptr) {
867*be431cd8SAndroid Build Coastguard Worker         unmapGrantorDescr(mWritePtr, hardware::details::WRITEPTRPOS);
868*be431cd8SAndroid Build Coastguard Worker     }
869*be431cd8SAndroid Build Coastguard Worker     if (mRing != nullptr) {
870*be431cd8SAndroid Build Coastguard Worker         unmapGrantorDescr(mRing, hardware::details::DATAPTRPOS);
871*be431cd8SAndroid Build Coastguard Worker     }
872*be431cd8SAndroid Build Coastguard Worker     if (mEvFlagWord != nullptr) {
873*be431cd8SAndroid Build Coastguard Worker         unmapGrantorDescr(mEvFlagWord, hardware::details::EVFLAGWORDPOS);
874*be431cd8SAndroid Build Coastguard Worker         android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
875*be431cd8SAndroid Build Coastguard Worker     }
876*be431cd8SAndroid Build Coastguard Worker }
877*be431cd8SAndroid Build Coastguard Worker 
878*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
write(const T * data)879*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::write(const T* data) {
880*be431cd8SAndroid Build Coastguard Worker     return write(data, 1);
881*be431cd8SAndroid Build Coastguard Worker }
882*be431cd8SAndroid Build Coastguard Worker 
883*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
read(T * data)884*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data) {
885*be431cd8SAndroid Build Coastguard Worker     return read(data, 1);
886*be431cd8SAndroid Build Coastguard Worker }
887*be431cd8SAndroid Build Coastguard Worker 
888*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
write(const T * data,size_t nMessages)889*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::write(const T* data, size_t nMessages) {
890*be431cd8SAndroid Build Coastguard Worker     MemTransaction tx;
891*be431cd8SAndroid Build Coastguard Worker     return beginWrite(nMessages, &tx) &&
892*be431cd8SAndroid Build Coastguard Worker            tx.copyToSized(data, 0 /* startIdx */, nMessages, quantum()) && commitWrite(nMessages);
893*be431cd8SAndroid Build Coastguard Worker }
894*be431cd8SAndroid Build Coastguard Worker 
895*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
writeBlocking(const T * data,size_t count,uint32_t readNotification,uint32_t writeNotification,int64_t timeOutNanos,android::hardware::EventFlag * evFlag)896*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(
897*be431cd8SAndroid Build Coastguard Worker         const T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
898*be431cd8SAndroid Build Coastguard Worker         int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
899*be431cd8SAndroid Build Coastguard Worker     static_assert(flavor == kSynchronizedReadWrite,
900*be431cd8SAndroid Build Coastguard Worker                   "writeBlocking can only be used with the "
901*be431cd8SAndroid Build Coastguard Worker                   "kSynchronizedReadWrite flavor.");
902*be431cd8SAndroid Build Coastguard Worker     /*
903*be431cd8SAndroid Build Coastguard Worker      * If evFlag is null and the FMQ does not have its own EventFlag object
904*be431cd8SAndroid Build Coastguard Worker      * return false;
905*be431cd8SAndroid Build Coastguard Worker      * If the flavor is kSynchronizedReadWrite and the readNotification
906*be431cd8SAndroid Build Coastguard Worker      * bit mask is zero return false;
907*be431cd8SAndroid Build Coastguard Worker      * If the count is greater than queue size, return false
908*be431cd8SAndroid Build Coastguard Worker      * to prevent blocking until timeOut.
909*be431cd8SAndroid Build Coastguard Worker      */
910*be431cd8SAndroid Build Coastguard Worker     if (evFlag == nullptr) {
911*be431cd8SAndroid Build Coastguard Worker         evFlag = mEventFlag;
912*be431cd8SAndroid Build Coastguard Worker         if (evFlag == nullptr) {
913*be431cd8SAndroid Build Coastguard Worker             hardware::details::logError(
914*be431cd8SAndroid Build Coastguard Worker                     "writeBlocking failed: called on MessageQueue with no Eventflag"
915*be431cd8SAndroid Build Coastguard Worker                     "configured or provided");
916*be431cd8SAndroid Build Coastguard Worker             return false;
917*be431cd8SAndroid Build Coastguard Worker         }
918*be431cd8SAndroid Build Coastguard Worker     }
919*be431cd8SAndroid Build Coastguard Worker 
920*be431cd8SAndroid Build Coastguard Worker     if (readNotification == 0 || (count > getQuantumCount())) {
921*be431cd8SAndroid Build Coastguard Worker         return false;
922*be431cd8SAndroid Build Coastguard Worker     }
923*be431cd8SAndroid Build Coastguard Worker 
924*be431cd8SAndroid Build Coastguard Worker     /*
925*be431cd8SAndroid Build Coastguard Worker      * There is no need to wait for a readNotification if there is sufficient
926*be431cd8SAndroid Build Coastguard Worker      * space to write is already present in the FMQ. The latter would be the case when
927*be431cd8SAndroid Build Coastguard Worker      * read operations read more number of messages than write operations write.
928*be431cd8SAndroid Build Coastguard Worker      * In other words, a single large read may clear the FMQ after multiple small
929*be431cd8SAndroid Build Coastguard Worker      * writes. This would fail to clear a pending readNotification bit since
930*be431cd8SAndroid Build Coastguard Worker      * EventFlag bits can only be cleared by a wait() call, however the bit would
931*be431cd8SAndroid Build Coastguard Worker      * be correctly cleared by the next writeBlocking() call.
932*be431cd8SAndroid Build Coastguard Worker      */
933*be431cd8SAndroid Build Coastguard Worker 
934*be431cd8SAndroid Build Coastguard Worker     bool result = write(data, count);
935*be431cd8SAndroid Build Coastguard Worker     if (result) {
936*be431cd8SAndroid Build Coastguard Worker         if (writeNotification) {
937*be431cd8SAndroid Build Coastguard Worker             evFlag->wake(writeNotification);
938*be431cd8SAndroid Build Coastguard Worker         }
939*be431cd8SAndroid Build Coastguard Worker         return result;
940*be431cd8SAndroid Build Coastguard Worker     }
941*be431cd8SAndroid Build Coastguard Worker 
942*be431cd8SAndroid Build Coastguard Worker     bool shouldTimeOut = timeOutNanos != 0;
943*be431cd8SAndroid Build Coastguard Worker     int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
944*be431cd8SAndroid Build Coastguard Worker 
945*be431cd8SAndroid Build Coastguard Worker     while (true) {
946*be431cd8SAndroid Build Coastguard Worker         /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
947*be431cd8SAndroid Build Coastguard Worker         if (shouldTimeOut) {
948*be431cd8SAndroid Build Coastguard Worker             /*
949*be431cd8SAndroid Build Coastguard Worker              * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
950*be431cd8SAndroid Build Coastguard Worker              * to Nanoseconds)
951*be431cd8SAndroid Build Coastguard Worker              */
952*be431cd8SAndroid Build Coastguard Worker             int64_t currentTimeNs = android::elapsedRealtimeNano();
953*be431cd8SAndroid Build Coastguard Worker             /*
954*be431cd8SAndroid Build Coastguard Worker              * Decrement 'timeOutNanos' to account for the time taken to complete the last
955*be431cd8SAndroid Build Coastguard Worker              * iteration of the while loop.
956*be431cd8SAndroid Build Coastguard Worker              */
957*be431cd8SAndroid Build Coastguard Worker             timeOutNanos -= currentTimeNs - prevTimeNanos;
958*be431cd8SAndroid Build Coastguard Worker             prevTimeNanos = currentTimeNs;
959*be431cd8SAndroid Build Coastguard Worker 
960*be431cd8SAndroid Build Coastguard Worker             if (timeOutNanos <= 0) {
961*be431cd8SAndroid Build Coastguard Worker                 /*
962*be431cd8SAndroid Build Coastguard Worker                  * Attempt write in case a context switch happened outside of
963*be431cd8SAndroid Build Coastguard Worker                  * evFlag->wait().
964*be431cd8SAndroid Build Coastguard Worker                  */
965*be431cd8SAndroid Build Coastguard Worker                 result = write(data, count);
966*be431cd8SAndroid Build Coastguard Worker                 break;
967*be431cd8SAndroid Build Coastguard Worker             }
968*be431cd8SAndroid Build Coastguard Worker         }
969*be431cd8SAndroid Build Coastguard Worker 
970*be431cd8SAndroid Build Coastguard Worker         /*
971*be431cd8SAndroid Build Coastguard Worker          * wait() will return immediately if there was a pending read
972*be431cd8SAndroid Build Coastguard Worker          * notification.
973*be431cd8SAndroid Build Coastguard Worker          */
974*be431cd8SAndroid Build Coastguard Worker         uint32_t efState = 0;
975*be431cd8SAndroid Build Coastguard Worker         status_t status = evFlag->wait(readNotification, &efState, timeOutNanos,
976*be431cd8SAndroid Build Coastguard Worker                                        true /* retry on spurious wake */);
977*be431cd8SAndroid Build Coastguard Worker 
978*be431cd8SAndroid Build Coastguard Worker         if (status != android::TIMED_OUT && status != android::NO_ERROR) {
979*be431cd8SAndroid Build Coastguard Worker             hardware::details::logError("Unexpected error code from EventFlag Wait status " +
980*be431cd8SAndroid Build Coastguard Worker                                         std::to_string(status));
981*be431cd8SAndroid Build Coastguard Worker             break;
982*be431cd8SAndroid Build Coastguard Worker         }
983*be431cd8SAndroid Build Coastguard Worker 
984*be431cd8SAndroid Build Coastguard Worker         if (status == android::TIMED_OUT) {
985*be431cd8SAndroid Build Coastguard Worker             break;
986*be431cd8SAndroid Build Coastguard Worker         }
987*be431cd8SAndroid Build Coastguard Worker 
988*be431cd8SAndroid Build Coastguard Worker         /*
989*be431cd8SAndroid Build Coastguard Worker          * If there is still insufficient space to write to the FMQ,
990*be431cd8SAndroid Build Coastguard Worker          * keep waiting for another readNotification.
991*be431cd8SAndroid Build Coastguard Worker          */
992*be431cd8SAndroid Build Coastguard Worker         if ((efState & readNotification) && write(data, count)) {
993*be431cd8SAndroid Build Coastguard Worker             result = true;
994*be431cd8SAndroid Build Coastguard Worker             break;
995*be431cd8SAndroid Build Coastguard Worker         }
996*be431cd8SAndroid Build Coastguard Worker     }
997*be431cd8SAndroid Build Coastguard Worker 
998*be431cd8SAndroid Build Coastguard Worker     if (result && writeNotification != 0) {
999*be431cd8SAndroid Build Coastguard Worker         evFlag->wake(writeNotification);
1000*be431cd8SAndroid Build Coastguard Worker     }
1001*be431cd8SAndroid Build Coastguard Worker 
1002*be431cd8SAndroid Build Coastguard Worker     return result;
1003*be431cd8SAndroid Build Coastguard Worker }
1004*be431cd8SAndroid Build Coastguard Worker 
1005*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
writeBlocking(const T * data,size_t count,int64_t timeOutNanos)1006*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(const T* data, size_t count,
1007*be431cd8SAndroid Build Coastguard Worker                                                                   int64_t timeOutNanos) {
1008*be431cd8SAndroid Build Coastguard Worker     return writeBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
1009*be431cd8SAndroid Build Coastguard Worker }
1010*be431cd8SAndroid Build Coastguard Worker 
1011*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
readBlocking(T * data,size_t count,uint32_t readNotification,uint32_t writeNotification,int64_t timeOutNanos,android::hardware::EventFlag * evFlag)1012*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(
1013*be431cd8SAndroid Build Coastguard Worker         T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
1014*be431cd8SAndroid Build Coastguard Worker         int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
1015*be431cd8SAndroid Build Coastguard Worker     static_assert(flavor == kSynchronizedReadWrite,
1016*be431cd8SAndroid Build Coastguard Worker                   "readBlocking can only be used with the "
1017*be431cd8SAndroid Build Coastguard Worker                   "kSynchronizedReadWrite flavor.");
1018*be431cd8SAndroid Build Coastguard Worker 
1019*be431cd8SAndroid Build Coastguard Worker     /*
1020*be431cd8SAndroid Build Coastguard Worker      * If evFlag is null and the FMQ does not own its own EventFlag object
1021*be431cd8SAndroid Build Coastguard Worker      * return false;
1022*be431cd8SAndroid Build Coastguard Worker      * If the writeNotification bit mask is zero return false;
1023*be431cd8SAndroid Build Coastguard Worker      * If the count is greater than queue size, return false to prevent
1024*be431cd8SAndroid Build Coastguard Worker      * blocking until timeOut.
1025*be431cd8SAndroid Build Coastguard Worker      */
1026*be431cd8SAndroid Build Coastguard Worker     if (evFlag == nullptr) {
1027*be431cd8SAndroid Build Coastguard Worker         evFlag = mEventFlag;
1028*be431cd8SAndroid Build Coastguard Worker         if (evFlag == nullptr) {
1029*be431cd8SAndroid Build Coastguard Worker             hardware::details::logError(
1030*be431cd8SAndroid Build Coastguard Worker                     "readBlocking failed: called on MessageQueue with no Eventflag"
1031*be431cd8SAndroid Build Coastguard Worker                     "configured or provided");
1032*be431cd8SAndroid Build Coastguard Worker             return false;
1033*be431cd8SAndroid Build Coastguard Worker         }
1034*be431cd8SAndroid Build Coastguard Worker     }
1035*be431cd8SAndroid Build Coastguard Worker 
1036*be431cd8SAndroid Build Coastguard Worker     if (writeNotification == 0 || count > getQuantumCount()) {
1037*be431cd8SAndroid Build Coastguard Worker         return false;
1038*be431cd8SAndroid Build Coastguard Worker     }
1039*be431cd8SAndroid Build Coastguard Worker 
1040*be431cd8SAndroid Build Coastguard Worker     /*
1041*be431cd8SAndroid Build Coastguard Worker      * There is no need to wait for a write notification if sufficient
1042*be431cd8SAndroid Build Coastguard Worker      * data to read is already present in the FMQ. This would be the
1043*be431cd8SAndroid Build Coastguard Worker      * case when read operations read lesser number of messages than
1044*be431cd8SAndroid Build Coastguard Worker      * a write operation and multiple reads would be required to clear the queue
1045*be431cd8SAndroid Build Coastguard Worker      * after a single write operation. This check would fail to clear a pending
1046*be431cd8SAndroid Build Coastguard Worker      * writeNotification bit since EventFlag bits can only be cleared
1047*be431cd8SAndroid Build Coastguard Worker      * by a wait() call, however the bit would be correctly cleared by the next
1048*be431cd8SAndroid Build Coastguard Worker      * readBlocking() call.
1049*be431cd8SAndroid Build Coastguard Worker      */
1050*be431cd8SAndroid Build Coastguard Worker 
1051*be431cd8SAndroid Build Coastguard Worker     bool result = read(data, count);
1052*be431cd8SAndroid Build Coastguard Worker     if (result) {
1053*be431cd8SAndroid Build Coastguard Worker         if (readNotification) {
1054*be431cd8SAndroid Build Coastguard Worker             evFlag->wake(readNotification);
1055*be431cd8SAndroid Build Coastguard Worker         }
1056*be431cd8SAndroid Build Coastguard Worker         return result;
1057*be431cd8SAndroid Build Coastguard Worker     }
1058*be431cd8SAndroid Build Coastguard Worker 
1059*be431cd8SAndroid Build Coastguard Worker     bool shouldTimeOut = timeOutNanos != 0;
1060*be431cd8SAndroid Build Coastguard Worker     int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
1061*be431cd8SAndroid Build Coastguard Worker 
1062*be431cd8SAndroid Build Coastguard Worker     while (true) {
1063*be431cd8SAndroid Build Coastguard Worker         /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
1064*be431cd8SAndroid Build Coastguard Worker         if (shouldTimeOut) {
1065*be431cd8SAndroid Build Coastguard Worker             /*
1066*be431cd8SAndroid Build Coastguard Worker              * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
1067*be431cd8SAndroid Build Coastguard Worker              * to Nanoseconds)
1068*be431cd8SAndroid Build Coastguard Worker              */
1069*be431cd8SAndroid Build Coastguard Worker             int64_t currentTimeNs = android::elapsedRealtimeNano();
1070*be431cd8SAndroid Build Coastguard Worker             /*
1071*be431cd8SAndroid Build Coastguard Worker              * Decrement 'timeOutNanos' to account for the time taken to complete the last
1072*be431cd8SAndroid Build Coastguard Worker              * iteration of the while loop.
1073*be431cd8SAndroid Build Coastguard Worker              */
1074*be431cd8SAndroid Build Coastguard Worker             timeOutNanos -= currentTimeNs - prevTimeNanos;
1075*be431cd8SAndroid Build Coastguard Worker             prevTimeNanos = currentTimeNs;
1076*be431cd8SAndroid Build Coastguard Worker 
1077*be431cd8SAndroid Build Coastguard Worker             if (timeOutNanos <= 0) {
1078*be431cd8SAndroid Build Coastguard Worker                 /*
1079*be431cd8SAndroid Build Coastguard Worker                  * Attempt read in case a context switch happened outside of
1080*be431cd8SAndroid Build Coastguard Worker                  * evFlag->wait().
1081*be431cd8SAndroid Build Coastguard Worker                  */
1082*be431cd8SAndroid Build Coastguard Worker                 result = read(data, count);
1083*be431cd8SAndroid Build Coastguard Worker                 break;
1084*be431cd8SAndroid Build Coastguard Worker             }
1085*be431cd8SAndroid Build Coastguard Worker         }
1086*be431cd8SAndroid Build Coastguard Worker 
1087*be431cd8SAndroid Build Coastguard Worker         /*
1088*be431cd8SAndroid Build Coastguard Worker          * wait() will return immediately if there was a pending write
1089*be431cd8SAndroid Build Coastguard Worker          * notification.
1090*be431cd8SAndroid Build Coastguard Worker          */
1091*be431cd8SAndroid Build Coastguard Worker         uint32_t efState = 0;
1092*be431cd8SAndroid Build Coastguard Worker         status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos,
1093*be431cd8SAndroid Build Coastguard Worker                                        true /* retry on spurious wake */);
1094*be431cd8SAndroid Build Coastguard Worker 
1095*be431cd8SAndroid Build Coastguard Worker         if (status != android::TIMED_OUT && status != android::NO_ERROR) {
1096*be431cd8SAndroid Build Coastguard Worker             hardware::details::logError("Unexpected error code from EventFlag Wait status " +
1097*be431cd8SAndroid Build Coastguard Worker                                         std::to_string(status));
1098*be431cd8SAndroid Build Coastguard Worker             break;
1099*be431cd8SAndroid Build Coastguard Worker         }
1100*be431cd8SAndroid Build Coastguard Worker 
1101*be431cd8SAndroid Build Coastguard Worker         if (status == android::TIMED_OUT) {
1102*be431cd8SAndroid Build Coastguard Worker             break;
1103*be431cd8SAndroid Build Coastguard Worker         }
1104*be431cd8SAndroid Build Coastguard Worker 
1105*be431cd8SAndroid Build Coastguard Worker         /*
1106*be431cd8SAndroid Build Coastguard Worker          * If the data in FMQ is still insufficient, go back to waiting
1107*be431cd8SAndroid Build Coastguard Worker          * for another write notification.
1108*be431cd8SAndroid Build Coastguard Worker          */
1109*be431cd8SAndroid Build Coastguard Worker         if ((efState & writeNotification) && read(data, count)) {
1110*be431cd8SAndroid Build Coastguard Worker             result = true;
1111*be431cd8SAndroid Build Coastguard Worker             break;
1112*be431cd8SAndroid Build Coastguard Worker         }
1113*be431cd8SAndroid Build Coastguard Worker     }
1114*be431cd8SAndroid Build Coastguard Worker 
1115*be431cd8SAndroid Build Coastguard Worker     if (result && readNotification != 0) {
1116*be431cd8SAndroid Build Coastguard Worker         evFlag->wake(readNotification);
1117*be431cd8SAndroid Build Coastguard Worker     }
1118*be431cd8SAndroid Build Coastguard Worker     return result;
1119*be431cd8SAndroid Build Coastguard Worker }
1120*be431cd8SAndroid Build Coastguard Worker 
1121*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
readBlocking(T * data,size_t count,int64_t timeOutNanos)1122*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(T* data, size_t count,
1123*be431cd8SAndroid Build Coastguard Worker                                                                  int64_t timeOutNanos) {
1124*be431cd8SAndroid Build Coastguard Worker     return readBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
1125*be431cd8SAndroid Build Coastguard Worker }
1126*be431cd8SAndroid Build Coastguard Worker 
1127*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
quantum()1128*be431cd8SAndroid Build Coastguard Worker inline size_t MessageQueueBase<MQDescriptorType, T, flavor>::quantum() const {
1129*be431cd8SAndroid Build Coastguard Worker     if constexpr (std::is_same<T, MQErased>::value) {
1130*be431cd8SAndroid Build Coastguard Worker         return mDesc->getQuantum();
1131*be431cd8SAndroid Build Coastguard Worker     } else {
1132*be431cd8SAndroid Build Coastguard Worker         return kQuantumValue<T>;
1133*be431cd8SAndroid Build Coastguard Worker     }
1134*be431cd8SAndroid Build Coastguard Worker }
1135*be431cd8SAndroid Build Coastguard Worker 
1136*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
availableToWriteBytes()1137*be431cd8SAndroid Build Coastguard Worker size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWriteBytes() const {
1138*be431cd8SAndroid Build Coastguard Worker     size_t queueSizeBytes = mDesc->getSize();
1139*be431cd8SAndroid Build Coastguard Worker     size_t availableBytes = availableToReadBytes();
1140*be431cd8SAndroid Build Coastguard Worker     if (queueSizeBytes < availableBytes) {
1141*be431cd8SAndroid Build Coastguard Worker         std::string errorMsg =
1142*be431cd8SAndroid Build Coastguard Worker                 "The write or read pointer has become corrupted. Writing to the queue is no "
1143*be431cd8SAndroid Build Coastguard Worker                 "longer possible. Queue size: " +
1144*be431cd8SAndroid Build Coastguard Worker                 std::to_string(queueSizeBytes) + ", available: " + std::to_string(availableBytes);
1145*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError(errorMsg);
1146*be431cd8SAndroid Build Coastguard Worker         if (mErrorHandler) {
1147*be431cd8SAndroid Build Coastguard Worker             mErrorHandler(Error::POINTER_CORRUPTION, std::move(errorMsg));
1148*be431cd8SAndroid Build Coastguard Worker         }
1149*be431cd8SAndroid Build Coastguard Worker         return 0;
1150*be431cd8SAndroid Build Coastguard Worker     }
1151*be431cd8SAndroid Build Coastguard Worker     return queueSizeBytes - availableBytes;
1152*be431cd8SAndroid Build Coastguard Worker }
1153*be431cd8SAndroid Build Coastguard Worker 
1154*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
availableToWrite()1155*be431cd8SAndroid Build Coastguard Worker size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWrite() const {
1156*be431cd8SAndroid Build Coastguard Worker     return availableToWriteBytes() / quantum();
1157*be431cd8SAndroid Build Coastguard Worker }
1158*be431cd8SAndroid Build Coastguard Worker 
1159*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
availableToRead()1160*be431cd8SAndroid Build Coastguard Worker size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToRead() const {
1161*be431cd8SAndroid Build Coastguard Worker     return availableToReadBytes() / quantum();
1162*be431cd8SAndroid Build Coastguard Worker }
1163*be431cd8SAndroid Build Coastguard Worker 
1164*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
beginWrite(size_t nMessages,MemTransaction * result)1165*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::beginWrite(size_t nMessages,
1166*be431cd8SAndroid Build Coastguard Worker                                                                MemTransaction* result) const {
1167*be431cd8SAndroid Build Coastguard Worker     /*
1168*be431cd8SAndroid Build Coastguard Worker      * If nMessages is greater than size of FMQ or in case of the synchronized
1169*be431cd8SAndroid Build Coastguard Worker      * FMQ flavor, if there is not enough space to write nMessages, then return
1170*be431cd8SAndroid Build Coastguard Worker      * result with null addresses.
1171*be431cd8SAndroid Build Coastguard Worker      */
1172*be431cd8SAndroid Build Coastguard Worker     if ((flavor == kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
1173*be431cd8SAndroid Build Coastguard Worker         nMessages > getQuantumCount()) {
1174*be431cd8SAndroid Build Coastguard Worker         *result = MemTransaction();
1175*be431cd8SAndroid Build Coastguard Worker         return false;
1176*be431cd8SAndroid Build Coastguard Worker     }
1177*be431cd8SAndroid Build Coastguard Worker 
1178*be431cd8SAndroid Build Coastguard Worker     auto writePtr = mWritePtr->load(std::memory_order_relaxed);
1179*be431cd8SAndroid Build Coastguard Worker     if (writePtr % quantum() != 0) {
1180*be431cd8SAndroid Build Coastguard Worker         std::string errorMsg =
1181*be431cd8SAndroid Build Coastguard Worker                 "The write pointer has become misaligned. Writing to the queue is not possible. "
1182*be431cd8SAndroid Build Coastguard Worker                 "Pointer: " +
1183*be431cd8SAndroid Build Coastguard Worker                 std::to_string(writePtr) + ", quantum: " + std::to_string(quantum());
1184*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError(errorMsg);
1185*be431cd8SAndroid Build Coastguard Worker         hardware::details::errorWriteLog(0x534e4554, "184963385");
1186*be431cd8SAndroid Build Coastguard Worker         if (mErrorHandler) {
1187*be431cd8SAndroid Build Coastguard Worker             mErrorHandler(Error::POINTER_CORRUPTION, std::move(errorMsg));
1188*be431cd8SAndroid Build Coastguard Worker         }
1189*be431cd8SAndroid Build Coastguard Worker         return false;
1190*be431cd8SAndroid Build Coastguard Worker     }
1191*be431cd8SAndroid Build Coastguard Worker     size_t writeOffset = writePtr % mDesc->getSize();
1192*be431cd8SAndroid Build Coastguard Worker 
1193*be431cd8SAndroid Build Coastguard Worker     /*
1194*be431cd8SAndroid Build Coastguard Worker      * From writeOffset, the number of messages that can be written
1195*be431cd8SAndroid Build Coastguard Worker      * contiguously without wrapping around the ring buffer are calculated.
1196*be431cd8SAndroid Build Coastguard Worker      */
1197*be431cd8SAndroid Build Coastguard Worker     size_t contiguousMessages = (mDesc->getSize() - writeOffset) / quantum();
1198*be431cd8SAndroid Build Coastguard Worker 
1199*be431cd8SAndroid Build Coastguard Worker     if (contiguousMessages < nMessages) {
1200*be431cd8SAndroid Build Coastguard Worker         /*
1201*be431cd8SAndroid Build Coastguard Worker          * Wrap around is required. Both result.first and result.second are
1202*be431cd8SAndroid Build Coastguard Worker          * populated.
1203*be431cd8SAndroid Build Coastguard Worker          */
1204*be431cd8SAndroid Build Coastguard Worker         *result = MemTransaction(
1205*be431cd8SAndroid Build Coastguard Worker                 MemRegion(reinterpret_cast<T*>(mRing + writeOffset), contiguousMessages),
1206*be431cd8SAndroid Build Coastguard Worker                 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
1207*be431cd8SAndroid Build Coastguard Worker     } else {
1208*be431cd8SAndroid Build Coastguard Worker         /*
1209*be431cd8SAndroid Build Coastguard Worker          * A wrap around is not required to write nMessages. Only result.first
1210*be431cd8SAndroid Build Coastguard Worker          * is populated.
1211*be431cd8SAndroid Build Coastguard Worker          */
1212*be431cd8SAndroid Build Coastguard Worker         *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset), nMessages),
1213*be431cd8SAndroid Build Coastguard Worker                                  MemRegion());
1214*be431cd8SAndroid Build Coastguard Worker     }
1215*be431cd8SAndroid Build Coastguard Worker 
1216*be431cd8SAndroid Build Coastguard Worker     return true;
1217*be431cd8SAndroid Build Coastguard Worker }
1218*be431cd8SAndroid Build Coastguard Worker 
1219*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
1220*be431cd8SAndroid Build Coastguard Worker /*
1221*be431cd8SAndroid Build Coastguard Worker  * Disable integer sanitization since integer overflow here is allowed
1222*be431cd8SAndroid Build Coastguard Worker  * and legal.
1223*be431cd8SAndroid Build Coastguard Worker  */
1224*be431cd8SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer"))) bool
commitWrite(size_t nMessages)1225*be431cd8SAndroid Build Coastguard Worker MessageQueueBase<MQDescriptorType, T, flavor>::commitWrite(size_t nMessages) {
1226*be431cd8SAndroid Build Coastguard Worker     size_t nBytesWritten = nMessages * quantum();
1227*be431cd8SAndroid Build Coastguard Worker     auto writePtr = mWritePtr->load(std::memory_order_relaxed);
1228*be431cd8SAndroid Build Coastguard Worker     writePtr += nBytesWritten;
1229*be431cd8SAndroid Build Coastguard Worker     mWritePtr->store(writePtr, std::memory_order_release);
1230*be431cd8SAndroid Build Coastguard Worker     /*
1231*be431cd8SAndroid Build Coastguard Worker      * This method cannot fail now since we are only incrementing the writePtr
1232*be431cd8SAndroid Build Coastguard Worker      * counter.
1233*be431cd8SAndroid Build Coastguard Worker      */
1234*be431cd8SAndroid Build Coastguard Worker     return true;
1235*be431cd8SAndroid Build Coastguard Worker }
1236*be431cd8SAndroid Build Coastguard Worker 
1237*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
availableToReadBytes()1238*be431cd8SAndroid Build Coastguard Worker size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToReadBytes() const {
1239*be431cd8SAndroid Build Coastguard Worker     /*
1240*be431cd8SAndroid Build Coastguard Worker      * This method is invoked by implementations of both read() and write() and
1241*be431cd8SAndroid Build Coastguard Worker      * hence requires a memory_order_acquired load for both mReadPtr and
1242*be431cd8SAndroid Build Coastguard Worker      * mWritePtr.
1243*be431cd8SAndroid Build Coastguard Worker      */
1244*be431cd8SAndroid Build Coastguard Worker     uint64_t writePtr = mWritePtr->load(std::memory_order_acquire);
1245*be431cd8SAndroid Build Coastguard Worker     uint64_t readPtr = mReadPtr->load(std::memory_order_acquire);
1246*be431cd8SAndroid Build Coastguard Worker     if (writePtr < readPtr) {
1247*be431cd8SAndroid Build Coastguard Worker         std::string errorMsg =
1248*be431cd8SAndroid Build Coastguard Worker                 "The write or read pointer has become corrupted. Reading from the queue is no "
1249*be431cd8SAndroid Build Coastguard Worker                 "longer possible. Write pointer: " +
1250*be431cd8SAndroid Build Coastguard Worker                 std::to_string(writePtr) + ", read pointer: " + std::to_string(readPtr);
1251*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError(errorMsg);
1252*be431cd8SAndroid Build Coastguard Worker         if (mErrorHandler) {
1253*be431cd8SAndroid Build Coastguard Worker             mErrorHandler(Error::POINTER_CORRUPTION, std::move(errorMsg));
1254*be431cd8SAndroid Build Coastguard Worker         }
1255*be431cd8SAndroid Build Coastguard Worker         return 0;
1256*be431cd8SAndroid Build Coastguard Worker     }
1257*be431cd8SAndroid Build Coastguard Worker     return writePtr - readPtr;
1258*be431cd8SAndroid Build Coastguard Worker }
1259*be431cd8SAndroid Build Coastguard Worker 
1260*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
read(T * data,size_t nMessages)1261*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data, size_t nMessages) {
1262*be431cd8SAndroid Build Coastguard Worker     MemTransaction tx;
1263*be431cd8SAndroid Build Coastguard Worker     return beginRead(nMessages, &tx) &&
1264*be431cd8SAndroid Build Coastguard Worker            tx.copyFromSized(data, 0 /* startIdx */, nMessages, quantum()) && commitRead(nMessages);
1265*be431cd8SAndroid Build Coastguard Worker }
1266*be431cd8SAndroid Build Coastguard Worker 
1267*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
1268*be431cd8SAndroid Build Coastguard Worker /*
1269*be431cd8SAndroid Build Coastguard Worker  * Disable integer sanitization since integer overflow here is allowed
1270*be431cd8SAndroid Build Coastguard Worker  * and legal.
1271*be431cd8SAndroid Build Coastguard Worker  */
1272*be431cd8SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer"))) bool
processOverflow(uint64_t readPtr,uint64_t writePtr)1273*be431cd8SAndroid Build Coastguard Worker MessageQueueBase<MQDescriptorType, T, flavor>::processOverflow(uint64_t readPtr,
1274*be431cd8SAndroid Build Coastguard Worker                                                                uint64_t writePtr) const {
1275*be431cd8SAndroid Build Coastguard Worker     if (writePtr - readPtr > mDesc->getSize()) {
1276*be431cd8SAndroid Build Coastguard Worker         /*
1277*be431cd8SAndroid Build Coastguard Worker          * Preserved history can be as big as mDesc->getSize() but we expose only half of that.
1278*be431cd8SAndroid Build Coastguard Worker          * Half of the buffer will be discarded to make space for fast writers and
1279*be431cd8SAndroid Build Coastguard Worker          * reduce chance of repeated overflows. The other half is available to read.
1280*be431cd8SAndroid Build Coastguard Worker          */
1281*be431cd8SAndroid Build Coastguard Worker         size_t historyOffset = getQuantumCount() / 2 * getQuantumSize();
1282*be431cd8SAndroid Build Coastguard Worker         mReadPtr->store(writePtr - historyOffset, std::memory_order_release);
1283*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError("Read failed after an overflow. Resetting read pointer.");
1284*be431cd8SAndroid Build Coastguard Worker         return true;
1285*be431cd8SAndroid Build Coastguard Worker     }
1286*be431cd8SAndroid Build Coastguard Worker     return false;
1287*be431cd8SAndroid Build Coastguard Worker }
1288*be431cd8SAndroid Build Coastguard Worker 
1289*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
1290*be431cd8SAndroid Build Coastguard Worker /*
1291*be431cd8SAndroid Build Coastguard Worker  * Disable integer sanitization since integer overflow here is allowed
1292*be431cd8SAndroid Build Coastguard Worker  * and legal.
1293*be431cd8SAndroid Build Coastguard Worker  */
1294*be431cd8SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer"))) bool
beginRead(size_t nMessages,MemTransaction * result)1295*be431cd8SAndroid Build Coastguard Worker MessageQueueBase<MQDescriptorType, T, flavor>::beginRead(size_t nMessages,
1296*be431cd8SAndroid Build Coastguard Worker                                                          MemTransaction* result) const {
1297*be431cd8SAndroid Build Coastguard Worker     *result = MemTransaction();
1298*be431cd8SAndroid Build Coastguard Worker     /*
1299*be431cd8SAndroid Build Coastguard Worker      * If it is detected that the data in the queue was overwritten
1300*be431cd8SAndroid Build Coastguard Worker      * due to the reader process being too slow, the read pointer counter
1301*be431cd8SAndroid Build Coastguard Worker      * is set to the same as the write pointer counter to indicate error
1302*be431cd8SAndroid Build Coastguard Worker      * and the read returns false;
1303*be431cd8SAndroid Build Coastguard Worker      * Need acquire/release memory ordering for mWritePtr.
1304*be431cd8SAndroid Build Coastguard Worker      */
1305*be431cd8SAndroid Build Coastguard Worker     auto writePtr = mWritePtr->load(std::memory_order_acquire);
1306*be431cd8SAndroid Build Coastguard Worker     /*
1307*be431cd8SAndroid Build Coastguard Worker      * A relaxed load is sufficient for mReadPtr since there will be no
1308*be431cd8SAndroid Build Coastguard Worker      * stores to mReadPtr from a different thread.
1309*be431cd8SAndroid Build Coastguard Worker      */
1310*be431cd8SAndroid Build Coastguard Worker     auto readPtr = mReadPtr->load(std::memory_order_relaxed);
1311*be431cd8SAndroid Build Coastguard Worker     if (writePtr % quantum() != 0 || readPtr % quantum() != 0) {
1312*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError(
1313*be431cd8SAndroid Build Coastguard Worker                 "The write or read pointer has become misaligned. Reading from the queue is no "
1314*be431cd8SAndroid Build Coastguard Worker                 "longer possible.");
1315*be431cd8SAndroid Build Coastguard Worker         hardware::details::errorWriteLog(0x534e4554, "184963385");
1316*be431cd8SAndroid Build Coastguard Worker         return false;
1317*be431cd8SAndroid Build Coastguard Worker     }
1318*be431cd8SAndroid Build Coastguard Worker 
1319*be431cd8SAndroid Build Coastguard Worker     if (processOverflow(readPtr, writePtr)) {
1320*be431cd8SAndroid Build Coastguard Worker         return false;
1321*be431cd8SAndroid Build Coastguard Worker     }
1322*be431cd8SAndroid Build Coastguard Worker 
1323*be431cd8SAndroid Build Coastguard Worker     size_t nBytesDesired = nMessages * quantum();
1324*be431cd8SAndroid Build Coastguard Worker     /*
1325*be431cd8SAndroid Build Coastguard Worker      * Return if insufficient data to read in FMQ.
1326*be431cd8SAndroid Build Coastguard Worker      */
1327*be431cd8SAndroid Build Coastguard Worker     if (writePtr - readPtr < nBytesDesired) {
1328*be431cd8SAndroid Build Coastguard Worker         return false;
1329*be431cd8SAndroid Build Coastguard Worker     }
1330*be431cd8SAndroid Build Coastguard Worker 
1331*be431cd8SAndroid Build Coastguard Worker     size_t readOffset = readPtr % mDesc->getSize();
1332*be431cd8SAndroid Build Coastguard Worker     /*
1333*be431cd8SAndroid Build Coastguard Worker      * From readOffset, the number of messages that can be read contiguously
1334*be431cd8SAndroid Build Coastguard Worker      * without wrapping around the ring buffer are calculated.
1335*be431cd8SAndroid Build Coastguard Worker      */
1336*be431cd8SAndroid Build Coastguard Worker     size_t contiguousMessages = (mDesc->getSize() - readOffset) / quantum();
1337*be431cd8SAndroid Build Coastguard Worker 
1338*be431cd8SAndroid Build Coastguard Worker     if (contiguousMessages < nMessages) {
1339*be431cd8SAndroid Build Coastguard Worker         /*
1340*be431cd8SAndroid Build Coastguard Worker          * A wrap around is required. Both result.first and result.second
1341*be431cd8SAndroid Build Coastguard Worker          * are populated.
1342*be431cd8SAndroid Build Coastguard Worker          */
1343*be431cd8SAndroid Build Coastguard Worker         *result = MemTransaction(
1344*be431cd8SAndroid Build Coastguard Worker                 MemRegion(reinterpret_cast<T*>(mRing + readOffset), contiguousMessages),
1345*be431cd8SAndroid Build Coastguard Worker                 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
1346*be431cd8SAndroid Build Coastguard Worker     } else {
1347*be431cd8SAndroid Build Coastguard Worker         /*
1348*be431cd8SAndroid Build Coastguard Worker          * A wrap around is not required. Only result.first need to be
1349*be431cd8SAndroid Build Coastguard Worker          * populated.
1350*be431cd8SAndroid Build Coastguard Worker          */
1351*be431cd8SAndroid Build Coastguard Worker         *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset), nMessages),
1352*be431cd8SAndroid Build Coastguard Worker                                  MemRegion());
1353*be431cd8SAndroid Build Coastguard Worker     }
1354*be431cd8SAndroid Build Coastguard Worker 
1355*be431cd8SAndroid Build Coastguard Worker     return true;
1356*be431cd8SAndroid Build Coastguard Worker }
1357*be431cd8SAndroid Build Coastguard Worker 
1358*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
1359*be431cd8SAndroid Build Coastguard Worker /*
1360*be431cd8SAndroid Build Coastguard Worker  * Disable integer sanitization since integer overflow here is allowed
1361*be431cd8SAndroid Build Coastguard Worker  * and legal.
1362*be431cd8SAndroid Build Coastguard Worker  */
1363*be431cd8SAndroid Build Coastguard Worker __attribute__((no_sanitize("integer"))) bool
commitRead(size_t nMessages)1364*be431cd8SAndroid Build Coastguard Worker MessageQueueBase<MQDescriptorType, T, flavor>::commitRead(size_t nMessages) {
1365*be431cd8SAndroid Build Coastguard Worker     // TODO: Use a local copy of readPtr to avoid relazed mReadPtr loads.
1366*be431cd8SAndroid Build Coastguard Worker     auto readPtr = mReadPtr->load(std::memory_order_relaxed);
1367*be431cd8SAndroid Build Coastguard Worker     auto writePtr = mWritePtr->load(std::memory_order_acquire);
1368*be431cd8SAndroid Build Coastguard Worker 
1369*be431cd8SAndroid Build Coastguard Worker     /*
1370*be431cd8SAndroid Build Coastguard Worker      * If the flavor is unsynchronized, it is possible that a write overflow may
1371*be431cd8SAndroid Build Coastguard Worker      * have occurred between beginRead() and commitRead().
1372*be431cd8SAndroid Build Coastguard Worker      */
1373*be431cd8SAndroid Build Coastguard Worker     if (processOverflow(readPtr, writePtr)) {
1374*be431cd8SAndroid Build Coastguard Worker         return false;
1375*be431cd8SAndroid Build Coastguard Worker     }
1376*be431cd8SAndroid Build Coastguard Worker 
1377*be431cd8SAndroid Build Coastguard Worker     size_t nBytesRead = nMessages * quantum();
1378*be431cd8SAndroid Build Coastguard Worker     readPtr += nBytesRead;
1379*be431cd8SAndroid Build Coastguard Worker     mReadPtr->store(readPtr, std::memory_order_release);
1380*be431cd8SAndroid Build Coastguard Worker     return true;
1381*be431cd8SAndroid Build Coastguard Worker }
1382*be431cd8SAndroid Build Coastguard Worker 
1383*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
getQuantumSize()1384*be431cd8SAndroid Build Coastguard Worker size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumSize() const {
1385*be431cd8SAndroid Build Coastguard Worker     return mDesc->getQuantum();
1386*be431cd8SAndroid Build Coastguard Worker }
1387*be431cd8SAndroid Build Coastguard Worker 
1388*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
getQuantumCount()1389*be431cd8SAndroid Build Coastguard Worker size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumCount() const {
1390*be431cd8SAndroid Build Coastguard Worker     return mDesc->getSize() / mDesc->getQuantum();
1391*be431cd8SAndroid Build Coastguard Worker }
1392*be431cd8SAndroid Build Coastguard Worker 
1393*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
isValid()1394*be431cd8SAndroid Build Coastguard Worker bool MessageQueueBase<MQDescriptorType, T, flavor>::isValid() const {
1395*be431cd8SAndroid Build Coastguard Worker     return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
1396*be431cd8SAndroid Build Coastguard Worker }
1397*be431cd8SAndroid Build Coastguard Worker 
1398*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
mapGrantorDescr(uint32_t grantorIdx)1399*be431cd8SAndroid Build Coastguard Worker void* MessageQueueBase<MQDescriptorType, T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
1400*be431cd8SAndroid Build Coastguard Worker     const native_handle_t* handle = mDesc->handle();
1401*be431cd8SAndroid Build Coastguard Worker     const std::vector<android::hardware::GrantorDescriptor> grantors = mDesc->grantors();
1402*be431cd8SAndroid Build Coastguard Worker     if (handle == nullptr) {
1403*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError("mDesc->handle is null");
1404*be431cd8SAndroid Build Coastguard Worker         return nullptr;
1405*be431cd8SAndroid Build Coastguard Worker     }
1406*be431cd8SAndroid Build Coastguard Worker 
1407*be431cd8SAndroid Build Coastguard Worker     if (grantorIdx >= grantors.size()) {
1408*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError(std::string("grantorIdx must be less than ") +
1409*be431cd8SAndroid Build Coastguard Worker                                     std::to_string(grantors.size()));
1410*be431cd8SAndroid Build Coastguard Worker         return nullptr;
1411*be431cd8SAndroid Build Coastguard Worker     }
1412*be431cd8SAndroid Build Coastguard Worker 
1413*be431cd8SAndroid Build Coastguard Worker     int fdIndex = grantors[grantorIdx].fdIndex;
1414*be431cd8SAndroid Build Coastguard Worker     if (fdIndex < 0 || fdIndex >= handle->numFds) {
1415*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError(
1416*be431cd8SAndroid Build Coastguard Worker                 std::string("fdIndex (" + std::to_string(fdIndex) + ") from grantor (index " +
1417*be431cd8SAndroid Build Coastguard Worker                             std::to_string(grantorIdx) +
1418*be431cd8SAndroid Build Coastguard Worker                             ") must be smaller than the number of fds in the handle: " +
1419*be431cd8SAndroid Build Coastguard Worker                             std::to_string(handle->numFds)));
1420*be431cd8SAndroid Build Coastguard Worker         return nullptr;
1421*be431cd8SAndroid Build Coastguard Worker     }
1422*be431cd8SAndroid Build Coastguard Worker 
1423*be431cd8SAndroid Build Coastguard Worker     /*
1424*be431cd8SAndroid Build Coastguard Worker      * Offset for mmap must be a multiple of kPageSize.
1425*be431cd8SAndroid Build Coastguard Worker      */
1426*be431cd8SAndroid Build Coastguard Worker     if (!hardware::details::isAlignedToWordBoundary(grantors[grantorIdx].offset)) {
1427*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError("Grantor (index " + std::to_string(grantorIdx) +
1428*be431cd8SAndroid Build Coastguard Worker                                     ") offset needs to be aligned to word boundary but is: " +
1429*be431cd8SAndroid Build Coastguard Worker                                     std::to_string(grantors[grantorIdx].offset));
1430*be431cd8SAndroid Build Coastguard Worker         return nullptr;
1431*be431cd8SAndroid Build Coastguard Worker     }
1432*be431cd8SAndroid Build Coastguard Worker 
1433*be431cd8SAndroid Build Coastguard Worker     /*
1434*be431cd8SAndroid Build Coastguard Worker      * Expect some grantors to be at least a min size
1435*be431cd8SAndroid Build Coastguard Worker      */
1436*be431cd8SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < grantors.size(); i++) {
1437*be431cd8SAndroid Build Coastguard Worker         switch (i) {
1438*be431cd8SAndroid Build Coastguard Worker             case hardware::details::READPTRPOS:
1439*be431cd8SAndroid Build Coastguard Worker                 if (grantors[i].extent < sizeof(uint64_t)) return nullptr;
1440*be431cd8SAndroid Build Coastguard Worker                 break;
1441*be431cd8SAndroid Build Coastguard Worker             case hardware::details::WRITEPTRPOS:
1442*be431cd8SAndroid Build Coastguard Worker                 if (grantors[i].extent < sizeof(uint64_t)) return nullptr;
1443*be431cd8SAndroid Build Coastguard Worker                 break;
1444*be431cd8SAndroid Build Coastguard Worker             case hardware::details::DATAPTRPOS:
1445*be431cd8SAndroid Build Coastguard Worker                 // We don't expect specific data size
1446*be431cd8SAndroid Build Coastguard Worker                 break;
1447*be431cd8SAndroid Build Coastguard Worker             case hardware::details::EVFLAGWORDPOS:
1448*be431cd8SAndroid Build Coastguard Worker                 if (grantors[i].extent < sizeof(uint32_t)) return nullptr;
1449*be431cd8SAndroid Build Coastguard Worker                 break;
1450*be431cd8SAndroid Build Coastguard Worker             default:
1451*be431cd8SAndroid Build Coastguard Worker                 // We don't care about unknown grantors
1452*be431cd8SAndroid Build Coastguard Worker                 break;
1453*be431cd8SAndroid Build Coastguard Worker         }
1454*be431cd8SAndroid Build Coastguard Worker     }
1455*be431cd8SAndroid Build Coastguard Worker 
1456*be431cd8SAndroid Build Coastguard Worker     int mapOffset = (grantors[grantorIdx].offset / kPageSize) * kPageSize;
1457*be431cd8SAndroid Build Coastguard Worker     if (grantors[grantorIdx].extent < 0 || grantors[grantorIdx].extent > INT_MAX - kPageSize) {
1458*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError(std::string("Grantor (index " + std::to_string(grantorIdx) +
1459*be431cd8SAndroid Build Coastguard Worker                                                 ") extent value is too large or negative: " +
1460*be431cd8SAndroid Build Coastguard Worker                                                 std::to_string(grantors[grantorIdx].extent)));
1461*be431cd8SAndroid Build Coastguard Worker         return nullptr;
1462*be431cd8SAndroid Build Coastguard Worker     }
1463*be431cd8SAndroid Build Coastguard Worker     int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
1464*be431cd8SAndroid Build Coastguard Worker 
1465*be431cd8SAndroid Build Coastguard Worker     void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED, handle->data[fdIndex],
1466*be431cd8SAndroid Build Coastguard Worker                          mapOffset);
1467*be431cd8SAndroid Build Coastguard Worker     if (address == MAP_FAILED && errno == EPERM && flavor == kUnsynchronizedWrite) {
1468*be431cd8SAndroid Build Coastguard Worker         // If the supplied memory is read-only, it would fail with EPERM.
1469*be431cd8SAndroid Build Coastguard Worker         // Try again to mmap read-only for the kUnsynchronizedWrite case.
1470*be431cd8SAndroid Build Coastguard Worker         // kSynchronizedReadWrite cannot use read-only memory because the
1471*be431cd8SAndroid Build Coastguard Worker         // read pointer is stored in the shared memory as well.
1472*be431cd8SAndroid Build Coastguard Worker         address = mmap(0, mapLength, PROT_READ, MAP_SHARED, handle->data[fdIndex], mapOffset);
1473*be431cd8SAndroid Build Coastguard Worker     }
1474*be431cd8SAndroid Build Coastguard Worker     if (address == MAP_FAILED) {
1475*be431cd8SAndroid Build Coastguard Worker         hardware::details::logError(std::string("mmap failed: ") + std::to_string(errno));
1476*be431cd8SAndroid Build Coastguard Worker         return nullptr;
1477*be431cd8SAndroid Build Coastguard Worker     }
1478*be431cd8SAndroid Build Coastguard Worker     return reinterpret_cast<uint8_t*>(address) + (grantors[grantorIdx].offset - mapOffset);
1479*be431cd8SAndroid Build Coastguard Worker }
1480*be431cd8SAndroid Build Coastguard Worker 
1481*be431cd8SAndroid Build Coastguard Worker template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
unmapGrantorDescr(void * address,uint32_t grantorIdx)1482*be431cd8SAndroid Build Coastguard Worker void MessageQueueBase<MQDescriptorType, T, flavor>::unmapGrantorDescr(void* address,
1483*be431cd8SAndroid Build Coastguard Worker                                                                       uint32_t grantorIdx) {
1484*be431cd8SAndroid Build Coastguard Worker     auto grantors = mDesc->grantors();
1485*be431cd8SAndroid Build Coastguard Worker     if ((address == nullptr) || (grantorIdx >= grantors.size())) {
1486*be431cd8SAndroid Build Coastguard Worker         return;
1487*be431cd8SAndroid Build Coastguard Worker     }
1488*be431cd8SAndroid Build Coastguard Worker 
1489*be431cd8SAndroid Build Coastguard Worker     int mapOffset = (grantors[grantorIdx].offset / kPageSize) * kPageSize;
1490*be431cd8SAndroid Build Coastguard Worker     int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
1491*be431cd8SAndroid Build Coastguard Worker     void* baseAddress =
1492*be431cd8SAndroid Build Coastguard Worker             reinterpret_cast<uint8_t*>(address) - (grantors[grantorIdx].offset - mapOffset);
1493*be431cd8SAndroid Build Coastguard Worker     if (baseAddress) munmap(baseAddress, mapLength);
1494*be431cd8SAndroid Build Coastguard Worker }
1495*be431cd8SAndroid Build Coastguard Worker 
1496*be431cd8SAndroid Build Coastguard Worker }  // namespace android
1497