blob: 44fe7097453bafd42b48397aaf0c7b454a8fc442 [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
17#ifndef HIDL_MQ_H
18#define HIDL_MQ_H
19
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080020#include <cutils/ashmem.h>
21#include <fmq/EventFlag.h>
22#include <hidl/MQDescriptor.h>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080023#include <sys/mman.h>
24#include <utils/Log.h>
Hridya Valsaraju2abefb62017-01-19 13:06:58 -080025#include <utils/SystemClock.h>
Devin Moore77d279e2020-07-07 10:38:52 -070026#include <atomic>
27#include <new>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080028
29namespace android {
30namespace hardware {
31
Yifan Hongdc5bd672017-04-11 17:11:57 -070032namespace details {
33void check(bool exp);
Devin Moore77d279e2020-07-07 10:38:52 -070034void logError(const std::string& message);
Yifan Hongdc5bd672017-04-11 17:11:57 -070035} // namespace details
36
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080037template <typename T, MQFlavor flavor>
38struct MessageQueue {
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -080039 typedef MQDescriptor<T, flavor> Descriptor;
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -080040
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080041 /**
42 * @param Desc MQDescriptor describing the FMQ.
43 * @param resetPointers bool indicating whether the read/write pointers
44 * should be reset or not.
45 */
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -080046 MessageQueue(const Descriptor& Desc, bool resetPointers = true);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080047
48 ~MessageQueue();
49
50 /**
51 * This constructor uses Ashmem shared memory to create an FMQ
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080052 * that can contain a maximum of 'numElementsInQueue' elements of type T.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080053 *
54 * @param numElementsInQueue Capacity of the MessageQueue in terms of T.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -080055 * @param configureEventFlagWord Boolean that specifies if memory should
56 * also be allocated and mapped for an EventFlag word.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080057 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -080058 MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord = false);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080059
60 /**
61 * @return Number of items of type T that can be written into the FMQ
62 * without a read.
63 */
64 size_t availableToWrite() const;
65
66 /**
67 * @return Number of items of type T that are waiting to be read from the
68 * FMQ.
69 */
70 size_t availableToRead() const;
71
72 /**
73 * Returns the size of type T in bytes.
74 *
75 * @param Size of T.
76 */
77 size_t getQuantumSize() const;
78
79 /**
80 * Returns the size of the FMQ in terms of the size of type T.
81 *
82 * @return Number of items of type T that will fit in the FMQ.
83 */
84 size_t getQuantumCount() const;
85
86 /**
87 * @return Whether the FMQ is configured correctly.
88 */
89 bool isValid() const;
90
91 /**
92 * Non-blocking write to FMQ.
93 *
94 * @param data Pointer to the object of type T to be written into the FMQ.
95 *
96 * @return Whether the write was successful.
97 */
98 bool write(const T* data);
99
100 /**
101 * Non-blocking read from FMQ.
102 *
103 * @param data Pointer to the memory where the object read from the FMQ is
104 * copied to.
105 *
106 * @return Whether the read was successful.
107 */
108 bool read(T* data);
109
110 /**
111 * Write some data into the FMQ without blocking.
112 *
113 * @param data Pointer to the array of items of type T.
114 * @param count Number of items in array.
115 *
116 * @return Whether the write was successful.
117 */
118 bool write(const T* data, size_t count);
119
120 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800121 * Perform a blocking write of 'count' items into the FMQ using EventFlags.
122 * Does not support partial writes.
123 *
124 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
125 * associated with the FMQ and it is used in that case.
126 *
127 * The application code must ensure that 'evFlag' used by the
128 * reader(s)/writer is based upon the same EventFlag word.
129 *
130 * The method will return false without blocking if any of the following
131 * conditions are true:
132 * - If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700133 * - If the 'readNotification' bit mask is zero.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800134 * - If 'count' is greater than the FMQ size.
135 *
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700136 * If the there is insufficient space available to write into it, the
137 * EventFlag bit mask 'readNotification' is is waited upon.
138 *
139 * This method should only be used with a MessageQueue of the flavor
140 * 'kSynchronizedReadWrite'.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800141 *
142 * Upon a successful write, wake is called on 'writeNotification' (if
143 * non-zero).
144 *
145 * @param data Pointer to the array of items of type T.
146 * @param count Number of items in array.
147 * @param readNotification The EventFlag bit mask to wait on if there is not
148 * enough space in FMQ to write 'count' items.
149 * @param writeNotification The EventFlag bit mask to call wake on
150 * a successful write. No wake is called if 'writeNotification' is zero.
151 * @param timeOutNanos Number of nanoseconds after which the blocking
152 * write attempt is aborted.
153 * @param evFlag The EventFlag object to be used for blocking. If nullptr,
154 * it is checked whether the FMQ owns an EventFlag object and that is used
155 * for blocking instead.
156 *
157 * @return Whether the write was successful.
158 */
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800159 bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
160 uint32_t writeNotification, int64_t timeOutNanos = 0,
161 android::hardware::EventFlag* evFlag = nullptr);
162
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800163 bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
164
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800165 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800166 * Read some data from the FMQ without blocking.
167 *
168 * @param data Pointer to the array to which read data is to be written.
169 * @param count Number of items to be read.
170 *
171 * @return Whether the read was successful.
172 */
173 bool read(T* data, size_t count);
174
175 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800176 * Perform a blocking read operation of 'count' items from the FMQ. Does not
177 * perform a partial read.
178 *
179 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
180 * associated with the FMQ and it is used in that case.
181 *
182 * The application code must ensure that 'evFlag' used by the
183 * reader(s)/writer is based upon the same EventFlag word.
184 *
185 * The method will return false without blocking if any of the following
186 * conditions are true:
187 * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
188 * -If the 'writeNotification' bit mask is zero.
189 * -If 'count' is greater than the FMQ size.
190 *
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700191 * This method should only be used with a MessageQueue of the flavor
192 * 'kSynchronizedReadWrite'.
193
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800194 * If FMQ does not contain 'count' items, the eventFlag bit mask
195 * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
196 * wake is called on 'readNotification' (if non-zero).
197 *
198 * @param data Pointer to the array to which read data is to be written.
199 * @param count Number of items to be read.
200 * @param readNotification The EventFlag bit mask to call wake on after
201 * a successful read. No wake is called if 'readNotification' is zero.
202 * @param writeNotification The EventFlag bit mask to call a wait on
203 * if there is insufficient data in the FMQ to be read.
204 * @param timeOutNanos Number of nanoseconds after which the blocking
205 * read attempt is aborted.
206 * @param evFlag The EventFlag object to be used for blocking.
207 *
208 * @return Whether the read was successful.
209 */
Devin Moore77d279e2020-07-07 10:38:52 -0700210 bool readBlocking(T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
211 int64_t timeOutNanos = 0, android::hardware::EventFlag* evFlag = nullptr);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800212
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800213 bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);
214
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800215 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800216 * Get a pointer to the MQDescriptor object that describes this FMQ.
217 *
218 * @return Pointer to the MQDescriptor associated with the FMQ.
219 */
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800220 const Descriptor* getDesc() const { return mDesc.get(); }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800221
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800222 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800223 * Get a pointer to the EventFlag word if there is one associated with this FMQ.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800224 *
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800225 * @return Pointer to an EventFlag word, will return nullptr if not
226 * configured. This method does not transfer ownership. The EventFlag
227 * word will be unmapped by the MessageQueue destructor.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800228 */
229 std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800230
231 /**
232 * Describes a memory region in the FMQ.
233 */
234 struct MemRegion {
235 MemRegion() : MemRegion(nullptr, 0) {}
236
237 MemRegion(T* base, size_t size) : address(base), length(size) {}
238
Devin Moore77d279e2020-07-07 10:38:52 -0700239 MemRegion& operator=(const MemRegion& other) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800240 address = other.address;
241 length = other.length;
242 return *this;
243 }
244
245 /**
246 * Gets a pointer to the base address of the MemRegion.
247 */
248 inline T* getAddress() const { return address; }
249
250 /**
251 * Gets the length of the MemRegion. This would equal to the number
252 * of items of type T that can be read from/written into the MemRegion.
253 */
254 inline size_t getLength() const { return length; }
255
256 /**
257 * Gets the length of the MemRegion in bytes.
258 */
259 inline size_t getLengthInBytes() const { return length * sizeof(T); }
260
Devin Moore77d279e2020-07-07 10:38:52 -0700261 private:
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800262 /* Base address */
263 T* address;
264
265 /*
266 * Number of items of type T that can be written to/read from the base
267 * address.
268 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800269 size_t length;
270 };
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800271
272 /**
273 * Describes the memory regions to be used for a read or write.
274 * The struct contains two MemRegion objects since the FMQ is a ring
275 * buffer and a read or write operation can wrap around. A single message
276 * of type T will never be broken between the two MemRegions.
277 */
278 struct MemTransaction {
279 MemTransaction() : MemTransaction(MemRegion(), MemRegion()) {}
280
Devin Moore77d279e2020-07-07 10:38:52 -0700281 MemTransaction(const MemRegion& regionFirst, const MemRegion& regionSecond)
282 : first(regionFirst), second(regionSecond) {}
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800283
Devin Moore77d279e2020-07-07 10:38:52 -0700284 MemTransaction& operator=(const MemTransaction& other) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800285 first = other.first;
286 second = other.second;
287 return *this;
288 }
289
290 /**
291 * Helper method to calculate the address for a particular index for
292 * the MemTransaction object.
293 *
294 * @param idx Index of the slot to be read/written. If the
295 * MemTransaction object is representing the memory region to read/write
296 * N items of type T, the valid range of idx is between 0 and N-1.
297 *
298 * @return Pointer to the slot idx. Will be nullptr for an invalid idx.
299 */
300 T* getSlot(size_t idx);
301
302 /**
303 * Helper method to write 'nMessages' items of type T into the memory
304 * regions described by the object starting from 'startIdx'. This method
305 * uses memcpy() and is not to meant to be used for a zero copy operation.
306 * Partial writes are not supported.
307 *
308 * @param data Pointer to the source buffer.
309 * @param nMessages Number of items of type T.
310 * @param startIdx The slot number to begin the write from. If the
311 * MemTransaction object is representing the memory region to read/write
312 * N items of type T, the valid range of startIdx is between 0 and N-1;
313 *
314 * @return Whether the write operation of size 'nMessages' succeeded.
315 */
316 bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
317
318 /*
319 * Helper method to read 'nMessages' items of type T from the memory
320 * regions described by the object starting from 'startIdx'. This method uses
321 * memcpy() and is not meant to be used for a zero copy operation. Partial reads
322 * are not supported.
323 *
324 * @param data Pointer to the destination buffer.
325 * @param nMessages Number of items of type T.
326 * @param startIdx The slot number to begin the read from. If the
327 * MemTransaction object is representing the memory region to read/write
328 * N items of type T, the valid range of startIdx is between 0 and N-1.
329 *
330 * @return Whether the read operation of size 'nMessages' succeeded.
331 */
332 bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
333
334 /**
335 * Returns a const reference to the first MemRegion in the
336 * MemTransaction object.
337 */
338 inline const MemRegion& getFirstRegion() const { return first; }
339
340 /**
341 * Returns a const reference to the second MemRegion in the
342 * MemTransaction object.
343 */
344 inline const MemRegion& getSecondRegion() const { return second; }
345
Devin Moore77d279e2020-07-07 10:38:52 -0700346 private:
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800347 /*
348 * Given a start index and the number of messages to be
349 * read/written, this helper method calculates the
350 * number of messages that should should be written to both the first
351 * and second MemRegions and the base addresses to be used for
352 * the read/write operation.
353 *
354 * Returns false if the 'startIdx' and 'nMessages' is
355 * invalid for the MemTransaction object.
356 */
Devin Moore77d279e2020-07-07 10:38:52 -0700357 bool inline getMemRegionInfo(size_t idx, size_t nMessages, size_t& firstCount,
358 size_t& secondCount, T** firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800359 T** secondBaseAddress);
360 MemRegion first;
361 MemRegion second;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800362 };
363
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800364 /**
365 * Get a MemTransaction object to write 'nMessages' items of type T.
366 * Once the write is performed using the information from MemTransaction,
367 * the write operation is to be committed using a call to commitWrite().
368 *
369 * @param nMessages Number of messages of type T.
370 * @param Pointer to MemTransaction struct that describes memory to write 'nMessages'
371 * items of type T. If a write of size 'nMessages' is not possible, the base
372 * addresses in the MemTransaction object would be set to nullptr.
373 *
374 * @return Whether it is possible to write 'nMessages' items of type T
375 * into the FMQ.
376 */
377 bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800378
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800379 /**
380 * Commit a write of size 'nMessages'. To be only used after a call to beginWrite().
381 *
382 * @param nMessages number of messages of type T to be written.
383 *
384 * @return Whether the write operation of size 'nMessages' succeeded.
385 */
386 bool commitWrite(size_t nMessages);
387
388 /**
389 * Get a MemTransaction object to read 'nMessages' items of type T.
390 * Once the read is performed using the information from MemTransaction,
391 * the read operation is to be committed using a call to commitRead().
392 *
393 * @param nMessages Number of messages of type T.
394 * @param pointer to MemTransaction struct that describes memory to read 'nMessages'
395 * items of type T. If a read of size 'nMessages' is not possible, the base
396 * pointers in the MemTransaction object returned will be set to nullptr.
397 *
398 * @return bool Whether it is possible to read 'nMessages' items of type T
399 * from the FMQ.
400 */
401 bool beginRead(size_t nMessages, MemTransaction* memTx) const;
402
403 /**
404 * Commit a read of size 'nMessages'. To be only used after a call to beginRead().
405 * For the unsynchronized flavor of FMQ, this method will return a failure
406 * if a write overflow happened after beginRead() was invoked.
407 *
408 * @param nMessages number of messages of type T to be read.
409 *
410 * @return bool Whether the read operation of size 'nMessages' succeeded.
411 */
412 bool commitRead(size_t nMessages);
413
Devin Moore77d279e2020-07-07 10:38:52 -0700414 private:
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800415 size_t availableToWriteBytes() const;
416 size_t availableToReadBytes() const;
417
418 MessageQueue(const MessageQueue& other) = delete;
419 MessageQueue& operator=(const MessageQueue& other) = delete;
420 MessageQueue();
421
422 void* mapGrantorDescr(uint32_t grantorIdx);
423 void unmapGrantorDescr(void* address, uint32_t grantorIdx);
424 void initMemory(bool resetPointers);
425
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800426 enum DefaultEventNotification : uint32_t {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800427 /*
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700428 * These are only used internally by the readBlocking()/writeBlocking()
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800429 * methods and hence once other bit combinations are not required.
430 */
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700431 FMQ_NOT_FULL = 0x01,
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800432 FMQ_NOT_EMPTY = 0x02
433 };
434
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800435 std::unique_ptr<Descriptor> mDesc;
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800436 uint8_t* mRing = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800437 /*
438 * TODO(b/31550092): Change to 32 bit read and write pointer counters.
439 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800440 std::atomic<uint64_t>* mReadPtr = nullptr;
441 std::atomic<uint64_t>* mWritePtr = nullptr;
442
443 std::atomic<uint32_t>* mEvFlagWord = nullptr;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800444
445 /*
446 * This EventFlag object will be owned by the FMQ and will have the same
447 * lifetime.
448 */
449 android::hardware::EventFlag* mEventFlag = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800450};
451
452template <typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800453T* MessageQueue<T, flavor>::MemTransaction::getSlot(size_t idx) {
454 size_t firstRegionLength = first.getLength();
455 size_t secondRegionLength = second.getLength();
456
457 if (idx > firstRegionLength + secondRegionLength) {
458 return nullptr;
459 }
460
461 if (idx < firstRegionLength) {
462 return first.getAddress() + idx;
463 }
464
465 return second.getAddress() + idx - firstRegionLength;
466}
467
468template <typename T, MQFlavor flavor>
Devin Moore77d279e2020-07-07 10:38:52 -0700469bool MessageQueue<T, flavor>::MemTransaction::getMemRegionInfo(size_t startIdx, size_t nMessages,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800470 size_t& firstCount,
471 size_t& secondCount,
472 T** firstBaseAddress,
473 T** secondBaseAddress) {
474 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
504template <typename T, MQFlavor flavor>
505bool MessageQueue<T, flavor>::MemTransaction::copyFrom(T* data, size_t startIdx, size_t nMessages) {
506 if (data == nullptr) {
507 return false;
508 }
509
510 size_t firstReadCount = 0, secondReadCount = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700511 T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800512
Devin Moore77d279e2020-07-07 10:38:52 -0700513 if (getMemRegionInfo(startIdx, nMessages, firstReadCount, secondReadCount, &firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800514 &secondBaseAddress) == false) {
515 /*
516 * Returns false if 'startIdx' and 'nMessages' are invalid for this
517 * MemTransaction object.
518 */
519 return false;
520 }
521
522 if (firstReadCount != 0) {
523 memcpy(data, firstBaseAddress, firstReadCount * sizeof(T));
524 }
525
526 if (secondReadCount != 0) {
Devin Moore77d279e2020-07-07 10:38:52 -0700527 memcpy(data + firstReadCount, secondBaseAddress, secondReadCount * sizeof(T));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800528 }
529
530 return true;
531}
532
533template <typename T, MQFlavor flavor>
Devin Moore77d279e2020-07-07 10:38:52 -0700534bool MessageQueue<T, flavor>::MemTransaction::copyTo(const T* data, size_t startIdx,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800535 size_t nMessages) {
536 if (data == nullptr) {
537 return false;
538 }
539
540 size_t firstWriteCount = 0, secondWriteCount = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700541 T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800542
Devin Moore77d279e2020-07-07 10:38:52 -0700543 if (getMemRegionInfo(startIdx, nMessages, firstWriteCount, secondWriteCount, &firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800544 &secondBaseAddress) == false) {
545 /*
546 * Returns false if 'startIdx' and 'nMessages' are invalid for this
547 * MemTransaction object.
548 */
549 return false;
550 }
551
552 if (firstWriteCount != 0) {
553 memcpy(firstBaseAddress, data, firstWriteCount * sizeof(T));
554 }
555
556 if (secondWriteCount != 0) {
Devin Moore77d279e2020-07-07 10:38:52 -0700557 memcpy(secondBaseAddress, data + firstWriteCount, secondWriteCount * sizeof(T));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800558 }
559
560 return true;
561}
562
563template <typename T, MQFlavor flavor>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800564void MessageQueue<T, flavor>::initMemory(bool resetPointers) {
565 /*
566 * Verify that the the Descriptor contains the minimum number of grantors
567 * the native_handle is valid and T matches quantum size.
568 */
569 if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800570 (mDesc->countGrantors() < Descriptor::kMinGrantorCount) ||
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800571 (mDesc->getQuantum() != sizeof(T))) {
572 return;
573 }
574
575 if (flavor == kSynchronizedReadWrite) {
Devin Moore77d279e2020-07-07 10:38:52 -0700576 mReadPtr =
577 reinterpret_cast<std::atomic<uint64_t>*>(mapGrantorDescr(Descriptor::READPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800578 } else {
579 /*
580 * The unsynchronized write flavor of the FMQ may have multiple readers
581 * and each reader would have their own read pointer counter.
582 */
583 mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
584 }
585
Yifan Hongdc5bd672017-04-11 17:11:57 -0700586 details::check(mReadPtr != nullptr);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800587
Devin Moore77d279e2020-07-07 10:38:52 -0700588 mWritePtr = reinterpret_cast<std::atomic<uint64_t>*>(mapGrantorDescr(Descriptor::WRITEPTRPOS));
Yifan Hongdc5bd672017-04-11 17:11:57 -0700589 details::check(mWritePtr != nullptr);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800590
591 if (resetPointers) {
592 mReadPtr->store(0, std::memory_order_release);
593 mWritePtr->store(0, std::memory_order_release);
594 } else if (flavor != kSynchronizedReadWrite) {
595 // Always reset the read pointer.
596 mReadPtr->store(0, std::memory_order_release);
597 }
598
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800599 mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(Descriptor::DATAPTRPOS));
Yifan Hongdc5bd672017-04-11 17:11:57 -0700600 details::check(mRing != nullptr);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800601
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800602 mEvFlagWord = static_cast<std::atomic<uint32_t>*>(mapGrantorDescr(Descriptor::EVFLAGWORDPOS));
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800603 if (mEvFlagWord != nullptr) {
604 android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
605 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800606}
607
608template <typename T, MQFlavor flavor>
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800609MessageQueue<T, flavor>::MessageQueue(const Descriptor& Desc, bool resetPointers) {
610 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800611 if (mDesc == nullptr) {
612 return;
613 }
614
615 initMemory(resetPointers);
616}
617
618template <typename T, MQFlavor flavor>
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800619MessageQueue<T, flavor>::MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord) {
Kevin Rocard1d6e40f2017-04-03 11:51:13 -0700620 // Check if the buffer size would not overflow size_t
621 if (numElementsInQueue > SIZE_MAX / sizeof(T)) {
622 return;
623 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800624 /*
625 * The FMQ needs to allocate memory for the ringbuffer as well as for the
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800626 * read and write pointer counters. If an EventFlag word is to be configured,
627 * we also need to allocate memory for the same/
628 */
629 size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
630 size_t kMetaDataSize = 2 * sizeof(android::hardware::RingBufferPosition);
631
632 if (configureEventFlagWord) {
Devin Moore77d279e2020-07-07 10:38:52 -0700633 kMetaDataSize += sizeof(std::atomic<uint32_t>);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800634 }
635
636 /*
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800637 * Ashmem memory region size needs to be specified in page-aligned bytes.
638 * kQueueSizeBytes needs to be aligned to word boundary so that all offsets
639 * in the grantorDescriptor will be word aligned.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800640 */
641 size_t kAshmemSizePageAligned =
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800642 (Descriptor::alignToWordBoundary(kQueueSizeBytes) + kMetaDataSize + PAGE_SIZE - 1) &
643 ~(PAGE_SIZE - 1);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800644
645 /*
646 * Create an ashmem region to map the memory for the ringbuffer,
647 * read counter and write counter.
648 */
649 int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
650 ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
651
652 /*
653 * The native handle will contain the fds to be mapped.
654 */
Devin Moore77d279e2020-07-07 10:38:52 -0700655 native_handle_t* mqHandle = native_handle_create(1 /* numFds */, 0 /* numInts */);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800656 if (mqHandle == nullptr) {
657 return;
658 }
659
660 mqHandle->data[0] = ashmemFd;
Devin Moore77d279e2020-07-07 10:38:52 -0700661 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(
662 kQueueSizeBytes, mqHandle, sizeof(T), configureEventFlagWord));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800663 if (mDesc == nullptr) {
664 return;
665 }
666 initMemory(true);
667}
668
669template <typename T, MQFlavor flavor>
670MessageQueue<T, flavor>::~MessageQueue() {
671 if (flavor == kUnsynchronizedWrite) {
672 delete mReadPtr;
673 } else {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800674 unmapGrantorDescr(mReadPtr, Descriptor::READPTRPOS);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800675 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800676 if (mWritePtr != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800677 unmapGrantorDescr(mWritePtr, Descriptor::WRITEPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800678 }
679 if (mRing != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800680 unmapGrantorDescr(mRing, Descriptor::DATAPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800681 }
682 if (mEvFlagWord != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800683 unmapGrantorDescr(mEvFlagWord, Descriptor::EVFLAGWORDPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800684 android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
685 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800686}
687
688template <typename T, MQFlavor flavor>
689bool MessageQueue<T, flavor>::write(const T* data) {
690 return write(data, 1);
691}
692
693template <typename T, MQFlavor flavor>
694bool MessageQueue<T, flavor>::read(T* data) {
695 return read(data, 1);
696}
697
698template <typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800699bool MessageQueue<T, flavor>::write(const T* data, size_t nMessages) {
700 MemTransaction tx;
Devin Moore77d279e2020-07-07 10:38:52 -0700701 return beginWrite(nMessages, &tx) && tx.copyTo(data, 0 /* startIdx */, nMessages) &&
702 commitWrite(nMessages);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800703}
704
705template <typename T, MQFlavor flavor>
Devin Moore77d279e2020-07-07 10:38:52 -0700706bool MessageQueue<T, flavor>::writeBlocking(const T* data, size_t count, uint32_t readNotification,
707 uint32_t writeNotification, int64_t timeOutNanos,
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800708 android::hardware::EventFlag* evFlag) {
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700709 static_assert(flavor == kSynchronizedReadWrite,
710 "writeBlocking can only be used with the "
711 "kSynchronizedReadWrite flavor.");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800712 /*
713 * If evFlag is null and the FMQ does not have its own EventFlag object
714 * return false;
715 * If the flavor is kSynchronizedReadWrite and the readNotification
716 * bit mask is zero return false;
717 * If the count is greater than queue size, return false
718 * to prevent blocking until timeOut.
719 */
720 if (evFlag == nullptr) {
721 evFlag = mEventFlag;
722 if (evFlag == nullptr) {
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700723 details::logError(
Devin Moore77d279e2020-07-07 10:38:52 -0700724 "writeBlocking failed: called on MessageQueue with no Eventflag"
725 "configured or provided");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800726 return false;
727 }
728 }
729
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700730 if (readNotification == 0 || (count > getQuantumCount())) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800731 return false;
732 }
733
734 /*
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700735 * There is no need to wait for a readNotification if there is sufficient
736 * space to write is already present in the FMQ. The latter would be the case when
737 * read operations read more number of messages than write operations write.
738 * In other words, a single large read may clear the FMQ after multiple small
739 * writes. This would fail to clear a pending readNotification bit since
740 * EventFlag bits can only be cleared by a wait() call, however the bit would
741 * be correctly cleared by the next writeBlocking() call.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800742 */
743
744 bool result = write(data, count);
745 if (result) {
746 if (writeNotification) {
747 evFlag->wake(writeNotification);
748 }
749 return result;
750 }
751
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800752 bool shouldTimeOut = timeOutNanos != 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700753 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800754
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700755 while (true) {
756 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800757 if (shouldTimeOut) {
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700758 /*
759 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
760 * to Nanoseconds)
761 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800762 int64_t currentTimeNs = android::elapsedRealtimeNano();
763 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700764 * Decrement 'timeOutNanos' to account for the time taken to complete the last
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800765 * iteration of the while loop.
766 */
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700767 timeOutNanos -= currentTimeNs - prevTimeNanos;
768 prevTimeNanos = currentTimeNs;
769
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800770 if (timeOutNanos <= 0) {
771 /*
772 * Attempt write in case a context switch happened outside of
773 * evFlag->wait().
774 */
775 result = write(data, count);
776 break;
777 }
778 }
779
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800780 /*
781 * wait() will return immediately if there was a pending read
782 * notification.
783 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800784 uint32_t efState = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700785 status_t status = evFlag->wait(readNotification, &efState, timeOutNanos,
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700786 true /* retry on spurious wake */);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800787
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700788 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
Devin Moore77d279e2020-07-07 10:38:52 -0700789 details::logError("Unexpected error code from EventFlag Wait status " +
790 std::to_string(status));
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700791 break;
792 }
793
794 if (status == android::TIMED_OUT) {
795 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800796 }
797
798 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700799 * If there is still insufficient space to write to the FMQ,
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800800 * keep waiting for another readNotification.
801 */
802 if ((efState & readNotification) && write(data, count)) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800803 result = true;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700804 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800805 }
806 }
807
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800808 if (result && writeNotification != 0) {
809 evFlag->wake(writeNotification);
810 }
811
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800812 return result;
813}
814
815template <typename T, MQFlavor flavor>
Devin Moore77d279e2020-07-07 10:38:52 -0700816bool MessageQueue<T, flavor>::writeBlocking(const T* data, size_t count, int64_t timeOutNanos) {
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800817 return writeBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
818}
819
820template <typename T, MQFlavor flavor>
Devin Moore77d279e2020-07-07 10:38:52 -0700821bool MessageQueue<T, flavor>::readBlocking(T* data, size_t count, uint32_t readNotification,
822 uint32_t writeNotification, int64_t timeOutNanos,
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800823 android::hardware::EventFlag* evFlag) {
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700824 static_assert(flavor == kSynchronizedReadWrite,
825 "readBlocking can only be used with the "
826 "kSynchronizedReadWrite flavor.");
827
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800828 /*
829 * If evFlag is null and the FMQ does not own its own EventFlag object
830 * return false;
831 * If the writeNotification bit mask is zero return false;
832 * If the count is greater than queue size, return false to prevent
833 * blocking until timeOut.
834 */
835 if (evFlag == nullptr) {
836 evFlag = mEventFlag;
837 if (evFlag == nullptr) {
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700838 details::logError(
Devin Moore77d279e2020-07-07 10:38:52 -0700839 "readBlocking failed: called on MessageQueue with no Eventflag"
840 "configured or provided");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800841 return false;
842 }
843 }
844
845 if (writeNotification == 0 || count > getQuantumCount()) {
846 return false;
847 }
848
849 /*
850 * There is no need to wait for a write notification if sufficient
851 * data to read is already present in the FMQ. This would be the
852 * case when read operations read lesser number of messages than
853 * a write operation and multiple reads would be required to clear the queue
854 * after a single write operation. This check would fail to clear a pending
855 * writeNotification bit since EventFlag bits can only be cleared
856 * by a wait() call, however the bit would be correctly cleared by the next
857 * readBlocking() call.
858 */
859
860 bool result = read(data, count);
861 if (result) {
862 if (readNotification) {
863 evFlag->wake(readNotification);
864 }
865 return result;
866 }
867
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800868 bool shouldTimeOut = timeOutNanos != 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700869 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800870
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700871 while (true) {
872 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800873 if (shouldTimeOut) {
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700874 /*
875 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
876 * to Nanoseconds)
877 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800878 int64_t currentTimeNs = android::elapsedRealtimeNano();
879 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700880 * Decrement 'timeOutNanos' to account for the time taken to complete the last
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800881 * iteration of the while loop.
882 */
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700883 timeOutNanos -= currentTimeNs - prevTimeNanos;
884 prevTimeNanos = currentTimeNs;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800885
886 if (timeOutNanos <= 0) {
887 /*
888 * Attempt read in case a context switch happened outside of
889 * evFlag->wait().
890 */
891 result = read(data, count);
892 break;
893 }
894 }
895
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800896 /*
897 * wait() will return immediately if there was a pending write
898 * notification.
899 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800900 uint32_t efState = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700901 status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos,
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700902 true /* retry on spurious wake */);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800903
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700904 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
Devin Moore77d279e2020-07-07 10:38:52 -0700905 details::logError("Unexpected error code from EventFlag Wait status " +
906 std::to_string(status));
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700907 break;
908 }
909
910 if (status == android::TIMED_OUT) {
911 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800912 }
913
914 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700915 * If the data in FMQ is still insufficient, go back to waiting
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800916 * for another write notification.
917 */
918 if ((efState & writeNotification) && read(data, count)) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800919 result = true;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700920 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800921 }
922 }
923
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800924 if (result && readNotification != 0) {
925 evFlag->wake(readNotification);
926 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800927 return result;
928}
929
930template <typename T, MQFlavor flavor>
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800931bool MessageQueue<T, flavor>::readBlocking(T* data, size_t count, int64_t timeOutNanos) {
932 return readBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
933}
934
935template <typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800936size_t MessageQueue<T, flavor>::availableToWriteBytes() const {
937 return mDesc->getSize() - availableToReadBytes();
938}
939
940template <typename T, MQFlavor flavor>
941size_t MessageQueue<T, flavor>::availableToWrite() const {
942 return availableToWriteBytes() / sizeof(T);
943}
944
945template <typename T, MQFlavor flavor>
946size_t MessageQueue<T, flavor>::availableToRead() const {
947 return availableToReadBytes() / sizeof(T);
948}
949
950template <typename T, MQFlavor flavor>
951bool MessageQueue<T, flavor>::beginWrite(size_t nMessages, MemTransaction* result) const {
952 /*
953 * If nMessages is greater than size of FMQ or in case of the synchronized
954 * FMQ flavor, if there is not enough space to write nMessages, then return
955 * result with null addresses.
956 */
957 if ((flavor == kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
958 nMessages > getQuantumCount()) {
959 *result = MemTransaction();
960 return false;
961 }
962
963 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
964 size_t writeOffset = writePtr % mDesc->getSize();
965
966 /*
967 * From writeOffset, the number of messages that can be written
968 * contiguously without wrapping around the ring buffer are calculated.
969 */
970 size_t contiguousMessages = (mDesc->getSize() - writeOffset) / sizeof(T);
971
972 if (contiguousMessages < nMessages) {
973 /*
974 * Wrap around is required. Both result.first and result.second are
975 * populated.
976 */
Devin Moore77d279e2020-07-07 10:38:52 -0700977 *result = MemTransaction(
978 MemRegion(reinterpret_cast<T*>(mRing + writeOffset), contiguousMessages),
979 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800980 } else {
981 /*
982 * A wrap around is not required to write nMessages. Only result.first
983 * is populated.
984 */
985 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset), nMessages),
986 MemRegion());
987 }
988
989 return true;
990}
991
992template <typename T, MQFlavor flavor>
993/*
994 * Disable integer sanitization since integer overflow here is allowed
995 * and legal.
996 */
Devin Moore77d279e2020-07-07 10:38:52 -0700997__attribute__((no_sanitize("integer"))) bool MessageQueue<T, flavor>::commitWrite(
998 size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800999 size_t nBytesWritten = nMessages * sizeof(T);
1000 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
1001 writePtr += nBytesWritten;
1002 mWritePtr->store(writePtr, std::memory_order_release);
1003 /*
1004 * This method cannot fail now since we are only incrementing the writePtr
1005 * counter.
1006 */
1007 return true;
1008}
1009
1010template <typename T, MQFlavor flavor>
1011size_t MessageQueue<T, flavor>::availableToReadBytes() const {
1012 /*
1013 * This method is invoked by implementations of both read() and write() and
1014 * hence requries a memory_order_acquired load for both mReadPtr and
1015 * mWritePtr.
1016 */
Devin Moore77d279e2020-07-07 10:38:52 -07001017 return mWritePtr->load(std::memory_order_acquire) - mReadPtr->load(std::memory_order_acquire);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001018}
1019
1020template <typename T, MQFlavor flavor>
1021bool MessageQueue<T, flavor>::read(T* data, size_t nMessages) {
1022 MemTransaction tx;
Devin Moore77d279e2020-07-07 10:38:52 -07001023 return beginRead(nMessages, &tx) && tx.copyFrom(data, 0 /* startIdx */, nMessages) &&
1024 commitRead(nMessages);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001025}
1026
1027template <typename T, MQFlavor flavor>
1028/*
1029 * Disable integer sanitization since integer overflow here is allowed
1030 * and legal.
1031 */
Devin Moore77d279e2020-07-07 10:38:52 -07001032__attribute__((no_sanitize("integer"))) bool MessageQueue<T, flavor>::beginRead(
1033 size_t nMessages, MemTransaction* result) const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001034 *result = MemTransaction();
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001035 /*
1036 * If it is detected that the data in the queue was overwritten
1037 * due to the reader process being too slow, the read pointer counter
1038 * is set to the same as the write pointer counter to indicate error
1039 * and the read returns false;
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001040 * Need acquire/release memory ordering for mWritePtr.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001041 */
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001042 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1043 /*
1044 * A relaxed load is sufficient for mReadPtr since there will be no
1045 * stores to mReadPtr from a different thread.
1046 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001047 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
1048
1049 if (writePtr - readPtr > mDesc->getSize()) {
1050 mReadPtr->store(writePtr, std::memory_order_release);
1051 return false;
1052 }
1053
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001054 size_t nBytesDesired = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001055 /*
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001056 * Return if insufficient data to read in FMQ.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001057 */
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001058 if (writePtr - readPtr < nBytesDesired) {
1059 return false;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001060 }
1061
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001062 size_t readOffset = readPtr % mDesc->getSize();
1063 /*
1064 * From readOffset, the number of messages that can be read contiguously
1065 * without wrapping around the ring buffer are calculated.
1066 */
1067 size_t contiguousMessages = (mDesc->getSize() - readOffset) / sizeof(T);
1068
1069 if (contiguousMessages < nMessages) {
1070 /*
1071 * A wrap around is required. Both result.first and result.second
1072 * are populated.
1073 */
Devin Moore77d279e2020-07-07 10:38:52 -07001074 *result = MemTransaction(
1075 MemRegion(reinterpret_cast<T*>(mRing + readOffset), contiguousMessages),
1076 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001077 } else {
1078 /*
1079 * A wrap around is not required. Only result.first need to be
1080 * populated.
1081 */
1082 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset), nMessages),
1083 MemRegion());
1084 }
1085
1086 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001087}
1088
1089template <typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001090/*
1091 * Disable integer sanitization since integer overflow here is allowed
1092 * and legal.
1093 */
Devin Moore77d279e2020-07-07 10:38:52 -07001094__attribute__((no_sanitize("integer"))) bool MessageQueue<T, flavor>::commitRead(size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001095 // TODO: Use a local copy of readPtr to avoid relazed mReadPtr loads.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001096 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001097 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1098 /*
1099 * If the flavor is unsynchronized, it is possible that a write overflow may
1100 * have occured between beginRead() and commitRead().
1101 */
1102 if (writePtr - readPtr > mDesc->getSize()) {
1103 mReadPtr->store(writePtr, std::memory_order_release);
1104 return false;
1105 }
1106
1107 size_t nBytesRead = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001108 readPtr += nBytesRead;
1109 mReadPtr->store(readPtr, std::memory_order_release);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001110 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001111}
1112
1113template <typename T, MQFlavor flavor>
1114size_t MessageQueue<T, flavor>::getQuantumSize() const {
1115 return mDesc->getQuantum();
1116}
1117
1118template <typename T, MQFlavor flavor>
1119size_t MessageQueue<T, flavor>::getQuantumCount() const {
1120 return mDesc->getSize() / mDesc->getQuantum();
1121}
1122
1123template <typename T, MQFlavor flavor>
1124bool MessageQueue<T, flavor>::isValid() const {
1125 return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
1126}
1127
1128template <typename T, MQFlavor flavor>
1129void* MessageQueue<T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001130 const native_handle_t* handle = mDesc->handle();
1131 auto grantors = mDesc->grantors();
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001132 if (handle == nullptr) {
1133 details::logError("mDesc->handle is null");
1134 return nullptr;
1135 }
1136
1137 if (grantorIdx >= grantors.size()) {
1138 details::logError(std::string("grantorIdx must be less than ") +
1139 std::to_string(grantors.size()));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001140 return nullptr;
1141 }
1142
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001143 int fdIndex = grantors[grantorIdx].fdIndex;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001144 /*
1145 * Offset for mmap must be a multiple of PAGE_SIZE.
1146 */
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001147 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
Devin Moore77d279e2020-07-07 10:38:52 -07001148 int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001149
Devin Moore77d279e2020-07-07 10:38:52 -07001150 void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED, handle->data[fdIndex],
1151 mapOffset);
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001152 if (address == MAP_FAILED) {
1153 details::logError(std::string("mmap failed: ") + std::to_string(errno));
1154 return nullptr;
1155 }
1156 return reinterpret_cast<uint8_t*>(address) + (grantors[grantorIdx].offset - mapOffset);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001157}
1158
1159template <typename T, MQFlavor flavor>
Devin Moore77d279e2020-07-07 10:38:52 -07001160void MessageQueue<T, flavor>::unmapGrantorDescr(void* address, uint32_t grantorIdx) {
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001161 auto grantors = mDesc->grantors();
1162 if ((address == nullptr) || (grantorIdx >= grantors.size())) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001163 return;
1164 }
1165
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001166 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
Devin Moore77d279e2020-07-07 10:38:52 -07001167 int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
1168 void* baseAddress =
1169 reinterpret_cast<uint8_t*>(address) - (grantors[grantorIdx].offset - mapOffset);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001170 if (baseAddress) munmap(baseAddress, mapLength);
1171}
1172
1173} // namespace hardware
1174} // namespace android
1175#endif // HIDL_MQ_H