blob: 6f315b2f97125a8ddd274f5dd6935fc4b01ca0bf [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
20#include <android-base/logging.h>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080021#include <atomic>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080022#include <cutils/ashmem.h>
23#include <fmq/EventFlag.h>
24#include <hidl/MQDescriptor.h>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080025#include <new>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080026#include <sys/mman.h>
27#include <utils/Log.h>
Hridya Valsaraju2abefb62017-01-19 13:06:58 -080028#include <utils/SystemClock.h>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080029
30namespace android {
31namespace hardware {
32
33template <typename T, MQFlavor flavor>
34struct MessageQueue {
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -080035 typedef MQDescriptor<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 */
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -080042 MessageQueue(const Descriptor& Desc, bool resetPointers = true);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080043
44 ~MessageQueue();
45
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 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -080054 MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord = false);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080055
56 /**
57 * @return Number of items of type T that can be written into the FMQ
58 * without a read.
59 */
60 size_t availableToWrite() const;
61
62 /**
63 * @return Number of items of type T that are waiting to be read from the
64 * FMQ.
65 */
66 size_t availableToRead() const;
67
68 /**
69 * Returns the size of type T in bytes.
70 *
71 * @param Size of T.
72 */
73 size_t getQuantumSize() const;
74
75 /**
76 * Returns the size of the FMQ in terms of the size of type T.
77 *
78 * @return Number of items of type T that will fit in the FMQ.
79 */
80 size_t getQuantumCount() const;
81
82 /**
83 * @return Whether the FMQ is configured correctly.
84 */
85 bool isValid() const;
86
87 /**
88 * Non-blocking write to FMQ.
89 *
90 * @param data Pointer to the object of type T to be written into the FMQ.
91 *
92 * @return Whether the write was successful.
93 */
94 bool write(const T* data);
95
96 /**
97 * Non-blocking read from FMQ.
98 *
99 * @param data Pointer to the memory where the object read from the FMQ is
100 * copied to.
101 *
102 * @return Whether the read was successful.
103 */
104 bool read(T* data);
105
106 /**
107 * Write some data into the FMQ without blocking.
108 *
109 * @param data Pointer to the array of items of type T.
110 * @param count Number of items in array.
111 *
112 * @return Whether the write was successful.
113 */
114 bool write(const T* data, size_t count);
115
116 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800117 * Perform a blocking write of 'count' items into the FMQ using EventFlags.
118 * Does not support partial writes.
119 *
120 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
121 * associated with the FMQ and it is used in that case.
122 *
123 * The application code must ensure that 'evFlag' used by the
124 * reader(s)/writer is based upon the same EventFlag word.
125 *
126 * The method will return false without blocking if any of the following
127 * conditions are true:
128 * - If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
129 * - If the flavor of the FMQ is synchronized and the 'readNotification' bit mask is zero.
130 * - If 'count' is greater than the FMQ size.
131 *
132 * If the flavor of the FMQ is synchronized and there is insufficient space
133 * available to write into it, the EventFlag bit mask 'readNotification' is
134 * is waited upon.
135 *
136 * Upon a successful write, wake is called on 'writeNotification' (if
137 * non-zero).
138 *
139 * @param data Pointer to the array of items of type T.
140 * @param count Number of items in array.
141 * @param readNotification The EventFlag bit mask to wait on if there is not
142 * enough space in FMQ to write 'count' items.
143 * @param writeNotification The EventFlag bit mask to call wake on
144 * a successful write. No wake is called if 'writeNotification' is zero.
145 * @param timeOutNanos Number of nanoseconds after which the blocking
146 * write attempt is aborted.
147 * @param evFlag The EventFlag object to be used for blocking. If nullptr,
148 * it is checked whether the FMQ owns an EventFlag object and that is used
149 * for blocking instead.
150 *
151 * @return Whether the write was successful.
152 */
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800153 bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
154 uint32_t writeNotification, int64_t timeOutNanos = 0,
155 android::hardware::EventFlag* evFlag = nullptr);
156
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800157 bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
158
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800159 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800160 * Read some data from the FMQ without blocking.
161 *
162 * @param data Pointer to the array to which read data is to be written.
163 * @param count Number of items to be read.
164 *
165 * @return Whether the read was successful.
166 */
167 bool read(T* data, size_t count);
168
169 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800170 * Perform a blocking read operation of 'count' items from the FMQ. Does not
171 * perform a partial read.
172 *
173 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
174 * associated with the FMQ and it is used in that case.
175 *
176 * The application code must ensure that 'evFlag' used by the
177 * reader(s)/writer is based upon the same EventFlag word.
178 *
179 * The method will return false without blocking if any of the following
180 * conditions are true:
181 * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
182 * -If the 'writeNotification' bit mask is zero.
183 * -If 'count' is greater than the FMQ size.
184 *
185 * If FMQ does not contain 'count' items, the eventFlag bit mask
186 * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
187 * wake is called on 'readNotification' (if non-zero).
188 *
189 * @param data Pointer to the array to which read data is to be written.
190 * @param count Number of items to be read.
191 * @param readNotification The EventFlag bit mask to call wake on after
192 * a successful read. No wake is called if 'readNotification' is zero.
193 * @param writeNotification The EventFlag bit mask to call a wait on
194 * if there is insufficient data in the FMQ to be read.
195 * @param timeOutNanos Number of nanoseconds after which the blocking
196 * read attempt is aborted.
197 * @param evFlag The EventFlag object to be used for blocking.
198 *
199 * @return Whether the read was successful.
200 */
201 bool readBlocking(T* data, size_t count, uint32_t readNotification,
202 uint32_t writeNotification, int64_t timeOutNanos = 0,
203 android::hardware::EventFlag* evFlag = nullptr);
204
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800205 bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);
206
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800207 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800208 * Get a pointer to the MQDescriptor object that describes this FMQ.
209 *
210 * @return Pointer to the MQDescriptor associated with the FMQ.
211 */
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800212 const Descriptor* getDesc() const { return mDesc.get(); }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800213
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800214 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800215 * Get a pointer to the EventFlag word if there is one associated with this FMQ.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800216 *
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800217 * @return Pointer to an EventFlag word, will return nullptr if not
218 * configured. This method does not transfer ownership. The EventFlag
219 * word will be unmapped by the MessageQueue destructor.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800220 */
221 std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800222
223 /**
224 * Describes a memory region in the FMQ.
225 */
226 struct MemRegion {
227 MemRegion() : MemRegion(nullptr, 0) {}
228
229 MemRegion(T* base, size_t size) : address(base), length(size) {}
230
231 MemRegion& operator=(const MemRegion &other) {
232 address = other.address;
233 length = other.length;
234 return *this;
235 }
236
237 /**
238 * Gets a pointer to the base address of the MemRegion.
239 */
240 inline T* getAddress() const { return address; }
241
242 /**
243 * Gets the length of the MemRegion. This would equal to the number
244 * of items of type T that can be read from/written into the MemRegion.
245 */
246 inline size_t getLength() const { return length; }
247
248 /**
249 * Gets the length of the MemRegion in bytes.
250 */
251 inline size_t getLengthInBytes() const { return length * sizeof(T); }
252
253 private:
254 /* Base address */
255 T* address;
256
257 /*
258 * Number of items of type T that can be written to/read from the base
259 * address.
260 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800261 size_t length;
262 };
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800263
264 /**
265 * Describes the memory regions to be used for a read or write.
266 * The struct contains two MemRegion objects since the FMQ is a ring
267 * buffer and a read or write operation can wrap around. A single message
268 * of type T will never be broken between the two MemRegions.
269 */
270 struct MemTransaction {
271 MemTransaction() : MemTransaction(MemRegion(), MemRegion()) {}
272
273 MemTransaction(const MemRegion& regionFirst, const MemRegion& regionSecond) :
274 first(regionFirst), second(regionSecond) {}
275
276 MemTransaction& operator=(const MemTransaction &other) {
277 first = other.first;
278 second = other.second;
279 return *this;
280 }
281
282 /**
283 * Helper method to calculate the address for a particular index for
284 * the MemTransaction object.
285 *
286 * @param idx Index of the slot to be read/written. If the
287 * MemTransaction object is representing the memory region to read/write
288 * N items of type T, the valid range of idx is between 0 and N-1.
289 *
290 * @return Pointer to the slot idx. Will be nullptr for an invalid idx.
291 */
292 T* getSlot(size_t idx);
293
294 /**
295 * Helper method to write 'nMessages' items of type T into the memory
296 * regions described by the object starting from 'startIdx'. This method
297 * uses memcpy() and is not to meant to be used for a zero copy operation.
298 * Partial writes are not supported.
299 *
300 * @param data Pointer to the source buffer.
301 * @param nMessages Number of items of type T.
302 * @param startIdx The slot number to begin the write from. If the
303 * MemTransaction object is representing the memory region to read/write
304 * N items of type T, the valid range of startIdx is between 0 and N-1;
305 *
306 * @return Whether the write operation of size 'nMessages' succeeded.
307 */
308 bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
309
310 /*
311 * Helper method to read 'nMessages' items of type T from the memory
312 * regions described by the object starting from 'startIdx'. This method uses
313 * memcpy() and is not meant to be used for a zero copy operation. Partial reads
314 * are not supported.
315 *
316 * @param data Pointer to the destination buffer.
317 * @param nMessages Number of items of type T.
318 * @param startIdx The slot number to begin the read from. If the
319 * MemTransaction object is representing the memory region to read/write
320 * N items of type T, the valid range of startIdx is between 0 and N-1.
321 *
322 * @return Whether the read operation of size 'nMessages' succeeded.
323 */
324 bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
325
326 /**
327 * Returns a const reference to the first MemRegion in the
328 * MemTransaction object.
329 */
330 inline const MemRegion& getFirstRegion() const { return first; }
331
332 /**
333 * Returns a const reference to the second MemRegion in the
334 * MemTransaction object.
335 */
336 inline const MemRegion& getSecondRegion() const { return second; }
337
338 private:
339 /*
340 * Given a start index and the number of messages to be
341 * read/written, this helper method calculates the
342 * number of messages that should should be written to both the first
343 * and second MemRegions and the base addresses to be used for
344 * the read/write operation.
345 *
346 * Returns false if the 'startIdx' and 'nMessages' is
347 * invalid for the MemTransaction object.
348 */
349 bool inline getMemRegionInfo(size_t idx,
350 size_t nMessages,
351 size_t& firstCount,
352 size_t& secondCount,
353 T** firstBaseAddress,
354 T** secondBaseAddress);
355 MemRegion first;
356 MemRegion second;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800357 };
358
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800359 /**
360 * Get a MemTransaction object to write 'nMessages' items of type T.
361 * Once the write is performed using the information from MemTransaction,
362 * the write operation is to be committed using a call to commitWrite().
363 *
364 * @param nMessages Number of messages of type T.
365 * @param Pointer to MemTransaction struct that describes memory to write 'nMessages'
366 * items of type T. If a write of size 'nMessages' is not possible, the base
367 * addresses in the MemTransaction object would be set to nullptr.
368 *
369 * @return Whether it is possible to write 'nMessages' items of type T
370 * into the FMQ.
371 */
372 bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800373
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800374 /**
375 * Commit a write of size 'nMessages'. To be only used after a call to beginWrite().
376 *
377 * @param nMessages number of messages of type T to be written.
378 *
379 * @return Whether the write operation of size 'nMessages' succeeded.
380 */
381 bool commitWrite(size_t nMessages);
382
383 /**
384 * Get a MemTransaction object to read 'nMessages' items of type T.
385 * Once the read is performed using the information from MemTransaction,
386 * the read operation is to be committed using a call to commitRead().
387 *
388 * @param nMessages Number of messages of type T.
389 * @param pointer to MemTransaction struct that describes memory to read 'nMessages'
390 * items of type T. If a read of size 'nMessages' is not possible, the base
391 * pointers in the MemTransaction object returned will be set to nullptr.
392 *
393 * @return bool Whether it is possible to read 'nMessages' items of type T
394 * from the FMQ.
395 */
396 bool beginRead(size_t nMessages, MemTransaction* memTx) const;
397
398 /**
399 * Commit a read of size 'nMessages'. To be only used after a call to beginRead().
400 * For the unsynchronized flavor of FMQ, this method will return a failure
401 * if a write overflow happened after beginRead() was invoked.
402 *
403 * @param nMessages number of messages of type T to be read.
404 *
405 * @return bool Whether the read operation of size 'nMessages' succeeded.
406 */
407 bool commitRead(size_t nMessages);
408
409private:
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800410
411 size_t availableToWriteBytes() const;
412 size_t availableToReadBytes() const;
413
414 MessageQueue(const MessageQueue& other) = delete;
415 MessageQueue& operator=(const MessageQueue& other) = delete;
416 MessageQueue();
417
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 /*
424 * These are only used internally by the blockingRead()/blockingWrite()
425 * methods and hence once other bit combinations are not required.
426 */
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800427 FMQ_NOT_FULL = 0x01,
428 FMQ_NOT_EMPTY = 0x02
429 };
430
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800431 std::unique_ptr<Descriptor> mDesc;
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800432 uint8_t* mRing = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800433 /*
434 * TODO(b/31550092): Change to 32 bit read and write pointer counters.
435 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800436 std::atomic<uint64_t>* mReadPtr = nullptr;
437 std::atomic<uint64_t>* mWritePtr = nullptr;
438
439 std::atomic<uint32_t>* mEvFlagWord = nullptr;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800440
441 /*
442 * This EventFlag object will be owned by the FMQ and will have the same
443 * lifetime.
444 */
445 android::hardware::EventFlag* mEventFlag = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800446};
447
448template <typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800449T* MessageQueue<T, flavor>::MemTransaction::getSlot(size_t idx) {
450 size_t firstRegionLength = first.getLength();
451 size_t secondRegionLength = second.getLength();
452
453 if (idx > firstRegionLength + secondRegionLength) {
454 return nullptr;
455 }
456
457 if (idx < firstRegionLength) {
458 return first.getAddress() + idx;
459 }
460
461 return second.getAddress() + idx - firstRegionLength;
462}
463
464template <typename T, MQFlavor flavor>
465bool MessageQueue<T, flavor>::MemTransaction::getMemRegionInfo(size_t startIdx,
466 size_t nMessages,
467 size_t& firstCount,
468 size_t& secondCount,
469 T** firstBaseAddress,
470 T** secondBaseAddress) {
471 size_t firstRegionLength = first.getLength();
472 size_t secondRegionLength = second.getLength();
473
474 if (startIdx + nMessages > firstRegionLength + secondRegionLength) {
475 /*
476 * Return false if 'nMessages' starting at 'startIdx' cannot be
477 * accomodated by the MemTransaction object.
478 */
479 return false;
480 }
481
482 /* Number of messages to be read/written to the first MemRegion. */
483 firstCount = startIdx < firstRegionLength ?
484 std::min(nMessages, firstRegionLength - startIdx) : 0;
485
486 /* Number of messages to be read/written to the second MemRegion. */
487 secondCount = nMessages - firstCount;
488
489 if (firstCount != 0) {
490 *firstBaseAddress = first.getAddress() + startIdx;
491 }
492
493 if (secondCount != 0) {
494 size_t secondStartIdx = startIdx > firstRegionLength ? startIdx - firstRegionLength : 0;
495 *secondBaseAddress = second.getAddress() + secondStartIdx;
496 }
497
498 return true;
499}
500
501template <typename T, MQFlavor flavor>
502bool MessageQueue<T, flavor>::MemTransaction::copyFrom(T* data, size_t startIdx, size_t nMessages) {
503 if (data == nullptr) {
504 return false;
505 }
506
507 size_t firstReadCount = 0, secondReadCount = 0;
508 T* firstBaseAddress = nullptr, * secondBaseAddress = nullptr;
509
510 if (getMemRegionInfo(startIdx,
511 nMessages,
512 firstReadCount,
513 secondReadCount,
514 &firstBaseAddress,
515 &secondBaseAddress) == false) {
516 /*
517 * Returns false if 'startIdx' and 'nMessages' are invalid for this
518 * MemTransaction object.
519 */
520 return false;
521 }
522
523 if (firstReadCount != 0) {
524 memcpy(data, firstBaseAddress, firstReadCount * sizeof(T));
525 }
526
527 if (secondReadCount != 0) {
528 memcpy(data + firstReadCount,
529 secondBaseAddress,
530 secondReadCount * sizeof(T));
531 }
532
533 return true;
534}
535
536template <typename T, MQFlavor flavor>
537bool MessageQueue<T, flavor>::MemTransaction::copyTo(const T* data,
538 size_t startIdx,
539 size_t nMessages) {
540 if (data == nullptr) {
541 return false;
542 }
543
544 size_t firstWriteCount = 0, secondWriteCount = 0;
545 T * firstBaseAddress = nullptr, * secondBaseAddress = nullptr;
546
547 if (getMemRegionInfo(startIdx,
548 nMessages,
549 firstWriteCount,
550 secondWriteCount,
551 &firstBaseAddress,
552 &secondBaseAddress) == false) {
553 /*
554 * Returns false if 'startIdx' and 'nMessages' are invalid for this
555 * MemTransaction object.
556 */
557 return false;
558 }
559
560 if (firstWriteCount != 0) {
561 memcpy(firstBaseAddress, data, firstWriteCount * sizeof(T));
562 }
563
564 if (secondWriteCount != 0) {
565 memcpy(secondBaseAddress,
566 data + firstWriteCount,
567 secondWriteCount * sizeof(T));
568 }
569
570 return true;
571}
572
573template <typename T, MQFlavor flavor>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800574void MessageQueue<T, flavor>::initMemory(bool resetPointers) {
575 /*
576 * Verify that the the Descriptor contains the minimum number of grantors
577 * the native_handle is valid and T matches quantum size.
578 */
579 if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800580 (mDesc->countGrantors() < Descriptor::kMinGrantorCount) ||
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800581 (mDesc->getQuantum() != sizeof(T))) {
582 return;
583 }
584
585 if (flavor == kSynchronizedReadWrite) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800586 mReadPtr = reinterpret_cast<std::atomic<uint64_t>*>(
587 mapGrantorDescr(Descriptor::READPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800588 } else {
589 /*
590 * The unsynchronized write flavor of the FMQ may have multiple readers
591 * and each reader would have their own read pointer counter.
592 */
593 mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
594 }
595
596 CHECK(mReadPtr != nullptr);
597
598 mWritePtr =
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800599 reinterpret_cast<std::atomic<uint64_t>*>(mapGrantorDescr(Descriptor::WRITEPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800600 CHECK(mWritePtr != nullptr);
601
602 if (resetPointers) {
603 mReadPtr->store(0, std::memory_order_release);
604 mWritePtr->store(0, std::memory_order_release);
605 } else if (flavor != kSynchronizedReadWrite) {
606 // Always reset the read pointer.
607 mReadPtr->store(0, std::memory_order_release);
608 }
609
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800610 mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(Descriptor::DATAPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800611 CHECK(mRing != nullptr);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800612
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800613 mEvFlagWord = static_cast<std::atomic<uint32_t>*>(mapGrantorDescr(Descriptor::EVFLAGWORDPOS));
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800614 if (mEvFlagWord != nullptr) {
615 android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
616 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800617}
618
619template <typename T, MQFlavor flavor>
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800620MessageQueue<T, flavor>::MessageQueue(const Descriptor& Desc, bool resetPointers) {
621 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800622 if (mDesc == nullptr) {
623 return;
624 }
625
626 initMemory(resetPointers);
627}
628
629template <typename T, MQFlavor flavor>
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800630MessageQueue<T, flavor>::MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord) {
Kevin Rocard1d6e40f2017-04-03 11:51:13 -0700631
632 // Check if the buffer size would not overflow size_t
633 if (numElementsInQueue > SIZE_MAX / sizeof(T)) {
634 return;
635 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800636 /*
637 * The FMQ needs to allocate memory for the ringbuffer as well as for the
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800638 * read and write pointer counters. If an EventFlag word is to be configured,
639 * we also need to allocate memory for the same/
640 */
641 size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
642 size_t kMetaDataSize = 2 * sizeof(android::hardware::RingBufferPosition);
643
644 if (configureEventFlagWord) {
645 kMetaDataSize+= sizeof(std::atomic<uint32_t>);
646 }
647
648 /*
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800649 * Ashmem memory region size needs to be specified in page-aligned bytes.
650 * kQueueSizeBytes needs to be aligned to word boundary so that all offsets
651 * in the grantorDescriptor will be word aligned.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800652 */
653 size_t kAshmemSizePageAligned =
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800654 (Descriptor::alignToWordBoundary(kQueueSizeBytes) + kMetaDataSize + PAGE_SIZE - 1) &
655 ~(PAGE_SIZE - 1);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800656
657 /*
658 * Create an ashmem region to map the memory for the ringbuffer,
659 * read counter and write counter.
660 */
661 int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
662 ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
663
664 /*
665 * The native handle will contain the fds to be mapped.
666 */
667 native_handle_t* mqHandle =
668 native_handle_create(1 /* numFds */, 0 /* numInts */);
669 if (mqHandle == nullptr) {
670 return;
671 }
672
673 mqHandle->data[0] = ashmemFd;
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800674 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(kQueueSizeBytes,
675 mqHandle,
676 sizeof(T),
677 configureEventFlagWord));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800678 if (mDesc == nullptr) {
679 return;
680 }
681 initMemory(true);
682}
683
684template <typename T, MQFlavor flavor>
685MessageQueue<T, flavor>::~MessageQueue() {
686 if (flavor == kUnsynchronizedWrite) {
687 delete mReadPtr;
688 } else {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800689 unmapGrantorDescr(mReadPtr, Descriptor::READPTRPOS);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800690 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800691 if (mWritePtr != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800692 unmapGrantorDescr(mWritePtr, Descriptor::WRITEPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800693 }
694 if (mRing != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800695 unmapGrantorDescr(mRing, Descriptor::DATAPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800696 }
697 if (mEvFlagWord != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800698 unmapGrantorDescr(mEvFlagWord, Descriptor::EVFLAGWORDPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800699 android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
700 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800701}
702
703template <typename T, MQFlavor flavor>
704bool MessageQueue<T, flavor>::write(const T* data) {
705 return write(data, 1);
706}
707
708template <typename T, MQFlavor flavor>
709bool MessageQueue<T, flavor>::read(T* data) {
710 return read(data, 1);
711}
712
713template <typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800714bool MessageQueue<T, flavor>::write(const T* data, size_t nMessages) {
715 MemTransaction tx;
716 return beginWrite(nMessages, &tx) &&
717 tx.copyTo(data, 0 /* startIdx */, nMessages) &&
718 commitWrite(nMessages);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800719}
720
721template <typename T, MQFlavor flavor>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800722bool MessageQueue<T, flavor>::writeBlocking(const T* data,
723 size_t count,
724 uint32_t readNotification,
725 uint32_t writeNotification,
726 int64_t timeOutNanos,
727 android::hardware::EventFlag* evFlag) {
728 /*
729 * If evFlag is null and the FMQ does not have its own EventFlag object
730 * return false;
731 * If the flavor is kSynchronizedReadWrite and the readNotification
732 * bit mask is zero return false;
733 * If the count is greater than queue size, return false
734 * to prevent blocking until timeOut.
735 */
736 if (evFlag == nullptr) {
737 evFlag = mEventFlag;
738 if (evFlag == nullptr) {
739 return false;
740 }
741 }
742
743 if ((readNotification == 0 && flavor == kSynchronizedReadWrite) ||
744 (count > getQuantumCount())) {
745 return false;
746 }
747
748 /*
749 * There is no need to wait for a readNotification if the flavor
750 * of the queue is kUnsynchronizedWrite or sufficient space to write
751 * is already present in the FMQ. The latter would be the case when
752 * read operations read more number of messages than
753 * write operations write. In other words, a single large read may clear the FMQ
754 * after multiple small writes. This would fail to clear a pending
755 * readNotification bit since EventFlag bits can only be cleared
756 * by a wait() call, however the bit would be correctly cleared by the next
757 * blockingWrite() call.
758 */
759
760 bool result = write(data, count);
761 if (result) {
762 if (writeNotification) {
763 evFlag->wake(writeNotification);
764 }
765 return result;
766 }
767
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800768 bool shouldTimeOut = timeOutNanos != 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700769 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800770
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700771 while (true) {
772 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800773 if (shouldTimeOut) {
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700774 /*
775 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
776 * to Nanoseconds)
777 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800778 int64_t currentTimeNs = android::elapsedRealtimeNano();
779 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700780 * Decrement 'timeOutNanos' to account for the time taken to complete the last
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800781 * iteration of the while loop.
782 */
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700783 timeOutNanos -= currentTimeNs - prevTimeNanos;
784 prevTimeNanos = currentTimeNs;
785
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800786 if (timeOutNanos <= 0) {
787 /*
788 * Attempt write in case a context switch happened outside of
789 * evFlag->wait().
790 */
791 result = write(data, count);
792 break;
793 }
794 }
795
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800796 /*
797 * wait() will return immediately if there was a pending read
798 * notification.
799 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800800 uint32_t efState = 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700801 status_t status = evFlag->wait(readNotification,
802 &efState,
803 timeOutNanos,
804 true /* retry on spurious wake */);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800805
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700806 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
807 ALOGE("Unexpected error code from EventFlag Wait write %d", status);
808 break;
809 }
810
811 if (status == android::TIMED_OUT) {
812 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800813 }
814
815 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700816 * If there is still insufficient space to write to the FMQ,
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800817 * keep waiting for another readNotification.
818 */
819 if ((efState & readNotification) && write(data, count)) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800820 result = true;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700821 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800822 }
823 }
824
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800825 if (result && writeNotification != 0) {
826 evFlag->wake(writeNotification);
827 }
828
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800829 return result;
830}
831
832template <typename T, MQFlavor flavor>
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800833bool MessageQueue<T, flavor>::writeBlocking(const T* data,
834 size_t count,
835 int64_t timeOutNanos) {
836 return writeBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
837}
838
839template <typename T, MQFlavor flavor>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800840bool MessageQueue<T, flavor>::readBlocking(T* data,
841 size_t count,
842 uint32_t readNotification,
843 uint32_t writeNotification,
844 int64_t timeOutNanos,
845 android::hardware::EventFlag* evFlag) {
846 /*
847 * If evFlag is null and the FMQ does not own its own EventFlag object
848 * return false;
849 * If the writeNotification bit mask is zero return false;
850 * If the count is greater than queue size, return false to prevent
851 * blocking until timeOut.
852 */
853 if (evFlag == nullptr) {
854 evFlag = mEventFlag;
855 if (evFlag == nullptr) {
856 return false;
857 }
858 }
859
860 if (writeNotification == 0 || count > getQuantumCount()) {
861 return false;
862 }
863
864 /*
865 * There is no need to wait for a write notification if sufficient
866 * data to read is already present in the FMQ. This would be the
867 * case when read operations read lesser number of messages than
868 * a write operation and multiple reads would be required to clear the queue
869 * after a single write operation. This check would fail to clear a pending
870 * writeNotification bit since EventFlag bits can only be cleared
871 * by a wait() call, however the bit would be correctly cleared by the next
872 * readBlocking() call.
873 */
874
875 bool result = read(data, count);
876 if (result) {
877 if (readNotification) {
878 evFlag->wake(readNotification);
879 }
880 return result;
881 }
882
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800883 bool shouldTimeOut = timeOutNanos != 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700884 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800885
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700886 while (true) {
887 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800888 if (shouldTimeOut) {
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700889 /*
890 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
891 * to Nanoseconds)
892 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800893 int64_t currentTimeNs = android::elapsedRealtimeNano();
894 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700895 * Decrement 'timeOutNanos' to account for the time taken to complete the last
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800896 * iteration of the while loop.
897 */
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700898 timeOutNanos -= currentTimeNs - prevTimeNanos;
899 prevTimeNanos = currentTimeNs;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800900
901 if (timeOutNanos <= 0) {
902 /*
903 * Attempt read in case a context switch happened outside of
904 * evFlag->wait().
905 */
906 result = read(data, count);
907 break;
908 }
909 }
910
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800911 /*
912 * wait() will return immediately if there was a pending write
913 * notification.
914 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800915 uint32_t efState = 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700916 status_t status = evFlag->wait(writeNotification,
917 &efState,
918 timeOutNanos,
919 true /* retry on spurious wake */);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800920
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700921 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
922 ALOGE("Unexpected error code from EventFlag Wait status %d", status);
923 break;
924 }
925
926 if (status == android::TIMED_OUT) {
927 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800928 }
929
930 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700931 * If the data in FMQ is still insufficient, go back to waiting
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800932 * for another write notification.
933 */
934 if ((efState & writeNotification) && read(data, count)) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800935 result = true;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700936 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800937 }
938 }
939
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800940 if (result && readNotification != 0) {
941 evFlag->wake(readNotification);
942 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800943 return result;
944}
945
946template <typename T, MQFlavor flavor>
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800947bool MessageQueue<T, flavor>::readBlocking(T* data, size_t count, int64_t timeOutNanos) {
948 return readBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
949}
950
951template <typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800952size_t MessageQueue<T, flavor>::availableToWriteBytes() const {
953 return mDesc->getSize() - availableToReadBytes();
954}
955
956template <typename T, MQFlavor flavor>
957size_t MessageQueue<T, flavor>::availableToWrite() const {
958 return availableToWriteBytes() / sizeof(T);
959}
960
961template <typename T, MQFlavor flavor>
962size_t MessageQueue<T, flavor>::availableToRead() const {
963 return availableToReadBytes() / sizeof(T);
964}
965
966template <typename T, MQFlavor flavor>
967bool MessageQueue<T, flavor>::beginWrite(size_t nMessages, MemTransaction* result) const {
968 /*
969 * If nMessages is greater than size of FMQ or in case of the synchronized
970 * FMQ flavor, if there is not enough space to write nMessages, then return
971 * result with null addresses.
972 */
973 if ((flavor == kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
974 nMessages > getQuantumCount()) {
975 *result = MemTransaction();
976 return false;
977 }
978
979 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
980 size_t writeOffset = writePtr % mDesc->getSize();
981
982 /*
983 * From writeOffset, the number of messages that can be written
984 * contiguously without wrapping around the ring buffer are calculated.
985 */
986 size_t contiguousMessages = (mDesc->getSize() - writeOffset) / sizeof(T);
987
988 if (contiguousMessages < nMessages) {
989 /*
990 * Wrap around is required. Both result.first and result.second are
991 * populated.
992 */
993 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset),
994 contiguousMessages),
995 MemRegion(reinterpret_cast<T*>(mRing),
996 nMessages - contiguousMessages));
997 } else {
998 /*
999 * A wrap around is not required to write nMessages. Only result.first
1000 * is populated.
1001 */
1002 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset), nMessages),
1003 MemRegion());
1004 }
1005
1006 return true;
1007}
1008
1009template <typename T, MQFlavor flavor>
1010/*
1011 * Disable integer sanitization since integer overflow here is allowed
1012 * and legal.
1013 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001014__attribute__((no_sanitize("integer")))
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001015bool MessageQueue<T, flavor>::commitWrite(size_t nMessages) {
1016 size_t nBytesWritten = nMessages * sizeof(T);
1017 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
1018 writePtr += nBytesWritten;
1019 mWritePtr->store(writePtr, std::memory_order_release);
1020 /*
1021 * This method cannot fail now since we are only incrementing the writePtr
1022 * counter.
1023 */
1024 return true;
1025}
1026
1027template <typename T, MQFlavor flavor>
1028size_t MessageQueue<T, flavor>::availableToReadBytes() const {
1029 /*
1030 * This method is invoked by implementations of both read() and write() and
1031 * hence requries a memory_order_acquired load for both mReadPtr and
1032 * mWritePtr.
1033 */
1034 return mWritePtr->load(std::memory_order_acquire) -
1035 mReadPtr->load(std::memory_order_acquire);
1036}
1037
1038template <typename T, MQFlavor flavor>
1039bool MessageQueue<T, flavor>::read(T* data, size_t nMessages) {
1040 MemTransaction tx;
1041 return beginRead(nMessages, &tx) &&
1042 tx.copyFrom(data, 0 /* startIdx */, nMessages) &&
1043 commitRead(nMessages);
1044}
1045
1046template <typename T, MQFlavor flavor>
1047/*
1048 * Disable integer sanitization since integer overflow here is allowed
1049 * and legal.
1050 */
1051__attribute__((no_sanitize("integer")))
1052bool MessageQueue<T, flavor>::beginRead(size_t nMessages, MemTransaction* result) const {
1053 *result = MemTransaction();
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001054 /*
1055 * If it is detected that the data in the queue was overwritten
1056 * due to the reader process being too slow, the read pointer counter
1057 * is set to the same as the write pointer counter to indicate error
1058 * and the read returns false;
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001059 * Need acquire/release memory ordering for mWritePtr.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001060 */
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001061 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1062 /*
1063 * A relaxed load is sufficient for mReadPtr since there will be no
1064 * stores to mReadPtr from a different thread.
1065 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001066 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
1067
1068 if (writePtr - readPtr > mDesc->getSize()) {
1069 mReadPtr->store(writePtr, std::memory_order_release);
1070 return false;
1071 }
1072
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001073 size_t nBytesDesired = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001074 /*
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001075 * Return if insufficient data to read in FMQ.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001076 */
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001077 if (writePtr - readPtr < nBytesDesired) {
1078 return false;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001079 }
1080
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001081 size_t readOffset = readPtr % mDesc->getSize();
1082 /*
1083 * From readOffset, the number of messages that can be read contiguously
1084 * without wrapping around the ring buffer are calculated.
1085 */
1086 size_t contiguousMessages = (mDesc->getSize() - readOffset) / sizeof(T);
1087
1088 if (contiguousMessages < nMessages) {
1089 /*
1090 * A wrap around is required. Both result.first and result.second
1091 * are populated.
1092 */
1093 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset),
1094 contiguousMessages),
1095 MemRegion(reinterpret_cast<T*>(mRing),
1096 nMessages - contiguousMessages));
1097 } else {
1098 /*
1099 * A wrap around is not required. Only result.first need to be
1100 * populated.
1101 */
1102 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset), nMessages),
1103 MemRegion());
1104 }
1105
1106 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001107}
1108
1109template <typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001110/*
1111 * Disable integer sanitization since integer overflow here is allowed
1112 * and legal.
1113 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001114__attribute__((no_sanitize("integer")))
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001115bool MessageQueue<T, flavor>::commitRead(size_t nMessages) {
1116 // TODO: Use a local copy of readPtr to avoid relazed mReadPtr loads.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001117 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001118 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1119 /*
1120 * If the flavor is unsynchronized, it is possible that a write overflow may
1121 * have occured between beginRead() and commitRead().
1122 */
1123 if (writePtr - readPtr > mDesc->getSize()) {
1124 mReadPtr->store(writePtr, std::memory_order_release);
1125 return false;
1126 }
1127
1128 size_t nBytesRead = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001129 readPtr += nBytesRead;
1130 mReadPtr->store(readPtr, std::memory_order_release);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001131 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001132}
1133
1134template <typename T, MQFlavor flavor>
1135size_t MessageQueue<T, flavor>::getQuantumSize() const {
1136 return mDesc->getQuantum();
1137}
1138
1139template <typename T, MQFlavor flavor>
1140size_t MessageQueue<T, flavor>::getQuantumCount() const {
1141 return mDesc->getSize() / mDesc->getQuantum();
1142}
1143
1144template <typename T, MQFlavor flavor>
1145bool MessageQueue<T, flavor>::isValid() const {
1146 return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
1147}
1148
1149template <typename T, MQFlavor flavor>
1150void* MessageQueue<T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001151 const native_handle_t* handle = mDesc->handle();
1152 auto grantors = mDesc->grantors();
1153 if ((handle == nullptr) || (grantorIdx >= grantors.size())) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001154 return nullptr;
1155 }
1156
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001157 int fdIndex = grantors[grantorIdx].fdIndex;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001158 /*
1159 * Offset for mmap must be a multiple of PAGE_SIZE.
1160 */
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001161 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001162 int mapLength =
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001163 grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001164
1165 void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED,
1166 handle->data[fdIndex], mapOffset);
1167 return (address == MAP_FAILED)
1168 ? nullptr
1169 : reinterpret_cast<uint8_t*>(address) +
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001170 (grantors[grantorIdx].offset - mapOffset);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001171}
1172
1173template <typename T, MQFlavor flavor>
1174void MessageQueue<T, flavor>::unmapGrantorDescr(void* address,
1175 uint32_t grantorIdx) {
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001176 auto grantors = mDesc->grantors();
1177 if ((address == nullptr) || (grantorIdx >= grantors.size())) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001178 return;
1179 }
1180
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001181 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001182 int mapLength =
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001183 grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001184 void* baseAddress = reinterpret_cast<uint8_t*>(address) -
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001185 (grantors[grantorIdx].offset - mapOffset);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001186 if (baseAddress) munmap(baseAddress, mapLength);
1187}
1188
1189} // namespace hardware
1190} // namespace android
1191#endif // HIDL_MQ_H