blob: 49d74d623b11383c62e9bf278c4ae82713f02fe9 [file] [log] [blame]
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Devin Moore9a27da52020-07-06 14:01:21 -070017#pragma once
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080018
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080019#include <cutils/ashmem.h>
20#include <fmq/EventFlag.h>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080021#include <sys/mman.h>
22#include <utils/Log.h>
Hridya Valsaraju2abefb62017-01-19 13:06:58 -080023#include <utils/SystemClock.h>
Devin Moore77d279e2020-07-07 10:38:52 -070024#include <atomic>
25#include <new>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080026
Devin Moore133cb5e2020-07-07 16:31:22 -070027using android::hardware::kSynchronizedReadWrite;
28using android::hardware::kUnsynchronizedWrite;
29using android::hardware::MQFlavor;
30
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080031namespace android {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080032
Devin Moore9a27da52020-07-06 14:01:21 -070033namespace hardware {
Yifan Hongdc5bd672017-04-11 17:11:57 -070034namespace details {
35void check(bool exp);
Devin Moore77d279e2020-07-07 10:38:52 -070036void logError(const std::string& message);
Yifan Hongdc5bd672017-04-11 17:11:57 -070037} // namespace details
Devin Moore9a27da52020-07-06 14:01:21 -070038} // namespace hardware
Yifan Hongdc5bd672017-04-11 17:11:57 -070039
Devin Moore133cb5e2020-07-07 16:31:22 -070040template <template <typename, MQFlavor> class MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -070041struct MessageQueueBase {
42 typedef MQDescriptorType<T, flavor> Descriptor;
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -080043
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080044 /**
45 * @param Desc MQDescriptor describing the FMQ.
46 * @param resetPointers bool indicating whether the read/write pointers
47 * should be reset or not.
48 */
Devin Moore9a27da52020-07-06 14:01:21 -070049 MessageQueueBase(const Descriptor& Desc, bool resetPointers = true);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080050
Devin Moore9a27da52020-07-06 14:01:21 -070051 ~MessageQueueBase();
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080052
53 /**
54 * This constructor uses Ashmem shared memory to create an FMQ
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080055 * that can contain a maximum of 'numElementsInQueue' elements of type T.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080056 *
57 * @param numElementsInQueue Capacity of the MessageQueue in terms of T.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -080058 * @param configureEventFlagWord Boolean that specifies if memory should
59 * also be allocated and mapped for an EventFlag word.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080060 */
Devin Moore9a27da52020-07-06 14:01:21 -070061
62 MessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord = false);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080063
64 /**
65 * @return Number of items of type T that can be written into the FMQ
66 * without a read.
67 */
68 size_t availableToWrite() const;
69
70 /**
71 * @return Number of items of type T that are waiting to be read from the
72 * FMQ.
73 */
74 size_t availableToRead() const;
75
76 /**
77 * Returns the size of type T in bytes.
78 *
79 * @param Size of T.
80 */
81 size_t getQuantumSize() const;
82
83 /**
84 * Returns the size of the FMQ in terms of the size of type T.
85 *
86 * @return Number of items of type T that will fit in the FMQ.
87 */
88 size_t getQuantumCount() const;
89
90 /**
91 * @return Whether the FMQ is configured correctly.
92 */
93 bool isValid() const;
94
95 /**
96 * Non-blocking write to FMQ.
97 *
98 * @param data Pointer to the object of type T to be written into the FMQ.
99 *
100 * @return Whether the write was successful.
101 */
102 bool write(const T* data);
103
104 /**
105 * Non-blocking read from FMQ.
106 *
107 * @param data Pointer to the memory where the object read from the FMQ is
108 * copied to.
109 *
110 * @return Whether the read was successful.
111 */
112 bool read(T* data);
113
114 /**
115 * Write some data into the FMQ without blocking.
116 *
117 * @param data Pointer to the array of items of type T.
118 * @param count Number of items in array.
119 *
120 * @return Whether the write was successful.
121 */
122 bool write(const T* data, size_t count);
123
124 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800125 * Perform a blocking write of 'count' items into the FMQ using EventFlags.
126 * Does not support partial writes.
127 *
128 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
129 * associated with the FMQ and it is used in that case.
130 *
131 * The application code must ensure that 'evFlag' used by the
132 * reader(s)/writer is based upon the same EventFlag word.
133 *
134 * The method will return false without blocking if any of the following
135 * conditions are true:
136 * - If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700137 * - If the 'readNotification' bit mask is zero.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800138 * - If 'count' is greater than the FMQ size.
139 *
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700140 * If the there is insufficient space available to write into it, the
141 * EventFlag bit mask 'readNotification' is is waited upon.
142 *
143 * This method should only be used with a MessageQueue of the flavor
Devin Moore133cb5e2020-07-07 16:31:22 -0700144 * 'kSynchronizedReadWrite'.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800145 *
146 * Upon a successful write, wake is called on 'writeNotification' (if
147 * non-zero).
148 *
149 * @param data Pointer to the array of items of type T.
150 * @param count Number of items in array.
151 * @param readNotification The EventFlag bit mask to wait on if there is not
152 * enough space in FMQ to write 'count' items.
153 * @param writeNotification The EventFlag bit mask to call wake on
154 * a successful write. No wake is called if 'writeNotification' is zero.
155 * @param timeOutNanos Number of nanoseconds after which the blocking
156 * write attempt is aborted.
157 * @param evFlag The EventFlag object to be used for blocking. If nullptr,
158 * it is checked whether the FMQ owns an EventFlag object and that is used
159 * for blocking instead.
160 *
161 * @return Whether the write was successful.
162 */
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800163 bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
164 uint32_t writeNotification, int64_t timeOutNanos = 0,
165 android::hardware::EventFlag* evFlag = nullptr);
166
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800167 bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
168
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800169 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800170 * Read some data from the FMQ without blocking.
171 *
172 * @param data Pointer to the array to which read data is to be written.
173 * @param count Number of items to be read.
174 *
175 * @return Whether the read was successful.
176 */
177 bool read(T* data, size_t count);
178
179 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800180 * Perform a blocking read operation of 'count' items from the FMQ. Does not
181 * perform a partial read.
182 *
183 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
184 * associated with the FMQ and it is used in that case.
185 *
186 * The application code must ensure that 'evFlag' used by the
187 * reader(s)/writer is based upon the same EventFlag word.
188 *
189 * The method will return false without blocking if any of the following
190 * conditions are true:
191 * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
192 * -If the 'writeNotification' bit mask is zero.
193 * -If 'count' is greater than the FMQ size.
194 *
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700195 * This method should only be used with a MessageQueue of the flavor
Devin Moore133cb5e2020-07-07 16:31:22 -0700196 * 'kSynchronizedReadWrite'.
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700197
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800198 * If FMQ does not contain 'count' items, the eventFlag bit mask
199 * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
200 * wake is called on 'readNotification' (if non-zero).
201 *
202 * @param data Pointer to the array to which read data is to be written.
203 * @param count Number of items to be read.
204 * @param readNotification The EventFlag bit mask to call wake on after
205 * a successful read. No wake is called if 'readNotification' is zero.
206 * @param writeNotification The EventFlag bit mask to call a wait on
207 * if there is insufficient data in the FMQ to be read.
208 * @param timeOutNanos Number of nanoseconds after which the blocking
209 * read attempt is aborted.
210 * @param evFlag The EventFlag object to be used for blocking.
211 *
212 * @return Whether the read was successful.
213 */
Devin Moore77d279e2020-07-07 10:38:52 -0700214 bool readBlocking(T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
215 int64_t timeOutNanos = 0, android::hardware::EventFlag* evFlag = nullptr);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800216
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800217 bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);
218
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800219 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800220 * Get a pointer to the MQDescriptor object that describes this FMQ.
221 *
222 * @return Pointer to the MQDescriptor associated with the FMQ.
223 */
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800224 const Descriptor* getDesc() const { return mDesc.get(); }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800225
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800226 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800227 * Get a pointer to the EventFlag word if there is one associated with this FMQ.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800228 *
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800229 * @return Pointer to an EventFlag word, will return nullptr if not
230 * configured. This method does not transfer ownership. The EventFlag
231 * word will be unmapped by the MessageQueue destructor.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800232 */
233 std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800234
235 /**
236 * Describes a memory region in the FMQ.
237 */
238 struct MemRegion {
239 MemRegion() : MemRegion(nullptr, 0) {}
240
241 MemRegion(T* base, size_t size) : address(base), length(size) {}
242
Devin Moore77d279e2020-07-07 10:38:52 -0700243 MemRegion& operator=(const MemRegion& other) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800244 address = other.address;
245 length = other.length;
246 return *this;
247 }
248
249 /**
250 * Gets a pointer to the base address of the MemRegion.
251 */
252 inline T* getAddress() const { return address; }
253
254 /**
255 * Gets the length of the MemRegion. This would equal to the number
256 * of items of type T that can be read from/written into the MemRegion.
257 */
258 inline size_t getLength() const { return length; }
259
260 /**
261 * Gets the length of the MemRegion in bytes.
262 */
263 inline size_t getLengthInBytes() const { return length * sizeof(T); }
264
Devin Moore77d279e2020-07-07 10:38:52 -0700265 private:
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800266 /* Base address */
267 T* address;
268
269 /*
270 * Number of items of type T that can be written to/read from the base
271 * address.
272 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800273 size_t length;
274 };
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800275
276 /**
277 * Describes the memory regions to be used for a read or write.
278 * The struct contains two MemRegion objects since the FMQ is a ring
279 * buffer and a read or write operation can wrap around. A single message
280 * of type T will never be broken between the two MemRegions.
281 */
282 struct MemTransaction {
283 MemTransaction() : MemTransaction(MemRegion(), MemRegion()) {}
284
Devin Moore77d279e2020-07-07 10:38:52 -0700285 MemTransaction(const MemRegion& regionFirst, const MemRegion& regionSecond)
286 : first(regionFirst), second(regionSecond) {}
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800287
Devin Moore77d279e2020-07-07 10:38:52 -0700288 MemTransaction& operator=(const MemTransaction& other) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800289 first = other.first;
290 second = other.second;
291 return *this;
292 }
293
294 /**
295 * Helper method to calculate the address for a particular index for
296 * the MemTransaction object.
297 *
298 * @param idx Index of the slot to be read/written. If the
299 * MemTransaction object is representing the memory region to read/write
300 * N items of type T, the valid range of idx is between 0 and N-1.
301 *
302 * @return Pointer to the slot idx. Will be nullptr for an invalid idx.
303 */
304 T* getSlot(size_t idx);
305
306 /**
307 * Helper method to write 'nMessages' items of type T into the memory
308 * regions described by the object starting from 'startIdx'. This method
309 * uses memcpy() and is not to meant to be used for a zero copy operation.
310 * Partial writes are not supported.
311 *
312 * @param data Pointer to the source buffer.
313 * @param nMessages Number of items of type T.
314 * @param startIdx The slot number to begin the write from. If the
315 * MemTransaction object is representing the memory region to read/write
316 * N items of type T, the valid range of startIdx is between 0 and N-1;
317 *
318 * @return Whether the write operation of size 'nMessages' succeeded.
319 */
320 bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
321
322 /*
323 * Helper method to read 'nMessages' items of type T from the memory
324 * regions described by the object starting from 'startIdx'. This method uses
325 * memcpy() and is not meant to be used for a zero copy operation. Partial reads
326 * are not supported.
327 *
328 * @param data Pointer to the destination buffer.
329 * @param nMessages Number of items of type T.
330 * @param startIdx The slot number to begin the read from. If the
331 * MemTransaction object is representing the memory region to read/write
332 * N items of type T, the valid range of startIdx is between 0 and N-1.
333 *
334 * @return Whether the read operation of size 'nMessages' succeeded.
335 */
336 bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
337
338 /**
339 * Returns a const reference to the first MemRegion in the
340 * MemTransaction object.
341 */
342 inline const MemRegion& getFirstRegion() const { return first; }
343
344 /**
345 * Returns a const reference to the second MemRegion in the
346 * MemTransaction object.
347 */
348 inline const MemRegion& getSecondRegion() const { return second; }
349
Devin Moore77d279e2020-07-07 10:38:52 -0700350 private:
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800351 /*
352 * Given a start index and the number of messages to be
353 * read/written, this helper method calculates the
354 * number of messages that should should be written to both the first
355 * and second MemRegions and the base addresses to be used for
356 * the read/write operation.
357 *
358 * Returns false if the 'startIdx' and 'nMessages' is
359 * invalid for the MemTransaction object.
360 */
Devin Moore77d279e2020-07-07 10:38:52 -0700361 bool inline getMemRegionInfo(size_t idx, size_t nMessages, size_t& firstCount,
362 size_t& secondCount, T** firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800363 T** secondBaseAddress);
364 MemRegion first;
365 MemRegion second;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800366 };
367
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800368 /**
369 * Get a MemTransaction object to write 'nMessages' items of type T.
370 * Once the write is performed using the information from MemTransaction,
371 * the write operation is to be committed using a call to commitWrite().
372 *
373 * @param nMessages Number of messages of type T.
374 * @param Pointer to MemTransaction struct that describes memory to write 'nMessages'
375 * items of type T. If a write of size 'nMessages' is not possible, the base
376 * addresses in the MemTransaction object would be set to nullptr.
377 *
378 * @return Whether it is possible to write 'nMessages' items of type T
379 * into the FMQ.
380 */
381 bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800382
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800383 /**
384 * Commit a write of size 'nMessages'. To be only used after a call to beginWrite().
385 *
386 * @param nMessages number of messages of type T to be written.
387 *
388 * @return Whether the write operation of size 'nMessages' succeeded.
389 */
390 bool commitWrite(size_t nMessages);
391
392 /**
393 * Get a MemTransaction object to read 'nMessages' items of type T.
394 * Once the read is performed using the information from MemTransaction,
395 * the read operation is to be committed using a call to commitRead().
396 *
397 * @param nMessages Number of messages of type T.
398 * @param pointer to MemTransaction struct that describes memory to read 'nMessages'
399 * items of type T. If a read of size 'nMessages' is not possible, the base
400 * pointers in the MemTransaction object returned will be set to nullptr.
401 *
402 * @return bool Whether it is possible to read 'nMessages' items of type T
403 * from the FMQ.
404 */
405 bool beginRead(size_t nMessages, MemTransaction* memTx) const;
406
407 /**
408 * Commit a read of size 'nMessages'. To be only used after a call to beginRead().
409 * For the unsynchronized flavor of FMQ, this method will return a failure
410 * if a write overflow happened after beginRead() was invoked.
411 *
412 * @param nMessages number of messages of type T to be read.
413 *
414 * @return bool Whether the read operation of size 'nMessages' succeeded.
415 */
416 bool commitRead(size_t nMessages);
417
Devin Moore77d279e2020-07-07 10:38:52 -0700418 private:
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800419 size_t availableToWriteBytes() const;
420 size_t availableToReadBytes() const;
421
Devin Moore9a27da52020-07-06 14:01:21 -0700422 MessageQueueBase(const MessageQueueBase& other) = delete;
423 MessageQueueBase& operator=(const MessageQueueBase& other) = delete;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800424
425 void* mapGrantorDescr(uint32_t grantorIdx);
426 void unmapGrantorDescr(void* address, uint32_t grantorIdx);
427 void initMemory(bool resetPointers);
428
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800429 enum DefaultEventNotification : uint32_t {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800430 /*
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700431 * These are only used internally by the readBlocking()/writeBlocking()
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800432 * methods and hence once other bit combinations are not required.
433 */
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700434 FMQ_NOT_FULL = 0x01,
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800435 FMQ_NOT_EMPTY = 0x02
436 };
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800437 std::unique_ptr<Descriptor> mDesc;
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800438 uint8_t* mRing = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800439 /*
440 * TODO(b/31550092): Change to 32 bit read and write pointer counters.
441 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800442 std::atomic<uint64_t>* mReadPtr = nullptr;
443 std::atomic<uint64_t>* mWritePtr = nullptr;
444
445 std::atomic<uint32_t>* mEvFlagWord = nullptr;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800446
447 /*
448 * This EventFlag object will be owned by the FMQ and will have the same
449 * lifetime.
450 */
451 android::hardware::EventFlag* mEventFlag = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800452};
453
Devin Moore133cb5e2020-07-07 16:31:22 -0700454template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700455T* MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getSlot(size_t idx) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800456 size_t firstRegionLength = first.getLength();
457 size_t secondRegionLength = second.getLength();
458
459 if (idx > firstRegionLength + secondRegionLength) {
460 return nullptr;
461 }
462
463 if (idx < firstRegionLength) {
464 return first.getAddress() + idx;
465 }
466
467 return second.getAddress() + idx - firstRegionLength;
468}
469
Devin Moore133cb5e2020-07-07 16:31:22 -0700470template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700471bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getMemRegionInfo(
472 size_t startIdx, size_t nMessages, size_t& firstCount, size_t& secondCount,
473 T** firstBaseAddress, T** secondBaseAddress) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800474 size_t firstRegionLength = first.getLength();
475 size_t secondRegionLength = second.getLength();
476
477 if (startIdx + nMessages > firstRegionLength + secondRegionLength) {
478 /*
479 * Return false if 'nMessages' starting at 'startIdx' cannot be
480 * accomodated by the MemTransaction object.
481 */
482 return false;
483 }
484
485 /* Number of messages to be read/written to the first MemRegion. */
Devin Moore77d279e2020-07-07 10:38:52 -0700486 firstCount =
487 startIdx < firstRegionLength ? std::min(nMessages, firstRegionLength - startIdx) : 0;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800488
489 /* Number of messages to be read/written to the second MemRegion. */
490 secondCount = nMessages - firstCount;
491
492 if (firstCount != 0) {
493 *firstBaseAddress = first.getAddress() + startIdx;
494 }
495
496 if (secondCount != 0) {
497 size_t secondStartIdx = startIdx > firstRegionLength ? startIdx - firstRegionLength : 0;
498 *secondBaseAddress = second.getAddress() + secondStartIdx;
499 }
500
501 return true;
502}
503
Devin Moore133cb5e2020-07-07 16:31:22 -0700504template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700505bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyFrom(T* data,
506 size_t startIdx,
507 size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800508 if (data == nullptr) {
509 return false;
510 }
511
512 size_t firstReadCount = 0, secondReadCount = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700513 T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800514
Devin Moore77d279e2020-07-07 10:38:52 -0700515 if (getMemRegionInfo(startIdx, nMessages, firstReadCount, secondReadCount, &firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800516 &secondBaseAddress) == false) {
517 /*
518 * Returns false if 'startIdx' and 'nMessages' are invalid for this
519 * MemTransaction object.
520 */
521 return false;
522 }
523
524 if (firstReadCount != 0) {
525 memcpy(data, firstBaseAddress, firstReadCount * sizeof(T));
526 }
527
528 if (secondReadCount != 0) {
Devin Moore77d279e2020-07-07 10:38:52 -0700529 memcpy(data + firstReadCount, secondBaseAddress, secondReadCount * sizeof(T));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800530 }
531
532 return true;
533}
534
Devin Moore133cb5e2020-07-07 16:31:22 -0700535template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700536bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyTo(const T* data,
537 size_t startIdx,
538 size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800539 if (data == nullptr) {
540 return false;
541 }
542
543 size_t firstWriteCount = 0, secondWriteCount = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700544 T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800545
Devin Moore77d279e2020-07-07 10:38:52 -0700546 if (getMemRegionInfo(startIdx, nMessages, firstWriteCount, secondWriteCount, &firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800547 &secondBaseAddress) == false) {
548 /*
549 * Returns false if 'startIdx' and 'nMessages' are invalid for this
550 * MemTransaction object.
551 */
552 return false;
553 }
554
555 if (firstWriteCount != 0) {
556 memcpy(firstBaseAddress, data, firstWriteCount * sizeof(T));
557 }
558
559 if (secondWriteCount != 0) {
Devin Moore77d279e2020-07-07 10:38:52 -0700560 memcpy(secondBaseAddress, data + firstWriteCount, secondWriteCount * sizeof(T));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800561 }
562
563 return true;
564}
565
Devin Moore133cb5e2020-07-07 16:31:22 -0700566template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700567void MessageQueueBase<MQDescriptorType, T, flavor>::initMemory(bool resetPointers) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800568 /*
Devin Moore9a27da52020-07-06 14:01:21 -0700569 * Verify that the Descriptor contains the minimum number of grantors
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800570 * the native_handle is valid and T matches quantum size.
571 */
572 if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
Devin Moore133cb5e2020-07-07 16:31:22 -0700573 (mDesc->countGrantors() < hardware::details::kMinGrantorCount) ||
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800574 (mDesc->getQuantum() != sizeof(T))) {
575 return;
576 }
Devin Moore133cb5e2020-07-07 16:31:22 -0700577 const auto& grantors = mDesc->grantors();
578 for (const auto& grantor : grantors) {
579 if (hardware::details::isAlignedToWordBoundary(grantor.offset) == false) {
580 __assert(__FILE__, __LINE__, "Grantor offsets need to be aligned");
581 }
582 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800583
Devin Moore133cb5e2020-07-07 16:31:22 -0700584 if (flavor == kSynchronizedReadWrite) {
585 mReadPtr = reinterpret_cast<std::atomic<uint64_t>*>(
586 mapGrantorDescr(hardware::details::READPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800587 } else {
588 /*
589 * The unsynchronized write flavor of the FMQ may have multiple readers
590 * and each reader would have their own read pointer counter.
591 */
592 mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
593 }
594
Devin Moore9a27da52020-07-06 14:01:21 -0700595 hardware::details::check(mReadPtr != nullptr);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800596
Devin Moore133cb5e2020-07-07 16:31:22 -0700597 mWritePtr = reinterpret_cast<std::atomic<uint64_t>*>(
598 mapGrantorDescr(hardware::details::WRITEPTRPOS));
Devin Moore9a27da52020-07-06 14:01:21 -0700599 hardware::details::check(mWritePtr != nullptr);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800600
601 if (resetPointers) {
602 mReadPtr->store(0, std::memory_order_release);
603 mWritePtr->store(0, std::memory_order_release);
Devin Moore133cb5e2020-07-07 16:31:22 -0700604 } else if (flavor != kSynchronizedReadWrite) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800605 // Always reset the read pointer.
606 mReadPtr->store(0, std::memory_order_release);
607 }
608
Devin Moore133cb5e2020-07-07 16:31:22 -0700609 mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(hardware::details::DATAPTRPOS));
Devin Moore9a27da52020-07-06 14:01:21 -0700610 hardware::details::check(mRing != nullptr);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800611
Devin Moore133cb5e2020-07-07 16:31:22 -0700612 mEvFlagWord =
613 static_cast<std::atomic<uint32_t>*>(mapGrantorDescr(hardware::details::EVFLAGWORDPOS));
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800614 if (mEvFlagWord != nullptr) {
615 android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
616 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800617}
618
Devin Moore133cb5e2020-07-07 16:31:22 -0700619template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700620MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(const Descriptor& Desc,
621 bool resetPointers) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800622 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800623 if (mDesc == nullptr) {
624 return;
625 }
626
627 initMemory(resetPointers);
628}
629
Devin Moore133cb5e2020-07-07 16:31:22 -0700630template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700631MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(size_t numElementsInQueue,
632 bool configureEventFlagWord) {
Kevin Rocard1d6e40f2017-04-03 11:51:13 -0700633 // Check if the buffer size would not overflow size_t
634 if (numElementsInQueue > SIZE_MAX / sizeof(T)) {
635 return;
636 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800637 /*
638 * The FMQ needs to allocate memory for the ringbuffer as well as for the
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800639 * read and write pointer counters. If an EventFlag word is to be configured,
640 * we also need to allocate memory for the same/
641 */
642 size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
Devin Moore133cb5e2020-07-07 16:31:22 -0700643 size_t kMetaDataSize = 2 * sizeof(android::hardware::details::RingBufferPosition);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800644
645 if (configureEventFlagWord) {
Devin Moore77d279e2020-07-07 10:38:52 -0700646 kMetaDataSize += sizeof(std::atomic<uint32_t>);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800647 }
648
649 /*
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800650 * Ashmem memory region size needs to be specified in page-aligned bytes.
651 * kQueueSizeBytes needs to be aligned to word boundary so that all offsets
652 * in the grantorDescriptor will be word aligned.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800653 */
Devin Moore133cb5e2020-07-07 16:31:22 -0700654 size_t kAshmemSizePageAligned = (hardware::details::alignToWordBoundary(kQueueSizeBytes) +
655 kMetaDataSize + PAGE_SIZE - 1) &
656 ~(PAGE_SIZE - 1);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800657
658 /*
659 * Create an ashmem region to map the memory for the ringbuffer,
660 * read counter and write counter.
661 */
662 int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
663 ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
664
665 /*
666 * The native handle will contain the fds to be mapped.
667 */
Devin Moore77d279e2020-07-07 10:38:52 -0700668 native_handle_t* mqHandle = native_handle_create(1 /* numFds */, 0 /* numInts */);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800669 if (mqHandle == nullptr) {
670 return;
671 }
672
673 mqHandle->data[0] = ashmemFd;
Devin Moore77d279e2020-07-07 10:38:52 -0700674 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(
675 kQueueSizeBytes, mqHandle, sizeof(T), configureEventFlagWord));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800676 if (mDesc == nullptr) {
677 return;
678 }
679 initMemory(true);
680}
681
Devin Moore133cb5e2020-07-07 16:31:22 -0700682template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700683MessageQueueBase<MQDescriptorType, T, flavor>::~MessageQueueBase() {
Devin Moore133cb5e2020-07-07 16:31:22 -0700684 if (flavor == kUnsynchronizedWrite) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800685 delete mReadPtr;
686 } else {
Devin Moore133cb5e2020-07-07 16:31:22 -0700687 unmapGrantorDescr(mReadPtr, hardware::details::READPTRPOS);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800688 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800689 if (mWritePtr != nullptr) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700690 unmapGrantorDescr(mWritePtr, hardware::details::WRITEPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800691 }
692 if (mRing != nullptr) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700693 unmapGrantorDescr(mRing, hardware::details::DATAPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800694 }
695 if (mEvFlagWord != nullptr) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700696 unmapGrantorDescr(mEvFlagWord, hardware::details::EVFLAGWORDPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800697 android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
698 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800699}
700
Devin Moore133cb5e2020-07-07 16:31:22 -0700701template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700702bool MessageQueueBase<MQDescriptorType, T, flavor>::write(const T* data) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800703 return write(data, 1);
704}
705
Devin Moore133cb5e2020-07-07 16:31:22 -0700706template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700707bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800708 return read(data, 1);
709}
710
Devin Moore133cb5e2020-07-07 16:31:22 -0700711template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700712bool MessageQueueBase<MQDescriptorType, T, flavor>::write(const T* data, size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800713 MemTransaction tx;
Devin Moore77d279e2020-07-07 10:38:52 -0700714 return beginWrite(nMessages, &tx) && tx.copyTo(data, 0 /* startIdx */, nMessages) &&
715 commitWrite(nMessages);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800716}
717
Devin Moore133cb5e2020-07-07 16:31:22 -0700718template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700719bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(
720 const T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
721 int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700722 static_assert(flavor == kSynchronizedReadWrite,
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700723 "writeBlocking can only be used with the "
Devin Moore133cb5e2020-07-07 16:31:22 -0700724 "kSynchronizedReadWrite flavor.");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800725 /*
726 * If evFlag is null and the FMQ does not have its own EventFlag object
727 * return false;
Devin Moore133cb5e2020-07-07 16:31:22 -0700728 * If the flavor is kSynchronizedReadWrite and the readNotification
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800729 * bit mask is zero return false;
730 * If the count is greater than queue size, return false
731 * to prevent blocking until timeOut.
732 */
733 if (evFlag == nullptr) {
734 evFlag = mEventFlag;
735 if (evFlag == nullptr) {
Devin Moore9a27da52020-07-06 14:01:21 -0700736 hardware::details::logError(
Devin Moore77d279e2020-07-07 10:38:52 -0700737 "writeBlocking failed: called on MessageQueue with no Eventflag"
738 "configured or provided");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800739 return false;
740 }
741 }
742
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700743 if (readNotification == 0 || (count > getQuantumCount())) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800744 return false;
745 }
746
747 /*
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700748 * There is no need to wait for a readNotification if there is sufficient
749 * space to write is already present in the FMQ. The latter would be the case when
750 * read operations read more number of messages than write operations write.
751 * In other words, a single large read may clear the FMQ after multiple small
752 * writes. This would fail to clear a pending readNotification bit since
753 * EventFlag bits can only be cleared by a wait() call, however the bit would
754 * be correctly cleared by the next writeBlocking() call.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800755 */
756
757 bool result = write(data, count);
758 if (result) {
759 if (writeNotification) {
760 evFlag->wake(writeNotification);
761 }
762 return result;
763 }
764
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800765 bool shouldTimeOut = timeOutNanos != 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700766 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800767
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700768 while (true) {
769 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800770 if (shouldTimeOut) {
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700771 /*
772 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
773 * to Nanoseconds)
774 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800775 int64_t currentTimeNs = android::elapsedRealtimeNano();
776 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700777 * Decrement 'timeOutNanos' to account for the time taken to complete the last
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800778 * iteration of the while loop.
779 */
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700780 timeOutNanos -= currentTimeNs - prevTimeNanos;
781 prevTimeNanos = currentTimeNs;
782
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800783 if (timeOutNanos <= 0) {
784 /*
785 * Attempt write in case a context switch happened outside of
786 * evFlag->wait().
787 */
788 result = write(data, count);
789 break;
790 }
791 }
792
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800793 /*
794 * wait() will return immediately if there was a pending read
795 * notification.
796 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800797 uint32_t efState = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700798 status_t status = evFlag->wait(readNotification, &efState, timeOutNanos,
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700799 true /* retry on spurious wake */);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800800
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700801 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
Devin Moore9a27da52020-07-06 14:01:21 -0700802 hardware::details::logError("Unexpected error code from EventFlag Wait status " +
803 std::to_string(status));
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700804 break;
805 }
806
807 if (status == android::TIMED_OUT) {
808 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800809 }
810
811 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700812 * If there is still insufficient space to write to the FMQ,
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800813 * keep waiting for another readNotification.
814 */
815 if ((efState & readNotification) && write(data, count)) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800816 result = true;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700817 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800818 }
819 }
820
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800821 if (result && writeNotification != 0) {
822 evFlag->wake(writeNotification);
823 }
824
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800825 return result;
826}
827
Devin Moore133cb5e2020-07-07 16:31:22 -0700828template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700829bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(const T* data, size_t count,
830 int64_t timeOutNanos) {
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800831 return writeBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
832}
833
Devin Moore133cb5e2020-07-07 16:31:22 -0700834template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700835bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(
836 T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
837 int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700838 static_assert(flavor == kSynchronizedReadWrite,
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700839 "readBlocking can only be used with the "
Devin Moore133cb5e2020-07-07 16:31:22 -0700840 "kSynchronizedReadWrite flavor.");
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700841
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800842 /*
843 * If evFlag is null and the FMQ does not own its own EventFlag object
844 * return false;
845 * If the writeNotification bit mask is zero return false;
846 * If the count is greater than queue size, return false to prevent
847 * blocking until timeOut.
848 */
849 if (evFlag == nullptr) {
850 evFlag = mEventFlag;
851 if (evFlag == nullptr) {
Devin Moore9a27da52020-07-06 14:01:21 -0700852 hardware::details::logError(
Devin Moore77d279e2020-07-07 10:38:52 -0700853 "readBlocking failed: called on MessageQueue with no Eventflag"
854 "configured or provided");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800855 return false;
856 }
857 }
858
859 if (writeNotification == 0 || count > getQuantumCount()) {
860 return false;
861 }
862
863 /*
864 * There is no need to wait for a write notification if sufficient
865 * data to read is already present in the FMQ. This would be the
866 * case when read operations read lesser number of messages than
867 * a write operation and multiple reads would be required to clear the queue
868 * after a single write operation. This check would fail to clear a pending
869 * writeNotification bit since EventFlag bits can only be cleared
870 * by a wait() call, however the bit would be correctly cleared by the next
871 * readBlocking() call.
872 */
873
874 bool result = read(data, count);
875 if (result) {
876 if (readNotification) {
877 evFlag->wake(readNotification);
878 }
879 return result;
880 }
881
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800882 bool shouldTimeOut = timeOutNanos != 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700883 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800884
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700885 while (true) {
886 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800887 if (shouldTimeOut) {
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700888 /*
889 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
890 * to Nanoseconds)
891 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800892 int64_t currentTimeNs = android::elapsedRealtimeNano();
893 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700894 * Decrement 'timeOutNanos' to account for the time taken to complete the last
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800895 * iteration of the while loop.
896 */
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700897 timeOutNanos -= currentTimeNs - prevTimeNanos;
898 prevTimeNanos = currentTimeNs;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800899
900 if (timeOutNanos <= 0) {
901 /*
902 * Attempt read in case a context switch happened outside of
903 * evFlag->wait().
904 */
905 result = read(data, count);
906 break;
907 }
908 }
909
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800910 /*
911 * wait() will return immediately if there was a pending write
912 * notification.
913 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800914 uint32_t efState = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700915 status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos,
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700916 true /* retry on spurious wake */);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800917
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700918 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
Devin Moore9a27da52020-07-06 14:01:21 -0700919 hardware::details::logError("Unexpected error code from EventFlag Wait status " +
920 std::to_string(status));
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700921 break;
922 }
923
924 if (status == android::TIMED_OUT) {
925 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800926 }
927
928 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700929 * If the data in FMQ is still insufficient, go back to waiting
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800930 * for another write notification.
931 */
932 if ((efState & writeNotification) && read(data, count)) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800933 result = true;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700934 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800935 }
936 }
937
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800938 if (result && readNotification != 0) {
939 evFlag->wake(readNotification);
940 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800941 return result;
942}
943
Devin Moore133cb5e2020-07-07 16:31:22 -0700944template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700945bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(T* data, size_t count,
946 int64_t timeOutNanos) {
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800947 return readBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
948}
949
Devin Moore133cb5e2020-07-07 16:31:22 -0700950template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700951size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWriteBytes() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800952 return mDesc->getSize() - availableToReadBytes();
953}
954
Devin Moore133cb5e2020-07-07 16:31:22 -0700955template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700956size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWrite() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800957 return availableToWriteBytes() / sizeof(T);
958}
959
Devin Moore133cb5e2020-07-07 16:31:22 -0700960template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700961size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToRead() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800962 return availableToReadBytes() / sizeof(T);
963}
964
Devin Moore133cb5e2020-07-07 16:31:22 -0700965template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700966bool MessageQueueBase<MQDescriptorType, T, flavor>::beginWrite(size_t nMessages,
967 MemTransaction* result) const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800968 /*
969 * If nMessages is greater than size of FMQ or in case of the synchronized
970 * FMQ flavor, if there is not enough space to write nMessages, then return
971 * result with null addresses.
972 */
Devin Moore133cb5e2020-07-07 16:31:22 -0700973 if ((flavor == kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800974 nMessages > getQuantumCount()) {
975 *result = MemTransaction();
976 return false;
977 }
978
979 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
980 size_t writeOffset = writePtr % mDesc->getSize();
981
982 /*
983 * From writeOffset, the number of messages that can be written
984 * contiguously without wrapping around the ring buffer are calculated.
985 */
986 size_t contiguousMessages = (mDesc->getSize() - writeOffset) / sizeof(T);
987
988 if (contiguousMessages < nMessages) {
989 /*
990 * Wrap around is required. Both result.first and result.second are
991 * populated.
992 */
Devin Moore77d279e2020-07-07 10:38:52 -0700993 *result = MemTransaction(
994 MemRegion(reinterpret_cast<T*>(mRing + writeOffset), contiguousMessages),
995 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800996 } else {
997 /*
998 * A wrap around is not required to write nMessages. Only result.first
999 * is populated.
1000 */
1001 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset), nMessages),
1002 MemRegion());
1003 }
1004
1005 return true;
1006}
1007
Devin Moore133cb5e2020-07-07 16:31:22 -07001008template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001009/*
1010 * Disable integer sanitization since integer overflow here is allowed
1011 * and legal.
1012 */
Devin Moore9a27da52020-07-06 14:01:21 -07001013__attribute__((no_sanitize("integer"))) bool
1014MessageQueueBase<MQDescriptorType, T, flavor>::commitWrite(size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001015 size_t nBytesWritten = nMessages * sizeof(T);
1016 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
1017 writePtr += nBytesWritten;
1018 mWritePtr->store(writePtr, std::memory_order_release);
1019 /*
1020 * This method cannot fail now since we are only incrementing the writePtr
1021 * counter.
1022 */
1023 return true;
1024}
1025
Devin Moore133cb5e2020-07-07 16:31:22 -07001026template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001027size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToReadBytes() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001028 /*
1029 * This method is invoked by implementations of both read() and write() and
Devin Moore9a27da52020-07-06 14:01:21 -07001030 * hence requires a memory_order_acquired load for both mReadPtr and
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001031 * mWritePtr.
1032 */
Devin Moore77d279e2020-07-07 10:38:52 -07001033 return mWritePtr->load(std::memory_order_acquire) - mReadPtr->load(std::memory_order_acquire);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001034}
1035
Devin Moore133cb5e2020-07-07 16:31:22 -07001036template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001037bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data, size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001038 MemTransaction tx;
Devin Moore77d279e2020-07-07 10:38:52 -07001039 return beginRead(nMessages, &tx) && tx.copyFrom(data, 0 /* startIdx */, nMessages) &&
1040 commitRead(nMessages);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001041}
1042
Devin Moore133cb5e2020-07-07 16:31:22 -07001043template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001044/*
1045 * Disable integer sanitization since integer overflow here is allowed
1046 * and legal.
1047 */
Devin Moore9a27da52020-07-06 14:01:21 -07001048__attribute__((no_sanitize("integer"))) bool
1049MessageQueueBase<MQDescriptorType, T, flavor>::beginRead(size_t nMessages,
1050 MemTransaction* result) const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001051 *result = MemTransaction();
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001052 /*
1053 * If it is detected that the data in the queue was overwritten
1054 * due to the reader process being too slow, the read pointer counter
1055 * is set to the same as the write pointer counter to indicate error
1056 * and the read returns false;
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001057 * Need acquire/release memory ordering for mWritePtr.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001058 */
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001059 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1060 /*
1061 * A relaxed load is sufficient for mReadPtr since there will be no
1062 * stores to mReadPtr from a different thread.
1063 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001064 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
1065
1066 if (writePtr - readPtr > mDesc->getSize()) {
1067 mReadPtr->store(writePtr, std::memory_order_release);
1068 return false;
1069 }
1070
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001071 size_t nBytesDesired = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001072 /*
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001073 * Return if insufficient data to read in FMQ.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001074 */
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001075 if (writePtr - readPtr < nBytesDesired) {
1076 return false;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001077 }
1078
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001079 size_t readOffset = readPtr % mDesc->getSize();
1080 /*
1081 * From readOffset, the number of messages that can be read contiguously
1082 * without wrapping around the ring buffer are calculated.
1083 */
1084 size_t contiguousMessages = (mDesc->getSize() - readOffset) / sizeof(T);
1085
1086 if (contiguousMessages < nMessages) {
1087 /*
1088 * A wrap around is required. Both result.first and result.second
1089 * are populated.
1090 */
Devin Moore77d279e2020-07-07 10:38:52 -07001091 *result = MemTransaction(
1092 MemRegion(reinterpret_cast<T*>(mRing + readOffset), contiguousMessages),
1093 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001094 } else {
1095 /*
1096 * A wrap around is not required. Only result.first need to be
1097 * populated.
1098 */
1099 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset), nMessages),
1100 MemRegion());
1101 }
1102
1103 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001104}
1105
Devin Moore133cb5e2020-07-07 16:31:22 -07001106template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001107/*
1108 * Disable integer sanitization since integer overflow here is allowed
1109 * and legal.
1110 */
Devin Moore9a27da52020-07-06 14:01:21 -07001111__attribute__((no_sanitize("integer"))) bool
1112MessageQueueBase<MQDescriptorType, T, flavor>::commitRead(size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001113 // TODO: Use a local copy of readPtr to avoid relazed mReadPtr loads.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001114 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001115 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1116 /*
1117 * If the flavor is unsynchronized, it is possible that a write overflow may
Devin Moore9a27da52020-07-06 14:01:21 -07001118 * have occurred between beginRead() and commitRead().
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001119 */
1120 if (writePtr - readPtr > mDesc->getSize()) {
1121 mReadPtr->store(writePtr, std::memory_order_release);
1122 return false;
1123 }
1124
1125 size_t nBytesRead = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001126 readPtr += nBytesRead;
1127 mReadPtr->store(readPtr, std::memory_order_release);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001128 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001129}
1130
Devin Moore133cb5e2020-07-07 16:31:22 -07001131template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001132size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumSize() const {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001133 return mDesc->getQuantum();
1134}
1135
Devin Moore133cb5e2020-07-07 16:31:22 -07001136template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001137size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumCount() const {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001138 return mDesc->getSize() / mDesc->getQuantum();
1139}
1140
Devin Moore133cb5e2020-07-07 16:31:22 -07001141template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001142bool MessageQueueBase<MQDescriptorType, T, flavor>::isValid() const {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001143 return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
1144}
1145
Devin Moore133cb5e2020-07-07 16:31:22 -07001146template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001147void* MessageQueueBase<MQDescriptorType, T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001148 const native_handle_t* handle = mDesc->handle();
1149 auto grantors = mDesc->grantors();
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001150 if (handle == nullptr) {
Devin Moore9a27da52020-07-06 14:01:21 -07001151 hardware::details::logError("mDesc->handle is null");
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001152 return nullptr;
1153 }
1154
1155 if (grantorIdx >= grantors.size()) {
Devin Moore9a27da52020-07-06 14:01:21 -07001156 hardware::details::logError(std::string("grantorIdx must be less than ") +
1157 std::to_string(grantors.size()));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001158 return nullptr;
1159 }
1160
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001161 int fdIndex = grantors[grantorIdx].fdIndex;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001162 /*
1163 * Offset for mmap must be a multiple of PAGE_SIZE.
1164 */
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001165 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
Devin Moore77d279e2020-07-07 10:38:52 -07001166 int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001167
Devin Moore77d279e2020-07-07 10:38:52 -07001168 void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED, handle->data[fdIndex],
1169 mapOffset);
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001170 if (address == MAP_FAILED) {
Devin Moore9a27da52020-07-06 14:01:21 -07001171 hardware::details::logError(std::string("mmap failed: ") + std::to_string(errno));
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001172 return nullptr;
1173 }
1174 return reinterpret_cast<uint8_t*>(address) + (grantors[grantorIdx].offset - mapOffset);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001175}
1176
Devin Moore133cb5e2020-07-07 16:31:22 -07001177template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001178void MessageQueueBase<MQDescriptorType, T, flavor>::unmapGrantorDescr(void* address,
1179 uint32_t grantorIdx) {
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001180 auto grantors = mDesc->grantors();
1181 if ((address == nullptr) || (grantorIdx >= grantors.size())) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001182 return;
1183 }
1184
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001185 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
Devin Moore77d279e2020-07-07 10:38:52 -07001186 int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
1187 void* baseAddress =
1188 reinterpret_cast<uint8_t*>(address) - (grantors[grantorIdx].offset - mapOffset);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001189 if (baseAddress) munmap(baseAddress, mapLength);
1190}
1191
1192} // namespace hardware