blob: 1f90cb1b54f7c08cccb8f995244451be821e5ec5 [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 Valsaraju8b0d5a52016-12-16 10:29:03 -080028
29namespace android {
30namespace hardware {
31
32template <typename T, MQFlavor flavor>
33struct MessageQueue {
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -080034 typedef MQDescriptor<T, flavor> Descriptor;
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -080035
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080036 /**
37 * @param Desc MQDescriptor describing the FMQ.
38 * @param resetPointers bool indicating whether the read/write pointers
39 * should be reset or not.
40 */
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -080041 MessageQueue(const Descriptor& Desc, bool resetPointers = true);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080042
43 ~MessageQueue();
44
45 /**
46 * This constructor uses Ashmem shared memory to create an FMQ
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080047 * that can contain a maximum of 'numElementsInQueue' elements of type T.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080048 *
49 * @param numElementsInQueue Capacity of the MessageQueue in terms of T.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -080050 * @param configureEventFlagWord Boolean that specifies if memory should
51 * also be allocated and mapped for an EventFlag word.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080052 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -080053 MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord = false);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080054
55 /**
56 * @return Number of items of type T that can be written into the FMQ
57 * without a read.
58 */
59 size_t availableToWrite() const;
60
61 /**
62 * @return Number of items of type T that are waiting to be read from the
63 * FMQ.
64 */
65 size_t availableToRead() const;
66
67 /**
68 * Returns the size of type T in bytes.
69 *
70 * @param Size of T.
71 */
72 size_t getQuantumSize() const;
73
74 /**
75 * Returns the size of the FMQ in terms of the size of type T.
76 *
77 * @return Number of items of type T that will fit in the FMQ.
78 */
79 size_t getQuantumCount() const;
80
81 /**
82 * @return Whether the FMQ is configured correctly.
83 */
84 bool isValid() const;
85
86 /**
87 * Non-blocking write to FMQ.
88 *
89 * @param data Pointer to the object of type T to be written into the FMQ.
90 *
91 * @return Whether the write was successful.
92 */
93 bool write(const T* data);
94
95 /**
96 * Non-blocking read from FMQ.
97 *
98 * @param data Pointer to the memory where the object read from the FMQ is
99 * copied to.
100 *
101 * @return Whether the read was successful.
102 */
103 bool read(T* data);
104
105 /**
106 * Write some data into the FMQ without blocking.
107 *
108 * @param data Pointer to the array of items of type T.
109 * @param count Number of items in array.
110 *
111 * @return Whether the write was successful.
112 */
113 bool write(const T* data, size_t count);
114
115 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800116 * Perform a blocking write of 'count' items into the FMQ using EventFlags.
117 * Does not support partial writes.
118 *
119 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
120 * associated with the FMQ and it is used in that case.
121 *
122 * The application code must ensure that 'evFlag' used by the
123 * reader(s)/writer is based upon the same EventFlag word.
124 *
125 * The method will return false without blocking if any of the following
126 * conditions are true:
127 * - If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
128 * - If the flavor of the FMQ is synchronized and the 'readNotification' bit mask is zero.
129 * - If 'count' is greater than the FMQ size.
130 *
131 * If the flavor of the FMQ is synchronized and there is insufficient space
132 * available to write into it, the EventFlag bit mask 'readNotification' is
133 * is waited upon.
134 *
135 * Upon a successful write, wake is called on 'writeNotification' (if
136 * non-zero).
137 *
138 * @param data Pointer to the array of items of type T.
139 * @param count Number of items in array.
140 * @param readNotification The EventFlag bit mask to wait on if there is not
141 * enough space in FMQ to write 'count' items.
142 * @param writeNotification The EventFlag bit mask to call wake on
143 * a successful write. No wake is called if 'writeNotification' is zero.
144 * @param timeOutNanos Number of nanoseconds after which the blocking
145 * write attempt is aborted.
146 * @param evFlag The EventFlag object to be used for blocking. If nullptr,
147 * it is checked whether the FMQ owns an EventFlag object and that is used
148 * for blocking instead.
149 *
150 * @return Whether the write was successful.
151 */
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800152 bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
153 uint32_t writeNotification, int64_t timeOutNanos = 0,
154 android::hardware::EventFlag* evFlag = nullptr);
155
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800156 bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
157
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800158 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800159 * Read some data from the FMQ without blocking.
160 *
161 * @param data Pointer to the array to which read data is to be written.
162 * @param count Number of items to be read.
163 *
164 * @return Whether the read was successful.
165 */
166 bool read(T* data, size_t count);
167
168 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800169 * Perform a blocking read operation of 'count' items from the FMQ. Does not
170 * perform a partial read.
171 *
172 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
173 * associated with the FMQ and it is used in that case.
174 *
175 * The application code must ensure that 'evFlag' used by the
176 * reader(s)/writer is based upon the same EventFlag word.
177 *
178 * The method will return false without blocking if any of the following
179 * conditions are true:
180 * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
181 * -If the 'writeNotification' bit mask is zero.
182 * -If 'count' is greater than the FMQ size.
183 *
184 * If FMQ does not contain 'count' items, the eventFlag bit mask
185 * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
186 * wake is called on 'readNotification' (if non-zero).
187 *
188 * @param data Pointer to the array to which read data is to be written.
189 * @param count Number of items to be read.
190 * @param readNotification The EventFlag bit mask to call wake on after
191 * a successful read. No wake is called if 'readNotification' is zero.
192 * @param writeNotification The EventFlag bit mask to call a wait on
193 * if there is insufficient data in the FMQ to be read.
194 * @param timeOutNanos Number of nanoseconds after which the blocking
195 * read attempt is aborted.
196 * @param evFlag The EventFlag object to be used for blocking.
197 *
198 * @return Whether the read was successful.
199 */
200 bool readBlocking(T* data, size_t count, uint32_t readNotification,
201 uint32_t writeNotification, int64_t timeOutNanos = 0,
202 android::hardware::EventFlag* evFlag = nullptr);
203
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800204 bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);
205
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800206 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800207 * Get a pointer to the MQDescriptor object that describes this FMQ.
208 *
209 * @return Pointer to the MQDescriptor associated with the FMQ.
210 */
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800211 const Descriptor* getDesc() const { return mDesc.get(); }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800212
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800213 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800214 * Get a pointer to the EventFlag word if there is one associated with this FMQ.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800215 *
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800216 * @return Pointer to an EventFlag word, will return nullptr if not
217 * configured. This method does not transfer ownership. The EventFlag
218 * word will be unmapped by the MessageQueue destructor.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800219 */
220 std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800221
222 /**
223 * Describes a memory region in the FMQ.
224 */
225 struct MemRegion {
226 MemRegion() : MemRegion(nullptr, 0) {}
227
228 MemRegion(T* base, size_t size) : address(base), length(size) {}
229
230 MemRegion& operator=(const MemRegion &other) {
231 address = other.address;
232 length = other.length;
233 return *this;
234 }
235
236 /**
237 * Gets a pointer to the base address of the MemRegion.
238 */
239 inline T* getAddress() const { return address; }
240
241 /**
242 * Gets the length of the MemRegion. This would equal to the number
243 * of items of type T that can be read from/written into the MemRegion.
244 */
245 inline size_t getLength() const { return length; }
246
247 /**
248 * Gets the length of the MemRegion in bytes.
249 */
250 inline size_t getLengthInBytes() const { return length * sizeof(T); }
251
252 private:
253 /* Base address */
254 T* address;
255
256 /*
257 * Number of items of type T that can be written to/read from the base
258 * address.
259 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800260 size_t length;
261 };
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800262
263 /**
264 * Describes the memory regions to be used for a read or write.
265 * The struct contains two MemRegion objects since the FMQ is a ring
266 * buffer and a read or write operation can wrap around. A single message
267 * of type T will never be broken between the two MemRegions.
268 */
269 struct MemTransaction {
270 MemTransaction() : MemTransaction(MemRegion(), MemRegion()) {}
271
272 MemTransaction(const MemRegion& regionFirst, const MemRegion& regionSecond) :
273 first(regionFirst), second(regionSecond) {}
274
275 MemTransaction& operator=(const MemTransaction &other) {
276 first = other.first;
277 second = other.second;
278 return *this;
279 }
280
281 /**
282 * Helper method to calculate the address for a particular index for
283 * the MemTransaction object.
284 *
285 * @param idx Index of the slot to be read/written. If the
286 * MemTransaction object is representing the memory region to read/write
287 * N items of type T, the valid range of idx is between 0 and N-1.
288 *
289 * @return Pointer to the slot idx. Will be nullptr for an invalid idx.
290 */
291 T* getSlot(size_t idx);
292
293 /**
294 * Helper method to write 'nMessages' items of type T into the memory
295 * regions described by the object starting from 'startIdx'. This method
296 * uses memcpy() and is not to meant to be used for a zero copy operation.
297 * Partial writes are not supported.
298 *
299 * @param data Pointer to the source buffer.
300 * @param nMessages Number of items of type T.
301 * @param startIdx The slot number to begin the write from. If the
302 * MemTransaction object is representing the memory region to read/write
303 * N items of type T, the valid range of startIdx is between 0 and N-1;
304 *
305 * @return Whether the write operation of size 'nMessages' succeeded.
306 */
307 bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
308
309 /*
310 * Helper method to read 'nMessages' items of type T from the memory
311 * regions described by the object starting from 'startIdx'. This method uses
312 * memcpy() and is not meant to be used for a zero copy operation. Partial reads
313 * are not supported.
314 *
315 * @param data Pointer to the destination buffer.
316 * @param nMessages Number of items of type T.
317 * @param startIdx The slot number to begin the read from. If the
318 * MemTransaction object is representing the memory region to read/write
319 * N items of type T, the valid range of startIdx is between 0 and N-1.
320 *
321 * @return Whether the read operation of size 'nMessages' succeeded.
322 */
323 bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
324
325 /**
326 * Returns a const reference to the first MemRegion in the
327 * MemTransaction object.
328 */
329 inline const MemRegion& getFirstRegion() const { return first; }
330
331 /**
332 * Returns a const reference to the second MemRegion in the
333 * MemTransaction object.
334 */
335 inline const MemRegion& getSecondRegion() const { return second; }
336
337 private:
338 /*
339 * Given a start index and the number of messages to be
340 * read/written, this helper method calculates the
341 * number of messages that should should be written to both the first
342 * and second MemRegions and the base addresses to be used for
343 * the read/write operation.
344 *
345 * Returns false if the 'startIdx' and 'nMessages' is
346 * invalid for the MemTransaction object.
347 */
348 bool inline getMemRegionInfo(size_t idx,
349 size_t nMessages,
350 size_t& firstCount,
351 size_t& secondCount,
352 T** firstBaseAddress,
353 T** secondBaseAddress);
354 MemRegion first;
355 MemRegion second;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800356 };
357
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800358 /**
359 * Get a MemTransaction object to write 'nMessages' items of type T.
360 * Once the write is performed using the information from MemTransaction,
361 * the write operation is to be committed using a call to commitWrite().
362 *
363 * @param nMessages Number of messages of type T.
364 * @param Pointer to MemTransaction struct that describes memory to write 'nMessages'
365 * items of type T. If a write of size 'nMessages' is not possible, the base
366 * addresses in the MemTransaction object would be set to nullptr.
367 *
368 * @return Whether it is possible to write 'nMessages' items of type T
369 * into the FMQ.
370 */
371 bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800372
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800373 /**
374 * Commit a write of size 'nMessages'. To be only used after a call to beginWrite().
375 *
376 * @param nMessages number of messages of type T to be written.
377 *
378 * @return Whether the write operation of size 'nMessages' succeeded.
379 */
380 bool commitWrite(size_t nMessages);
381
382 /**
383 * Get a MemTransaction object to read 'nMessages' items of type T.
384 * Once the read is performed using the information from MemTransaction,
385 * the read operation is to be committed using a call to commitRead().
386 *
387 * @param nMessages Number of messages of type T.
388 * @param pointer to MemTransaction struct that describes memory to read 'nMessages'
389 * items of type T. If a read of size 'nMessages' is not possible, the base
390 * pointers in the MemTransaction object returned will be set to nullptr.
391 *
392 * @return bool Whether it is possible to read 'nMessages' items of type T
393 * from the FMQ.
394 */
395 bool beginRead(size_t nMessages, MemTransaction* memTx) const;
396
397 /**
398 * Commit a read of size 'nMessages'. To be only used after a call to beginRead().
399 * For the unsynchronized flavor of FMQ, this method will return a failure
400 * if a write overflow happened after beginRead() was invoked.
401 *
402 * @param nMessages number of messages of type T to be read.
403 *
404 * @return bool Whether the read operation of size 'nMessages' succeeded.
405 */
406 bool commitRead(size_t nMessages);
407
408private:
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800409
410 size_t availableToWriteBytes() const;
411 size_t availableToReadBytes() const;
412
413 MessageQueue(const MessageQueue& other) = delete;
414 MessageQueue& operator=(const MessageQueue& other) = delete;
415 MessageQueue();
416
417 void* mapGrantorDescr(uint32_t grantorIdx);
418 void unmapGrantorDescr(void* address, uint32_t grantorIdx);
419 void initMemory(bool resetPointers);
420
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800421 enum DefaultEventNotification : uint32_t {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800422 /*
423 * These are only used internally by the blockingRead()/blockingWrite()
424 * methods and hence once other bit combinations are not required.
425 */
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800426 FMQ_NOT_FULL = 0x01,
427 FMQ_NOT_EMPTY = 0x02
428 };
429
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800430 std::unique_ptr<Descriptor> mDesc;
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800431 uint8_t* mRing = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800432 /*
433 * TODO(b/31550092): Change to 32 bit read and write pointer counters.
434 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800435 std::atomic<uint64_t>* mReadPtr = nullptr;
436 std::atomic<uint64_t>* mWritePtr = nullptr;
437
438 std::atomic<uint32_t>* mEvFlagWord = nullptr;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800439
440 /*
441 * This EventFlag object will be owned by the FMQ and will have the same
442 * lifetime.
443 */
444 android::hardware::EventFlag* mEventFlag = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800445};
446
447template <typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800448T* MessageQueue<T, flavor>::MemTransaction::getSlot(size_t idx) {
449 size_t firstRegionLength = first.getLength();
450 size_t secondRegionLength = second.getLength();
451
452 if (idx > firstRegionLength + secondRegionLength) {
453 return nullptr;
454 }
455
456 if (idx < firstRegionLength) {
457 return first.getAddress() + idx;
458 }
459
460 return second.getAddress() + idx - firstRegionLength;
461}
462
463template <typename T, MQFlavor flavor>
464bool MessageQueue<T, flavor>::MemTransaction::getMemRegionInfo(size_t startIdx,
465 size_t nMessages,
466 size_t& firstCount,
467 size_t& secondCount,
468 T** firstBaseAddress,
469 T** secondBaseAddress) {
470 size_t firstRegionLength = first.getLength();
471 size_t secondRegionLength = second.getLength();
472
473 if (startIdx + nMessages > firstRegionLength + secondRegionLength) {
474 /*
475 * Return false if 'nMessages' starting at 'startIdx' cannot be
476 * accomodated by the MemTransaction object.
477 */
478 return false;
479 }
480
481 /* Number of messages to be read/written to the first MemRegion. */
482 firstCount = startIdx < firstRegionLength ?
483 std::min(nMessages, firstRegionLength - startIdx) : 0;
484
485 /* Number of messages to be read/written to the second MemRegion. */
486 secondCount = nMessages - firstCount;
487
488 if (firstCount != 0) {
489 *firstBaseAddress = first.getAddress() + startIdx;
490 }
491
492 if (secondCount != 0) {
493 size_t secondStartIdx = startIdx > firstRegionLength ? startIdx - firstRegionLength : 0;
494 *secondBaseAddress = second.getAddress() + secondStartIdx;
495 }
496
497 return true;
498}
499
500template <typename T, MQFlavor flavor>
501bool MessageQueue<T, flavor>::MemTransaction::copyFrom(T* data, size_t startIdx, size_t nMessages) {
502 if (data == nullptr) {
503 return false;
504 }
505
506 size_t firstReadCount = 0, secondReadCount = 0;
507 T* firstBaseAddress = nullptr, * secondBaseAddress = nullptr;
508
509 if (getMemRegionInfo(startIdx,
510 nMessages,
511 firstReadCount,
512 secondReadCount,
513 &firstBaseAddress,
514 &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) {
527 memcpy(data + firstReadCount,
528 secondBaseAddress,
529 secondReadCount * sizeof(T));
530 }
531
532 return true;
533}
534
535template <typename T, MQFlavor flavor>
536bool MessageQueue<T, flavor>::MemTransaction::copyTo(const T* data,
537 size_t startIdx,
538 size_t nMessages) {
539 if (data == nullptr) {
540 return false;
541 }
542
543 size_t firstWriteCount = 0, secondWriteCount = 0;
544 T * firstBaseAddress = nullptr, * secondBaseAddress = nullptr;
545
546 if (getMemRegionInfo(startIdx,
547 nMessages,
548 firstWriteCount,
549 secondWriteCount,
550 &firstBaseAddress,
551 &secondBaseAddress) == false) {
552 /*
553 * Returns false if 'startIdx' and 'nMessages' are invalid for this
554 * MemTransaction object.
555 */
556 return false;
557 }
558
559 if (firstWriteCount != 0) {
560 memcpy(firstBaseAddress, data, firstWriteCount * sizeof(T));
561 }
562
563 if (secondWriteCount != 0) {
564 memcpy(secondBaseAddress,
565 data + firstWriteCount,
566 secondWriteCount * sizeof(T));
567 }
568
569 return true;
570}
571
572template <typename T, MQFlavor flavor>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800573void MessageQueue<T, flavor>::initMemory(bool resetPointers) {
574 /*
575 * Verify that the the Descriptor contains the minimum number of grantors
576 * the native_handle is valid and T matches quantum size.
577 */
578 if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800579 (mDesc->countGrantors() < Descriptor::kMinGrantorCount) ||
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800580 (mDesc->getQuantum() != sizeof(T))) {
581 return;
582 }
583
584 if (flavor == kSynchronizedReadWrite) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800585 mReadPtr = reinterpret_cast<std::atomic<uint64_t>*>(
586 mapGrantorDescr(Descriptor::READPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800587 } else {
588 /*
589 * The unsynchronized write flavor of the FMQ may have multiple readers
590 * and each reader would have their own read pointer counter.
591 */
592 mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
593 }
594
595 CHECK(mReadPtr != nullptr);
596
597 mWritePtr =
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800598 reinterpret_cast<std::atomic<uint64_t>*>(mapGrantorDescr(Descriptor::WRITEPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800599 CHECK(mWritePtr != nullptr);
600
601 if (resetPointers) {
602 mReadPtr->store(0, std::memory_order_release);
603 mWritePtr->store(0, std::memory_order_release);
604 } else if (flavor != kSynchronizedReadWrite) {
605 // Always reset the read pointer.
606 mReadPtr->store(0, std::memory_order_release);
607 }
608
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800609 mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(Descriptor::DATAPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800610 CHECK(mRing != nullptr);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800611
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800612 mEvFlagWord = static_cast<std::atomic<uint32_t>*>(mapGrantorDescr(Descriptor::EVFLAGWORDPOS));
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800613 if (mEvFlagWord != nullptr) {
614 android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
615 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800616}
617
618template <typename T, MQFlavor flavor>
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800619MessageQueue<T, flavor>::MessageQueue(const Descriptor& Desc, bool resetPointers) {
620 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800621 if (mDesc == nullptr) {
622 return;
623 }
624
625 initMemory(resetPointers);
626}
627
628template <typename T, MQFlavor flavor>
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800629MessageQueue<T, flavor>::MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800630 /*
631 * The FMQ needs to allocate memory for the ringbuffer as well as for the
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800632 * read and write pointer counters. If an EventFlag word is to be configured,
633 * we also need to allocate memory for the same/
634 */
635 size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
636 size_t kMetaDataSize = 2 * sizeof(android::hardware::RingBufferPosition);
637
638 if (configureEventFlagWord) {
639 kMetaDataSize+= sizeof(std::atomic<uint32_t>);
640 }
641
642 /*
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800643 * Ashmem memory region size needs to be specified in page-aligned bytes.
644 * kQueueSizeBytes needs to be aligned to word boundary so that all offsets
645 * in the grantorDescriptor will be word aligned.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800646 */
647 size_t kAshmemSizePageAligned =
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800648 (Descriptor::alignToWordBoundary(kQueueSizeBytes) + kMetaDataSize + PAGE_SIZE - 1) &
649 ~(PAGE_SIZE - 1);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800650
651 /*
652 * Create an ashmem region to map the memory for the ringbuffer,
653 * read counter and write counter.
654 */
655 int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
656 ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
657
658 /*
659 * The native handle will contain the fds to be mapped.
660 */
661 native_handle_t* mqHandle =
662 native_handle_create(1 /* numFds */, 0 /* numInts */);
663 if (mqHandle == nullptr) {
664 return;
665 }
666
667 mqHandle->data[0] = ashmemFd;
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800668 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(kQueueSizeBytes,
669 mqHandle,
670 sizeof(T),
671 configureEventFlagWord));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800672 if (mDesc == nullptr) {
673 return;
674 }
675 initMemory(true);
676}
677
678template <typename T, MQFlavor flavor>
679MessageQueue<T, flavor>::~MessageQueue() {
680 if (flavor == kUnsynchronizedWrite) {
681 delete mReadPtr;
682 } else {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800683 unmapGrantorDescr(mReadPtr, Descriptor::READPTRPOS);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800684 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800685 if (mWritePtr != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800686 unmapGrantorDescr(mWritePtr, Descriptor::WRITEPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800687 }
688 if (mRing != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800689 unmapGrantorDescr(mRing, Descriptor::DATAPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800690 }
691 if (mEvFlagWord != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800692 unmapGrantorDescr(mEvFlagWord, Descriptor::EVFLAGWORDPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800693 android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
694 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800695}
696
697template <typename T, MQFlavor flavor>
698bool MessageQueue<T, flavor>::write(const T* data) {
699 return write(data, 1);
700}
701
702template <typename T, MQFlavor flavor>
703bool MessageQueue<T, flavor>::read(T* data) {
704 return read(data, 1);
705}
706
707template <typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800708bool MessageQueue<T, flavor>::write(const T* data, size_t nMessages) {
709 MemTransaction tx;
710 return beginWrite(nMessages, &tx) &&
711 tx.copyTo(data, 0 /* startIdx */, nMessages) &&
712 commitWrite(nMessages);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800713}
714
715template <typename T, MQFlavor flavor>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800716bool MessageQueue<T, flavor>::writeBlocking(const T* data,
717 size_t count,
718 uint32_t readNotification,
719 uint32_t writeNotification,
720 int64_t timeOutNanos,
721 android::hardware::EventFlag* evFlag) {
722 /*
723 * If evFlag is null and the FMQ does not have its own EventFlag object
724 * return false;
725 * If the flavor is kSynchronizedReadWrite and the readNotification
726 * bit mask is zero return false;
727 * If the count is greater than queue size, return false
728 * to prevent blocking until timeOut.
729 */
730 if (evFlag == nullptr) {
731 evFlag = mEventFlag;
732 if (evFlag == nullptr) {
733 return false;
734 }
735 }
736
737 if ((readNotification == 0 && flavor == kSynchronizedReadWrite) ||
738 (count > getQuantumCount())) {
739 return false;
740 }
741
742 /*
743 * There is no need to wait for a readNotification if the flavor
744 * of the queue is kUnsynchronizedWrite or sufficient space to write
745 * is already present in the FMQ. The latter would be the case when
746 * read operations read more number of messages than
747 * write operations write. In other words, a single large read may clear the FMQ
748 * after multiple small writes. This would fail to clear a pending
749 * readNotification bit since EventFlag bits can only be cleared
750 * by a wait() call, however the bit would be correctly cleared by the next
751 * blockingWrite() call.
752 */
753
754 bool result = write(data, count);
755 if (result) {
756 if (writeNotification) {
757 evFlag->wake(writeNotification);
758 }
759 return result;
760 }
761
762 bool endWait = false;
763 while (endWait == false) {
764 uint32_t efState = 0;
765 /*
766 * wait() will return immediately if there was a pending read
767 * notification.
768 */
769 status_t status = evFlag->wait(readNotification, &efState, timeOutNanos);
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800770 switch (status) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800771 case android::NO_ERROR:
772 /*
773 * If wait() returns NO_ERROR, break and check efState.
774 */
775 break;
776 case android::TIMED_OUT:
777 /*
778 * If wait() returns android::TIMEDOUT, break out of the while loop
779 * and return false;
780 */
781 endWait = true;
782 continue;
783 case -EAGAIN:
784 case -EINTR:
785 /*
786 * For errors -EAGAIN and -EINTR, go back to wait.
787 */
788 continue;
789 default:
790 /*
791 * Throw an error for any other error code since it is unexpected.
792 */
793
794 endWait = true;
795 ALOGE("Unexpected error code from EventFlag Wait %d", status);
796 continue;
797 }
798
799 /*
800 * If the wake() was not due to the readNotification bit or if
801 * there is still insufficient space to write to the FMQ,
802 * keep waiting for another readNotification.
803 */
804 if ((efState & readNotification) && write(data, count)) {
805 if (writeNotification) {
806 evFlag->wake(writeNotification);
807 }
808 result = true;
809 endWait = true;
810 }
811 }
812
813 return result;
814}
815
816template <typename T, MQFlavor flavor>
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800817bool MessageQueue<T, flavor>::writeBlocking(const T* data,
818 size_t count,
819 int64_t timeOutNanos) {
820 return writeBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
821}
822
823template <typename T, MQFlavor flavor>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800824bool MessageQueue<T, flavor>::readBlocking(T* data,
825 size_t count,
826 uint32_t readNotification,
827 uint32_t writeNotification,
828 int64_t timeOutNanos,
829 android::hardware::EventFlag* evFlag) {
830 /*
831 * If evFlag is null and the FMQ does not own its own EventFlag object
832 * return false;
833 * If the writeNotification bit mask is zero return false;
834 * If the count is greater than queue size, return false to prevent
835 * blocking until timeOut.
836 */
837 if (evFlag == nullptr) {
838 evFlag = mEventFlag;
839 if (evFlag == nullptr) {
840 return false;
841 }
842 }
843
844 if (writeNotification == 0 || count > getQuantumCount()) {
845 return false;
846 }
847
848 /*
849 * There is no need to wait for a write notification if sufficient
850 * data to read is already present in the FMQ. This would be the
851 * case when read operations read lesser number of messages than
852 * a write operation and multiple reads would be required to clear the queue
853 * after a single write operation. This check would fail to clear a pending
854 * writeNotification bit since EventFlag bits can only be cleared
855 * by a wait() call, however the bit would be correctly cleared by the next
856 * readBlocking() call.
857 */
858
859 bool result = read(data, count);
860 if (result) {
861 if (readNotification) {
862 evFlag->wake(readNotification);
863 }
864 return result;
865 }
866
867 bool endWait = false;
868 while (endWait == false) {
869 uint32_t efState = 0;
870 /*
871 * wait() will return immediately if there was a pending write
872 * notification.
873 */
874 status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos);
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800875 switch (status) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800876 case android::NO_ERROR:
877 /*
878 * If wait() returns NO_ERROR, break and check efState.
879 */
880 break;
881 case android::TIMED_OUT:
882 /*
883 * If wait() returns android::TIMEDOUT, break out of the while loop
884 * and return false;
885 */
886 endWait = true;
887 continue;
888 case -EAGAIN:
889 case -EINTR:
890 /*
891 * For errors -EAGAIN and -EINTR, go back to wait.
892 */
893 continue;
894 default:
895 /*
896 * Throw an error for any other error code since it is unexpected.
897 */
898
899 endWait = true;
900 ALOGE("Unexpected error code from EventFlag Wait %d", status);
901 continue;
902 }
903
904 /*
905 * If the wake() was not due to the writeNotification bit being set
906 * or if the data in FMQ is still insufficient, go back to waiting
907 * for another write notification.
908 */
909 if ((efState & writeNotification) && read(data, count)) {
910 if (readNotification) {
911 evFlag->wake(readNotification);
912 }
913 result = true;
914 endWait = true;
915 }
916 }
917
918 return result;
919}
920
921template <typename T, MQFlavor flavor>
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800922bool MessageQueue<T, flavor>::readBlocking(T* data, size_t count, int64_t timeOutNanos) {
923 return readBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
924}
925
926template <typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800927size_t MessageQueue<T, flavor>::availableToWriteBytes() const {
928 return mDesc->getSize() - availableToReadBytes();
929}
930
931template <typename T, MQFlavor flavor>
932size_t MessageQueue<T, flavor>::availableToWrite() const {
933 return availableToWriteBytes() / sizeof(T);
934}
935
936template <typename T, MQFlavor flavor>
937size_t MessageQueue<T, flavor>::availableToRead() const {
938 return availableToReadBytes() / sizeof(T);
939}
940
941template <typename T, MQFlavor flavor>
942bool MessageQueue<T, flavor>::beginWrite(size_t nMessages, MemTransaction* result) const {
943 /*
944 * If nMessages is greater than size of FMQ or in case of the synchronized
945 * FMQ flavor, if there is not enough space to write nMessages, then return
946 * result with null addresses.
947 */
948 if ((flavor == kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
949 nMessages > getQuantumCount()) {
950 *result = MemTransaction();
951 return false;
952 }
953
954 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
955 size_t writeOffset = writePtr % mDesc->getSize();
956
957 /*
958 * From writeOffset, the number of messages that can be written
959 * contiguously without wrapping around the ring buffer are calculated.
960 */
961 size_t contiguousMessages = (mDesc->getSize() - writeOffset) / sizeof(T);
962
963 if (contiguousMessages < nMessages) {
964 /*
965 * Wrap around is required. Both result.first and result.second are
966 * populated.
967 */
968 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset),
969 contiguousMessages),
970 MemRegion(reinterpret_cast<T*>(mRing),
971 nMessages - contiguousMessages));
972 } else {
973 /*
974 * A wrap around is not required to write nMessages. Only result.first
975 * is populated.
976 */
977 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset), nMessages),
978 MemRegion());
979 }
980
981 return true;
982}
983
984template <typename T, MQFlavor flavor>
985/*
986 * Disable integer sanitization since integer overflow here is allowed
987 * and legal.
988 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800989__attribute__((no_sanitize("integer")))
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800990bool MessageQueue<T, flavor>::commitWrite(size_t nMessages) {
991 size_t nBytesWritten = nMessages * sizeof(T);
992 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
993 writePtr += nBytesWritten;
994 mWritePtr->store(writePtr, std::memory_order_release);
995 /*
996 * This method cannot fail now since we are only incrementing the writePtr
997 * counter.
998 */
999 return true;
1000}
1001
1002template <typename T, MQFlavor flavor>
1003size_t MessageQueue<T, flavor>::availableToReadBytes() const {
1004 /*
1005 * This method is invoked by implementations of both read() and write() and
1006 * hence requries a memory_order_acquired load for both mReadPtr and
1007 * mWritePtr.
1008 */
1009 return mWritePtr->load(std::memory_order_acquire) -
1010 mReadPtr->load(std::memory_order_acquire);
1011}
1012
1013template <typename T, MQFlavor flavor>
1014bool MessageQueue<T, flavor>::read(T* data, size_t nMessages) {
1015 MemTransaction tx;
1016 return beginRead(nMessages, &tx) &&
1017 tx.copyFrom(data, 0 /* startIdx */, nMessages) &&
1018 commitRead(nMessages);
1019}
1020
1021template <typename T, MQFlavor flavor>
1022/*
1023 * Disable integer sanitization since integer overflow here is allowed
1024 * and legal.
1025 */
1026__attribute__((no_sanitize("integer")))
1027bool MessageQueue<T, flavor>::beginRead(size_t nMessages, MemTransaction* result) const {
1028 *result = MemTransaction();
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001029 /*
1030 * If it is detected that the data in the queue was overwritten
1031 * due to the reader process being too slow, the read pointer counter
1032 * is set to the same as the write pointer counter to indicate error
1033 * and the read returns false;
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001034 * Need acquire/release memory ordering for mWritePtr.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001035 */
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001036 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1037 /*
1038 * A relaxed load is sufficient for mReadPtr since there will be no
1039 * stores to mReadPtr from a different thread.
1040 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001041 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
1042
1043 if (writePtr - readPtr > mDesc->getSize()) {
1044 mReadPtr->store(writePtr, std::memory_order_release);
1045 return false;
1046 }
1047
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001048 size_t nBytesDesired = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001049 /*
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001050 * Return if insufficient data to read in FMQ.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001051 */
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001052 if (writePtr - readPtr < nBytesDesired) {
1053 return false;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001054 }
1055
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001056 size_t readOffset = readPtr % mDesc->getSize();
1057 /*
1058 * From readOffset, the number of messages that can be read contiguously
1059 * without wrapping around the ring buffer are calculated.
1060 */
1061 size_t contiguousMessages = (mDesc->getSize() - readOffset) / sizeof(T);
1062
1063 if (contiguousMessages < nMessages) {
1064 /*
1065 * A wrap around is required. Both result.first and result.second
1066 * are populated.
1067 */
1068 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset),
1069 contiguousMessages),
1070 MemRegion(reinterpret_cast<T*>(mRing),
1071 nMessages - contiguousMessages));
1072 } else {
1073 /*
1074 * A wrap around is not required. Only result.first need to be
1075 * populated.
1076 */
1077 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset), nMessages),
1078 MemRegion());
1079 }
1080
1081 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001082}
1083
1084template <typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001085/*
1086 * Disable integer sanitization since integer overflow here is allowed
1087 * and legal.
1088 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001089__attribute__((no_sanitize("integer")))
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001090bool MessageQueue<T, flavor>::commitRead(size_t nMessages) {
1091 // TODO: Use a local copy of readPtr to avoid relazed mReadPtr loads.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001092 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001093 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1094 /*
1095 * If the flavor is unsynchronized, it is possible that a write overflow may
1096 * have occured between beginRead() and commitRead().
1097 */
1098 if (writePtr - readPtr > mDesc->getSize()) {
1099 mReadPtr->store(writePtr, std::memory_order_release);
1100 return false;
1101 }
1102
1103 size_t nBytesRead = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001104 readPtr += nBytesRead;
1105 mReadPtr->store(readPtr, std::memory_order_release);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001106 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001107}
1108
1109template <typename T, MQFlavor flavor>
1110size_t MessageQueue<T, flavor>::getQuantumSize() const {
1111 return mDesc->getQuantum();
1112}
1113
1114template <typename T, MQFlavor flavor>
1115size_t MessageQueue<T, flavor>::getQuantumCount() const {
1116 return mDesc->getSize() / mDesc->getQuantum();
1117}
1118
1119template <typename T, MQFlavor flavor>
1120bool MessageQueue<T, flavor>::isValid() const {
1121 return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
1122}
1123
1124template <typename T, MQFlavor flavor>
1125void* MessageQueue<T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
1126 const native_handle_t* handle = mDesc->getNativeHandle()->handle();
1127 auto mGrantors = mDesc->getGrantors();
1128 if ((handle == nullptr) || (grantorIdx >= mGrantors.size())) {
1129 return nullptr;
1130 }
1131
1132 int fdIndex = mGrantors[grantorIdx].fdIndex;
1133 /*
1134 * Offset for mmap must be a multiple of PAGE_SIZE.
1135 */
1136 int mapOffset = (mGrantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
1137 int mapLength =
1138 mGrantors[grantorIdx].offset - mapOffset + mGrantors[grantorIdx].extent;
1139
1140 void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED,
1141 handle->data[fdIndex], mapOffset);
1142 return (address == MAP_FAILED)
1143 ? nullptr
1144 : reinterpret_cast<uint8_t*>(address) +
1145 (mGrantors[grantorIdx].offset - mapOffset);
1146}
1147
1148template <typename T, MQFlavor flavor>
1149void MessageQueue<T, flavor>::unmapGrantorDescr(void* address,
1150 uint32_t grantorIdx) {
1151 auto mGrantors = mDesc->getGrantors();
1152 if ((address == nullptr) || (grantorIdx >= mGrantors.size())) {
1153 return;
1154 }
1155
1156 int mapOffset = (mGrantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
1157 int mapLength =
1158 mGrantors[grantorIdx].offset - mapOffset + mGrantors[grantorIdx].extent;
1159 void* baseAddress = reinterpret_cast<uint8_t*>(address) -
1160 (mGrantors[grantorIdx].offset - mapOffset);
1161 if (baseAddress) munmap(baseAddress, mapLength);
1162}
1163
1164} // namespace hardware
1165} // namespace android
1166#endif // HIDL_MQ_H