blob: cdd7202e333472209396bcb4cd0bcec452fd26fd [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
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080019#include <cutils/ashmem.h>
20#include <fmq/EventFlag.h>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080021#include <sys/mman.h>
22#include <utils/Log.h>
Hridya Valsaraju2abefb62017-01-19 13:06:58 -080023#include <utils/SystemClock.h>
Devin Moore77d279e2020-07-07 10:38:52 -070024#include <atomic>
25#include <new>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080026
27namespace android {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080028
Devin Moore9a27da52020-07-06 14:01:21 -070029namespace hardware {
Yifan Hongdc5bd672017-04-11 17:11:57 -070030namespace details {
31void check(bool exp);
Devin Moore77d279e2020-07-07 10:38:52 -070032void logError(const std::string& message);
Yifan Hongdc5bd672017-04-11 17:11:57 -070033} // namespace details
Devin Moore9a27da52020-07-06 14:01:21 -070034} // namespace hardware
Yifan Hongdc5bd672017-04-11 17:11:57 -070035
Devin Moore9a27da52020-07-06 14:01:21 -070036template <template <typename, hardware::MQFlavor> class MQDescriptorType, typename T,
37 hardware::MQFlavor flavor>
38struct MessageQueueBase {
39 typedef MQDescriptorType<T, flavor> Descriptor;
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -080040
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080041 /**
42 * @param Desc MQDescriptor describing the FMQ.
43 * @param resetPointers bool indicating whether the read/write pointers
44 * should be reset or not.
45 */
Devin Moore9a27da52020-07-06 14:01:21 -070046 MessageQueueBase(const Descriptor& Desc, bool resetPointers = true);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080047
Devin Moore9a27da52020-07-06 14:01:21 -070048 ~MessageQueueBase();
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080049
50 /**
51 * This constructor uses Ashmem shared memory to create an FMQ
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080052 * that can contain a maximum of 'numElementsInQueue' elements of type T.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080053 *
54 * @param numElementsInQueue Capacity of the MessageQueue in terms of T.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -080055 * @param configureEventFlagWord Boolean that specifies if memory should
56 * also be allocated and mapped for an EventFlag word.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080057 */
Devin Moore9a27da52020-07-06 14:01:21 -070058
59 MessageQueueBase(size_t numElementsInQueue, bool configureEventFlagWord = false);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080060
61 /**
62 * @return Number of items of type T that can be written into the FMQ
63 * without a read.
64 */
65 size_t availableToWrite() const;
66
67 /**
68 * @return Number of items of type T that are waiting to be read from the
69 * FMQ.
70 */
71 size_t availableToRead() const;
72
73 /**
74 * Returns the size of type T in bytes.
75 *
76 * @param Size of T.
77 */
78 size_t getQuantumSize() const;
79
80 /**
81 * Returns the size of the FMQ in terms of the size of type T.
82 *
83 * @return Number of items of type T that will fit in the FMQ.
84 */
85 size_t getQuantumCount() const;
86
87 /**
88 * @return Whether the FMQ is configured correctly.
89 */
90 bool isValid() const;
91
92 /**
93 * Non-blocking write to FMQ.
94 *
95 * @param data Pointer to the object of type T to be written into the FMQ.
96 *
97 * @return Whether the write was successful.
98 */
99 bool write(const T* data);
100
101 /**
102 * Non-blocking read from FMQ.
103 *
104 * @param data Pointer to the memory where the object read from the FMQ is
105 * copied to.
106 *
107 * @return Whether the read was successful.
108 */
109 bool read(T* data);
110
111 /**
112 * Write some data into the FMQ without blocking.
113 *
114 * @param data Pointer to the array of items of type T.
115 * @param count Number of items in array.
116 *
117 * @return Whether the write was successful.
118 */
119 bool write(const T* data, size_t count);
120
121 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800122 * Perform a blocking write of 'count' items into the FMQ using EventFlags.
123 * Does not support partial writes.
124 *
125 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
126 * associated with the FMQ and it is used in that case.
127 *
128 * The application code must ensure that 'evFlag' used by the
129 * reader(s)/writer is based upon the same EventFlag word.
130 *
131 * The method will return false without blocking if any of the following
132 * conditions are true:
133 * - If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700134 * - If the 'readNotification' bit mask is zero.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800135 * - If 'count' is greater than the FMQ size.
136 *
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700137 * If the there is insufficient space available to write into it, the
138 * EventFlag bit mask 'readNotification' is is waited upon.
139 *
140 * This method should only be used with a MessageQueue of the flavor
Devin Moore9a27da52020-07-06 14:01:21 -0700141 * 'hardware::kSynchronizedReadWrite'.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800142 *
143 * Upon a successful write, wake is called on 'writeNotification' (if
144 * non-zero).
145 *
146 * @param data Pointer to the array of items of type T.
147 * @param count Number of items in array.
148 * @param readNotification The EventFlag bit mask to wait on if there is not
149 * enough space in FMQ to write 'count' items.
150 * @param writeNotification The EventFlag bit mask to call wake on
151 * a successful write. No wake is called if 'writeNotification' is zero.
152 * @param timeOutNanos Number of nanoseconds after which the blocking
153 * write attempt is aborted.
154 * @param evFlag The EventFlag object to be used for blocking. If nullptr,
155 * it is checked whether the FMQ owns an EventFlag object and that is used
156 * for blocking instead.
157 *
158 * @return Whether the write was successful.
159 */
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800160 bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
161 uint32_t writeNotification, int64_t timeOutNanos = 0,
162 android::hardware::EventFlag* evFlag = nullptr);
163
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800164 bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
165
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800166 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800167 * Read some data from the FMQ without blocking.
168 *
169 * @param data Pointer to the array to which read data is to be written.
170 * @param count Number of items to be read.
171 *
172 * @return Whether the read was successful.
173 */
174 bool read(T* data, size_t count);
175
176 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800177 * Perform a blocking read operation of 'count' items from the FMQ. Does not
178 * perform a partial read.
179 *
180 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
181 * associated with the FMQ and it is used in that case.
182 *
183 * The application code must ensure that 'evFlag' used by the
184 * reader(s)/writer is based upon the same EventFlag word.
185 *
186 * The method will return false without blocking if any of the following
187 * conditions are true:
188 * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
189 * -If the 'writeNotification' bit mask is zero.
190 * -If 'count' is greater than the FMQ size.
191 *
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700192 * This method should only be used with a MessageQueue of the flavor
Devin Moore9a27da52020-07-06 14:01:21 -0700193 * 'hardware::kSynchronizedReadWrite'.
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700194
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800195 * If FMQ does not contain 'count' items, the eventFlag bit mask
196 * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
197 * wake is called on 'readNotification' (if non-zero).
198 *
199 * @param data Pointer to the array to which read data is to be written.
200 * @param count Number of items to be read.
201 * @param readNotification The EventFlag bit mask to call wake on after
202 * a successful read. No wake is called if 'readNotification' is zero.
203 * @param writeNotification The EventFlag bit mask to call a wait on
204 * if there is insufficient data in the FMQ to be read.
205 * @param timeOutNanos Number of nanoseconds after which the blocking
206 * read attempt is aborted.
207 * @param evFlag The EventFlag object to be used for blocking.
208 *
209 * @return Whether the read was successful.
210 */
Devin Moore77d279e2020-07-07 10:38:52 -0700211 bool readBlocking(T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
212 int64_t timeOutNanos = 0, android::hardware::EventFlag* evFlag = nullptr);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800213
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800214 bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);
215
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800216 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800217 * Get a pointer to the MQDescriptor object that describes this FMQ.
218 *
219 * @return Pointer to the MQDescriptor associated with the FMQ.
220 */
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800221 const Descriptor* getDesc() const { return mDesc.get(); }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800222
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800223 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800224 * Get a pointer to the EventFlag word if there is one associated with this FMQ.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800225 *
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800226 * @return Pointer to an EventFlag word, will return nullptr if not
227 * configured. This method does not transfer ownership. The EventFlag
228 * word will be unmapped by the MessageQueue destructor.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800229 */
230 std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800231
232 /**
233 * Describes a memory region in the FMQ.
234 */
235 struct MemRegion {
236 MemRegion() : MemRegion(nullptr, 0) {}
237
238 MemRegion(T* base, size_t size) : address(base), length(size) {}
239
Devin Moore77d279e2020-07-07 10:38:52 -0700240 MemRegion& operator=(const MemRegion& other) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800241 address = other.address;
242 length = other.length;
243 return *this;
244 }
245
246 /**
247 * Gets a pointer to the base address of the MemRegion.
248 */
249 inline T* getAddress() const { return address; }
250
251 /**
252 * Gets the length of the MemRegion. This would equal to the number
253 * of items of type T that can be read from/written into the MemRegion.
254 */
255 inline size_t getLength() const { return length; }
256
257 /**
258 * Gets the length of the MemRegion in bytes.
259 */
260 inline size_t getLengthInBytes() const { return length * sizeof(T); }
261
Devin Moore77d279e2020-07-07 10:38:52 -0700262 private:
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800263 /* Base address */
264 T* address;
265
266 /*
267 * Number of items of type T that can be written to/read from the base
268 * address.
269 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800270 size_t length;
271 };
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800272
273 /**
274 * Describes the memory regions to be used for a read or write.
275 * The struct contains two MemRegion objects since the FMQ is a ring
276 * buffer and a read or write operation can wrap around. A single message
277 * of type T will never be broken between the two MemRegions.
278 */
279 struct MemTransaction {
280 MemTransaction() : MemTransaction(MemRegion(), MemRegion()) {}
281
Devin Moore77d279e2020-07-07 10:38:52 -0700282 MemTransaction(const MemRegion& regionFirst, const MemRegion& regionSecond)
283 : first(regionFirst), second(regionSecond) {}
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800284
Devin Moore77d279e2020-07-07 10:38:52 -0700285 MemTransaction& operator=(const MemTransaction& other) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800286 first = other.first;
287 second = other.second;
288 return *this;
289 }
290
291 /**
292 * Helper method to calculate the address for a particular index for
293 * the MemTransaction object.
294 *
295 * @param idx Index of the slot to be read/written. If the
296 * MemTransaction object is representing the memory region to read/write
297 * N items of type T, the valid range of idx is between 0 and N-1.
298 *
299 * @return Pointer to the slot idx. Will be nullptr for an invalid idx.
300 */
301 T* getSlot(size_t idx);
302
303 /**
304 * Helper method to write 'nMessages' items of type T into the memory
305 * regions described by the object starting from 'startIdx'. This method
306 * uses memcpy() and is not to meant to be used for a zero copy operation.
307 * Partial writes are not supported.
308 *
309 * @param data Pointer to the source buffer.
310 * @param nMessages Number of items of type T.
311 * @param startIdx The slot number to begin the write from. If the
312 * MemTransaction object is representing the memory region to read/write
313 * N items of type T, the valid range of startIdx is between 0 and N-1;
314 *
315 * @return Whether the write operation of size 'nMessages' succeeded.
316 */
317 bool copyTo(const T* data, size_t startIdx, size_t nMessages = 1);
318
319 /*
320 * Helper method to read 'nMessages' items of type T from the memory
321 * regions described by the object starting from 'startIdx'. This method uses
322 * memcpy() and is not meant to be used for a zero copy operation. Partial reads
323 * are not supported.
324 *
325 * @param data Pointer to the destination buffer.
326 * @param nMessages Number of items of type T.
327 * @param startIdx The slot number to begin the read from. If the
328 * MemTransaction object is representing the memory region to read/write
329 * N items of type T, the valid range of startIdx is between 0 and N-1.
330 *
331 * @return Whether the read operation of size 'nMessages' succeeded.
332 */
333 bool copyFrom(T* data, size_t startIdx, size_t nMessages = 1);
334
335 /**
336 * Returns a const reference to the first MemRegion in the
337 * MemTransaction object.
338 */
339 inline const MemRegion& getFirstRegion() const { return first; }
340
341 /**
342 * Returns a const reference to the second MemRegion in the
343 * MemTransaction object.
344 */
345 inline const MemRegion& getSecondRegion() const { return second; }
346
Devin Moore77d279e2020-07-07 10:38:52 -0700347 private:
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800348 /*
349 * Given a start index and the number of messages to be
350 * read/written, this helper method calculates the
351 * number of messages that should should be written to both the first
352 * and second MemRegions and the base addresses to be used for
353 * the read/write operation.
354 *
355 * Returns false if the 'startIdx' and 'nMessages' is
356 * invalid for the MemTransaction object.
357 */
Devin Moore77d279e2020-07-07 10:38:52 -0700358 bool inline getMemRegionInfo(size_t idx, size_t nMessages, size_t& firstCount,
359 size_t& secondCount, T** firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800360 T** secondBaseAddress);
361 MemRegion first;
362 MemRegion second;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800363 };
364
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800365 /**
366 * Get a MemTransaction object to write 'nMessages' items of type T.
367 * Once the write is performed using the information from MemTransaction,
368 * the write operation is to be committed using a call to commitWrite().
369 *
370 * @param nMessages Number of messages of type T.
371 * @param Pointer to MemTransaction struct that describes memory to write 'nMessages'
372 * items of type T. If a write of size 'nMessages' is not possible, the base
373 * addresses in the MemTransaction object would be set to nullptr.
374 *
375 * @return Whether it is possible to write 'nMessages' items of type T
376 * into the FMQ.
377 */
378 bool beginWrite(size_t nMessages, MemTransaction* memTx) const;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800379
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800380 /**
381 * Commit a write of size 'nMessages'. To be only used after a call to beginWrite().
382 *
383 * @param nMessages number of messages of type T to be written.
384 *
385 * @return Whether the write operation of size 'nMessages' succeeded.
386 */
387 bool commitWrite(size_t nMessages);
388
389 /**
390 * Get a MemTransaction object to read 'nMessages' items of type T.
391 * Once the read is performed using the information from MemTransaction,
392 * the read operation is to be committed using a call to commitRead().
393 *
394 * @param nMessages Number of messages of type T.
395 * @param pointer to MemTransaction struct that describes memory to read 'nMessages'
396 * items of type T. If a read of size 'nMessages' is not possible, the base
397 * pointers in the MemTransaction object returned will be set to nullptr.
398 *
399 * @return bool Whether it is possible to read 'nMessages' items of type T
400 * from the FMQ.
401 */
402 bool beginRead(size_t nMessages, MemTransaction* memTx) const;
403
404 /**
405 * Commit a read of size 'nMessages'. To be only used after a call to beginRead().
406 * For the unsynchronized flavor of FMQ, this method will return a failure
407 * if a write overflow happened after beginRead() was invoked.
408 *
409 * @param nMessages number of messages of type T to be read.
410 *
411 * @return bool Whether the read operation of size 'nMessages' succeeded.
412 */
413 bool commitRead(size_t nMessages);
414
Devin Moore77d279e2020-07-07 10:38:52 -0700415 private:
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800416 size_t availableToWriteBytes() const;
417 size_t availableToReadBytes() const;
418
Devin Moore9a27da52020-07-06 14:01:21 -0700419 MessageQueueBase(const MessageQueueBase& other) = delete;
420 MessageQueueBase& operator=(const MessageQueueBase& other) = delete;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800421
422 void* mapGrantorDescr(uint32_t grantorIdx);
423 void unmapGrantorDescr(void* address, uint32_t grantorIdx);
424 void initMemory(bool resetPointers);
425
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800426 enum DefaultEventNotification : uint32_t {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800427 /*
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700428 * These are only used internally by the readBlocking()/writeBlocking()
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800429 * methods and hence once other bit combinations are not required.
430 */
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700431 FMQ_NOT_FULL = 0x01,
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800432 FMQ_NOT_EMPTY = 0x02
433 };
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800434 std::unique_ptr<Descriptor> mDesc;
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800435 uint8_t* mRing = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800436 /*
437 * TODO(b/31550092): Change to 32 bit read and write pointer counters.
438 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800439 std::atomic<uint64_t>* mReadPtr = nullptr;
440 std::atomic<uint64_t>* mWritePtr = nullptr;
441
442 std::atomic<uint32_t>* mEvFlagWord = nullptr;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800443
444 /*
445 * This EventFlag object will be owned by the FMQ and will have the same
446 * lifetime.
447 */
448 android::hardware::EventFlag* mEventFlag = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800449};
450
Devin Moore9a27da52020-07-06 14:01:21 -0700451template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
452 hardware::MQFlavor flavor>
453T* MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getSlot(size_t idx) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800454 size_t firstRegionLength = first.getLength();
455 size_t secondRegionLength = second.getLength();
456
457 if (idx > firstRegionLength + secondRegionLength) {
458 return nullptr;
459 }
460
461 if (idx < firstRegionLength) {
462 return first.getAddress() + idx;
463 }
464
465 return second.getAddress() + idx - firstRegionLength;
466}
467
Devin Moore9a27da52020-07-06 14:01:21 -0700468template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
469 hardware::MQFlavor flavor>
470bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::getMemRegionInfo(
471 size_t startIdx, size_t nMessages, size_t& firstCount, size_t& secondCount,
472 T** firstBaseAddress, T** secondBaseAddress) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800473 size_t firstRegionLength = first.getLength();
474 size_t secondRegionLength = second.getLength();
475
476 if (startIdx + nMessages > firstRegionLength + secondRegionLength) {
477 /*
478 * Return false if 'nMessages' starting at 'startIdx' cannot be
479 * accomodated by the MemTransaction object.
480 */
481 return false;
482 }
483
484 /* Number of messages to be read/written to the first MemRegion. */
Devin Moore77d279e2020-07-07 10:38:52 -0700485 firstCount =
486 startIdx < firstRegionLength ? std::min(nMessages, firstRegionLength - startIdx) : 0;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800487
488 /* Number of messages to be read/written to the second MemRegion. */
489 secondCount = nMessages - firstCount;
490
491 if (firstCount != 0) {
492 *firstBaseAddress = first.getAddress() + startIdx;
493 }
494
495 if (secondCount != 0) {
496 size_t secondStartIdx = startIdx > firstRegionLength ? startIdx - firstRegionLength : 0;
497 *secondBaseAddress = second.getAddress() + secondStartIdx;
498 }
499
500 return true;
501}
502
Devin Moore9a27da52020-07-06 14:01:21 -0700503template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
504 hardware::MQFlavor flavor>
505bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyFrom(T* data,
506 size_t startIdx,
507 size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800508 if (data == nullptr) {
509 return false;
510 }
511
512 size_t firstReadCount = 0, secondReadCount = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700513 T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800514
Devin Moore77d279e2020-07-07 10:38:52 -0700515 if (getMemRegionInfo(startIdx, nMessages, firstReadCount, secondReadCount, &firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800516 &secondBaseAddress) == false) {
517 /*
518 * Returns false if 'startIdx' and 'nMessages' are invalid for this
519 * MemTransaction object.
520 */
521 return false;
522 }
523
524 if (firstReadCount != 0) {
525 memcpy(data, firstBaseAddress, firstReadCount * sizeof(T));
526 }
527
528 if (secondReadCount != 0) {
Devin Moore77d279e2020-07-07 10:38:52 -0700529 memcpy(data + firstReadCount, secondBaseAddress, secondReadCount * sizeof(T));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800530 }
531
532 return true;
533}
534
Devin Moore9a27da52020-07-06 14:01:21 -0700535template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
536 hardware::MQFlavor flavor>
537bool MessageQueueBase<MQDescriptorType, T, flavor>::MemTransaction::copyTo(const T* data,
538 size_t startIdx,
539 size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800540 if (data == nullptr) {
541 return false;
542 }
543
544 size_t firstWriteCount = 0, secondWriteCount = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700545 T *firstBaseAddress = nullptr, *secondBaseAddress = nullptr;
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800546
Devin Moore77d279e2020-07-07 10:38:52 -0700547 if (getMemRegionInfo(startIdx, nMessages, firstWriteCount, secondWriteCount, &firstBaseAddress,
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800548 &secondBaseAddress) == false) {
549 /*
550 * Returns false if 'startIdx' and 'nMessages' are invalid for this
551 * MemTransaction object.
552 */
553 return false;
554 }
555
556 if (firstWriteCount != 0) {
557 memcpy(firstBaseAddress, data, firstWriteCount * sizeof(T));
558 }
559
560 if (secondWriteCount != 0) {
Devin Moore77d279e2020-07-07 10:38:52 -0700561 memcpy(secondBaseAddress, data + firstWriteCount, secondWriteCount * sizeof(T));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800562 }
563
564 return true;
565}
566
Devin Moore9a27da52020-07-06 14:01:21 -0700567template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
568 hardware::MQFlavor flavor>
569void MessageQueueBase<MQDescriptorType, T, flavor>::initMemory(bool resetPointers) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800570 /*
Devin Moore9a27da52020-07-06 14:01:21 -0700571 * Verify that the Descriptor contains the minimum number of grantors
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800572 * the native_handle is valid and T matches quantum size.
573 */
574 if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800575 (mDesc->countGrantors() < Descriptor::kMinGrantorCount) ||
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800576 (mDesc->getQuantum() != sizeof(T))) {
577 return;
578 }
579
Devin Moore9a27da52020-07-06 14:01:21 -0700580 if (flavor == hardware::kSynchronizedReadWrite) {
Devin Moore77d279e2020-07-07 10:38:52 -0700581 mReadPtr =
582 reinterpret_cast<std::atomic<uint64_t>*>(mapGrantorDescr(Descriptor::READPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800583 } else {
584 /*
585 * The unsynchronized write flavor of the FMQ may have multiple readers
586 * and each reader would have their own read pointer counter.
587 */
588 mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
589 }
590
Devin Moore9a27da52020-07-06 14:01:21 -0700591 hardware::details::check(mReadPtr != nullptr);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800592
Devin Moore77d279e2020-07-07 10:38:52 -0700593 mWritePtr = reinterpret_cast<std::atomic<uint64_t>*>(mapGrantorDescr(Descriptor::WRITEPTRPOS));
Devin Moore9a27da52020-07-06 14:01:21 -0700594 hardware::details::check(mWritePtr != nullptr);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800595
596 if (resetPointers) {
597 mReadPtr->store(0, std::memory_order_release);
598 mWritePtr->store(0, std::memory_order_release);
Devin Moore9a27da52020-07-06 14:01:21 -0700599 } else if (flavor != hardware::kSynchronizedReadWrite) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800600 // Always reset the read pointer.
601 mReadPtr->store(0, std::memory_order_release);
602 }
603
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800604 mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(Descriptor::DATAPTRPOS));
Devin Moore9a27da52020-07-06 14:01:21 -0700605 hardware::details::check(mRing != nullptr);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800606
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800607 mEvFlagWord = static_cast<std::atomic<uint32_t>*>(mapGrantorDescr(Descriptor::EVFLAGWORDPOS));
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800608 if (mEvFlagWord != nullptr) {
609 android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
610 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800611}
612
Devin Moore9a27da52020-07-06 14:01:21 -0700613template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
614 hardware::MQFlavor flavor>
615MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(const Descriptor& Desc,
616 bool resetPointers) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800617 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800618 if (mDesc == nullptr) {
619 return;
620 }
621
622 initMemory(resetPointers);
623}
624
Devin Moore9a27da52020-07-06 14:01:21 -0700625template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
626 hardware::MQFlavor flavor>
627MessageQueueBase<MQDescriptorType, T, flavor>::MessageQueueBase(size_t numElementsInQueue,
628 bool configureEventFlagWord) {
Kevin Rocard1d6e40f2017-04-03 11:51:13 -0700629 // Check if the buffer size would not overflow size_t
630 if (numElementsInQueue > SIZE_MAX / sizeof(T)) {
631 return;
632 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800633 /*
634 * The FMQ needs to allocate memory for the ringbuffer as well as for the
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800635 * read and write pointer counters. If an EventFlag word is to be configured,
636 * we also need to allocate memory for the same/
637 */
638 size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
639 size_t kMetaDataSize = 2 * sizeof(android::hardware::RingBufferPosition);
640
641 if (configureEventFlagWord) {
Devin Moore77d279e2020-07-07 10:38:52 -0700642 kMetaDataSize += sizeof(std::atomic<uint32_t>);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800643 }
644
645 /*
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800646 * Ashmem memory region size needs to be specified in page-aligned bytes.
647 * kQueueSizeBytes needs to be aligned to word boundary so that all offsets
648 * in the grantorDescriptor will be word aligned.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800649 */
650 size_t kAshmemSizePageAligned =
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800651 (Descriptor::alignToWordBoundary(kQueueSizeBytes) + kMetaDataSize + PAGE_SIZE - 1) &
652 ~(PAGE_SIZE - 1);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800653
654 /*
655 * Create an ashmem region to map the memory for the ringbuffer,
656 * read counter and write counter.
657 */
658 int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
659 ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
660
661 /*
662 * The native handle will contain the fds to be mapped.
663 */
Devin Moore77d279e2020-07-07 10:38:52 -0700664 native_handle_t* mqHandle = native_handle_create(1 /* numFds */, 0 /* numInts */);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800665 if (mqHandle == nullptr) {
666 return;
667 }
668
669 mqHandle->data[0] = ashmemFd;
Devin Moore77d279e2020-07-07 10:38:52 -0700670 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(
671 kQueueSizeBytes, mqHandle, sizeof(T), configureEventFlagWord));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800672 if (mDesc == nullptr) {
673 return;
674 }
675 initMemory(true);
676}
677
Devin Moore9a27da52020-07-06 14:01:21 -0700678template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
679 hardware::MQFlavor flavor>
680MessageQueueBase<MQDescriptorType, T, flavor>::~MessageQueueBase() {
681 if (flavor == hardware::kUnsynchronizedWrite) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800682 delete mReadPtr;
683 } else {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800684 unmapGrantorDescr(mReadPtr, Descriptor::READPTRPOS);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800685 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800686 if (mWritePtr != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800687 unmapGrantorDescr(mWritePtr, Descriptor::WRITEPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800688 }
689 if (mRing != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800690 unmapGrantorDescr(mRing, Descriptor::DATAPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800691 }
692 if (mEvFlagWord != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800693 unmapGrantorDescr(mEvFlagWord, Descriptor::EVFLAGWORDPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800694 android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
695 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800696}
697
Devin Moore9a27da52020-07-06 14:01:21 -0700698template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
699 hardware::MQFlavor flavor>
700bool MessageQueueBase<MQDescriptorType, T, flavor>::write(const T* data) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800701 return write(data, 1);
702}
703
Devin Moore9a27da52020-07-06 14:01:21 -0700704template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
705 hardware::MQFlavor flavor>
706bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800707 return read(data, 1);
708}
709
Devin Moore9a27da52020-07-06 14:01:21 -0700710template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
711 hardware::MQFlavor flavor>
712bool MessageQueueBase<MQDescriptorType, T, flavor>::write(const T* data, size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800713 MemTransaction tx;
Devin Moore77d279e2020-07-07 10:38:52 -0700714 return beginWrite(nMessages, &tx) && tx.copyTo(data, 0 /* startIdx */, nMessages) &&
715 commitWrite(nMessages);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800716}
717
Devin Moore9a27da52020-07-06 14:01:21 -0700718template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
719 hardware::MQFlavor flavor>
720bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(
721 const T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
722 int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
723 static_assert(flavor == hardware::kSynchronizedReadWrite,
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700724 "writeBlocking can only be used with the "
Devin Moore9a27da52020-07-06 14:01:21 -0700725 "hardware::kSynchronizedReadWrite flavor.");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800726 /*
727 * If evFlag is null and the FMQ does not have its own EventFlag object
728 * return false;
Devin Moore9a27da52020-07-06 14:01:21 -0700729 * If the flavor is hardware::kSynchronizedReadWrite and the readNotification
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800730 * bit mask is zero return false;
731 * If the count is greater than queue size, return false
732 * to prevent blocking until timeOut.
733 */
734 if (evFlag == nullptr) {
735 evFlag = mEventFlag;
736 if (evFlag == nullptr) {
Devin Moore9a27da52020-07-06 14:01:21 -0700737 hardware::details::logError(
Devin Moore77d279e2020-07-07 10:38:52 -0700738 "writeBlocking failed: called on MessageQueue with no Eventflag"
739 "configured or provided");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800740 return false;
741 }
742 }
743
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700744 if (readNotification == 0 || (count > getQuantumCount())) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800745 return false;
746 }
747
748 /*
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700749 * There is no need to wait for a readNotification if there is sufficient
750 * space to write is already present in the FMQ. The latter would be the case when
751 * read operations read more number of messages than write operations write.
752 * In other words, a single large read may clear the FMQ after multiple small
753 * writes. This would fail to clear a pending readNotification bit since
754 * EventFlag bits can only be cleared by a wait() call, however the bit would
755 * be correctly cleared by the next writeBlocking() call.
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800756 */
757
758 bool result = write(data, count);
759 if (result) {
760 if (writeNotification) {
761 evFlag->wake(writeNotification);
762 }
763 return result;
764 }
765
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800766 bool shouldTimeOut = timeOutNanos != 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700767 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800768
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700769 while (true) {
770 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800771 if (shouldTimeOut) {
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700772 /*
773 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
774 * to Nanoseconds)
775 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800776 int64_t currentTimeNs = android::elapsedRealtimeNano();
777 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700778 * Decrement 'timeOutNanos' to account for the time taken to complete the last
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800779 * iteration of the while loop.
780 */
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700781 timeOutNanos -= currentTimeNs - prevTimeNanos;
782 prevTimeNanos = currentTimeNs;
783
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800784 if (timeOutNanos <= 0) {
785 /*
786 * Attempt write in case a context switch happened outside of
787 * evFlag->wait().
788 */
789 result = write(data, count);
790 break;
791 }
792 }
793
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800794 /*
795 * wait() will return immediately if there was a pending read
796 * notification.
797 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800798 uint32_t efState = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700799 status_t status = evFlag->wait(readNotification, &efState, timeOutNanos,
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700800 true /* retry on spurious wake */);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800801
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700802 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
Devin Moore9a27da52020-07-06 14:01:21 -0700803 hardware::details::logError("Unexpected error code from EventFlag Wait status " +
804 std::to_string(status));
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700805 break;
806 }
807
808 if (status == android::TIMED_OUT) {
809 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800810 }
811
812 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700813 * If there is still insufficient space to write to the FMQ,
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800814 * keep waiting for another readNotification.
815 */
816 if ((efState & readNotification) && write(data, count)) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800817 result = true;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700818 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800819 }
820 }
821
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800822 if (result && writeNotification != 0) {
823 evFlag->wake(writeNotification);
824 }
825
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800826 return result;
827}
828
Devin Moore9a27da52020-07-06 14:01:21 -0700829template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
830 hardware::MQFlavor flavor>
831bool MessageQueueBase<MQDescriptorType, T, flavor>::writeBlocking(const T* data, size_t count,
832 int64_t timeOutNanos) {
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800833 return writeBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
834}
835
Devin Moore9a27da52020-07-06 14:01:21 -0700836template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
837 hardware::MQFlavor flavor>
838bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(
839 T* data, size_t count, uint32_t readNotification, uint32_t writeNotification,
840 int64_t timeOutNanos, android::hardware::EventFlag* evFlag) {
841 static_assert(flavor == hardware::kSynchronizedReadWrite,
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700842 "readBlocking can only be used with the "
Devin Moore9a27da52020-07-06 14:01:21 -0700843 "hardware::kSynchronizedReadWrite flavor.");
Jayant Chowdhary8819e812017-08-28 15:01:42 -0700844
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800845 /*
846 * If evFlag is null and the FMQ does not own its own EventFlag object
847 * return false;
848 * If the writeNotification bit mask is zero return false;
849 * If the count is greater than queue size, return false to prevent
850 * blocking until timeOut.
851 */
852 if (evFlag == nullptr) {
853 evFlag = mEventFlag;
854 if (evFlag == nullptr) {
Devin Moore9a27da52020-07-06 14:01:21 -0700855 hardware::details::logError(
Devin Moore77d279e2020-07-07 10:38:52 -0700856 "readBlocking failed: called on MessageQueue with no Eventflag"
857 "configured or provided");
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800858 return false;
859 }
860 }
861
862 if (writeNotification == 0 || count > getQuantumCount()) {
863 return false;
864 }
865
866 /*
867 * There is no need to wait for a write notification if sufficient
868 * data to read is already present in the FMQ. This would be the
869 * case when read operations read lesser number of messages than
870 * a write operation and multiple reads would be required to clear the queue
871 * after a single write operation. This check would fail to clear a pending
872 * writeNotification bit since EventFlag bits can only be cleared
873 * by a wait() call, however the bit would be correctly cleared by the next
874 * readBlocking() call.
875 */
876
877 bool result = read(data, count);
878 if (result) {
879 if (readNotification) {
880 evFlag->wake(readNotification);
881 }
882 return result;
883 }
884
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800885 bool shouldTimeOut = timeOutNanos != 0;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700886 int64_t prevTimeNanos = shouldTimeOut ? android::elapsedRealtimeNano() : 0;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800887
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700888 while (true) {
889 /* It is not required to adjust 'timeOutNanos' if 'shouldTimeOut' is false */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800890 if (shouldTimeOut) {
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700891 /*
892 * The current time and 'prevTimeNanos' are both CLOCK_BOOTTIME clock values(converted
893 * to Nanoseconds)
894 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800895 int64_t currentTimeNs = android::elapsedRealtimeNano();
896 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700897 * Decrement 'timeOutNanos' to account for the time taken to complete the last
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800898 * iteration of the while loop.
899 */
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700900 timeOutNanos -= currentTimeNs - prevTimeNanos;
901 prevTimeNanos = currentTimeNs;
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800902
903 if (timeOutNanos <= 0) {
904 /*
905 * Attempt read in case a context switch happened outside of
906 * evFlag->wait().
907 */
908 result = read(data, count);
909 break;
910 }
911 }
912
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800913 /*
914 * wait() will return immediately if there was a pending write
915 * notification.
916 */
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800917 uint32_t efState = 0;
Devin Moore77d279e2020-07-07 10:38:52 -0700918 status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos,
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700919 true /* retry on spurious wake */);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800920
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700921 if (status != android::TIMED_OUT && status != android::NO_ERROR) {
Devin Moore9a27da52020-07-06 14:01:21 -0700922 hardware::details::logError("Unexpected error code from EventFlag Wait status " +
923 std::to_string(status));
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700924 break;
925 }
926
927 if (status == android::TIMED_OUT) {
928 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800929 }
930
931 /*
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700932 * If the data in FMQ is still insufficient, go back to waiting
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800933 * for another write notification.
934 */
935 if ((efState & writeNotification) && read(data, count)) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800936 result = true;
Hridya Valsarajuf542b5a2017-03-21 11:33:33 -0700937 break;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800938 }
939 }
940
Hridya Valsaraju2abefb62017-01-19 13:06:58 -0800941 if (result && readNotification != 0) {
942 evFlag->wake(readNotification);
943 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800944 return result;
945}
946
Devin Moore9a27da52020-07-06 14:01:21 -0700947template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
948 hardware::MQFlavor flavor>
949bool MessageQueueBase<MQDescriptorType, T, flavor>::readBlocking(T* data, size_t count,
950 int64_t timeOutNanos) {
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800951 return readBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
952}
953
Devin Moore9a27da52020-07-06 14:01:21 -0700954template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
955 hardware::MQFlavor flavor>
956size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWriteBytes() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800957 return mDesc->getSize() - availableToReadBytes();
958}
959
Devin Moore9a27da52020-07-06 14:01:21 -0700960template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
961 hardware::MQFlavor flavor>
962size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToWrite() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800963 return availableToWriteBytes() / sizeof(T);
964}
965
Devin Moore9a27da52020-07-06 14:01:21 -0700966template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
967 hardware::MQFlavor flavor>
968size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToRead() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800969 return availableToReadBytes() / sizeof(T);
970}
971
Devin Moore9a27da52020-07-06 14:01:21 -0700972template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
973 hardware::MQFlavor flavor>
974bool MessageQueueBase<MQDescriptorType, T, flavor>::beginWrite(size_t nMessages,
975 MemTransaction* result) const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800976 /*
977 * If nMessages is greater than size of FMQ or in case of the synchronized
978 * FMQ flavor, if there is not enough space to write nMessages, then return
979 * result with null addresses.
980 */
Devin Moore9a27da52020-07-06 14:01:21 -0700981 if ((flavor == hardware::kSynchronizedReadWrite && (availableToWrite() < nMessages)) ||
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -0800982 nMessages > getQuantumCount()) {
983 *result = MemTransaction();
984 return false;
985 }
986
987 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
988 size_t writeOffset = writePtr % mDesc->getSize();
989
990 /*
991 * From writeOffset, the number of messages that can be written
992 * contiguously without wrapping around the ring buffer are calculated.
993 */
994 size_t contiguousMessages = (mDesc->getSize() - writeOffset) / sizeof(T);
995
996 if (contiguousMessages < nMessages) {
997 /*
998 * Wrap around is required. Both result.first and result.second are
999 * populated.
1000 */
Devin Moore77d279e2020-07-07 10:38:52 -07001001 *result = MemTransaction(
1002 MemRegion(reinterpret_cast<T*>(mRing + writeOffset), contiguousMessages),
1003 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001004 } else {
1005 /*
1006 * A wrap around is not required to write nMessages. Only result.first
1007 * is populated.
1008 */
1009 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + writeOffset), nMessages),
1010 MemRegion());
1011 }
1012
1013 return true;
1014}
1015
Devin Moore9a27da52020-07-06 14:01:21 -07001016template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
1017 hardware::MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001018/*
1019 * Disable integer sanitization since integer overflow here is allowed
1020 * and legal.
1021 */
Devin Moore9a27da52020-07-06 14:01:21 -07001022__attribute__((no_sanitize("integer"))) bool
1023MessageQueueBase<MQDescriptorType, T, flavor>::commitWrite(size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001024 size_t nBytesWritten = nMessages * sizeof(T);
1025 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
1026 writePtr += nBytesWritten;
1027 mWritePtr->store(writePtr, std::memory_order_release);
1028 /*
1029 * This method cannot fail now since we are only incrementing the writePtr
1030 * counter.
1031 */
1032 return true;
1033}
1034
Devin Moore9a27da52020-07-06 14:01:21 -07001035template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
1036 hardware::MQFlavor flavor>
1037size_t MessageQueueBase<MQDescriptorType, T, flavor>::availableToReadBytes() const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001038 /*
1039 * This method is invoked by implementations of both read() and write() and
Devin Moore9a27da52020-07-06 14:01:21 -07001040 * hence requires a memory_order_acquired load for both mReadPtr and
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001041 * mWritePtr.
1042 */
Devin Moore77d279e2020-07-07 10:38:52 -07001043 return mWritePtr->load(std::memory_order_acquire) - mReadPtr->load(std::memory_order_acquire);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001044}
1045
Devin Moore9a27da52020-07-06 14:01:21 -07001046template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
1047 hardware::MQFlavor flavor>
1048bool MessageQueueBase<MQDescriptorType, T, flavor>::read(T* data, size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001049 MemTransaction tx;
Devin Moore77d279e2020-07-07 10:38:52 -07001050 return beginRead(nMessages, &tx) && tx.copyFrom(data, 0 /* startIdx */, nMessages) &&
1051 commitRead(nMessages);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001052}
1053
Devin Moore9a27da52020-07-06 14:01:21 -07001054template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
1055 hardware::MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001056/*
1057 * Disable integer sanitization since integer overflow here is allowed
1058 * and legal.
1059 */
Devin Moore9a27da52020-07-06 14:01:21 -07001060__attribute__((no_sanitize("integer"))) bool
1061MessageQueueBase<MQDescriptorType, T, flavor>::beginRead(size_t nMessages,
1062 MemTransaction* result) const {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001063 *result = MemTransaction();
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001064 /*
1065 * If it is detected that the data in the queue was overwritten
1066 * due to the reader process being too slow, the read pointer counter
1067 * is set to the same as the write pointer counter to indicate error
1068 * and the read returns false;
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001069 * Need acquire/release memory ordering for mWritePtr.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001070 */
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -08001071 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1072 /*
1073 * A relaxed load is sufficient for mReadPtr since there will be no
1074 * stores to mReadPtr from a different thread.
1075 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001076 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
1077
1078 if (writePtr - readPtr > mDesc->getSize()) {
1079 mReadPtr->store(writePtr, std::memory_order_release);
1080 return false;
1081 }
1082
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001083 size_t nBytesDesired = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001084 /*
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001085 * Return if insufficient data to read in FMQ.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001086 */
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001087 if (writePtr - readPtr < nBytesDesired) {
1088 return false;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001089 }
1090
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001091 size_t readOffset = readPtr % mDesc->getSize();
1092 /*
1093 * From readOffset, the number of messages that can be read contiguously
1094 * without wrapping around the ring buffer are calculated.
1095 */
1096 size_t contiguousMessages = (mDesc->getSize() - readOffset) / sizeof(T);
1097
1098 if (contiguousMessages < nMessages) {
1099 /*
1100 * A wrap around is required. Both result.first and result.second
1101 * are populated.
1102 */
Devin Moore77d279e2020-07-07 10:38:52 -07001103 *result = MemTransaction(
1104 MemRegion(reinterpret_cast<T*>(mRing + readOffset), contiguousMessages),
1105 MemRegion(reinterpret_cast<T*>(mRing), nMessages - contiguousMessages));
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001106 } else {
1107 /*
1108 * A wrap around is not required. Only result.first need to be
1109 * populated.
1110 */
1111 *result = MemTransaction(MemRegion(reinterpret_cast<T*>(mRing + readOffset), nMessages),
1112 MemRegion());
1113 }
1114
1115 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001116}
1117
Devin Moore9a27da52020-07-06 14:01:21 -07001118template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
1119 hardware::MQFlavor flavor>
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001120/*
1121 * Disable integer sanitization since integer overflow here is allowed
1122 * and legal.
1123 */
Devin Moore9a27da52020-07-06 14:01:21 -07001124__attribute__((no_sanitize("integer"))) bool
1125MessageQueueBase<MQDescriptorType, T, flavor>::commitRead(size_t nMessages) {
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001126 // TODO: Use a local copy of readPtr to avoid relazed mReadPtr loads.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001127 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001128 auto writePtr = mWritePtr->load(std::memory_order_acquire);
1129 /*
1130 * If the flavor is unsynchronized, it is possible that a write overflow may
Devin Moore9a27da52020-07-06 14:01:21 -07001131 * have occurred between beginRead() and commitRead().
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001132 */
1133 if (writePtr - readPtr > mDesc->getSize()) {
1134 mReadPtr->store(writePtr, std::memory_order_release);
1135 return false;
1136 }
1137
1138 size_t nBytesRead = nMessages * sizeof(T);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001139 readPtr += nBytesRead;
1140 mReadPtr->store(readPtr, std::memory_order_release);
Hridya Valsaraju8f0e8e52017-01-09 07:57:00 -08001141 return true;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001142}
1143
Devin Moore9a27da52020-07-06 14:01:21 -07001144template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
1145 hardware::MQFlavor flavor>
1146size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumSize() const {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001147 return mDesc->getQuantum();
1148}
1149
Devin Moore9a27da52020-07-06 14:01:21 -07001150template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
1151 hardware::MQFlavor flavor>
1152size_t MessageQueueBase<MQDescriptorType, T, flavor>::getQuantumCount() const {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001153 return mDesc->getSize() / mDesc->getQuantum();
1154}
1155
Devin Moore9a27da52020-07-06 14:01:21 -07001156template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
1157 hardware::MQFlavor flavor>
1158bool MessageQueueBase<MQDescriptorType, T, flavor>::isValid() const {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001159 return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
1160}
1161
Devin Moore9a27da52020-07-06 14:01:21 -07001162template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
1163 hardware::MQFlavor flavor>
1164void* MessageQueueBase<MQDescriptorType, T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001165 const native_handle_t* handle = mDesc->handle();
1166 auto grantors = mDesc->grantors();
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001167 if (handle == nullptr) {
Devin Moore9a27da52020-07-06 14:01:21 -07001168 hardware::details::logError("mDesc->handle is null");
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001169 return nullptr;
1170 }
1171
1172 if (grantorIdx >= grantors.size()) {
Devin Moore9a27da52020-07-06 14:01:21 -07001173 hardware::details::logError(std::string("grantorIdx must be less than ") +
1174 std::to_string(grantors.size()));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001175 return nullptr;
1176 }
1177
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001178 int fdIndex = grantors[grantorIdx].fdIndex;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001179 /*
1180 * Offset for mmap must be a multiple of PAGE_SIZE.
1181 */
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001182 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
Devin Moore77d279e2020-07-07 10:38:52 -07001183 int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001184
Devin Moore77d279e2020-07-07 10:38:52 -07001185 void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED, handle->data[fdIndex],
1186 mapOffset);
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001187 if (address == MAP_FAILED) {
Devin Moore9a27da52020-07-06 14:01:21 -07001188 hardware::details::logError(std::string("mmap failed: ") + std::to_string(errno));
Hridya Valsarajudf73d422020-06-10 15:36:03 -07001189 return nullptr;
1190 }
1191 return reinterpret_cast<uint8_t*>(address) + (grantors[grantorIdx].offset - mapOffset);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001192}
1193
Devin Moore9a27da52020-07-06 14:01:21 -07001194template <template <typename, hardware::MQFlavor> typename MQDescriptorType, typename T,
1195 hardware::MQFlavor flavor>
1196void MessageQueueBase<MQDescriptorType, T, flavor>::unmapGrantorDescr(void* address,
1197 uint32_t grantorIdx) {
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001198 auto grantors = mDesc->grantors();
1199 if ((address == nullptr) || (grantorIdx >= grantors.size())) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001200 return;
1201 }
1202
Hridya Valsaraju6ba72a52017-02-24 10:59:55 -08001203 int mapOffset = (grantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
Devin Moore77d279e2020-07-07 10:38:52 -07001204 int mapLength = grantors[grantorIdx].offset - mapOffset + grantors[grantorIdx].extent;
1205 void* baseAddress =
1206 reinterpret_cast<uint8_t*>(address) - (grantors[grantorIdx].offset - mapOffset);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001207 if (baseAddress) munmap(baseAddress, mapLength);
1208}
1209
1210} // namespace hardware