blob: 0cb83a6c956fa5d587e113d7cdb057ad8d706af9 [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 Moore133cb5e2020-07-07 16:31:22 -070033template <template <typename, MQFlavor> class MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -070034struct MessageQueueBase {
35 typedef MQDescriptorType<T, flavor> Descriptor;
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -080036
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080037 /**
38 * @param Desc MQDescriptor describing the FMQ.
39 * @param resetPointers bool indicating whether the read/write pointers
40 * should be reset or not.
41 */
Devin Moore9a27da52020-07-06 14:01:21 -070042 MessageQueueBase(const Descriptor& Desc, bool resetPointers = true);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080043
Devin Moore9a27da52020-07-06 14:01:21 -070044 ~MessageQueueBase();
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080045
46 /**
47 * This constructor uses Ashmem shared memory to create an FMQ
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080048 * that can contain a maximum of 'numElementsInQueue' elements of type T.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080049 *
50 * @param numElementsInQueue Capacity of the MessageQueue in terms of T.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -080051 * @param configureEventFlagWord Boolean that specifies if memory should
52 * also be allocated and mapped for an EventFlag word.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080053 */
Devin Moore9a27da52020-07-06 14:01:21 -070054
55 MessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord = false);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080056
57 /**
58 * @return Number of items of type T that can be written into the FMQ
59 * without a read.
60 */
61 size_t availableToWrite() const;
62
63 /**
64 * @return Number of items of type T that are waiting to be read from the
65 * FMQ.
66 */
67 size_t availableToRead() const;
68
69 /**
70 * Returns the size of type T in bytes.
71 *
72 * @param Size of T.
73 */
74 size_t getQuantumSize() const;
75
76 /**
77 * Returns the size of the FMQ in terms of the size of type T.
78 *
79 * @return Number of items of type T that will fit in the FMQ.
80 */
81 size_t getQuantumCount() const;
82
83 /**
84 * @return Whether the FMQ is configured correctly.
85 */
86 bool isValid() const;
87
88 /**
89 * Non-blocking write to FMQ.
90 *
91 * @param data Pointer to the object of type T to be written into the FMQ.
92 *
93 * @return Whether the write was successful.
94 */
95 bool write(const T* data);
96
97 /**
98 * Non-blocking read from FMQ.
99 *
100 * @param data Pointer to the memory where the object read from the FMQ is
101 * copied to.
102 *
103 * @return Whether the read was successful.
104 */
105 bool read(T* data);
106
107 /**
108 * Write some data into the FMQ without blocking.
109 *
110 * @param data Pointer to the array of items of type T.
111 * @param count Number of items in array.
112 *
113 * @return Whether the write was successful.
114 */
115 bool write(const T* data, size_t count);
116
117 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800118 * Perform a blocking write of 'count' items into the FMQ using EventFlags.
119 * Does not support partial writes.
120 *
121 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
122 * associated with the FMQ and it is used in that case.
123 *
124 * The application code must ensure that 'evFlag' used by the
125 * reader(s)/writer is based upon the same EventFlag word.
126 *
127 * The method will return false without blocking if any of the following
128 * conditions are true:
129 * - If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700130 * - If the 'readNotification' bit mask is zero.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800131 * - If 'count' is greater than the FMQ size.
132 *
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700133 * If the there is insufficient space available to write into it, the
134 * EventFlag bit mask 'readNotification' is is waited upon.
135 *
136 * This method should only be used with a MessageQueue of the flavor
Devin Moore133cb5e2020-07-07 16:31:22 -0700137 * 'kSynchronizedReadWrite'.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800138 *
139 * Upon a successful write, wake is called on 'writeNotification' (if
140 * non-zero).
141 *
142 * @param data Pointer to the array of items of type T.
143 * @param count Number of items in array.
144 * @param readNotification The EventFlag bit mask to wait on if there is not
145 * enough space in FMQ to write 'count' items.
146 * @param writeNotification The EventFlag bit mask to call wake on
147 * a successful write. No wake is called if 'writeNotification' is zero.
148 * @param timeOutNanos Number of nanoseconds after which the blocking
149 * write attempt is aborted.
150 * @param evFlag The EventFlag object to be used for blocking. If nullptr,
151 * it is checked whether the FMQ owns an EventFlag object and that is used
152 * for blocking instead.
153 *
154 * @return Whether the write was successful.
155 */
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800156 bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
157 uint32_t writeNotification, int64_t timeOutNanos = 0,
158 android::hardware::EventFlag* evFlag = nullptr);
159
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800160 bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
161
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800162 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800163 * Read some data from the FMQ without blocking.
164 *
165 * @param data Pointer to the array to which read data is to be written.
166 * @param count Number of items to be read.
167 *
168 * @return Whether the read was successful.
169 */
170 bool read(T* data, size_t count);
171
172 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800173 * Perform a blocking read operation of 'count' items from the FMQ. Does not
174 * perform a partial read.
175 *
176 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
177 * associated with the FMQ and it is used in that case.
178 *
179 * The application code must ensure that 'evFlag' used by the
180 * reader(s)/writer is based upon the same EventFlag word.
181 *
182 * The method will return false without blocking if any of the following
183 * conditions are true:
184 * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
185 * -If the 'writeNotification' bit mask is zero.
186 * -If 'count' is greater than the FMQ size.
187 *
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700188 * This method should only be used with a MessageQueue of the flavor
Devin Moore133cb5e2020-07-07 16:31:22 -0700189 * 'kSynchronizedReadWrite'.
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700190
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800191 * If FMQ does not contain 'count' items, the eventFlag bit mask
192 * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
193 * wake is called on 'readNotification' (if non-zero).
194 *
195 * @param data Pointer to the array to which read data is to be written.
196 * @param count Number of items to be read.
197 * @param readNotification The EventFlag bit mask to call wake on after
198 * a successful read. No wake is called if 'readNotification' is zero.
199 * @param writeNotification The EventFlag bit mask to call a wait on
200 * if there is insufficient data in the FMQ to be read.
201 * @param timeOutNanos Number of nanoseconds after which the blocking
202 * read attempt is aborted.
203 * @param evFlag The EventFlag object to be used for blocking.
204 *
205 * @return Whether the read was successful.
206 */
Devin Moore77d279e2020-07-07 10:38:52 -0700207 bool readBlocking(T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
208 int64_t timeOutNanos = 0, android::hardware::EventFlag* evFlag = nullptr);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800209
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800210 bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);
211
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800212 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800213 * Get a pointer to the MQDescriptor object that describes this FMQ.
214 *
215 * @return Pointer to the MQDescriptor associated with the FMQ.
216 */
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800217 const Descriptor* getDesc() const { return mDesc.get(); }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800218
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800219 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800220 * Get a pointer to the EventFlag word if there is one associated with this FMQ.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800221 *
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800222 * @return Pointer to an EventFlag word, will return nullptr if not
223 * configured. This method does not transfer ownership. The EventFlag
224 * word will be unmapped by the MessageQueue destructor.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800225 */
226 std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800227
228 /**
229 * Describes a memory region in the FMQ.
230 */
231 struct MemRegion {
232 MemRegion() : MemRegion(nullptr, 0) {}
233
234 MemRegion(T* base, size_t size) : address(base), length(size) {}
235
Devin Moore77d279e2020-07-07 10:38:52 -0700236 MemRegion& operator=(const MemRegion& other) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800237 address = other.address;
238 length = other.length;
239 return *this;
240 }
241
242 /**
243 * Gets a pointer to the base address of the MemRegion.
244 */
245 inline T* getAddress() const { return address; }
246
247 /**
248 * Gets the length of the MemRegion. This would equal to the number
249 * of items of type T that can be read from/written into the MemRegion.
250 */
251 inline size_t getLength() const { return length; }
252
253 /**
254 * Gets the length of the MemRegion in bytes.
255 */
256 inline size_t getLengthInBytes() const { return length * sizeof(T); }
257
Devin Moore77d279e2020-07-07 10:38:52 -0700258 private:
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800259 /* Base address */
260 T* address;
261
262 /*
263 * Number of items of type T that can be written to/read from the base
264 * address.
265 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800266 size_t length;
267 };
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800268
269 /**
270 * Describes the memory regions to be used for a read or write.
271 * The struct contains two MemRegion objects since the FMQ is a ring
272 * buffer and a read or write operation can wrap around. A single message
273 * of type T will never be broken between the two MemRegions.
274 */
275 struct MemTransaction {
276 MemTransaction() : MemTransaction(MemRegion(), MemRegion()) {}
277
Devin Moore77d279e2020-07-07 10:38:52 -0700278 MemTransaction(const MemRegion& regionFirst, const MemRegion& regionSecond)
279 : first(regionFirst), second(regionSecond) {}
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800280
Devin Moore77d279e2020-07-07 10:38:52 -0700281 MemTransaction& operator=(const MemTransaction& other) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800282 first = other.first;
283 second = other.second;
284 return *this;
285 }
286
287 /**
288 * Helper method to calculate the address for a particular index for
289 * the MemTransaction object.
290 *
291 * @param idx Index of the slot to be read/written. If the
292 * MemTransaction object is representing the memory region to read/write
293 * N items of type T, the valid range of idx is between 0 and N-1.
294 *
295 * @return Pointer to the slot idx. Will be nullptr for an invalid idx.
296 */
297 T* getSlot(size_t idx);
298
299 /**
300 * Helper method to write 'nMessages' items of type T into the memory
301 * regions described by the object starting from 'startIdx'. This method
302 * uses memcpy() and is not to meant to be used for a zero copy operation.
303 * Partial writes are not supported.
304 *
305 * @param data Pointer to the source buffer.
306 * @param nMessages Number of items of type T.
307 * @param startIdx The slot number to begin the write from. If the
308 * MemTransaction object is representing the memory region to read/write
309 * N items of type T, the valid range of startIdx is between 0 and N-1;
310 *
311 * @return Whether the write operation of size 'nMessages' succeeded.
312 */
313 bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
314
315 /*
316 * Helper method to read 'nMessages' items of type T from the memory
317 * regions described by the object starting from 'startIdx'. This method uses
318 * memcpy() and is not meant to be used for a zero copy operation. Partial reads
319 * are not supported.
320 *
321 * @param data Pointer to the destination buffer.
322 * @param nMessages Number of items of type T.
323 * @param startIdx The slot number to begin the read from. If the
324 * MemTransaction object is representing the memory region to read/write
325 * N items of type T, the valid range of startIdx is between 0 and N-1.
326 *
327 * @return Whether the read operation of size 'nMessages' succeeded.
328 */
329 bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
330
331 /**
332 * Returns a const reference to the first MemRegion in the
333 * MemTransaction object.
334 */
335 inline const MemRegion& getFirstRegion() const { return first; }
336
337 /**
338 * Returns a const reference to the second MemRegion in the
339 * MemTransaction object.
340 */
341 inline const MemRegion& getSecondRegion() const { return second; }
342
Devin Moore77d279e2020-07-07 10:38:52 -0700343 private:
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800344 /*
345 * Given a start index and the number of messages to be
346 * read/written, this helper method calculates the
347 * number of messages that should should be written to both the first
348 * and second MemRegions and the base addresses to be used for
349 * the read/write operation.
350 *
351 * Returns false if the 'startIdx' and 'nMessages' is
352 * invalid for the MemTransaction object.
353 */
Devin Moore77d279e2020-07-07 10:38:52 -0700354 bool inline getMemRegionInfo(size_t idx, size_t nMessages, size_t& firstCount,
355 size_t& secondCount, T** firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800356 T** secondBaseAddress);
357 MemRegion first;
358 MemRegion second;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800359 };
360
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800361 /**
362 * Get a MemTransaction object to write 'nMessages' items of type T.
363 * Once the write is performed using the information from MemTransaction,
364 * the write operation is to be committed using a call to commitWrite().
365 *
366 * @param nMessages Number of messages of type T.
367 * @param Pointer to MemTransaction struct that describes memory to write 'nMessages'
368 * items of type T. If a write of size 'nMessages' is not possible, the base
369 * addresses in the MemTransaction object would be set to nullptr.
370 *
371 * @return Whether it is possible to write 'nMessages' items of type T
372 * into the FMQ.
373 */
374 bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800375
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800376 /**
377 * Commit a write of size 'nMessages'. To be only used after a call to beginWrite().
378 *
379 * @param nMessages number of messages of type T to be written.
380 *
381 * @return Whether the write operation of size 'nMessages' succeeded.
382 */
383 bool commitWrite(size_t nMessages);
384
385 /**
386 * Get a MemTransaction object to read 'nMessages' items of type T.
387 * Once the read is performed using the information from MemTransaction,
388 * the read operation is to be committed using a call to commitRead().
389 *
390 * @param nMessages Number of messages of type T.
391 * @param pointer to MemTransaction struct that describes memory to read 'nMessages'
392 * items of type T. If a read of size 'nMessages' is not possible, the base
393 * pointers in the MemTransaction object returned will be set to nullptr.
394 *
395 * @return bool Whether it is possible to read 'nMessages' items of type T
396 * from the FMQ.
397 */
398 bool beginRead(size_t nMessages, MemTransaction* memTx) const;
399
400 /**
401 * Commit a read of size 'nMessages'. To be only used after a call to beginRead().
402 * For the unsynchronized flavor of FMQ, this method will return a failure
403 * if a write overflow happened after beginRead() was invoked.
404 *
405 * @param nMessages number of messages of type T to be read.
406 *
407 * @return bool Whether the read operation of size 'nMessages' succeeded.
408 */
409 bool commitRead(size_t nMessages);
410
Devin Moore77d279e2020-07-07 10:38:52 -0700411 private:
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800412 size_t availableToWriteBytes() const;
413 size_t availableToReadBytes() const;
414
Devin Moore9a27da52020-07-06 14:01:21 -0700415 MessageQueueBase(const MessageQueueBase& other) = delete;
416 MessageQueueBase& operator=(const MessageQueueBase& other) = delete;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800417
418 void* mapGrantorDescr(uint32_t grantorIdx);
419 void unmapGrantorDescr(void* address, uint32_t grantorIdx);
420 void initMemory(bool resetPointers);
421
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800422 enum DefaultEventNotification : uint32_t {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800423 /*
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700424 * These are only used internally by the readBlocking()/writeBlocking()
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800425 * methods and hence once other bit combinations are not required.
426 */
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700427 FMQ_NOT_FULL = 0x01,
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800428 FMQ_NOT_EMPTY = 0x02
429 };
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800430 std::unique_ptr<Descriptor> mDesc;
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800431 uint8_t* mRing = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800432 /*
433 * TODO(b/31550092): Change to 32 bit read and write pointer counters.
434 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800435 std::atomic<uint64_t>* mReadPtr = nullptr;
436 std::atomic<uint64_t>* mWritePtr = nullptr;
437
438 std::atomic<uint32_t>* mEvFlagWord = nullptr;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800439
440 /*
441 * This EventFlag object will be owned by the FMQ and will have the same
442 * lifetime.
443 */
444 android::hardware::EventFlag* mEventFlag = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800445};
446
Devin Moore133cb5e2020-07-07 16:31:22 -0700447template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700448T* MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getSlot(size_t idx) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800449 size_t firstRegionLength = first.getLength();
450 size_t secondRegionLength = second.getLength();
451
452 if (idx > firstRegionLength + secondRegionLength) {
453 return nullptr;
454 }
455
456 if (idx < firstRegionLength) {
457 return first.getAddress() + idx;
458 }
459
460 return second.getAddress() + idx - firstRegionLength;
461}
462
Devin Moore133cb5e2020-07-07 16:31:22 -0700463template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700464bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getMemRegionInfo(
465 size_t startIdx, size_t nMessages, size_t& firstCount, size_t& secondCount,
466 T** firstBaseAddress, T** secondBaseAddress) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800467 size_t firstRegionLength = first.getLength();
468 size_t secondRegionLength = second.getLength();
469
470 if (startIdx + nMessages > firstRegionLength + secondRegionLength) {
471 /*
472 * Return false if 'nMessages' starting at 'startIdx' cannot be
473 * accomodated by the MemTransaction object.
474 */
475 return false;
476 }
477
478 /* Number of messages to be read/written to the first MemRegion. */
Devin Moore77d279e2020-07-07 10:38:52 -0700479 firstCount =
480 startIdx < firstRegionLength ? std::min(nMessages, firstRegionLength - startIdx) : 0;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800481
482 /* Number of messages to be read/written to the second MemRegion. */
483 secondCount = nMessages - firstCount;
484
485 if (firstCount != 0) {
486 *firstBaseAddress = first.getAddress() + startIdx;
487 }
488
489 if (secondCount != 0) {
490 size_t secondStartIdx = startIdx > firstRegionLength ? startIdx - firstRegionLength : 0;
491 *secondBaseAddress = second.getAddress() + secondStartIdx;
492 }
493
494 return true;
495}
496
Devin Moore133cb5e2020-07-07 16:31:22 -0700497template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700498bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyFrom(T* data,
499 size_t startIdx,
500 size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800501 if (data == nullptr) {
502 return false;
503 }
504
505 size_t firstReadCount = 0, secondReadCount = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700506 T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800507
Devin Moore77d279e2020-07-07 10:38:52 -0700508 if (getMemRegionInfo(startIdx, nMessages, firstReadCount, secondReadCount, &firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800509 &secondBaseAddress) == false) {
510 /*
511 * Returns false if 'startIdx' and 'nMessages' are invalid for this
512 * MemTransaction object.
513 */
514 return false;
515 }
516
517 if (firstReadCount != 0) {
518 memcpy(data, firstBaseAddress, firstReadCount * sizeof(T));
519 }
520
521 if (secondReadCount != 0) {
Devin Moore77d279e2020-07-07 10:38:52 -0700522 memcpy(data + firstReadCount, secondBaseAddress, secondReadCount * sizeof(T));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800523 }
524
525 return true;
526}
527
Devin Moore133cb5e2020-07-07 16:31:22 -0700528template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700529bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyTo(const T* data,
530 size_t startIdx,
531 size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800532 if (data == nullptr) {
533 return false;
534 }
535
536 size_t firstWriteCount = 0, secondWriteCount = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700537 T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800538
Devin Moore77d279e2020-07-07 10:38:52 -0700539 if (getMemRegionInfo(startIdx, nMessages, firstWriteCount, secondWriteCount, &firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800540 &secondBaseAddress) == false) {
541 /*
542 * Returns false if 'startIdx' and 'nMessages' are invalid for this
543 * MemTransaction object.
544 */
545 return false;
546 }
547
548 if (firstWriteCount != 0) {
549 memcpy(firstBaseAddress, data, firstWriteCount * sizeof(T));
550 }
551
552 if (secondWriteCount != 0) {
Devin Moore77d279e2020-07-07 10:38:52 -0700553 memcpy(secondBaseAddress, data + firstWriteCount, secondWriteCount * sizeof(T));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800554 }
555
556 return true;
557}
558
Devin Moore133cb5e2020-07-07 16:31:22 -0700559template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700560void MessageQueueBase<MQDescriptorType, T, flavor>::initMemory(bool resetPointers) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800561 /*
Devin Moore9a27da52020-07-06 14:01:21 -0700562 * Verify that the Descriptor contains the minimum number of grantors
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800563 * the native_handle is valid and T matches quantum size.
564 */
565 if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
Devin Mooreb00fb7d2020-08-05 14:09:05 -0700566 (mDesc->countGrantors() < hardware::details::kMinGrantorCount)) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800567 return;
568 }
Devin Mooreb00fb7d2020-08-05 14:09:05 -0700569 if (mDesc->getQuantum() != sizeof(T)) {
570 hardware::details::logError(
571 "Payload size differs between the queue instantiation and the "
572 "MQDescriptor.");
573 return;
574 }
575
Devin Moore133cb5e2020-07-07 16:31:22 -0700576 const auto& grantors = mDesc->grantors();
577 for (const auto& grantor : grantors) {
578 if (hardware::details::isAlignedToWordBoundary(grantor.offset) == false) {
579 __assert(__FILE__, __LINE__, "Grantor offsets need to be aligned");
580 }
581 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800582
Devin Moore133cb5e2020-07-07 16:31:22 -0700583 if (flavor == kSynchronizedReadWrite) {
584 mReadPtr = reinterpret_cast<std::atomic<uint64_t>*>(
585 mapGrantorDescr(hardware::details::READPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800586 } else {
587 /*
588 * The unsynchronized write flavor of the FMQ may have multiple readers
589 * and each reader would have their own read pointer counter.
590 */
591 mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
592 }
Devin Moore96849b32020-08-26 08:49:34 -0700593 if (mReadPtr == nullptr) {
594#ifdef __BIONIC__
595 __assert(__FILE__, __LINE__, "mReadPtr is null");
596#endif
597 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800598
Devin Moore133cb5e2020-07-07 16:31:22 -0700599 mWritePtr = reinterpret_cast<std::atomic<uint64_t>*>(
600 mapGrantorDescr(hardware::details::WRITEPTRPOS));
Devin Moore96849b32020-08-26 08:49:34 -0700601 if (mWritePtr == nullptr) {
602#ifdef __BIONIC__
603 __assert(__FILE__, __LINE__, "mWritePtr is null");
604#endif
605 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800606
607 if (resetPointers) {
608 mReadPtr->store(0, std::memory_order_release);
609 mWritePtr->store(0, std::memory_order_release);
Devin Moore133cb5e2020-07-07 16:31:22 -0700610 } else if (flavor != kSynchronizedReadWrite) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800611 // Always reset the read pointer.
612 mReadPtr->store(0, std::memory_order_release);
613 }
614
Devin Moore133cb5e2020-07-07 16:31:22 -0700615 mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(hardware::details::DATAPTRPOS));
Devin Moore96849b32020-08-26 08:49:34 -0700616 if (mRing == nullptr) {
617#ifdef __BIONIC__
618 __assert(__FILE__, __LINE__, "mRing is null");
619#endif
620 }
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800621
Devin Moore133cb5e2020-07-07 16:31:22 -0700622 mEvFlagWord =
623 static_cast<std::atomic<uint32_t>*>(mapGrantorDescr(hardware::details::EVFLAGWORDPOS));
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800624 if (mEvFlagWord != nullptr) {
625 android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
626 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800627}
628
Devin Moore133cb5e2020-07-07 16:31:22 -0700629template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700630MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(const Descriptor& Desc,
631 bool resetPointers) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800632 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800633 if (mDesc == nullptr) {
634 return;
635 }
636
637 initMemory(resetPointers);
638}
639
Devin Moore133cb5e2020-07-07 16:31:22 -0700640template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700641MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(size_t numElementsInQueue,
642 bool configureEventFlagWord) {
Kevin Rocard1d6e40f2017-04-03 11:51:13 -0700643 // Check if the buffer size would not overflow size_t
644 if (numElementsInQueue > SIZE_MAX / sizeof(T)) {
645 return;
646 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800647 /*
648 * The FMQ needs to allocate memory for the ringbuffer as well as for the
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800649 * read and write pointer counters. If an EventFlag word is to be configured,
650 * we also need to allocate memory for the same/
651 */
652 size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
Devin Moore133cb5e2020-07-07 16:31:22 -0700653 size_t kMetaDataSize = 2 * sizeof(android::hardware::details::RingBufferPosition);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800654
655 if (configureEventFlagWord) {
Devin Moore77d279e2020-07-07 10:38:52 -0700656 kMetaDataSize += sizeof(std::atomic<uint32_t>);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800657 }
658
659 /*
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800660 * Ashmem memory region size needs to be specified in page-aligned bytes.
661 * kQueueSizeBytes needs to be aligned to word boundary so that all offsets
662 * in the grantorDescriptor will be word aligned.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800663 */
Devin Moore133cb5e2020-07-07 16:31:22 -0700664 size_t kAshmemSizePageAligned = (hardware::details::alignToWordBoundary(kQueueSizeBytes) +
665 kMetaDataSize + PAGE_SIZE - 1) &
666 ~(PAGE_SIZE - 1);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800667
668 /*
669 * Create an ashmem region to map the memory for the ringbuffer,
670 * read counter and write counter.
671 */
672 int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
673 ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
674
675 /*
676 * The native handle will contain the fds to be mapped.
677 */
Devin Moore77d279e2020-07-07 10:38:52 -0700678 native_handle_t* mqHandle = native_handle_create(1 /* numFds */, 0 /* numInts */);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800679 if (mqHandle == nullptr) {
680 return;
681 }
682
683 mqHandle->data[0] = ashmemFd;
Devin Moore77d279e2020-07-07 10:38:52 -0700684 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(
685 kQueueSizeBytes, mqHandle, sizeof(T), configureEventFlagWord));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800686 if (mDesc == nullptr) {
687 return;
688 }
689 initMemory(true);
690}
691
Devin Moore133cb5e2020-07-07 16:31:22 -0700692template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700693MessageQueueBase<MQDescriptorType, T, flavor>::~MessageQueueBase() {
Devin Moore133cb5e2020-07-07 16:31:22 -0700694 if (flavor == kUnsynchronizedWrite) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800695 delete mReadPtr;
696 } else {
Devin Moore133cb5e2020-07-07 16:31:22 -0700697 unmapGrantorDescr(mReadPtr, hardware::details::READPTRPOS);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800698 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800699 if (mWritePtr != nullptr) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700700 unmapGrantorDescr(mWritePtr, hardware::details::WRITEPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800701 }
702 if (mRing != nullptr) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700703 unmapGrantorDescr(mRing, hardware::details::DATAPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800704 }
705 if (mEvFlagWord != nullptr) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700706 unmapGrantorDescr(mEvFlagWord, hardware::details::EVFLAGWORDPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800707 android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
708 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800709}
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) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800713 return write(data, 1);
714}
715
Devin Moore133cb5e2020-07-07 16:31:22 -0700716template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700717bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800718 return read(data, 1);
719}
720
Devin Moore133cb5e2020-07-07 16:31:22 -0700721template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700722bool MessageQueueBase<MQDescriptorType, T, flavor>::write(const T* data, size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800723 MemTransaction tx;
Devin Moore77d279e2020-07-07 10:38:52 -0700724 return beginWrite(nMessages, &tx) && tx.copyTo(data, 0 /* startIdx */, nMessages) &&
725 commitWrite(nMessages);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800726}
727
Devin Moore133cb5e2020-07-07 16:31:22 -0700728template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700729bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(
730 const T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
731 int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700732 static_assert(flavor == kSynchronizedReadWrite,
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700733 "writeBlocking can only be used with the "
Devin Moore133cb5e2020-07-07 16:31:22 -0700734 "kSynchronizedReadWrite flavor.");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800735 /*
736 * If evFlag is null and the FMQ does not have its own EventFlag object
737 * return false;
Devin Moore133cb5e2020-07-07 16:31:22 -0700738 * If the flavor is kSynchronizedReadWrite and the readNotification
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800739 * bit mask is zero return false;
740 * If the count is greater than queue size, return false
741 * to prevent blocking until timeOut.
742 */
743 if (evFlag == nullptr) {
744 evFlag = mEventFlag;
745 if (evFlag == nullptr) {
Devin Moore9a27da52020-07-06 14:01:21 -0700746 hardware::details::logError(
Devin Moore77d279e2020-07-07 10:38:52 -0700747 "writeBlocking failed: called on MessageQueue with no Eventflag"
748 "configured or provided");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800749 return false;
750 }
751 }
752
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700753 if (readNotification == 0 || (count > getQuantumCount())) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800754 return false;
755 }
756
757 /*
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700758 * There is no need to wait for a readNotification if there is sufficient
759 * space to write is already present in the FMQ. The latter would be the case when
760 * read operations read more number of messages than write operations write.
761 * In other words, a single large read may clear the FMQ after multiple small
762 * writes. This would fail to clear a pending readNotification bit since
763 * EventFlag bits can only be cleared by a wait() call, however the bit would
764 * be correctly cleared by the next writeBlocking() call.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800765 */
766
767 bool result = write(data, count);
768 if (result) {
769 if (writeNotification) {
770 evFlag->wake(writeNotification);
771 }
772 return result;
773 }
774
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800775 bool shouldTimeOut = timeOutNanos != 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700776 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800777
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700778 while (true) {
779 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800780 if (shouldTimeOut) {
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700781 /*
782 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
783 * to Nanoseconds)
784 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800785 int64_t currentTimeNs = android::elapsedRealtimeNano();
786 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700787 * Decrement 'timeOutNanos' to account for the time taken to complete the last
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800788 * iteration of the while loop.
789 */
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700790 timeOutNanos -= currentTimeNs - prevTimeNanos;
791 prevTimeNanos = currentTimeNs;
792
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800793 if (timeOutNanos <= 0) {
794 /*
795 * Attempt write in case a context switch happened outside of
796 * evFlag->wait().
797 */
798 result = write(data, count);
799 break;
800 }
801 }
802
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800803 /*
804 * wait() will return immediately if there was a pending read
805 * notification.
806 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800807 uint32_t efState = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700808 status_t status = evFlag->wait(readNotification, &efState, timeOutNanos,
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700809 true /* retry on spurious wake */);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800810
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700811 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
Devin Moore9a27da52020-07-06 14:01:21 -0700812 hardware::details::logError("Unexpected error code from EventFlag Wait status " +
813 std::to_string(status));
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700814 break;
815 }
816
817 if (status == android::TIMED_OUT) {
818 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800819 }
820
821 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700822 * If there is still insufficient space to write to the FMQ,
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800823 * keep waiting for another readNotification.
824 */
825 if ((efState & readNotification) && write(data, count)) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800826 result = true;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700827 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800828 }
829 }
830
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800831 if (result && writeNotification != 0) {
832 evFlag->wake(writeNotification);
833 }
834
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800835 return result;
836}
837
Devin Moore133cb5e2020-07-07 16:31:22 -0700838template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700839bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(const T* data, size_t count,
840 int64_t timeOutNanos) {
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800841 return writeBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
842}
843
Devin Moore133cb5e2020-07-07 16:31:22 -0700844template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700845bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(
846 T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
847 int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700848 static_assert(flavor == kSynchronizedReadWrite,
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700849 "readBlocking can only be used with the "
Devin Moore133cb5e2020-07-07 16:31:22 -0700850 "kSynchronizedReadWrite flavor.");
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700851
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800852 /*
853 * If evFlag is null and the FMQ does not own its own EventFlag object
854 * return false;
855 * If the writeNotification bit mask is zero return false;
856 * If the count is greater than queue size, return false to prevent
857 * blocking until timeOut.
858 */
859 if (evFlag == nullptr) {
860 evFlag = mEventFlag;
861 if (evFlag == nullptr) {
Devin Moore9a27da52020-07-06 14:01:21 -0700862 hardware::details::logError(
Devin Moore77d279e2020-07-07 10:38:52 -0700863 "readBlocking failed: called on MessageQueue with no Eventflag"
864 "configured or provided");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800865 return false;
866 }
867 }
868
869 if (writeNotification == 0 || count > getQuantumCount()) {
870 return false;
871 }
872
873 /*
874 * There is no need to wait for a write notification if sufficient
875 * data to read is already present in the FMQ. This would be the
876 * case when read operations read lesser number of messages than
877 * a write operation and multiple reads would be required to clear the queue
878 * after a single write operation. This check would fail to clear a pending
879 * writeNotification bit since EventFlag bits can only be cleared
880 * by a wait() call, however the bit would be correctly cleared by the next
881 * readBlocking() call.
882 */
883
884 bool result = read(data, count);
885 if (result) {
886 if (readNotification) {
887 evFlag->wake(readNotification);
888 }
889 return result;
890 }
891
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800892 bool shouldTimeOut = timeOutNanos != 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700893 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800894
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700895 while (true) {
896 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800897 if (shouldTimeOut) {
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700898 /*
899 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
900 * to Nanoseconds)
901 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800902 int64_t currentTimeNs = android::elapsedRealtimeNano();
903 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700904 * Decrement 'timeOutNanos' to account for the time taken to complete the last
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800905 * iteration of the while loop.
906 */
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700907 timeOutNanos -= currentTimeNs - prevTimeNanos;
908 prevTimeNanos = currentTimeNs;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800909
910 if (timeOutNanos <= 0) {
911 /*
912 * Attempt read in case a context switch happened outside of
913 * evFlag->wait().
914 */
915 result = read(data, count);
916 break;
917 }
918 }
919
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800920 /*
921 * wait() will return immediately if there was a pending write
922 * notification.
923 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800924 uint32_t efState = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700925 status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos,
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700926 true /* retry on spurious wake */);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800927
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700928 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
Devin Moore9a27da52020-07-06 14:01:21 -0700929 hardware::details::logError("Unexpected error code from EventFlag Wait status " +
930 std::to_string(status));
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700931 break;
932 }
933
934 if (status == android::TIMED_OUT) {
935 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800936 }
937
938 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700939 * If the data in FMQ is still insufficient, go back to waiting
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800940 * for another write notification.
941 */
942 if ((efState & writeNotification) && read(data, count)) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800943 result = true;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700944 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800945 }
946 }
947
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800948 if (result && readNotification != 0) {
949 evFlag->wake(readNotification);
950 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800951 return result;
952}
953
Devin Moore133cb5e2020-07-07 16:31:22 -0700954template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700955bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(T* data, size_t count,
956 int64_t timeOutNanos) {
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800957 return readBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
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>::availableToWriteBytes() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800962 return mDesc->getSize() - availableToReadBytes();
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 -0700966size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWrite() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800967 return availableToWriteBytes() / sizeof(T);
968}
969
Devin Moore133cb5e2020-07-07 16:31:22 -0700970template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700971size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToRead() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800972 return availableToReadBytes() / sizeof(T);
973}
974
Devin Moore133cb5e2020-07-07 16:31:22 -0700975template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700976bool MessageQueueBase<MQDescriptorType, T, flavor>::beginWrite(size_t nMessages,
977 MemTransaction* result) const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800978 /*
979 * If nMessages is greater than size of FMQ or in case of the synchronized
980 * FMQ flavor, if there is not enough space to write nMessages, then return
981 * result with null addresses.
982 */
Devin Moore133cb5e2020-07-07 16:31:22 -0700983 if ((flavor == kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800984 nMessages > getQuantumCount()) {
985 *result = MemTransaction();
986 return false;
987 }
988
989 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
990 size_t writeOffset = writePtr % mDesc->getSize();
991
992 /*
993 * From writeOffset, the number of messages that can be written
994 * contiguously without wrapping around the ring buffer are calculated.
995 */
996 size_t contiguousMessages = (mDesc->getSize() - writeOffset) / sizeof(T);
997
998 if (contiguousMessages < nMessages) {
999 /*
1000 * Wrap around is required. Both result.first and result.second are
1001 * populated.
1002 */
Devin Moore77d279e2020-07-07 10:38:52 -07001003 *result = MemTransaction(
1004 MemRegion(reinterpret_cast<T*>(mRing + writeOffset), contiguousMessages),
1005 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001006 } else {
1007 /*
1008 * A wrap around is not required to write nMessages. Only result.first
1009 * is populated.
1010 */
1011 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset), nMessages),
1012 MemRegion());
1013 }
1014
1015 return true;
1016}
1017
Devin Moore133cb5e2020-07-07 16:31:22 -07001018template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001019/*
1020 * Disable integer sanitization since integer overflow here is allowed
1021 * and legal.
1022 */
Devin Moore9a27da52020-07-06 14:01:21 -07001023__attribute__((no_sanitize("integer"))) bool
1024MessageQueueBase<MQDescriptorType, T, flavor>::commitWrite(size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001025 size_t nBytesWritten = nMessages * sizeof(T);
1026 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
1027 writePtr += nBytesWritten;
1028 mWritePtr->store(writePtr, std::memory_order_release);
1029 /*
1030 * This method cannot fail now since we are only incrementing the writePtr
1031 * counter.
1032 */
1033 return true;
1034}
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 -07001037size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToReadBytes() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001038 /*
1039 * This method is invoked by implementations of both read() and write() and
Devin Moore9a27da52020-07-06 14:01:21 -07001040 * hence requires a memory_order_acquired load for both mReadPtr and
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001041 * mWritePtr.
1042 */
Devin Moore77d279e2020-07-07 10:38:52 -07001043 return mWritePtr->load(std::memory_order_acquire) - mReadPtr->load(std::memory_order_acquire);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001044}
1045
Devin Moore133cb5e2020-07-07 16:31:22 -07001046template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001047bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data, size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001048 MemTransaction tx;
Devin Moore77d279e2020-07-07 10:38:52 -07001049 return beginRead(nMessages, &tx) && tx.copyFrom(data, 0 /* startIdx */, nMessages) &&
1050 commitRead(nMessages);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001051}
1052
Devin Moore133cb5e2020-07-07 16:31:22 -07001053template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001054/*
1055 * Disable integer sanitization since integer overflow here is allowed
1056 * and legal.
1057 */
Devin Moore9a27da52020-07-06 14:01:21 -07001058__attribute__((no_sanitize("integer"))) bool
1059MessageQueueBase<MQDescriptorType, T, flavor>::beginRead(size_t nMessages,
1060 MemTransaction* result) const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001061 *result = MemTransaction();
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001062 /*
1063 * If it is detected that the data in the queue was overwritten
1064 * due to the reader process being too slow, the read pointer counter
1065 * is set to the same as the write pointer counter to indicate error
1066 * and the read returns false;
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001067 * Need acquire/release memory ordering for mWritePtr.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001068 */
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001069 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1070 /*
1071 * A relaxed load is sufficient for mReadPtr since there will be no
1072 * stores to mReadPtr from a different thread.
1073 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001074 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
1075
1076 if (writePtr - readPtr > mDesc->getSize()) {
1077 mReadPtr->store(writePtr, std::memory_order_release);
1078 return false;
1079 }
1080
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001081 size_t nBytesDesired = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001082 /*
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001083 * Return if insufficient data to read in FMQ.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001084 */
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001085 if (writePtr - readPtr < nBytesDesired) {
1086 return false;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001087 }
1088
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001089 size_t readOffset = readPtr % mDesc->getSize();
1090 /*
1091 * From readOffset, the number of messages that can be read contiguously
1092 * without wrapping around the ring buffer are calculated.
1093 */
1094 size_t contiguousMessages = (mDesc->getSize() - readOffset) / sizeof(T);
1095
1096 if (contiguousMessages < nMessages) {
1097 /*
1098 * A wrap around is required. Both result.first and result.second
1099 * are populated.
1100 */
Devin Moore77d279e2020-07-07 10:38:52 -07001101 *result = MemTransaction(
1102 MemRegion(reinterpret_cast<T*>(mRing + readOffset), contiguousMessages),
1103 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001104 } else {
1105 /*
1106 * A wrap around is not required. Only result.first need to be
1107 * populated.
1108 */
1109 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset), nMessages),
1110 MemRegion());
1111 }
1112
1113 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001114}
1115
Devin Moore133cb5e2020-07-07 16:31:22 -07001116template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001117/*
1118 * Disable integer sanitization since integer overflow here is allowed
1119 * and legal.
1120 */
Devin Moore9a27da52020-07-06 14:01:21 -07001121__attribute__((no_sanitize("integer"))) bool
1122MessageQueueBase<MQDescriptorType, T, flavor>::commitRead(size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001123 // TODO: Use a local copy of readPtr to avoid relazed mReadPtr loads.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001124 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001125 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1126 /*
1127 * If the flavor is unsynchronized, it is possible that a write overflow may
Devin Moore9a27da52020-07-06 14:01:21 -07001128 * have occurred between beginRead() and commitRead().
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001129 */
1130 if (writePtr - readPtr > mDesc->getSize()) {
1131 mReadPtr->store(writePtr, std::memory_order_release);
1132 return false;
1133 }
1134
1135 size_t nBytesRead = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001136 readPtr += nBytesRead;
1137 mReadPtr->store(readPtr, std::memory_order_release);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001138 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001139}
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 -07001142size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumSize() const {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001143 return mDesc->getQuantum();
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 -07001147size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumCount() const {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001148 return mDesc->getSize() / mDesc->getQuantum();
1149}
1150
Devin Moore133cb5e2020-07-07 16:31:22 -07001151template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001152bool MessageQueueBase<MQDescriptorType, T, flavor>::isValid() const {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001153 return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
1154}
1155
Devin Moore133cb5e2020-07-07 16:31:22 -07001156template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001157void* MessageQueueBase<MQDescriptorType, T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001158 const native_handle_t* handle = mDesc->handle();
1159 auto grantors = mDesc->grantors();
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001160 if (handle == nullptr) {
Devin Moore9a27da52020-07-06 14:01:21 -07001161 hardware::details::logError("mDesc->handle is null");
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001162 return nullptr;
1163 }
1164
1165 if (grantorIdx >= grantors.size()) {
Devin Moore9a27da52020-07-06 14:01:21 -07001166 hardware::details::logError(std::string("grantorIdx must be less than ") +
1167 std::to_string(grantors.size()));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001168 return nullptr;
1169 }
1170
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001171 int fdIndex = grantors[grantorIdx].fdIndex;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001172 /*
1173 * Offset for mmap must be a multiple of PAGE_SIZE.
1174 */
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001175 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
Devin Moore77d279e2020-07-07 10:38:52 -07001176 int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001177
Devin Moore77d279e2020-07-07 10:38:52 -07001178 void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED, handle->data[fdIndex],
1179 mapOffset);
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001180 if (address == MAP_FAILED) {
Devin Moore9a27da52020-07-06 14:01:21 -07001181 hardware::details::logError(std::string("mmap failed: ") + std::to_string(errno));
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001182 return nullptr;
1183 }
1184 return reinterpret_cast<uint8_t*>(address) + (grantors[grantorIdx].offset - mapOffset);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001185}
1186
Devin Moore133cb5e2020-07-07 16:31:22 -07001187template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001188void MessageQueueBase<MQDescriptorType, T, flavor>::unmapGrantorDescr(void* address,
1189 uint32_t grantorIdx) {
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001190 auto grantors = mDesc->grantors();
1191 if ((address == nullptr) || (grantorIdx >= grantors.size())) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001192 return;
1193 }
1194
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001195 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
Devin Moore77d279e2020-07-07 10:38:52 -07001196 int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
1197 void* baseAddress =
1198 reinterpret_cast<uint8_t*>(address) - (grantors[grantorIdx].offset - mapOffset);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001199 if (baseAddress) munmap(baseAddress, mapLength);
1200}
1201
1202} // namespace hardware