1 /*
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 #pragma once
18
19 #include <android-base/unique_fd.h>
20 #include <cutils/ashmem.h>
21 #include <fmq/EventFlag.h>
22 #include <sys/mman.h>
23 #include <sys/user.h>
24 #include <utils/Log.h>
25 #include <utils/SystemClock.h>
26 #include <atomic>
27 #include <new>
28
29 using android::hardware::kSynchronizedReadWrite;
30 using android::hardware::kUnsynchronizedWrite;
31 using android::hardware::MQFlavor;
32
33 namespace android {
34
35 template <template <typename, MQFlavor> class MQDescriptorType, typename T, MQFlavor flavor>
36 struct MessageQueueBase {
37 typedef MQDescriptorType<T, flavor> Descriptor;
38
39 /**
40 * @param Desc MQDescriptor describing the FMQ.
41 * @param resetPointers bool indicating whether the read/write pointers
42 * should be reset or not.
43 */
44 MessageQueueBase(const Descriptor& Desc, bool resetPointers = true);
45
46 ~MessageQueueBase();
47
48 /**
49 * This constructor uses Ashmem shared memory to create an FMQ
50 * that can contain a maximum of 'numElementsInQueue' elements of type T.
51 *
52 * @param numElementsInQueue Capacity of the MessageQueue in terms of T.
53 * @param configureEventFlagWord Boolean that specifies if memory should
54 * also be allocated and mapped for an EventFlag word.
55 * @param bufferFd User-supplied file descriptor to map the memory for the ringbuffer
56 * By default, bufferFd=-1 means library will allocate ashmem region for ringbuffer.
57 * MessageQueue takes ownership of the file descriptor.
58 * @param bufferSize size of buffer in bytes that bufferFd represents. This
59 * size must be larger than or equal to (numElementsInQueue * sizeof(T)).
60 * Otherwise, operations will cause out-of-bounds memory access.
61 */
62
63 MessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord,
64 android::base::unique_fd bufferFd, size_t bufferSize);
65
66 MessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord = false)
67 : MessageQueueBase(numElementsInQueue, configureEventFlagWord, android::base::unique_fd(),
68 0) {}
69
70 /**
71 * @return Number of items of type T that can be written into the FMQ
72 * without a read.
73 */
74 size_t availableToWrite() const;
75
76 /**
77 * @return Number of items of type T that are waiting to be read from the
78 * FMQ.
79 */
80 size_t availableToRead() const;
81
82 /**
83 * Returns the size of type T in bytes.
84 *
85 * @param Size of T.
86 */
87 size_t getQuantumSize() const;
88
89 /**
90 * Returns the size of the FMQ in terms of the size of type T.
91 *
92 * @return Number of items of type T that will fit in the FMQ.
93 */
94 size_t getQuantumCount() const;
95
96 /**
97 * @return Whether the FMQ is configured correctly.
98 */
99 bool isValid() const;
100
101 /**
102 * Non-blocking write to FMQ.
103 *
104 * @param data Pointer to the object of type T to be written into the FMQ.
105 *
106 * @return Whether the write was successful.
107 */
108 bool write(const T* data);
109
110 /**
111 * Non-blocking read from FMQ.
112 *
113 * @param data Pointer to the memory where the object read from the FMQ is
114 * copied to.
115 *
116 * @return Whether the read was successful.
117 */
118 bool read(T* data);
119
120 /**
121 * Write some data into the FMQ without blocking.
122 *
123 * @param data Pointer to the array of items of type T.
124 * @param count Number of items in array.
125 *
126 * @return Whether the write was successful.
127 */
128 bool write(const T* data, size_t count);
129
130 /**
131 * Perform a blocking write of 'count' items into the FMQ using EventFlags.
132 * Does not support partial writes.
133 *
134 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
135 * associated with the FMQ and it is used in that case.
136 *
137 * The application code must ensure that 'evFlag' used by the
138 * reader(s)/writer is based upon the same EventFlag word.
139 *
140 * The method will return false without blocking if any of the following
141 * conditions are true:
142 * - If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
143 * - If the 'readNotification' bit mask is zero.
144 * - If 'count' is greater than the FMQ size.
145 *
146 * If the there is insufficient space available to write into it, the
147 * EventFlag bit mask 'readNotification' is is waited upon.
148 *
149 * This method should only be used with a MessageQueue of the flavor
150 * 'kSynchronizedReadWrite'.
151 *
152 * Upon a successful write, wake is called on 'writeNotification' (if
153 * non-zero).
154 *
155 * @param data Pointer to the array of items of type T.
156 * @param count Number of items in array.
157 * @param readNotification The EventFlag bit mask to wait on if there is not
158 * enough space in FMQ to write 'count' items.
159 * @param writeNotification The EventFlag bit mask to call wake on
160 * a successful write. No wake is called if 'writeNotification' is zero.
161 * @param timeOutNanos Number of nanoseconds after which the blocking
162 * write attempt is aborted.
163 * @param evFlag The EventFlag object to be used for blocking. If nullptr,
164 * it is checked whether the FMQ owns an EventFlag object and that is used
165 * for blocking instead.
166 *
167 * @return Whether the write was successful.
168 */
169 bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
170 uint32_t writeNotification, int64_t timeOutNanos = 0,
171 android::hardware::EventFlag* evFlag = nullptr);
172
173 bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
174
175 /**
176 * Read some data from the FMQ without blocking.
177 *
178 * @param data Pointer to the array to which read data is to be written.
179 * @param count Number of items to be read.
180 *
181 * @return Whether the read was successful.
182 */
183 bool read(T* data, size_t count);
184
185 /**
186 * Perform a blocking read operation of 'count' items from the FMQ. Does not
187 * perform a partial read.
188 *
189 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
190 * associated with the FMQ and it is used in that case.
191 *
192 * The application code must ensure that 'evFlag' used by the
193 * reader(s)/writer is based upon the same EventFlag word.
194 *
195 * The method will return false without blocking if any of the following
196 * conditions are true:
197 * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
198 * -If the 'writeNotification' bit mask is zero.
199 * -If 'count' is greater than the FMQ size.
200 *
201 * This method should only be used with a MessageQueue of the flavor
202 * 'kSynchronizedReadWrite'.
203
204 * If FMQ does not contain 'count' items, the eventFlag bit mask
205 * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
206 * wake is called on 'readNotification' (if non-zero).
207 *
208 * @param data Pointer to the array to which read data is to be written.
209 * @param count Number of items to be read.
210 * @param readNotification The EventFlag bit mask to call wake on after
211 * a successful read. No wake is called if 'readNotification' is zero.
212 * @param writeNotification The EventFlag bit mask to call a wait on
213 * if there is insufficient data in the FMQ to be read.
214 * @param timeOutNanos Number of nanoseconds after which the blocking
215 * read attempt is aborted.
216 * @param evFlag The EventFlag object to be used for blocking.
217 *
218 * @return Whether the read was successful.
219 */
220 bool readBlocking(T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
221 int64_t timeOutNanos = 0, android::hardware::EventFlag* evFlag = nullptr);
222
223 bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);
224
225 /**
226 * Get a pointer to the MQDescriptor object that describes this FMQ.
227 *
228 * @return Pointer to the MQDescriptor associated with the FMQ.
229 */
getDescMessageQueueBase230 const Descriptor* getDesc() const { return mDesc.get(); }
231
232 /**
233 * Get a pointer to the EventFlag word if there is one associated with this FMQ.
234 *
235 * @return Pointer to an EventFlag word, will return nullptr if not
236 * configured. This method does not transfer ownership. The EventFlag
237 * word will be unmapped by the MessageQueue destructor.
238 */
getEventFlagWordMessageQueueBase239 std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
240
241 /**
242 * Describes a memory region in the FMQ.
243 */
244 struct MemRegion {
MemRegionMessageQueueBase::MemRegion245 MemRegion() : MemRegion(nullptr, 0) {}
246
MemRegionMessageQueueBase::MemRegion247 MemRegion(T* base, size_t size) : address(base), length(size) {}
248
249 MemRegion& operator=(const MemRegion& other) {
250 address = other.address;
251 length = other.length;
252 return *this;
253 }
254
255 /**
256 * Gets a pointer to the base address of the MemRegion.
257 */
getAddressMessageQueueBase::MemRegion258 inline T* getAddress() const { return address; }
259
260 /**
261 * Gets the length of the MemRegion. This would equal to the number
262 * of items of type T that can be read from/written into the MemRegion.
263 */
getLengthMessageQueueBase::MemRegion264 inline size_t getLength() const { return length; }
265
266 /**
267 * Gets the length of the MemRegion in bytes.
268 */
getLengthInBytesMessageQueueBase::MemRegion269 inline size_t getLengthInBytes() const { return length * sizeof(T); }
270
271 private:
272 /* Base address */
273 T* address;
274
275 /*
276 * Number of items of type T that can be written to/read from the base
277 * address.
278 */
279 size_t length;
280 };
281
282 /**
283 * Describes the memory regions to be used for a read or write.
284 * The struct contains two MemRegion objects since the FMQ is a ring
285 * buffer and a read or write operation can wrap around. A single message
286 * of type T will never be broken between the two MemRegions.
287 */
288 struct MemTransaction {
MemTransactionMessageQueueBase::MemTransaction289 MemTransaction() : MemTransaction(MemRegion(), MemRegion()) {}
290
MemTransactionMessageQueueBase::MemTransaction291 MemTransaction(const MemRegion& regionFirst, const MemRegion& regionSecond)
292 : first(regionFirst), second(regionSecond) {}
293
294 MemTransaction& operator=(const MemTransaction& other) {
295 first = other.first;
296 second = other.second;
297 return *this;
298 }
299
300 /**
301 * Helper method to calculate the address for a particular index for
302 * the MemTransaction object.
303 *
304 * @param idx Index of the slot to be read/written. If the
305 * MemTransaction object is representing the memory region to read/write
306 * N items of type T, the valid range of idx is between 0 and N-1.
307 *
308 * @return Pointer to the slot idx. Will be nullptr for an invalid idx.
309 */
310 T* getSlot(size_t idx);
311
312 /**
313 * Helper method to write 'nMessages' items of type T into the memory
314 * regions described by the object starting from 'startIdx'. This method
315 * uses memcpy() and is not to meant to be used for a zero copy operation.
316 * Partial writes are not supported.
317 *
318 * @param data Pointer to the source buffer.
319 * @param nMessages Number of items of type T.
320 * @param startIdx The slot number to begin the write from. If the
321 * MemTransaction object is representing the memory region to read/write
322 * N items of type T, the valid range of startIdx is between 0 and N-1;
323 *
324 * @return Whether the write operation of size 'nMessages' succeeded.
325 */
326 bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
327
328 /*
329 * Helper method to read 'nMessages' items of type T from the memory
330 * regions described by the object starting from 'startIdx'. This method uses
331 * memcpy() and is not meant to be used for a zero copy operation. Partial reads
332 * are not supported.
333 *
334 * @param data Pointer to the destination buffer.
335 * @param nMessages Number of items of type T.
336 * @param startIdx The slot number to begin the read from. If the
337 * MemTransaction object is representing the memory region to read/write
338 * N items of type T, the valid range of startIdx is between 0 and N-1.
339 *
340 * @return Whether the read operation of size 'nMessages' succeeded.
341 */
342 bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
343
344 /**
345 * Returns a const reference to the first MemRegion in the
346 * MemTransaction object.
347 */
getFirstRegionMessageQueueBase::MemTransaction348 inline const MemRegion& getFirstRegion() const { return first; }
349
350 /**
351 * Returns a const reference to the second MemRegion in the
352 * MemTransaction object.
353 */
getSecondRegionMessageQueueBase::MemTransaction354 inline const MemRegion& getSecondRegion() const { return second; }
355
356 private:
357 /*
358 * Given a start index and the number of messages to be
359 * read/written, this helper method calculates the
360 * number of messages that should should be written to both the first
361 * and second MemRegions and the base addresses to be used for
362 * the read/write operation.
363 *
364 * Returns false if the 'startIdx' and 'nMessages' is
365 * invalid for the MemTransaction object.
366 */
367 bool inline getMemRegionInfo(size_t idx, size_t nMessages, size_t& firstCount,
368 size_t& secondCount, T** firstBaseAddress,
369 T** secondBaseAddress);
370 MemRegion first;
371 MemRegion second;
372 };
373
374 /**
375 * Get a MemTransaction object to write 'nMessages' items of type T.
376 * Once the write is performed using the information from MemTransaction,
377 * the write operation is to be committed using a call to commitWrite().
378 *
379 * @param nMessages Number of messages of type T.
380 * @param Pointer to MemTransaction struct that describes memory to write 'nMessages'
381 * items of type T. If a write of size 'nMessages' is not possible, the base
382 * addresses in the MemTransaction object would be set to nullptr.
383 *
384 * @return Whether it is possible to write 'nMessages' items of type T
385 * into the FMQ.
386 */
387 bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
388
389 /**
390 * Commit a write of size 'nMessages'. To be only used after a call to beginWrite().
391 *
392 * @param nMessages number of messages of type T to be written.
393 *
394 * @return Whether the write operation of size 'nMessages' succeeded.
395 */
396 bool commitWrite(size_t nMessages);
397
398 /**
399 * Get a MemTransaction object to read 'nMessages' items of type T.
400 * Once the read is performed using the information from MemTransaction,
401 * the read operation is to be committed using a call to commitRead().
402 *
403 * @param nMessages Number of messages of type T.
404 * @param pointer to MemTransaction struct that describes memory to read 'nMessages'
405 * items of type T. If a read of size 'nMessages' is not possible, the base
406 * pointers in the MemTransaction object returned will be set to nullptr.
407 *
408 * @return bool Whether it is possible to read 'nMessages' items of type T
409 * from the FMQ.
410 */
411 bool beginRead(size_t nMessages, MemTransaction* memTx) const;
412
413 /**
414 * Commit a read of size 'nMessages'. To be only used after a call to beginRead().
415 * For the unsynchronized flavor of FMQ, this method will return a failure
416 * if a write overflow happened after beginRead() was invoked.
417 *
418 * @param nMessages number of messages of type T to be read.
419 *
420 * @return bool Whether the read operation of size 'nMessages' succeeded.
421 */
422 bool commitRead(size_t nMessages);
423
424 /**
425 * Get the pointer to the ring buffer. Useful for debugging and fuzzing.
426 */
getRingBufferPtrMessageQueueBase427 uint8_t* getRingBufferPtr() const { return mRing; }
428
429 private:
430 size_t availableToWriteBytes() const;
431 size_t availableToReadBytes() const;
432
433 MessageQueueBase(const MessageQueueBase& other) = delete;
434 MessageQueueBase& operator=(const MessageQueueBase& other) = delete;
435
436 void* mapGrantorDescr(uint32_t grantorIdx);
437 void unmapGrantorDescr(void* address, uint32_t grantorIdx);
438 void initMemory(bool resetPointers);
439
440 enum DefaultEventNotification : uint32_t {
441 /*
442 * These are only used internally by the readBlocking()/writeBlocking()
443 * methods and hence once other bit combinations are not required.
444 */
445 FMQ_NOT_FULL = 0x01,
446 FMQ_NOT_EMPTY = 0x02
447 };
448 std::unique_ptr<Descriptor> mDesc;
449 uint8_t* mRing = nullptr;
450 /*
451 * TODO(b/31550092): Change to 32 bit read and write pointer counters.
452 */
453 std::atomic<uint64_t>* mReadPtr = nullptr;
454 std::atomic<uint64_t>* mWritePtr = nullptr;
455
456 std::atomic<uint32_t>* mEvFlagWord = nullptr;
457
458 /*
459 * This EventFlag object will be owned by the FMQ and will have the same
460 * lifetime.
461 */
462 android::hardware::EventFlag* mEventFlag = nullptr;
463 };
464
465 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
getSlot(size_t idx)466 T* MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getSlot(size_t idx) {
467 size_t firstRegionLength = first.getLength();
468 size_t secondRegionLength = second.getLength();
469
470 if (idx > firstRegionLength + secondRegionLength) {
471 return nullptr;
472 }
473
474 if (idx < firstRegionLength) {
475 return first.getAddress() + idx;
476 }
477
478 return second.getAddress() + idx - firstRegionLength;
479 }
480
481 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
getMemRegionInfo(size_t startIdx,size_t nMessages,size_t & firstCount,size_t & secondCount,T ** firstBaseAddress,T ** secondBaseAddress)482 bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getMemRegionInfo(
483 size_t startIdx, size_t nMessages, size_t& firstCount, size_t& secondCount,
484 T** firstBaseAddress, T** secondBaseAddress) {
485 size_t firstRegionLength = first.getLength();
486 size_t secondRegionLength = second.getLength();
487
488 if (startIdx + nMessages > firstRegionLength + secondRegionLength) {
489 /*
490 * Return false if 'nMessages' starting at 'startIdx' cannot be
491 * accommodated by the MemTransaction object.
492 */
493 return false;
494 }
495
496 /* Number of messages to be read/written to the first MemRegion. */
497 firstCount =
498 startIdx < firstRegionLength ? std::min(nMessages, firstRegionLength - startIdx) : 0;
499
500 /* Number of messages to be read/written to the second MemRegion. */
501 secondCount = nMessages - firstCount;
502
503 if (firstCount != 0) {
504 *firstBaseAddress = first.getAddress() + startIdx;
505 }
506
507 if (secondCount != 0) {
508 size_t secondStartIdx = startIdx > firstRegionLength ? startIdx - firstRegionLength : 0;
509 *secondBaseAddress = second.getAddress() + secondStartIdx;
510 }
511
512 return true;
513 }
514
515 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
copyFrom(T * data,size_t startIdx,size_t nMessages)516 bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyFrom(T* data,
517 size_t startIdx,
518 size_t nMessages) {
519 if (data == nullptr) {
520 return false;
521 }
522
523 size_t firstReadCount = 0, secondReadCount = 0;
524 T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
525
526 if (getMemRegionInfo(startIdx, nMessages, firstReadCount, secondReadCount, &firstBaseAddress,
527 &secondBaseAddress) == false) {
528 /*
529 * Returns false if 'startIdx' and 'nMessages' are invalid for this
530 * MemTransaction object.
531 */
532 return false;
533 }
534
535 if (firstReadCount != 0) {
536 memcpy(data, firstBaseAddress, firstReadCount * sizeof(T));
537 }
538
539 if (secondReadCount != 0) {
540 memcpy(data + firstReadCount, secondBaseAddress, secondReadCount * sizeof(T));
541 }
542
543 return true;
544 }
545
546 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
copyTo(const T * data,size_t startIdx,size_t nMessages)547 bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyTo(const T* data,
548 size_t startIdx,
549 size_t nMessages) {
550 if (data == nullptr) {
551 return false;
552 }
553
554 size_t firstWriteCount = 0, secondWriteCount = 0;
555 T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
556
557 if (getMemRegionInfo(startIdx, nMessages, firstWriteCount, secondWriteCount, &firstBaseAddress,
558 &secondBaseAddress) == false) {
559 /*
560 * Returns false if 'startIdx' and 'nMessages' are invalid for this
561 * MemTransaction object.
562 */
563 return false;
564 }
565
566 if (firstWriteCount != 0) {
567 memcpy(firstBaseAddress, data, firstWriteCount * sizeof(T));
568 }
569
570 if (secondWriteCount != 0) {
571 memcpy(secondBaseAddress, data + firstWriteCount, secondWriteCount * sizeof(T));
572 }
573
574 return true;
575 }
576
577 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
initMemory(bool resetPointers)578 void MessageQueueBase<MQDescriptorType, T, flavor>::initMemory(bool resetPointers) {
579 /*
580 * Verify that the Descriptor contains the minimum number of grantors
581 * the native_handle is valid and T matches quantum size.
582 */
583 if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
584 (mDesc->countGrantors() < hardware::details::kMinGrantorCount)) {
585 return;
586 }
587 if (mDesc->getQuantum() != sizeof(T)) {
588 hardware::details::logError(
589 "Payload size differs between the queue instantiation and the "
590 "MQDescriptor.");
591 return;
592 }
593
594 if (flavor == kSynchronizedReadWrite) {
595 mReadPtr = reinterpret_cast<std::atomic<uint64_t>*>(
596 mapGrantorDescr(hardware::details::READPTRPOS));
597 } else {
598 /*
599 * The unsynchronized write flavor of the FMQ may have multiple readers
600 * and each reader would have their own read pointer counter.
601 */
602 mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
603 }
604 if (mReadPtr == nullptr) goto error;
605
606 mWritePtr = reinterpret_cast<std::atomic<uint64_t>*>(
607 mapGrantorDescr(hardware::details::WRITEPTRPOS));
608 if (mWritePtr == nullptr) goto error;
609
610 if (resetPointers) {
611 mReadPtr->store(0, std::memory_order_release);
612 mWritePtr->store(0, std::memory_order_release);
613 } else if (flavor != kSynchronizedReadWrite) {
614 // Always reset the read pointer.
615 mReadPtr->store(0, std::memory_order_release);
616 }
617
618 mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(hardware::details::DATAPTRPOS));
619 if (mRing == nullptr) goto error;
620
621 if (mDesc->countGrantors() > hardware::details::EVFLAGWORDPOS) {
622 mEvFlagWord = static_cast<std::atomic<uint32_t>*>(
623 mapGrantorDescr(hardware::details::EVFLAGWORDPOS));
624 if (mEvFlagWord == nullptr) goto error;
625 android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
626 }
627 return;
628 error:
629 if (mReadPtr) {
630 if (flavor == kSynchronizedReadWrite) {
631 unmapGrantorDescr(mReadPtr, hardware::details::READPTRPOS);
632 } else {
633 delete mReadPtr;
634 }
635 mReadPtr = nullptr;
636 }
637 if (mWritePtr) {
638 unmapGrantorDescr(mWritePtr, hardware::details::WRITEPTRPOS);
639 mWritePtr = nullptr;
640 }
641 if (mRing) {
642 unmapGrantorDescr(mRing, hardware::details::EVFLAGWORDPOS);
643 mRing = nullptr;
644 }
645 }
646
647 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
MessageQueueBase(const Descriptor & Desc,bool resetPointers)648 MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(const Descriptor& Desc,
649 bool resetPointers) {
650 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
651 if (mDesc == nullptr || mDesc->getSize() == 0) {
652 hardware::details::logError("MQDescriptor is invalid or queue size is 0.");
653 return;
654 }
655
656 initMemory(resetPointers);
657 }
658
659 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
MessageQueueBase(size_t numElementsInQueue,bool configureEventFlagWord,android::base::unique_fd bufferFd,size_t bufferSize)660 MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(size_t numElementsInQueue,
661 bool configureEventFlagWord,
662 android::base::unique_fd bufferFd,
663 size_t bufferSize) {
664 // Check if the buffer size would not overflow size_t
665 if (numElementsInQueue > SIZE_MAX / sizeof(T)) {
666 hardware::details::logError("Requested message queue size too large. Size of elements: " +
667 std::to_string(sizeof(T)) +
668 ". Number of elements: " + std::to_string(numElementsInQueue));
669 return;
670 }
671 if (numElementsInQueue == 0) {
672 hardware::details::logError("Requested queue size of 0.");
673 return;
674 }
675 if (bufferFd != -1 && numElementsInQueue * sizeof(T) > bufferSize) {
676 hardware::details::logError("The supplied buffer size(" + std::to_string(bufferSize) +
677 ") is smaller than the required size(" +
678 std::to_string(numElementsInQueue * sizeof(T)) + ").");
679 return;
680 }
681 /*
682 * The FMQ needs to allocate memory for the ringbuffer as well as for the
683 * read and write pointer counters. If an EventFlag word is to be configured,
684 * we also need to allocate memory for the same/
685 */
686 size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
687 size_t kMetaDataSize = 2 * sizeof(android::hardware::details::RingBufferPosition);
688
689 if (configureEventFlagWord) {
690 kMetaDataSize += sizeof(std::atomic<uint32_t>);
691 }
692
693 /*
694 * Ashmem memory region size needs to be specified in page-aligned bytes.
695 * kQueueSizeBytes needs to be aligned to word boundary so that all offsets
696 * in the grantorDescriptor will be word aligned.
697 */
698 size_t kAshmemSizePageAligned;
699 if (bufferFd != -1) {
700 // Allocate read counter and write counter only. User-supplied memory will be used for the
701 // ringbuffer.
702 kAshmemSizePageAligned = (kMetaDataSize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
703 } else {
704 // Allocate ringbuffer, read counter and write counter.
705 kAshmemSizePageAligned = (hardware::details::alignToWordBoundary(kQueueSizeBytes) +
706 kMetaDataSize + PAGE_SIZE - 1) &
707 ~(PAGE_SIZE - 1);
708 }
709
710 /*
711 * The native handle will contain the fds to be mapped.
712 */
713 int numFds = (bufferFd != -1) ? 2 : 1;
714 native_handle_t* mqHandle = native_handle_create(numFds, 0 /* numInts */);
715 if (mqHandle == nullptr) {
716 return;
717 }
718
719 /*
720 * Create an ashmem region to map the memory.
721 */
722 int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
723 ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
724 mqHandle->data[0] = ashmemFd;
725
726 if (bufferFd != -1) {
727 // Use user-supplied file descriptor for fdIndex 1
728 mqHandle->data[1] = bufferFd.get();
729 // release ownership of fd. mqHandle owns it now.
730 if (bufferFd.release() < 0) {
731 hardware::details::logError("Error releasing supplied bufferFd");
732 }
733
734 std::vector<android::hardware::GrantorDescriptor> grantors;
735 grantors.resize(configureEventFlagWord ? hardware::details::kMinGrantorCountForEvFlagSupport
736 : hardware::details::kMinGrantorCount);
737
738 size_t memSize[] = {
739 sizeof(hardware::details::RingBufferPosition), /* memory to be allocated for read
740 pointer counter */
741 sizeof(hardware::details::RingBufferPosition), /* memory to be allocated for write
742 pointer counter */
743 kQueueSizeBytes, /* memory to be allocated for data buffer */
744 sizeof(std::atomic<uint32_t>) /* memory to be allocated for EventFlag word */
745 };
746
747 for (size_t grantorPos = 0, offset = 0; grantorPos < grantors.size(); grantorPos++) {
748 uint32_t grantorFdIndex;
749 size_t grantorOffset;
750 if (grantorPos == hardware::details::DATAPTRPOS) {
751 grantorFdIndex = 1;
752 grantorOffset = 0;
753 } else {
754 grantorFdIndex = 0;
755 grantorOffset = offset;
756 offset += memSize[grantorPos];
757 }
758 grantors[grantorPos] = {
759 0 /* grantor flags */, grantorFdIndex,
760 static_cast<uint32_t>(hardware::details::alignToWordBoundary(grantorOffset)),
761 memSize[grantorPos]};
762 }
763
764 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow)
765 Descriptor(grantors, mqHandle, sizeof(T)));
766 } else {
767 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(
768 kQueueSizeBytes, mqHandle, sizeof(T), configureEventFlagWord));
769 }
770 if (mDesc == nullptr) {
771 native_handle_close(mqHandle);
772 native_handle_delete(mqHandle);
773 return;
774 }
775 initMemory(true);
776 }
777
778 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
~MessageQueueBase()779 MessageQueueBase<MQDescriptorType, T, flavor>::~MessageQueueBase() {
780 if (flavor == kSynchronizedReadWrite && mReadPtr != nullptr) {
781 unmapGrantorDescr(mReadPtr, hardware::details::READPTRPOS);
782 } else if (mReadPtr != nullptr) {
783 delete mReadPtr;
784 }
785 if (mWritePtr != nullptr) {
786 unmapGrantorDescr(mWritePtr, hardware::details::WRITEPTRPOS);
787 }
788 if (mRing != nullptr) {
789 unmapGrantorDescr(mRing, hardware::details::DATAPTRPOS);
790 }
791 if (mEvFlagWord != nullptr) {
792 unmapGrantorDescr(mEvFlagWord, hardware::details::EVFLAGWORDPOS);
793 android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
794 }
795 }
796
797 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
write(const T * data)798 bool MessageQueueBase<MQDescriptorType, T, flavor>::write(const T* data) {
799 return write(data, 1);
800 }
801
802 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
read(T * data)803 bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data) {
804 return read(data, 1);
805 }
806
807 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
write(const T * data,size_t nMessages)808 bool MessageQueueBase<MQDescriptorType, T, flavor>::write(const T* data, size_t nMessages) {
809 MemTransaction tx;
810 return beginWrite(nMessages, &tx) && tx.copyTo(data, 0 /* startIdx */, nMessages) &&
811 commitWrite(nMessages);
812 }
813
814 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
writeBlocking(const T * data,size_t count,uint32_t readNotification,uint32_t writeNotification,int64_t timeOutNanos,android::hardware::EventFlag * evFlag)815 bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(
816 const T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
817 int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
818 static_assert(flavor == kSynchronizedReadWrite,
819 "writeBlocking can only be used with the "
820 "kSynchronizedReadWrite flavor.");
821 /*
822 * If evFlag is null and the FMQ does not have its own EventFlag object
823 * return false;
824 * If the flavor is kSynchronizedReadWrite and the readNotification
825 * bit mask is zero return false;
826 * If the count is greater than queue size, return false
827 * to prevent blocking until timeOut.
828 */
829 if (evFlag == nullptr) {
830 evFlag = mEventFlag;
831 if (evFlag == nullptr) {
832 hardware::details::logError(
833 "writeBlocking failed: called on MessageQueue with no Eventflag"
834 "configured or provided");
835 return false;
836 }
837 }
838
839 if (readNotification == 0 || (count > getQuantumCount())) {
840 return false;
841 }
842
843 /*
844 * There is no need to wait for a readNotification if there is sufficient
845 * space to write is already present in the FMQ. The latter would be the case when
846 * read operations read more number of messages than write operations write.
847 * In other words, a single large read may clear the FMQ after multiple small
848 * writes. This would fail to clear a pending readNotification bit since
849 * EventFlag bits can only be cleared by a wait() call, however the bit would
850 * be correctly cleared by the next writeBlocking() call.
851 */
852
853 bool result = write(data, count);
854 if (result) {
855 if (writeNotification) {
856 evFlag->wake(writeNotification);
857 }
858 return result;
859 }
860
861 bool shouldTimeOut = timeOutNanos != 0;
862 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
863
864 while (true) {
865 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
866 if (shouldTimeOut) {
867 /*
868 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
869 * to Nanoseconds)
870 */
871 int64_t currentTimeNs = android::elapsedRealtimeNano();
872 /*
873 * Decrement 'timeOutNanos' to account for the time taken to complete the last
874 * iteration of the while loop.
875 */
876 timeOutNanos -= currentTimeNs - prevTimeNanos;
877 prevTimeNanos = currentTimeNs;
878
879 if (timeOutNanos <= 0) {
880 /*
881 * Attempt write in case a context switch happened outside of
882 * evFlag->wait().
883 */
884 result = write(data, count);
885 break;
886 }
887 }
888
889 /*
890 * wait() will return immediately if there was a pending read
891 * notification.
892 */
893 uint32_t efState = 0;
894 status_t status = evFlag->wait(readNotification, &efState, timeOutNanos,
895 true /* retry on spurious wake */);
896
897 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
898 hardware::details::logError("Unexpected error code from EventFlag Wait status " +
899 std::to_string(status));
900 break;
901 }
902
903 if (status == android::TIMED_OUT) {
904 break;
905 }
906
907 /*
908 * If there is still insufficient space to write to the FMQ,
909 * keep waiting for another readNotification.
910 */
911 if ((efState & readNotification) && write(data, count)) {
912 result = true;
913 break;
914 }
915 }
916
917 if (result && writeNotification != 0) {
918 evFlag->wake(writeNotification);
919 }
920
921 return result;
922 }
923
924 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
writeBlocking(const T * data,size_t count,int64_t timeOutNanos)925 bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(const T* data, size_t count,
926 int64_t timeOutNanos) {
927 return writeBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
928 }
929
930 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
readBlocking(T * data,size_t count,uint32_t readNotification,uint32_t writeNotification,int64_t timeOutNanos,android::hardware::EventFlag * evFlag)931 bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(
932 T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
933 int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
934 static_assert(flavor == kSynchronizedReadWrite,
935 "readBlocking can only be used with the "
936 "kSynchronizedReadWrite flavor.");
937
938 /*
939 * If evFlag is null and the FMQ does not own its own EventFlag object
940 * return false;
941 * If the writeNotification bit mask is zero return false;
942 * If the count is greater than queue size, return false to prevent
943 * blocking until timeOut.
944 */
945 if (evFlag == nullptr) {
946 evFlag = mEventFlag;
947 if (evFlag == nullptr) {
948 hardware::details::logError(
949 "readBlocking failed: called on MessageQueue with no Eventflag"
950 "configured or provided");
951 return false;
952 }
953 }
954
955 if (writeNotification == 0 || count > getQuantumCount()) {
956 return false;
957 }
958
959 /*
960 * There is no need to wait for a write notification if sufficient
961 * data to read is already present in the FMQ. This would be the
962 * case when read operations read lesser number of messages than
963 * a write operation and multiple reads would be required to clear the queue
964 * after a single write operation. This check would fail to clear a pending
965 * writeNotification bit since EventFlag bits can only be cleared
966 * by a wait() call, however the bit would be correctly cleared by the next
967 * readBlocking() call.
968 */
969
970 bool result = read(data, count);
971 if (result) {
972 if (readNotification) {
973 evFlag->wake(readNotification);
974 }
975 return result;
976 }
977
978 bool shouldTimeOut = timeOutNanos != 0;
979 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
980
981 while (true) {
982 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
983 if (shouldTimeOut) {
984 /*
985 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
986 * to Nanoseconds)
987 */
988 int64_t currentTimeNs = android::elapsedRealtimeNano();
989 /*
990 * Decrement 'timeOutNanos' to account for the time taken to complete the last
991 * iteration of the while loop.
992 */
993 timeOutNanos -= currentTimeNs - prevTimeNanos;
994 prevTimeNanos = currentTimeNs;
995
996 if (timeOutNanos <= 0) {
997 /*
998 * Attempt read in case a context switch happened outside of
999 * evFlag->wait().
1000 */
1001 result = read(data, count);
1002 break;
1003 }
1004 }
1005
1006 /*
1007 * wait() will return immediately if there was a pending write
1008 * notification.
1009 */
1010 uint32_t efState = 0;
1011 status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos,
1012 true /* retry on spurious wake */);
1013
1014 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
1015 hardware::details::logError("Unexpected error code from EventFlag Wait status " +
1016 std::to_string(status));
1017 break;
1018 }
1019
1020 if (status == android::TIMED_OUT) {
1021 break;
1022 }
1023
1024 /*
1025 * If the data in FMQ is still insufficient, go back to waiting
1026 * for another write notification.
1027 */
1028 if ((efState & writeNotification) && read(data, count)) {
1029 result = true;
1030 break;
1031 }
1032 }
1033
1034 if (result && readNotification != 0) {
1035 evFlag->wake(readNotification);
1036 }
1037 return result;
1038 }
1039
1040 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
readBlocking(T * data,size_t count,int64_t timeOutNanos)1041 bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(T* data, size_t count,
1042 int64_t timeOutNanos) {
1043 return readBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
1044 }
1045
1046 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
availableToWriteBytes()1047 size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWriteBytes() const {
1048 return mDesc->getSize() - availableToReadBytes();
1049 }
1050
1051 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
availableToWrite()1052 size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWrite() const {
1053 return availableToWriteBytes() / sizeof(T);
1054 }
1055
1056 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
availableToRead()1057 size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToRead() const {
1058 return availableToReadBytes() / sizeof(T);
1059 }
1060
1061 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
beginWrite(size_t nMessages,MemTransaction * result)1062 bool MessageQueueBase<MQDescriptorType, T, flavor>::beginWrite(size_t nMessages,
1063 MemTransaction* result) const {
1064 /*
1065 * If nMessages is greater than size of FMQ or in case of the synchronized
1066 * FMQ flavor, if there is not enough space to write nMessages, then return
1067 * result with null addresses.
1068 */
1069 if ((flavor == kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
1070 nMessages > getQuantumCount()) {
1071 *result = MemTransaction();
1072 return false;
1073 }
1074
1075 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
1076 if (writePtr % sizeof(T) != 0) {
1077 hardware::details::logError(
1078 "The write pointer has become misaligned. Writing to the queue is no longer "
1079 "possible.");
1080 hardware::details::errorWriteLog(0x534e4554, "184963385");
1081 return false;
1082 }
1083 size_t writeOffset = writePtr % mDesc->getSize();
1084
1085 /*
1086 * From writeOffset, the number of messages that can be written
1087 * contiguously without wrapping around the ring buffer are calculated.
1088 */
1089 size_t contiguousMessages = (mDesc->getSize() - writeOffset) / sizeof(T);
1090
1091 if (contiguousMessages < nMessages) {
1092 /*
1093 * Wrap around is required. Both result.first and result.second are
1094 * populated.
1095 */
1096 *result = MemTransaction(
1097 MemRegion(reinterpret_cast<T*>(mRing + writeOffset), contiguousMessages),
1098 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
1099 } else {
1100 /*
1101 * A wrap around is not required to write nMessages. Only result.first
1102 * is populated.
1103 */
1104 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset), nMessages),
1105 MemRegion());
1106 }
1107
1108 return true;
1109 }
1110
1111 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
1112 /*
1113 * Disable integer sanitization since integer overflow here is allowed
1114 * and legal.
1115 */
1116 __attribute__((no_sanitize("integer"))) bool
commitWrite(size_t nMessages)1117 MessageQueueBase<MQDescriptorType, T, flavor>::commitWrite(size_t nMessages) {
1118 size_t nBytesWritten = nMessages * sizeof(T);
1119 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
1120 writePtr += nBytesWritten;
1121 mWritePtr->store(writePtr, std::memory_order_release);
1122 /*
1123 * This method cannot fail now since we are only incrementing the writePtr
1124 * counter.
1125 */
1126 return true;
1127 }
1128
1129 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
availableToReadBytes()1130 size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToReadBytes() const {
1131 /*
1132 * This method is invoked by implementations of both read() and write() and
1133 * hence requires a memory_order_acquired load for both mReadPtr and
1134 * mWritePtr.
1135 */
1136 return mWritePtr->load(std::memory_order_acquire) - mReadPtr->load(std::memory_order_acquire);
1137 }
1138
1139 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
read(T * data,size_t nMessages)1140 bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data, size_t nMessages) {
1141 MemTransaction tx;
1142 return beginRead(nMessages, &tx) && tx.copyFrom(data, 0 /* startIdx */, nMessages) &&
1143 commitRead(nMessages);
1144 }
1145
1146 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
1147 /*
1148 * Disable integer sanitization since integer overflow here is allowed
1149 * and legal.
1150 */
1151 __attribute__((no_sanitize("integer"))) bool
beginRead(size_t nMessages,MemTransaction * result)1152 MessageQueueBase<MQDescriptorType, T, flavor>::beginRead(size_t nMessages,
1153 MemTransaction* result) const {
1154 *result = MemTransaction();
1155 /*
1156 * If it is detected that the data in the queue was overwritten
1157 * due to the reader process being too slow, the read pointer counter
1158 * is set to the same as the write pointer counter to indicate error
1159 * and the read returns false;
1160 * Need acquire/release memory ordering for mWritePtr.
1161 */
1162 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1163 /*
1164 * A relaxed load is sufficient for mReadPtr since there will be no
1165 * stores to mReadPtr from a different thread.
1166 */
1167 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
1168 if (writePtr % sizeof(T) != 0 || readPtr % sizeof(T) != 0) {
1169 hardware::details::logError(
1170 "The write or read pointer has become misaligned. Reading from the queue is no "
1171 "longer possible.");
1172 hardware::details::errorWriteLog(0x534e4554, "184963385");
1173 return false;
1174 }
1175
1176 if (writePtr - readPtr > mDesc->getSize()) {
1177 mReadPtr->store(writePtr, std::memory_order_release);
1178 return false;
1179 }
1180
1181 size_t nBytesDesired = nMessages * sizeof(T);
1182 /*
1183 * Return if insufficient data to read in FMQ.
1184 */
1185 if (writePtr - readPtr < nBytesDesired) {
1186 return false;
1187 }
1188
1189 size_t readOffset = readPtr % mDesc->getSize();
1190 /*
1191 * From readOffset, the number of messages that can be read contiguously
1192 * without wrapping around the ring buffer are calculated.
1193 */
1194 size_t contiguousMessages = (mDesc->getSize() - readOffset) / sizeof(T);
1195
1196 if (contiguousMessages < nMessages) {
1197 /*
1198 * A wrap around is required. Both result.first and result.second
1199 * are populated.
1200 */
1201 *result = MemTransaction(
1202 MemRegion(reinterpret_cast<T*>(mRing + readOffset), contiguousMessages),
1203 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
1204 } else {
1205 /*
1206 * A wrap around is not required. Only result.first need to be
1207 * populated.
1208 */
1209 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset), nMessages),
1210 MemRegion());
1211 }
1212
1213 return true;
1214 }
1215
1216 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
1217 /*
1218 * Disable integer sanitization since integer overflow here is allowed
1219 * and legal.
1220 */
1221 __attribute__((no_sanitize("integer"))) bool
commitRead(size_t nMessages)1222 MessageQueueBase<MQDescriptorType, T, flavor>::commitRead(size_t nMessages) {
1223 // TODO: Use a local copy of readPtr to avoid relazed mReadPtr loads.
1224 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
1225 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1226 /*
1227 * If the flavor is unsynchronized, it is possible that a write overflow may
1228 * have occurred between beginRead() and commitRead().
1229 */
1230 if (writePtr - readPtr > mDesc->getSize()) {
1231 mReadPtr->store(writePtr, std::memory_order_release);
1232 return false;
1233 }
1234
1235 size_t nBytesRead = nMessages * sizeof(T);
1236 readPtr += nBytesRead;
1237 mReadPtr->store(readPtr, std::memory_order_release);
1238 return true;
1239 }
1240
1241 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
getQuantumSize()1242 size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumSize() const {
1243 return mDesc->getQuantum();
1244 }
1245
1246 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
getQuantumCount()1247 size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumCount() const {
1248 return mDesc->getSize() / mDesc->getQuantum();
1249 }
1250
1251 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
isValid()1252 bool MessageQueueBase<MQDescriptorType, T, flavor>::isValid() const {
1253 return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
1254 }
1255
1256 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
mapGrantorDescr(uint32_t grantorIdx)1257 void* MessageQueueBase<MQDescriptorType, T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
1258 const native_handle_t* handle = mDesc->handle();
1259 const std::vector<android::hardware::GrantorDescriptor> grantors = mDesc->grantors();
1260 if (handle == nullptr) {
1261 hardware::details::logError("mDesc->handle is null");
1262 return nullptr;
1263 }
1264
1265 if (grantorIdx >= grantors.size()) {
1266 hardware::details::logError(std::string("grantorIdx must be less than ") +
1267 std::to_string(grantors.size()));
1268 return nullptr;
1269 }
1270
1271 int fdIndex = grantors[grantorIdx].fdIndex;
1272 if (fdIndex < 0 || fdIndex >= handle->numFds) {
1273 hardware::details::logError(
1274 std::string("fdIndex (" + std::to_string(fdIndex) + ") from grantor (index " +
1275 std::to_string(grantorIdx) +
1276 ") must be smaller than the number of fds in the handle: " +
1277 std::to_string(handle->numFds)));
1278 return nullptr;
1279 }
1280
1281 /*
1282 * Offset for mmap must be a multiple of PAGE_SIZE.
1283 */
1284 if (!hardware::details::isAlignedToWordBoundary(grantors[grantorIdx].offset)) {
1285 hardware::details::logError("Grantor (index " + std::to_string(grantorIdx) +
1286 ") offset needs to be aligned to word boundary but is: " +
1287 std::to_string(grantors[grantorIdx].offset));
1288 return nullptr;
1289 }
1290
1291 /*
1292 * Expect some grantors to be at least a min size
1293 */
1294 for (uint32_t i = 0; i < grantors.size(); i++) {
1295 switch (i) {
1296 case hardware::details::READPTRPOS:
1297 if (grantors[i].extent < sizeof(uint64_t)) return nullptr;
1298 break;
1299 case hardware::details::WRITEPTRPOS:
1300 if (grantors[i].extent < sizeof(uint64_t)) return nullptr;
1301 break;
1302 case hardware::details::DATAPTRPOS:
1303 // We don't expect specific data size
1304 break;
1305 case hardware::details::EVFLAGWORDPOS:
1306 if (grantors[i].extent < sizeof(uint32_t)) return nullptr;
1307 break;
1308 default:
1309 // We don't care about unknown grantors
1310 break;
1311 }
1312 }
1313
1314 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
1315 if (grantors[grantorIdx].extent < 0 || grantors[grantorIdx].extent > INT_MAX - PAGE_SIZE) {
1316 hardware::details::logError(std::string("Grantor (index " + std::to_string(grantorIdx) +
1317 ") extent value is too large or negative: " +
1318 std::to_string(grantors[grantorIdx].extent)));
1319 return nullptr;
1320 }
1321 int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
1322
1323 void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED, handle->data[fdIndex],
1324 mapOffset);
1325 if (address == MAP_FAILED) {
1326 hardware::details::logError(std::string("mmap failed: ") + std::to_string(errno));
1327 return nullptr;
1328 }
1329 return reinterpret_cast<uint8_t*>(address) + (grantors[grantorIdx].offset - mapOffset);
1330 }
1331
1332 template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
unmapGrantorDescr(void * address,uint32_t grantorIdx)1333 void MessageQueueBase<MQDescriptorType, T, flavor>::unmapGrantorDescr(void* address,
1334 uint32_t grantorIdx) {
1335 auto grantors = mDesc->grantors();
1336 if ((address == nullptr) || (grantorIdx >= grantors.size())) {
1337 return;
1338 }
1339
1340 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
1341 int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
1342 void* baseAddress =
1343 reinterpret_cast<uint8_t*>(address) - (grantors[grantorIdx].offset - mapOffset);
1344 if (baseAddress) munmap(baseAddress, mapLength);
1345 }
1346
1347 } // namespace hardware
1348