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