blob: f4bf7e248d1eb4352347a7c0e5303c2a4e144c46 [file] [log] [blame]
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Devin Moore9a27da52020-07-06 14:01:21 -070017#pragma once
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080018
Devin Moored7e702b2021-01-18 16:10:37 -080019#include <android-base/unique_fd.h>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080020#include <cutils/ashmem.h>
21#include <fmq/EventFlag.h>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080022#include <sys/mman.h>
Devin Mooreef38ed62021-04-07 10:10:36 -070023#include <sys/user.h>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080024#include <utils/Log.h>
Hridya Valsaraju2abefb62017-01-19 13:06:58 -080025#include <utils/SystemClock.h>
Devin Moore77d279e2020-07-07 10:38:52 -070026#include <atomic>
27#include <new>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080028
Devin Moore133cb5e2020-07-07 16:31:22 -070029using android::hardware::kSynchronizedReadWrite;
30using android::hardware::kUnsynchronizedWrite;
31using android::hardware::MQFlavor;
32
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080033namespace android {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080034
Devin Moore133cb5e2020-07-07 16:31:22 -070035template <template <typename, MQFlavor> class MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -070036struct MessageQueueBase {
37 typedef MQDescriptorType<T, flavor> Descriptor;
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -080038
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080039 /**
40 * @param Desc MQDescriptor describing the FMQ.
41 * @param resetPointers bool indicating whether the read/write pointers
42 * should be reset or not.
43 */
Devin Moore9a27da52020-07-06 14:01:21 -070044 MessageQueueBase(const Descriptor& Desc, bool resetPointers = true);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080045
Devin Moore9a27da52020-07-06 14:01:21 -070046 ~MessageQueueBase();
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080047
48 /**
49 * This constructor uses Ashmem shared memory to create an FMQ
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080050 * that can contain a maximum of 'numElementsInQueue' elements of type T.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080051 *
52 * @param numElementsInQueue Capacity of the MessageQueue in terms of T.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -080053 * @param configureEventFlagWord Boolean that specifies if memory should
54 * also be allocated and mapped for an EventFlag word.
Gareth Fenn1af25462020-11-11 20:46:32 +000055 * @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.
Devin Moored7e702b2021-01-18 16:10:37 -080058 * @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.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080061 */
Devin Moore9a27da52020-07-06 14:01:21 -070062
Devin Moored7e702b2021-01-18 16:10:37 -080063 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) {}
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080069
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 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800131 * 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.
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700143 * - If the 'readNotification' bit mask is zero.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800144 * - If 'count' is greater than the FMQ size.
145 *
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700146 * 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
Devin Moore133cb5e2020-07-07 16:31:22 -0700150 * 'kSynchronizedReadWrite'.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800151 *
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 */
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800169 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
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800173 bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
174
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800175 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800176 * 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 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800186 * 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 *
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700201 * This method should only be used with a MessageQueue of the flavor
Devin Moore133cb5e2020-07-07 16:31:22 -0700202 * 'kSynchronizedReadWrite'.
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700203
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800204 * 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 */
Devin Moore77d279e2020-07-07 10:38:52 -0700220 bool readBlocking(T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
221 int64_t timeOutNanos = 0, android::hardware::EventFlag* evFlag = nullptr);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800222
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800223 bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);
224
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800225 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800226 * Get a pointer to the MQDescriptor object that describes this FMQ.
227 *
228 * @return Pointer to the MQDescriptor associated with the FMQ.
229 */
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800230 const Descriptor* getDesc() const { return mDesc.get(); }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800231
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800232 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800233 * Get a pointer to the EventFlag word if there is one associated with this FMQ.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800234 *
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800235 * @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.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800238 */
239 std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800240
241 /**
242 * Describes a memory region in the FMQ.
243 */
244 struct MemRegion {
245 MemRegion() : MemRegion(nullptr, 0) {}
246
247 MemRegion(T* base, size_t size) : address(base), length(size) {}
248
Devin Moore77d279e2020-07-07 10:38:52 -0700249 MemRegion& operator=(const MemRegion& other) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800250 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 */
258 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 */
264 inline size_t getLength() const { return length; }
265
266 /**
267 * Gets the length of the MemRegion in bytes.
268 */
269 inline size_t getLengthInBytes() const { return length * sizeof(T); }
270
Devin Moore77d279e2020-07-07 10:38:52 -0700271 private:
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800272 /* 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 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800279 size_t length;
280 };
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800281
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 {
289 MemTransaction() : MemTransaction(MemRegion(), MemRegion()) {}
290
Devin Moore77d279e2020-07-07 10:38:52 -0700291 MemTransaction(const MemRegion& regionFirst, const MemRegion& regionSecond)
292 : first(regionFirst), second(regionSecond) {}
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800293
Devin Moore77d279e2020-07-07 10:38:52 -0700294 MemTransaction& operator=(const MemTransaction& other) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800295 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 */
348 inline const MemRegion& getFirstRegion() const { return first; }
349
350 /**
351 * Returns a const reference to the second MemRegion in the
352 * MemTransaction object.
353 */
354 inline const MemRegion& getSecondRegion() const { return second; }
355
Devin Moore77d279e2020-07-07 10:38:52 -0700356 private:
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800357 /*
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 */
Devin Moore77d279e2020-07-07 10:38:52 -0700367 bool inline getMemRegionInfo(size_t idx, size_t nMessages, size_t& firstCount,
368 size_t& secondCount, T** firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800369 T** secondBaseAddress);
370 MemRegion first;
371 MemRegion second;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800372 };
373
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800374 /**
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;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800388
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800389 /**
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
Devin Moore77d279e2020-07-07 10:38:52 -0700424 private:
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800425 size_t availableToWriteBytes() const;
426 size_t availableToReadBytes() const;
427
Devin Moore9a27da52020-07-06 14:01:21 -0700428 MessageQueueBase(const MessageQueueBase& other) = delete;
429 MessageQueueBase& operator=(const MessageQueueBase& other) = delete;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800430
431 void* mapGrantorDescr(uint32_t grantorIdx);
432 void unmapGrantorDescr(void* address, uint32_t grantorIdx);
433 void initMemory(bool resetPointers);
434
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800435 enum DefaultEventNotification : uint32_t {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800436 /*
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700437 * These are only used internally by the readBlocking()/writeBlocking()
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800438 * methods and hence once other bit combinations are not required.
439 */
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700440 FMQ_NOT_FULL = 0x01,
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800441 FMQ_NOT_EMPTY = 0x02
442 };
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800443 std::unique_ptr<Descriptor> mDesc;
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800444 uint8_t* mRing = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800445 /*
446 * TODO(b/31550092): Change to 32 bit read and write pointer counters.
447 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800448 std::atomic<uint64_t>* mReadPtr = nullptr;
449 std::atomic<uint64_t>* mWritePtr = nullptr;
450
451 std::atomic<uint32_t>* mEvFlagWord = nullptr;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800452
453 /*
454 * This EventFlag object will be owned by the FMQ and will have the same
455 * lifetime.
456 */
457 android::hardware::EventFlag* mEventFlag = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800458};
459
Devin Moore133cb5e2020-07-07 16:31:22 -0700460template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700461T* MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getSlot(size_t idx) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800462 size_t firstRegionLength = first.getLength();
463 size_t secondRegionLength = second.getLength();
464
465 if (idx > firstRegionLength + secondRegionLength) {
466 return nullptr;
467 }
468
469 if (idx < firstRegionLength) {
470 return first.getAddress() + idx;
471 }
472
473 return second.getAddress() + idx - firstRegionLength;
474}
475
Devin Moore133cb5e2020-07-07 16:31:22 -0700476template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700477bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getMemRegionInfo(
478 size_t startIdx, size_t nMessages, size_t& firstCount, size_t& secondCount,
479 T** firstBaseAddress, T** secondBaseAddress) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800480 size_t firstRegionLength = first.getLength();
481 size_t secondRegionLength = second.getLength();
482
483 if (startIdx + nMessages > firstRegionLength + secondRegionLength) {
484 /*
485 * Return false if 'nMessages' starting at 'startIdx' cannot be
Devin Moored7e702b2021-01-18 16:10:37 -0800486 * accommodated by the MemTransaction object.
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800487 */
488 return false;
489 }
490
491 /* Number of messages to be read/written to the first MemRegion. */
Devin Moore77d279e2020-07-07 10:38:52 -0700492 firstCount =
493 startIdx < firstRegionLength ? std::min(nMessages, firstRegionLength - startIdx) : 0;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800494
495 /* Number of messages to be read/written to the second MemRegion. */
496 secondCount = nMessages - firstCount;
497
498 if (firstCount != 0) {
499 *firstBaseAddress = first.getAddress() + startIdx;
500 }
501
502 if (secondCount != 0) {
503 size_t secondStartIdx = startIdx > firstRegionLength ? startIdx - firstRegionLength : 0;
504 *secondBaseAddress = second.getAddress() + secondStartIdx;
505 }
506
507 return true;
508}
509
Devin Moore133cb5e2020-07-07 16:31:22 -0700510template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700511bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyFrom(T* data,
512 size_t startIdx,
513 size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800514 if (data == nullptr) {
515 return false;
516 }
517
518 size_t firstReadCount = 0, secondReadCount = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700519 T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800520
Devin Moore77d279e2020-07-07 10:38:52 -0700521 if (getMemRegionInfo(startIdx, nMessages, firstReadCount, secondReadCount, &firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800522 &secondBaseAddress) == false) {
523 /*
524 * Returns false if 'startIdx' and 'nMessages' are invalid for this
525 * MemTransaction object.
526 */
527 return false;
528 }
529
530 if (firstReadCount != 0) {
531 memcpy(data, firstBaseAddress, firstReadCount * sizeof(T));
532 }
533
534 if (secondReadCount != 0) {
Devin Moore77d279e2020-07-07 10:38:52 -0700535 memcpy(data + firstReadCount, secondBaseAddress, secondReadCount * sizeof(T));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800536 }
537
538 return true;
539}
540
Devin Moore133cb5e2020-07-07 16:31:22 -0700541template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700542bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyTo(const T* data,
543 size_t startIdx,
544 size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800545 if (data == nullptr) {
546 return false;
547 }
548
549 size_t firstWriteCount = 0, secondWriteCount = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700550 T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800551
Devin Moore77d279e2020-07-07 10:38:52 -0700552 if (getMemRegionInfo(startIdx, nMessages, firstWriteCount, secondWriteCount, &firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800553 &secondBaseAddress) == false) {
554 /*
555 * Returns false if 'startIdx' and 'nMessages' are invalid for this
556 * MemTransaction object.
557 */
558 return false;
559 }
560
561 if (firstWriteCount != 0) {
562 memcpy(firstBaseAddress, data, firstWriteCount * sizeof(T));
563 }
564
565 if (secondWriteCount != 0) {
Devin Moore77d279e2020-07-07 10:38:52 -0700566 memcpy(secondBaseAddress, data + firstWriteCount, secondWriteCount * sizeof(T));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800567 }
568
569 return true;
570}
571
Devin Moore133cb5e2020-07-07 16:31:22 -0700572template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700573void MessageQueueBase<MQDescriptorType, T, flavor>::initMemory(bool resetPointers) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800574 /*
Devin Moore9a27da52020-07-06 14:01:21 -0700575 * Verify that the Descriptor contains the minimum number of grantors
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800576 * the native_handle is valid and T matches quantum size.
577 */
578 if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
Devin Mooreb00fb7d2020-08-05 14:09:05 -0700579 (mDesc->countGrantors() < hardware::details::kMinGrantorCount)) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800580 return;
581 }
Devin Mooreb00fb7d2020-08-05 14:09:05 -0700582 if (mDesc->getQuantum() != sizeof(T)) {
583 hardware::details::logError(
584 "Payload size differs between the queue instantiation and the "
585 "MQDescriptor.");
586 return;
587 }
588
Devin Moore133cb5e2020-07-07 16:31:22 -0700589 if (flavor == kSynchronizedReadWrite) {
590 mReadPtr = reinterpret_cast<std::atomic<uint64_t>*>(
591 mapGrantorDescr(hardware::details::READPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800592 } else {
593 /*
594 * The unsynchronized write flavor of the FMQ may have multiple readers
595 * and each reader would have their own read pointer counter.
596 */
597 mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
598 }
Devin Moore98f3a082022-09-22 23:58:46 +0000599 if (mReadPtr == nullptr) goto error;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800600
Devin Moore133cb5e2020-07-07 16:31:22 -0700601 mWritePtr = reinterpret_cast<std::atomic<uint64_t>*>(
602 mapGrantorDescr(hardware::details::WRITEPTRPOS));
Devin Moore98f3a082022-09-22 23:58:46 +0000603 if (mWritePtr == nullptr) goto error;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800604
605 if (resetPointers) {
606 mReadPtr->store(0, std::memory_order_release);
607 mWritePtr->store(0, std::memory_order_release);
Devin Moore133cb5e2020-07-07 16:31:22 -0700608 } else if (flavor != kSynchronizedReadWrite) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800609 // Always reset the read pointer.
610 mReadPtr->store(0, std::memory_order_release);
611 }
612
Devin Moore133cb5e2020-07-07 16:31:22 -0700613 mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(hardware::details::DATAPTRPOS));
Devin Moore98f3a082022-09-22 23:58:46 +0000614 if (mRing == nullptr) goto error;
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800615
Mikhail Naganov9017c2e2021-03-29 14:56:12 -0700616 if (mDesc->countGrantors() > hardware::details::EVFLAGWORDPOS) {
617 mEvFlagWord = static_cast<std::atomic<uint32_t>*>(
618 mapGrantorDescr(hardware::details::EVFLAGWORDPOS));
Devin Moore98f3a082022-09-22 23:58:46 +0000619 if (mEvFlagWord == nullptr) goto error;
Devin Moore19bde112021-07-21 17:14:01 +0000620 android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800621 }
Devin Moore98f3a082022-09-22 23:58:46 +0000622 return;
623error:
624 if (mReadPtr) {
625 if (flavor == kSynchronizedReadWrite) {
626 unmapGrantorDescr(mReadPtr, hardware::details::READPTRPOS);
627 } else {
628 delete mReadPtr;
629 }
630 mReadPtr = nullptr;
631 }
632 if (mWritePtr) {
633 unmapGrantorDescr(mWritePtr, hardware::details::WRITEPTRPOS);
634 mWritePtr = nullptr;
635 }
636 if (mRing) {
637 unmapGrantorDescr(mRing, hardware::details::EVFLAGWORDPOS);
638 mRing = nullptr;
639 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800640}
641
Devin Moore133cb5e2020-07-07 16:31:22 -0700642template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700643MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(const Descriptor& Desc,
644 bool resetPointers) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800645 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800646 if (mDesc == nullptr) {
647 return;
648 }
649
650 initMemory(resetPointers);
651}
652
Devin Moore133cb5e2020-07-07 16:31:22 -0700653template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700654MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(size_t numElementsInQueue,
Gareth Fenn1af25462020-11-11 20:46:32 +0000655 bool configureEventFlagWord,
Devin Moored7e702b2021-01-18 16:10:37 -0800656 android::base::unique_fd bufferFd,
657 size_t bufferSize) {
Kevin Rocard1d6e40f2017-04-03 11:51:13 -0700658 // Check if the buffer size would not overflow size_t
659 if (numElementsInQueue > SIZE_MAX / sizeof(T)) {
Devin Moored7e702b2021-01-18 16:10:37 -0800660 hardware::details::logError("Requested message queue size too large. Size of elements: " +
661 std::to_string(sizeof(T)) +
662 ". Number of elements: " + std::to_string(numElementsInQueue));
663 return;
664 }
665 if (bufferFd != -1 && numElementsInQueue * sizeof(T) > bufferSize) {
666 hardware::details::logError("The supplied buffer size(" + std::to_string(bufferSize) +
667 ") is smaller than the required size(" +
668 std::to_string(numElementsInQueue * sizeof(T)) + ").");
Kevin Rocard1d6e40f2017-04-03 11:51:13 -0700669 return;
670 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800671 /*
672 * The FMQ needs to allocate memory for the ringbuffer as well as for the
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800673 * read and write pointer counters. If an EventFlag word is to be configured,
674 * we also need to allocate memory for the same/
675 */
676 size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
Devin Moore133cb5e2020-07-07 16:31:22 -0700677 size_t kMetaDataSize = 2 * sizeof(android::hardware::details::RingBufferPosition);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800678
679 if (configureEventFlagWord) {
Devin Moore77d279e2020-07-07 10:38:52 -0700680 kMetaDataSize += sizeof(std::atomic<uint32_t>);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800681 }
682
683 /*
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800684 * Ashmem memory region size needs to be specified in page-aligned bytes.
685 * kQueueSizeBytes needs to be aligned to word boundary so that all offsets
686 * in the grantorDescriptor will be word aligned.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800687 */
Gareth Fenn1af25462020-11-11 20:46:32 +0000688 size_t kAshmemSizePageAligned;
689 if (bufferFd != -1) {
690 // Allocate read counter and write counter only. User-supplied memory will be used for the
691 // ringbuffer.
692 kAshmemSizePageAligned = (kMetaDataSize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
693 } else {
694 // Allocate ringbuffer, read counter and write counter.
695 kAshmemSizePageAligned = (hardware::details::alignToWordBoundary(kQueueSizeBytes) +
696 kMetaDataSize + PAGE_SIZE - 1) &
697 ~(PAGE_SIZE - 1);
698 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800699
700 /*
701 * The native handle will contain the fds to be mapped.
702 */
Gareth Fenn1af25462020-11-11 20:46:32 +0000703 int numFds = (bufferFd != -1) ? 2 : 1;
704 native_handle_t* mqHandle = native_handle_create(numFds, 0 /* numInts */);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800705 if (mqHandle == nullptr) {
706 return;
707 }
708
Gareth Fenn1af25462020-11-11 20:46:32 +0000709 /*
710 * Create an ashmem region to map the memory.
711 */
712 int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
713 ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800714 mqHandle->data[0] = ashmemFd;
Gareth Fenn1af25462020-11-11 20:46:32 +0000715
716 if (bufferFd != -1) {
717 // Use user-supplied file descriptor for fdIndex 1
Devin Moored7e702b2021-01-18 16:10:37 -0800718 mqHandle->data[1] = bufferFd.get();
719 // release ownership of fd. mqHandle owns it now.
720 if (bufferFd.release() < 0) {
721 hardware::details::logError("Error releasing supplied bufferFd");
722 }
Gareth Fenn1af25462020-11-11 20:46:32 +0000723
724 std::vector<android::hardware::GrantorDescriptor> grantors;
725 grantors.resize(configureEventFlagWord ? hardware::details::kMinGrantorCountForEvFlagSupport
726 : hardware::details::kMinGrantorCount);
727
728 size_t memSize[] = {
729 sizeof(hardware::details::RingBufferPosition), /* memory to be allocated for read
730 pointer counter */
731 sizeof(hardware::details::RingBufferPosition), /* memory to be allocated for write
732 pointer counter */
733 kQueueSizeBytes, /* memory to be allocated for data buffer */
734 sizeof(std::atomic<uint32_t>) /* memory to be allocated for EventFlag word */
735 };
736
737 for (size_t grantorPos = 0, offset = 0; grantorPos < grantors.size(); grantorPos++) {
738 uint32_t grantorFdIndex;
739 size_t grantorOffset;
740 if (grantorPos == hardware::details::DATAPTRPOS) {
741 grantorFdIndex = 1;
742 grantorOffset = 0;
743 } else {
744 grantorFdIndex = 0;
745 grantorOffset = offset;
746 offset += memSize[grantorPos];
747 }
748 grantors[grantorPos] = {
749 0 /* grantor flags */, grantorFdIndex,
750 static_cast<uint32_t>(hardware::details::alignToWordBoundary(grantorOffset)),
751 memSize[grantorPos]};
752 }
753
754 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow)
755 Descriptor(grantors, mqHandle, sizeof(T)));
756 } else {
757 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(
758 kQueueSizeBytes, mqHandle, sizeof(T), configureEventFlagWord));
759 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800760 if (mDesc == nullptr) {
Gareth Fenn1af25462020-11-11 20:46:32 +0000761 native_handle_close(mqHandle);
762 native_handle_delete(mqHandle);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800763 return;
764 }
765 initMemory(true);
766}
767
Devin Moore133cb5e2020-07-07 16:31:22 -0700768template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700769MessageQueueBase<MQDescriptorType, T, flavor>::~MessageQueueBase() {
Devin Moored7e702b2021-01-18 16:10:37 -0800770 if (flavor == kUnsynchronizedWrite && mReadPtr != nullptr) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800771 delete mReadPtr;
Devin Moored7e702b2021-01-18 16:10:37 -0800772 } else if (mReadPtr != nullptr) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700773 unmapGrantorDescr(mReadPtr, hardware::details::READPTRPOS);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800774 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800775 if (mWritePtr != nullptr) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700776 unmapGrantorDescr(mWritePtr, hardware::details::WRITEPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800777 }
778 if (mRing != nullptr) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700779 unmapGrantorDescr(mRing, hardware::details::DATAPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800780 }
781 if (mEvFlagWord != nullptr) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700782 unmapGrantorDescr(mEvFlagWord, hardware::details::EVFLAGWORDPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800783 android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
784 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800785}
786
Devin Moore133cb5e2020-07-07 16:31:22 -0700787template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700788bool MessageQueueBase<MQDescriptorType, T, flavor>::write(const T* data) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800789 return write(data, 1);
790}
791
Devin Moore133cb5e2020-07-07 16:31:22 -0700792template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700793bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800794 return read(data, 1);
795}
796
Devin Moore133cb5e2020-07-07 16:31:22 -0700797template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700798bool MessageQueueBase<MQDescriptorType, T, flavor>::write(const T* data, size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800799 MemTransaction tx;
Devin Moore77d279e2020-07-07 10:38:52 -0700800 return beginWrite(nMessages, &tx) && tx.copyTo(data, 0 /* startIdx */, nMessages) &&
801 commitWrite(nMessages);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800802}
803
Devin Moore133cb5e2020-07-07 16:31:22 -0700804template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700805bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(
806 const T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
807 int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700808 static_assert(flavor == kSynchronizedReadWrite,
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700809 "writeBlocking can only be used with the "
Devin Moore133cb5e2020-07-07 16:31:22 -0700810 "kSynchronizedReadWrite flavor.");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800811 /*
812 * If evFlag is null and the FMQ does not have its own EventFlag object
813 * return false;
Devin Moore133cb5e2020-07-07 16:31:22 -0700814 * If the flavor is kSynchronizedReadWrite and the readNotification
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800815 * bit mask is zero return false;
816 * If the count is greater than queue size, return false
817 * to prevent blocking until timeOut.
818 */
819 if (evFlag == nullptr) {
820 evFlag = mEventFlag;
821 if (evFlag == nullptr) {
Devin Moore9a27da52020-07-06 14:01:21 -0700822 hardware::details::logError(
Devin Moore77d279e2020-07-07 10:38:52 -0700823 "writeBlocking failed: called on MessageQueue with no Eventflag"
824 "configured or provided");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800825 return false;
826 }
827 }
828
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700829 if (readNotification == 0 || (count > getQuantumCount())) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800830 return false;
831 }
832
833 /*
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700834 * There is no need to wait for a readNotification if there is sufficient
835 * space to write is already present in the FMQ. The latter would be the case when
836 * read operations read more number of messages than write operations write.
837 * In other words, a single large read may clear the FMQ after multiple small
838 * writes. This would fail to clear a pending readNotification bit since
839 * EventFlag bits can only be cleared by a wait() call, however the bit would
840 * be correctly cleared by the next writeBlocking() call.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800841 */
842
843 bool result = write(data, count);
844 if (result) {
845 if (writeNotification) {
846 evFlag->wake(writeNotification);
847 }
848 return result;
849 }
850
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800851 bool shouldTimeOut = timeOutNanos != 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700852 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800853
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700854 while (true) {
855 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800856 if (shouldTimeOut) {
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700857 /*
858 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
859 * to Nanoseconds)
860 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800861 int64_t currentTimeNs = android::elapsedRealtimeNano();
862 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700863 * Decrement 'timeOutNanos' to account for the time taken to complete the last
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800864 * iteration of the while loop.
865 */
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700866 timeOutNanos -= currentTimeNs - prevTimeNanos;
867 prevTimeNanos = currentTimeNs;
868
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800869 if (timeOutNanos <= 0) {
870 /*
871 * Attempt write in case a context switch happened outside of
872 * evFlag->wait().
873 */
874 result = write(data, count);
875 break;
876 }
877 }
878
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800879 /*
880 * wait() will return immediately if there was a pending read
881 * notification.
882 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800883 uint32_t efState = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700884 status_t status = evFlag->wait(readNotification, &efState, timeOutNanos,
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700885 true /* retry on spurious wake */);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800886
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700887 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
Devin Moore9a27da52020-07-06 14:01:21 -0700888 hardware::details::logError("Unexpected error code from EventFlag Wait status " +
889 std::to_string(status));
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700890 break;
891 }
892
893 if (status == android::TIMED_OUT) {
894 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800895 }
896
897 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700898 * If there is still insufficient space to write to the FMQ,
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800899 * keep waiting for another readNotification.
900 */
901 if ((efState & readNotification) && write(data, count)) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800902 result = true;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700903 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800904 }
905 }
906
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800907 if (result && writeNotification != 0) {
908 evFlag->wake(writeNotification);
909 }
910
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800911 return result;
912}
913
Devin Moore133cb5e2020-07-07 16:31:22 -0700914template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700915bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(const T* data, size_t count,
916 int64_t timeOutNanos) {
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800917 return writeBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
918}
919
Devin Moore133cb5e2020-07-07 16:31:22 -0700920template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -0700921bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(
922 T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
923 int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
Devin Moore133cb5e2020-07-07 16:31:22 -0700924 static_assert(flavor == kSynchronizedReadWrite,
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700925 "readBlocking can only be used with the "
Devin Moore133cb5e2020-07-07 16:31:22 -0700926 "kSynchronizedReadWrite flavor.");
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700927
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800928 /*
929 * If evFlag is null and the FMQ does not own its own EventFlag object
930 * return false;
931 * If the writeNotification bit mask is zero return false;
932 * If the count is greater than queue size, return false to prevent
933 * blocking until timeOut.
934 */
935 if (evFlag == nullptr) {
936 evFlag = mEventFlag;
937 if (evFlag == nullptr) {
Devin Moore9a27da52020-07-06 14:01:21 -0700938 hardware::details::logError(
Devin Moore77d279e2020-07-07 10:38:52 -0700939 "readBlocking failed: called on MessageQueue with no Eventflag"
940 "configured or provided");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800941 return false;
942 }
943 }
944
945 if (writeNotification == 0 || count > getQuantumCount()) {
946 return false;
947 }
948
949 /*
950 * There is no need to wait for a write notification if sufficient
951 * data to read is already present in the FMQ. This would be the
952 * case when read operations read lesser number of messages than
953 * a write operation and multiple reads would be required to clear the queue
954 * after a single write operation. This check would fail to clear a pending
955 * writeNotification bit since EventFlag bits can only be cleared
956 * by a wait() call, however the bit would be correctly cleared by the next
957 * readBlocking() call.
958 */
959
960 bool result = read(data, count);
961 if (result) {
962 if (readNotification) {
963 evFlag->wake(readNotification);
964 }
965 return result;
966 }
967
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800968 bool shouldTimeOut = timeOutNanos != 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700969 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800970
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700971 while (true) {
972 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800973 if (shouldTimeOut) {
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700974 /*
975 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
976 * to Nanoseconds)
977 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800978 int64_t currentTimeNs = android::elapsedRealtimeNano();
979 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700980 * Decrement 'timeOutNanos' to account for the time taken to complete the last
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800981 * iteration of the while loop.
982 */
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700983 timeOutNanos -= currentTimeNs - prevTimeNanos;
984 prevTimeNanos = currentTimeNs;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800985
986 if (timeOutNanos <= 0) {
987 /*
988 * Attempt read in case a context switch happened outside of
989 * evFlag->wait().
990 */
991 result = read(data, count);
992 break;
993 }
994 }
995
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800996 /*
997 * wait() will return immediately if there was a pending write
998 * notification.
999 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -08001000 uint32_t efState = 0;
Devin Moore77d279e2020-07-07 10:38:52 -07001001 status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos,
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -07001002 true /* retry on spurious wake */);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -08001003
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -07001004 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
Devin Moore9a27da52020-07-06 14:01:21 -07001005 hardware::details::logError("Unexpected error code from EventFlag Wait status " +
1006 std::to_string(status));
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -07001007 break;
1008 }
1009
1010 if (status == android::TIMED_OUT) {
1011 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -08001012 }
1013
1014 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -07001015 * If the data in FMQ is still insufficient, go back to waiting
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -08001016 * for another write notification.
1017 */
1018 if ((efState & writeNotification) && read(data, count)) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -08001019 result = true;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -07001020 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -08001021 }
1022 }
1023
Hridya Valsaraju2abefb62017-01-19 13:06:58 -08001024 if (result && readNotification != 0) {
1025 evFlag->wake(readNotification);
1026 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -08001027 return result;
1028}
1029
Devin Moore133cb5e2020-07-07 16:31:22 -07001030template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001031bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(T* data, size_t count,
1032 int64_t timeOutNanos) {
Hridya Valsaraju4486ad02017-01-13 20:49:39 -08001033 return readBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
1034}
1035
Devin Moore133cb5e2020-07-07 16:31:22 -07001036template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001037size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWriteBytes() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001038 return mDesc->getSize() - availableToReadBytes();
1039}
1040
Devin Moore133cb5e2020-07-07 16:31:22 -07001041template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001042size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWrite() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001043 return availableToWriteBytes() / sizeof(T);
1044}
1045
Devin Moore133cb5e2020-07-07 16:31:22 -07001046template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001047size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToRead() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001048 return availableToReadBytes() / sizeof(T);
1049}
1050
Devin Moore133cb5e2020-07-07 16:31:22 -07001051template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001052bool MessageQueueBase<MQDescriptorType, T, flavor>::beginWrite(size_t nMessages,
1053 MemTransaction* result) const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001054 /*
1055 * If nMessages is greater than size of FMQ or in case of the synchronized
1056 * FMQ flavor, if there is not enough space to write nMessages, then return
1057 * result with null addresses.
1058 */
Devin Moore133cb5e2020-07-07 16:31:22 -07001059 if ((flavor == kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001060 nMessages > getQuantumCount()) {
1061 *result = MemTransaction();
1062 return false;
1063 }
1064
1065 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
Devin Moorea8b62612021-04-09 09:10:28 -07001066 if (writePtr % sizeof(T) != 0) {
1067 hardware::details::logError(
1068 "The write pointer has become misaligned. Writing to the queue is no longer "
1069 "possible.");
Devin Moore2741a812021-04-29 16:22:51 -07001070 hardware::details::errorWriteLog(0x534e4554, "184963385");
Devin Moorea8b62612021-04-09 09:10:28 -07001071 return false;
1072 }
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001073 size_t writeOffset = writePtr % mDesc->getSize();
1074
1075 /*
1076 * From writeOffset, the number of messages that can be written
1077 * contiguously without wrapping around the ring buffer are calculated.
1078 */
1079 size_t contiguousMessages = (mDesc->getSize() - writeOffset) / sizeof(T);
1080
1081 if (contiguousMessages < nMessages) {
1082 /*
1083 * Wrap around is required. Both result.first and result.second are
1084 * populated.
1085 */
Devin Moore77d279e2020-07-07 10:38:52 -07001086 *result = MemTransaction(
1087 MemRegion(reinterpret_cast<T*>(mRing + writeOffset), contiguousMessages),
1088 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001089 } else {
1090 /*
1091 * A wrap around is not required to write nMessages. Only result.first
1092 * is populated.
1093 */
1094 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset), nMessages),
1095 MemRegion());
1096 }
1097
1098 return true;
1099}
1100
Devin Moore133cb5e2020-07-07 16:31:22 -07001101template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001102/*
1103 * Disable integer sanitization since integer overflow here is allowed
1104 * and legal.
1105 */
Devin Moore9a27da52020-07-06 14:01:21 -07001106__attribute__((no_sanitize("integer"))) bool
1107MessageQueueBase<MQDescriptorType, T, flavor>::commitWrite(size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001108 size_t nBytesWritten = nMessages * sizeof(T);
1109 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
1110 writePtr += nBytesWritten;
1111 mWritePtr->store(writePtr, std::memory_order_release);
1112 /*
1113 * This method cannot fail now since we are only incrementing the writePtr
1114 * counter.
1115 */
1116 return true;
1117}
1118
Devin Moore133cb5e2020-07-07 16:31:22 -07001119template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001120size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToReadBytes() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001121 /*
1122 * This method is invoked by implementations of both read() and write() and
Devin Moore9a27da52020-07-06 14:01:21 -07001123 * hence requires a memory_order_acquired load for both mReadPtr and
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001124 * mWritePtr.
1125 */
Devin Moore77d279e2020-07-07 10:38:52 -07001126 return mWritePtr->load(std::memory_order_acquire) - mReadPtr->load(std::memory_order_acquire);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001127}
1128
Devin Moore133cb5e2020-07-07 16:31:22 -07001129template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001130bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data, size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001131 MemTransaction tx;
Devin Moore77d279e2020-07-07 10:38:52 -07001132 return beginRead(nMessages, &tx) && tx.copyFrom(data, 0 /* startIdx */, nMessages) &&
1133 commitRead(nMessages);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001134}
1135
Devin Moore133cb5e2020-07-07 16:31:22 -07001136template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001137/*
1138 * Disable integer sanitization since integer overflow here is allowed
1139 * and legal.
1140 */
Devin Moore9a27da52020-07-06 14:01:21 -07001141__attribute__((no_sanitize("integer"))) bool
1142MessageQueueBase<MQDescriptorType, T, flavor>::beginRead(size_t nMessages,
1143 MemTransaction* result) const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001144 *result = MemTransaction();
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001145 /*
1146 * If it is detected that the data in the queue was overwritten
1147 * due to the reader process being too slow, the read pointer counter
1148 * is set to the same as the write pointer counter to indicate error
1149 * and the read returns false;
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001150 * Need acquire/release memory ordering for mWritePtr.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001151 */
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001152 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1153 /*
1154 * A relaxed load is sufficient for mReadPtr since there will be no
1155 * stores to mReadPtr from a different thread.
1156 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001157 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
Devin Moorea8b62612021-04-09 09:10:28 -07001158 if (writePtr % sizeof(T) != 0 || readPtr % sizeof(T) != 0) {
1159 hardware::details::logError(
1160 "The write or read pointer has become misaligned. Reading from the queue is no "
1161 "longer possible.");
Devin Moore2741a812021-04-29 16:22:51 -07001162 hardware::details::errorWriteLog(0x534e4554, "184963385");
Devin Moorea8b62612021-04-09 09:10:28 -07001163 return false;
1164 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001165
1166 if (writePtr - readPtr > mDesc->getSize()) {
1167 mReadPtr->store(writePtr, std::memory_order_release);
1168 return false;
1169 }
1170
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001171 size_t nBytesDesired = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001172 /*
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001173 * Return if insufficient data to read in FMQ.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001174 */
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001175 if (writePtr - readPtr < nBytesDesired) {
1176 return false;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001177 }
1178
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001179 size_t readOffset = readPtr % mDesc->getSize();
1180 /*
1181 * From readOffset, the number of messages that can be read contiguously
1182 * without wrapping around the ring buffer are calculated.
1183 */
1184 size_t contiguousMessages = (mDesc->getSize() - readOffset) / sizeof(T);
1185
1186 if (contiguousMessages < nMessages) {
1187 /*
1188 * A wrap around is required. Both result.first and result.second
1189 * are populated.
1190 */
Devin Moore77d279e2020-07-07 10:38:52 -07001191 *result = MemTransaction(
1192 MemRegion(reinterpret_cast<T*>(mRing + readOffset), contiguousMessages),
1193 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001194 } else {
1195 /*
1196 * A wrap around is not required. Only result.first need to be
1197 * populated.
1198 */
1199 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset), nMessages),
1200 MemRegion());
1201 }
1202
1203 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001204}
1205
Devin Moore133cb5e2020-07-07 16:31:22 -07001206template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001207/*
1208 * Disable integer sanitization since integer overflow here is allowed
1209 * and legal.
1210 */
Devin Moore9a27da52020-07-06 14:01:21 -07001211__attribute__((no_sanitize("integer"))) bool
1212MessageQueueBase<MQDescriptorType, T, flavor>::commitRead(size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001213 // TODO: Use a local copy of readPtr to avoid relazed mReadPtr loads.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001214 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001215 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1216 /*
1217 * If the flavor is unsynchronized, it is possible that a write overflow may
Devin Moore9a27da52020-07-06 14:01:21 -07001218 * have occurred between beginRead() and commitRead().
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001219 */
1220 if (writePtr - readPtr > mDesc->getSize()) {
1221 mReadPtr->store(writePtr, std::memory_order_release);
1222 return false;
1223 }
1224
1225 size_t nBytesRead = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001226 readPtr += nBytesRead;
1227 mReadPtr->store(readPtr, std::memory_order_release);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001228 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001229}
1230
Devin Moore133cb5e2020-07-07 16:31:22 -07001231template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001232size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumSize() const {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001233 return mDesc->getQuantum();
1234}
1235
Devin Moore133cb5e2020-07-07 16:31:22 -07001236template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001237size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumCount() const {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001238 return mDesc->getSize() / mDesc->getQuantum();
1239}
1240
Devin Moore133cb5e2020-07-07 16:31:22 -07001241template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001242bool MessageQueueBase<MQDescriptorType, T, flavor>::isValid() const {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001243 return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
1244}
1245
Devin Moore133cb5e2020-07-07 16:31:22 -07001246template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001247void* MessageQueueBase<MQDescriptorType, T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001248 const native_handle_t* handle = mDesc->handle();
Devin Moore98f3a082022-09-22 23:58:46 +00001249 const std::vector<android::hardware::GrantorDescriptor> grantors = mDesc->grantors();
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001250 if (handle == nullptr) {
Devin Moore9a27da52020-07-06 14:01:21 -07001251 hardware::details::logError("mDesc->handle is null");
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001252 return nullptr;
1253 }
1254
1255 if (grantorIdx >= grantors.size()) {
Devin Moore9a27da52020-07-06 14:01:21 -07001256 hardware::details::logError(std::string("grantorIdx must be less than ") +
1257 std::to_string(grantors.size()));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001258 return nullptr;
1259 }
1260
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001261 int fdIndex = grantors[grantorIdx].fdIndex;
Devin Moore98f3a082022-09-22 23:58:46 +00001262 if (fdIndex < 0 || fdIndex >= handle->numFds) {
1263 hardware::details::logError(
1264 std::string("fdIndex (" + std::to_string(fdIndex) + ") from grantor (index " +
1265 std::to_string(grantorIdx) +
1266 ") must be smaller than the number of fds in the handle: " +
1267 std::to_string(handle->numFds)));
1268 return nullptr;
1269 }
1270
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001271 /*
1272 * Offset for mmap must be a multiple of PAGE_SIZE.
1273 */
Devin Moore98f3a082022-09-22 23:58:46 +00001274 if (!hardware::details::isAlignedToWordBoundary(grantors[grantorIdx].offset)) {
1275 hardware::details::logError("Grantor (index " + std::to_string(grantorIdx) +
1276 ") offset needs to be aligned to word boundary but is: " +
1277 std::to_string(grantors[grantorIdx].offset));
1278 return nullptr;
1279 }
1280
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001281 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
Devin Moore98f3a082022-09-22 23:58:46 +00001282 if (grantors[grantorIdx].extent < 0 || grantors[grantorIdx].extent > INT_MAX - PAGE_SIZE) {
1283 hardware::details::logError(std::string("Grantor (index " + std::to_string(grantorIdx) +
1284 ") extent value is too large or negative: " +
1285 std::to_string(grantors[grantorIdx].extent)));
1286 return nullptr;
1287 }
Devin Moore77d279e2020-07-07 10:38:52 -07001288 int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001289
Devin Moore77d279e2020-07-07 10:38:52 -07001290 void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED, handle->data[fdIndex],
1291 mapOffset);
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001292 if (address == MAP_FAILED) {
Devin Moore9a27da52020-07-06 14:01:21 -07001293 hardware::details::logError(std::string("mmap failed: ") + std::to_string(errno));
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001294 return nullptr;
1295 }
1296 return reinterpret_cast<uint8_t*>(address) + (grantors[grantorIdx].offset - mapOffset);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001297}
1298
Devin Moore133cb5e2020-07-07 16:31:22 -07001299template <template <typename, MQFlavor> typename MQDescriptorType, typename T, MQFlavor flavor>
Devin Moore9a27da52020-07-06 14:01:21 -07001300void MessageQueueBase<MQDescriptorType, T, flavor>::unmapGrantorDescr(void* address,
1301 uint32_t grantorIdx) {
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001302 auto grantors = mDesc->grantors();
1303 if ((address == nullptr) || (grantorIdx >= grantors.size())) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001304 return;
1305 }
1306
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001307 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
Devin Moore77d279e2020-07-07 10:38:52 -07001308 int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
1309 void* baseAddress =
1310 reinterpret_cast<uint8_t*>(address) - (grantors[grantorIdx].offset - mapOffset);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001311 if (baseAddress) munmap(baseAddress, mapLength);
1312}
1313
1314} // namespace hardware