blob: b458f39c8b0310cc65a1f13786bd3d92a189f6a7 [file] [log] [blame]
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef HIDL_MQ_H
18#define HIDL_MQ_H
19
20#include <android-base/logging.h>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080021#include <atomic>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080022#include <cutils/ashmem.h>
23#include <fmq/EventFlag.h>
24#include <hidl/MQDescriptor.h>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080025#include <new>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080026#include <sys/mman.h>
27#include <utils/Log.h>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080028
29namespace android {
30namespace hardware {
31
32template <typename T, MQFlavor flavor>
33struct MessageQueue {
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -080034 typedef MQDescriptor<T, flavor> Descriptor;
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -080035
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080036 /**
37 * @param Desc MQDescriptor describing the FMQ.
38 * @param resetPointers bool indicating whether the read/write pointers
39 * should be reset or not.
40 */
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -080041 MessageQueue(const Descriptor& Desc, bool resetPointers = true);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080042
43 ~MessageQueue();
44
45 /**
46 * This constructor uses Ashmem shared memory to create an FMQ
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080047 * that can contain a maximum of 'numElementsInQueue' elements of type T.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080048 *
49 * @param numElementsInQueue Capacity of the MessageQueue in terms of T.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -080050 * @param configureEventFlagWord Boolean that specifies if memory should
51 * also be allocated and mapped for an EventFlag word.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080052 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -080053 MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord = false);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080054
55 /**
56 * @return Number of items of type T that can be written into the FMQ
57 * without a read.
58 */
59 size_t availableToWrite() const;
60
61 /**
62 * @return Number of items of type T that are waiting to be read from the
63 * FMQ.
64 */
65 size_t availableToRead() const;
66
67 /**
68 * Returns the size of type T in bytes.
69 *
70 * @param Size of T.
71 */
72 size_t getQuantumSize() const;
73
74 /**
75 * Returns the size of the FMQ in terms of the size of type T.
76 *
77 * @return Number of items of type T that will fit in the FMQ.
78 */
79 size_t getQuantumCount() const;
80
81 /**
82 * @return Whether the FMQ is configured correctly.
83 */
84 bool isValid() const;
85
86 /**
87 * Non-blocking write to FMQ.
88 *
89 * @param data Pointer to the object of type T to be written into the FMQ.
90 *
91 * @return Whether the write was successful.
92 */
93 bool write(const T* data);
94
95 /**
96 * Non-blocking read from FMQ.
97 *
98 * @param data Pointer to the memory where the object read from the FMQ is
99 * copied to.
100 *
101 * @return Whether the read was successful.
102 */
103 bool read(T* data);
104
105 /**
106 * Write some data into the FMQ without blocking.
107 *
108 * @param data Pointer to the array of items of type T.
109 * @param count Number of items in array.
110 *
111 * @return Whether the write was successful.
112 */
113 bool write(const T* data, size_t count);
114
115 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800116 * Perform a blocking write of 'count' items into the FMQ using EventFlags.
117 * Does not support partial writes.
118 *
119 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
120 * associated with the FMQ and it is used in that case.
121 *
122 * The application code must ensure that 'evFlag' used by the
123 * reader(s)/writer is based upon the same EventFlag word.
124 *
125 * The method will return false without blocking if any of the following
126 * conditions are true:
127 * - If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
128 * - If the flavor of the FMQ is synchronized and the 'readNotification' bit mask is zero.
129 * - If 'count' is greater than the FMQ size.
130 *
131 * If the flavor of the FMQ is synchronized and there is insufficient space
132 * available to write into it, the EventFlag bit mask 'readNotification' is
133 * is waited upon.
134 *
135 * Upon a successful write, wake is called on 'writeNotification' (if
136 * non-zero).
137 *
138 * @param data Pointer to the array of items of type T.
139 * @param count Number of items in array.
140 * @param readNotification The EventFlag bit mask to wait on if there is not
141 * enough space in FMQ to write 'count' items.
142 * @param writeNotification The EventFlag bit mask to call wake on
143 * a successful write. No wake is called if 'writeNotification' is zero.
144 * @param timeOutNanos Number of nanoseconds after which the blocking
145 * write attempt is aborted.
146 * @param evFlag The EventFlag object to be used for blocking. If nullptr,
147 * it is checked whether the FMQ owns an EventFlag object and that is used
148 * for blocking instead.
149 *
150 * @return Whether the write was successful.
151 */
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800152 bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
153 uint32_t writeNotification, int64_t timeOutNanos = 0,
154 android::hardware::EventFlag* evFlag = nullptr);
155
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800156 bool writeBlocking(const T* data, size_t count, int64_t timeOutNanos = 0);
157
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800158 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800159 * Read some data from the FMQ without blocking.
160 *
161 * @param data Pointer to the array to which read data is to be written.
162 * @param count Number of items to be read.
163 *
164 * @return Whether the read was successful.
165 */
166 bool read(T* data, size_t count);
167
168 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800169 * Perform a blocking read operation of 'count' items from the FMQ. Does not
170 * perform a partial read.
171 *
172 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
173 * associated with the FMQ and it is used in that case.
174 *
175 * The application code must ensure that 'evFlag' used by the
176 * reader(s)/writer is based upon the same EventFlag word.
177 *
178 * The method will return false without blocking if any of the following
179 * conditions are true:
180 * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
181 * -If the 'writeNotification' bit mask is zero.
182 * -If 'count' is greater than the FMQ size.
183 *
184 * If FMQ does not contain 'count' items, the eventFlag bit mask
185 * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
186 * wake is called on 'readNotification' (if non-zero).
187 *
188 * @param data Pointer to the array to which read data is to be written.
189 * @param count Number of items to be read.
190 * @param readNotification The EventFlag bit mask to call wake on after
191 * a successful read. No wake is called if 'readNotification' is zero.
192 * @param writeNotification The EventFlag bit mask to call a wait on
193 * if there is insufficient data in the FMQ to be read.
194 * @param timeOutNanos Number of nanoseconds after which the blocking
195 * read attempt is aborted.
196 * @param evFlag The EventFlag object to be used for blocking.
197 *
198 * @return Whether the read was successful.
199 */
200 bool readBlocking(T* data, size_t count, uint32_t readNotification,
201 uint32_t writeNotification, int64_t timeOutNanos = 0,
202 android::hardware::EventFlag* evFlag = nullptr);
203
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800204 bool readBlocking(T* data, size_t count, int64_t timeOutNanos = 0);
205
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800206 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800207 * Get a pointer to the MQDescriptor object that describes this FMQ.
208 *
209 * @return Pointer to the MQDescriptor associated with the FMQ.
210 */
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800211 const Descriptor* getDesc() const { return mDesc.get(); }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800212
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800213 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800214 * Get a pointer to the EventFlag word if there is one associated with this FMQ.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800215 *
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800216 * @return Pointer to an EventFlag word, will return nullptr if not
217 * configured. This method does not transfer ownership. The EventFlag
218 * word will be unmapped by the MessageQueue destructor.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800219 */
220 std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800221private:
222 struct region {
223 uint8_t* address;
224 size_t length;
225 };
226 struct transaction {
227 region first;
228 region second;
229 };
230
231 size_t writeBytes(const uint8_t* data, size_t size);
232 transaction beginWrite(size_t nBytesDesired) const;
233 void commitWrite(size_t nBytesWritten);
234
235 size_t readBytes(uint8_t* data, size_t size);
236 transaction beginRead(size_t nBytesDesired) const;
237 void commitRead(size_t nBytesRead);
238
239 size_t availableToWriteBytes() const;
240 size_t availableToReadBytes() const;
241
242 MessageQueue(const MessageQueue& other) = delete;
243 MessageQueue& operator=(const MessageQueue& other) = delete;
244 MessageQueue();
245
246 void* mapGrantorDescr(uint32_t grantorIdx);
247 void unmapGrantorDescr(void* address, uint32_t grantorIdx);
248 void initMemory(bool resetPointers);
249
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800250 enum DefaultEventNotification : uint32_t {
251 FMQ_NOT_FULL = 0x01,
252 FMQ_NOT_EMPTY = 0x02
253 };
254
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800255 std::unique_ptr<Descriptor> mDesc;
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800256 uint8_t* mRing = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800257 /*
258 * TODO(b/31550092): Change to 32 bit read and write pointer counters.
259 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800260 std::atomic<uint64_t>* mReadPtr = nullptr;
261 std::atomic<uint64_t>* mWritePtr = nullptr;
262
263 std::atomic<uint32_t>* mEvFlagWord = nullptr;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800264
265 /*
266 * This EventFlag object will be owned by the FMQ and will have the same
267 * lifetime.
268 */
269 android::hardware::EventFlag* mEventFlag = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800270};
271
272template <typename T, MQFlavor flavor>
273void MessageQueue<T, flavor>::initMemory(bool resetPointers) {
274 /*
275 * Verify that the the Descriptor contains the minimum number of grantors
276 * the native_handle is valid and T matches quantum size.
277 */
278 if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800279 (mDesc->countGrantors() < Descriptor::kMinGrantorCount) ||
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800280 (mDesc->getQuantum() != sizeof(T))) {
281 return;
282 }
283
284 if (flavor == kSynchronizedReadWrite) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800285 mReadPtr = reinterpret_cast<std::atomic<uint64_t>*>(
286 mapGrantorDescr(Descriptor::READPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800287 } else {
288 /*
289 * The unsynchronized write flavor of the FMQ may have multiple readers
290 * and each reader would have their own read pointer counter.
291 */
292 mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
293 }
294
295 CHECK(mReadPtr != nullptr);
296
297 mWritePtr =
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800298 reinterpret_cast<std::atomic<uint64_t>*>(mapGrantorDescr(Descriptor::WRITEPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800299 CHECK(mWritePtr != nullptr);
300
301 if (resetPointers) {
302 mReadPtr->store(0, std::memory_order_release);
303 mWritePtr->store(0, std::memory_order_release);
304 } else if (flavor != kSynchronizedReadWrite) {
305 // Always reset the read pointer.
306 mReadPtr->store(0, std::memory_order_release);
307 }
308
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800309 mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(Descriptor::DATAPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800310 CHECK(mRing != nullptr);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800311
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800312 mEvFlagWord = static_cast<std::atomic<uint32_t>*>(mapGrantorDescr(Descriptor::EVFLAGWORDPOS));
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800313 if (mEvFlagWord != nullptr) {
314 android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
315 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800316}
317
318template <typename T, MQFlavor flavor>
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800319MessageQueue<T, flavor>::MessageQueue(const Descriptor& Desc, bool resetPointers) {
320 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800321 if (mDesc == nullptr) {
322 return;
323 }
324
325 initMemory(resetPointers);
326}
327
328template <typename T, MQFlavor flavor>
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800329MessageQueue<T, flavor>::MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800330 /*
331 * The FMQ needs to allocate memory for the ringbuffer as well as for the
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800332 * read and write pointer counters. If an EventFlag word is to be configured,
333 * we also need to allocate memory for the same/
334 */
335 size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
336 size_t kMetaDataSize = 2 * sizeof(android::hardware::RingBufferPosition);
337
338 if (configureEventFlagWord) {
339 kMetaDataSize+= sizeof(std::atomic<uint32_t>);
340 }
341
342 /*
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800343 * Ashmem memory region size needs to be specified in page-aligned bytes.
344 * kQueueSizeBytes needs to be aligned to word boundary so that all offsets
345 * in the grantorDescriptor will be word aligned.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800346 */
347 size_t kAshmemSizePageAligned =
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800348 (Descriptor::alignToWordBoundary(kQueueSizeBytes) + kMetaDataSize + PAGE_SIZE - 1) &
349 ~(PAGE_SIZE - 1);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800350
351 /*
352 * Create an ashmem region to map the memory for the ringbuffer,
353 * read counter and write counter.
354 */
355 int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
356 ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
357
358 /*
359 * The native handle will contain the fds to be mapped.
360 */
361 native_handle_t* mqHandle =
362 native_handle_create(1 /* numFds */, 0 /* numInts */);
363 if (mqHandle == nullptr) {
364 return;
365 }
366
367 mqHandle->data[0] = ashmemFd;
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800368 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(kQueueSizeBytes,
369 mqHandle,
370 sizeof(T),
371 configureEventFlagWord));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800372 if (mDesc == nullptr) {
373 return;
374 }
375 initMemory(true);
376}
377
378template <typename T, MQFlavor flavor>
379MessageQueue<T, flavor>::~MessageQueue() {
380 if (flavor == kUnsynchronizedWrite) {
381 delete mReadPtr;
382 } else {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800383 unmapGrantorDescr(mReadPtr, Descriptor::READPTRPOS);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800384 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800385 if (mWritePtr != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800386 unmapGrantorDescr(mWritePtr, Descriptor::WRITEPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800387 }
388 if (mRing != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800389 unmapGrantorDescr(mRing, Descriptor::DATAPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800390 }
391 if (mEvFlagWord != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800392 unmapGrantorDescr(mEvFlagWord, Descriptor::EVFLAGWORDPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800393 android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
394 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800395}
396
397template <typename T, MQFlavor flavor>
398bool MessageQueue<T, flavor>::write(const T* data) {
399 return write(data, 1);
400}
401
402template <typename T, MQFlavor flavor>
403bool MessageQueue<T, flavor>::read(T* data) {
404 return read(data, 1);
405}
406
407template <typename T, MQFlavor flavor>
408bool MessageQueue<T, flavor>::write(const T* data, size_t count) {
409 /*
410 * If read/write synchronization is not enabled, data in the queue
411 * will be overwritten by a write operation when full.
412 */
413 if ((flavor == kSynchronizedReadWrite && (availableToWriteBytes() < sizeof(T) * count)) ||
414 (count > getQuantumCount()))
415 return false;
416
417 return (writeBytes(reinterpret_cast<const uint8_t*>(data),
418 sizeof(T) * count) == sizeof(T) * count);
419}
420
421template <typename T, MQFlavor flavor>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800422bool MessageQueue<T, flavor>::writeBlocking(const T* data,
423 size_t count,
424 uint32_t readNotification,
425 uint32_t writeNotification,
426 int64_t timeOutNanos,
427 android::hardware::EventFlag* evFlag) {
428 /*
429 * If evFlag is null and the FMQ does not have its own EventFlag object
430 * return false;
431 * If the flavor is kSynchronizedReadWrite and the readNotification
432 * bit mask is zero return false;
433 * If the count is greater than queue size, return false
434 * to prevent blocking until timeOut.
435 */
436 if (evFlag == nullptr) {
437 evFlag = mEventFlag;
438 if (evFlag == nullptr) {
439 return false;
440 }
441 }
442
443 if ((readNotification == 0 && flavor == kSynchronizedReadWrite) ||
444 (count > getQuantumCount())) {
445 return false;
446 }
447
448 /*
449 * There is no need to wait for a readNotification if the flavor
450 * of the queue is kUnsynchronizedWrite or sufficient space to write
451 * is already present in the FMQ. The latter would be the case when
452 * read operations read more number of messages than
453 * write operations write. In other words, a single large read may clear the FMQ
454 * after multiple small writes. This would fail to clear a pending
455 * readNotification bit since EventFlag bits can only be cleared
456 * by a wait() call, however the bit would be correctly cleared by the next
457 * blockingWrite() call.
458 */
459
460 bool result = write(data, count);
461 if (result) {
462 if (writeNotification) {
463 evFlag->wake(writeNotification);
464 }
465 return result;
466 }
467
468 bool endWait = false;
469 while (endWait == false) {
470 uint32_t efState = 0;
471 /*
472 * wait() will return immediately if there was a pending read
473 * notification.
474 */
475 status_t status = evFlag->wait(readNotification, &efState, timeOutNanos);
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800476 switch (status) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800477 case android::NO_ERROR:
478 /*
479 * If wait() returns NO_ERROR, break and check efState.
480 */
481 break;
482 case android::TIMED_OUT:
483 /*
484 * If wait() returns android::TIMEDOUT, break out of the while loop
485 * and return false;
486 */
487 endWait = true;
488 continue;
489 case -EAGAIN:
490 case -EINTR:
491 /*
492 * For errors -EAGAIN and -EINTR, go back to wait.
493 */
494 continue;
495 default:
496 /*
497 * Throw an error for any other error code since it is unexpected.
498 */
499
500 endWait = true;
501 ALOGE("Unexpected error code from EventFlag Wait %d", status);
502 continue;
503 }
504
505 /*
506 * If the wake() was not due to the readNotification bit or if
507 * there is still insufficient space to write to the FMQ,
508 * keep waiting for another readNotification.
509 */
510 if ((efState & readNotification) && write(data, count)) {
511 if (writeNotification) {
512 evFlag->wake(writeNotification);
513 }
514 result = true;
515 endWait = true;
516 }
517 }
518
519 return result;
520}
521
522template <typename T, MQFlavor flavor>
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800523bool MessageQueue<T, flavor>::writeBlocking(const T* data,
524 size_t count,
525 int64_t timeOutNanos) {
526 return writeBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
527}
528
529template <typename T, MQFlavor flavor>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800530bool MessageQueue<T, flavor>::readBlocking(T* data,
531 size_t count,
532 uint32_t readNotification,
533 uint32_t writeNotification,
534 int64_t timeOutNanos,
535 android::hardware::EventFlag* evFlag) {
536 /*
537 * If evFlag is null and the FMQ does not own its own EventFlag object
538 * return false;
539 * If the writeNotification bit mask is zero return false;
540 * If the count is greater than queue size, return false to prevent
541 * blocking until timeOut.
542 */
543 if (evFlag == nullptr) {
544 evFlag = mEventFlag;
545 if (evFlag == nullptr) {
546 return false;
547 }
548 }
549
550 if (writeNotification == 0 || count > getQuantumCount()) {
551 return false;
552 }
553
554 /*
555 * There is no need to wait for a write notification if sufficient
556 * data to read is already present in the FMQ. This would be the
557 * case when read operations read lesser number of messages than
558 * a write operation and multiple reads would be required to clear the queue
559 * after a single write operation. This check would fail to clear a pending
560 * writeNotification bit since EventFlag bits can only be cleared
561 * by a wait() call, however the bit would be correctly cleared by the next
562 * readBlocking() call.
563 */
564
565 bool result = read(data, count);
566 if (result) {
567 if (readNotification) {
568 evFlag->wake(readNotification);
569 }
570 return result;
571 }
572
573 bool endWait = false;
574 while (endWait == false) {
575 uint32_t efState = 0;
576 /*
577 * wait() will return immediately if there was a pending write
578 * notification.
579 */
580 status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos);
Hridya Valsaraju2fb3a0c2017-01-10 14:31:43 -0800581 switch (status) {
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800582 case android::NO_ERROR:
583 /*
584 * If wait() returns NO_ERROR, break and check efState.
585 */
586 break;
587 case android::TIMED_OUT:
588 /*
589 * If wait() returns android::TIMEDOUT, break out of the while loop
590 * and return false;
591 */
592 endWait = true;
593 continue;
594 case -EAGAIN:
595 case -EINTR:
596 /*
597 * For errors -EAGAIN and -EINTR, go back to wait.
598 */
599 continue;
600 default:
601 /*
602 * Throw an error for any other error code since it is unexpected.
603 */
604
605 endWait = true;
606 ALOGE("Unexpected error code from EventFlag Wait %d", status);
607 continue;
608 }
609
610 /*
611 * If the wake() was not due to the writeNotification bit being set
612 * or if the data in FMQ is still insufficient, go back to waiting
613 * for another write notification.
614 */
615 if ((efState & writeNotification) && read(data, count)) {
616 if (readNotification) {
617 evFlag->wake(readNotification);
618 }
619 result = true;
620 endWait = true;
621 }
622 }
623
624 return result;
625}
626
627template <typename T, MQFlavor flavor>
Hridya Valsaraju4486ad02017-01-13 20:49:39 -0800628bool MessageQueue<T, flavor>::readBlocking(T* data, size_t count, int64_t timeOutNanos) {
629 return readBlocking(data, count, FMQ_NOT_FULL, FMQ_NOT_EMPTY, timeOutNanos);
630}
631
632template <typename T, MQFlavor flavor>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800633__attribute__((no_sanitize("integer")))
634bool MessageQueue<T, flavor>::read(T* data, size_t count) {
635 if (availableToReadBytes() < sizeof(T) * count) return false;
636 /*
637 * If it is detected that the data in the queue was overwritten
638 * due to the reader process being too slow, the read pointer counter
639 * is set to the same as the write pointer counter to indicate error
640 * and the read returns false;
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -0800641 * Need acquire/release memory ordering for mWritePtr.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800642 */
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -0800643 auto writePtr = mWritePtr->load(std::memory_order_acquire);
644 /*
645 * A relaxed load is sufficient for mReadPtr since there will be no
646 * stores to mReadPtr from a different thread.
647 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800648 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
649
650 if (writePtr - readPtr > mDesc->getSize()) {
651 mReadPtr->store(writePtr, std::memory_order_release);
652 return false;
653 }
654
655 return readBytes(reinterpret_cast<uint8_t*>(data), sizeof(T) * count) ==
656 sizeof(T) * count;
657}
658
659template <typename T, MQFlavor flavor>
660size_t MessageQueue<T, flavor>::availableToWriteBytes() const {
661 return mDesc->getSize() - availableToReadBytes();
662}
663
664template <typename T, MQFlavor flavor>
665size_t MessageQueue<T, flavor>::availableToWrite() const {
666 return availableToWriteBytes()/sizeof(T);
667}
668
669template <typename T, MQFlavor flavor>
670size_t MessageQueue<T, flavor>::availableToRead() const {
671 return availableToReadBytes()/sizeof(T);
672}
673
674template <typename T, MQFlavor flavor>
675size_t MessageQueue<T, flavor>::writeBytes(const uint8_t* data, size_t size) {
676 transaction tx = beginWrite(size);
677 memcpy(tx.first.address, data, tx.first.length);
678 memcpy(tx.second.address, data + tx.first.length, tx.second.length);
679 size_t result = tx.first.length + tx.second.length;
680 commitWrite(result);
681 return result;
682}
683
684/*
685 * The below method does not check for available space since it was already
686 * checked by write() API which invokes writeBytes() which in turn calls
687 * beginWrite().
688 */
689template <typename T, MQFlavor flavor>
690typename MessageQueue<T, flavor>::transaction MessageQueue<T, flavor>::beginWrite(
691 size_t nBytesDesired) const {
692 transaction result;
693 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
694 size_t writeOffset = writePtr % mDesc->getSize();
695 size_t contiguous = mDesc->getSize() - writeOffset;
696 if (contiguous < nBytesDesired) {
697 result = {{mRing + writeOffset, contiguous},
698 {mRing, nBytesDesired - contiguous}};
699 } else {
700 result = {
701 {mRing + writeOffset, nBytesDesired}, {0, 0},
702 };
703 }
704 return result;
705}
706
707template <typename T, MQFlavor flavor>
708__attribute__((no_sanitize("integer")))
709void MessageQueue<T, flavor>::commitWrite(size_t nBytesWritten) {
710 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
711 writePtr += nBytesWritten;
712 mWritePtr->store(writePtr, std::memory_order_release);
713}
714
715template <typename T, MQFlavor flavor>
716size_t MessageQueue<T, flavor>::availableToReadBytes() const {
717 /*
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -0800718 * This method is invoked by implementations of both read() and write() and
719 * hence requries a memory_order_acquired load for both mReadPtr and
720 * mWritePtr.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800721 */
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -0800722 return mWritePtr->load(std::memory_order_acquire) -
723 mReadPtr->load(std::memory_order_acquire);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800724}
725
726template <typename T, MQFlavor flavor>
727size_t MessageQueue<T, flavor>::readBytes(uint8_t* data, size_t size) {
728 transaction tx = beginRead(size);
729 memcpy(data, tx.first.address, tx.first.length);
730 memcpy(data + tx.first.length, tx.second.address, tx.second.length);
731 size_t result = tx.first.length + tx.second.length;
732 commitRead(result);
733 return result;
734}
735
736/*
737 * The below method does not check whether nBytesDesired bytes are available
738 * to read because the check is performed in the read() method before
739 * readBytes() is invoked.
740 */
741template <typename T, MQFlavor flavor>
742typename MessageQueue<T, flavor>::transaction MessageQueue<T, flavor>::beginRead(
743 size_t nBytesDesired) const {
744 transaction result;
745 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
746 size_t readOffset = readPtr % mDesc->getSize();
747 size_t contiguous = mDesc->getSize() - readOffset;
748
749 if (contiguous < nBytesDesired) {
750 result = {{mRing + readOffset, contiguous},
751 {mRing, nBytesDesired - contiguous}};
752 } else {
753 result = {
754 {mRing + readOffset, nBytesDesired}, {0, 0},
755 };
756 }
757
758 return result;
759}
760
761template <typename T, MQFlavor flavor>
762__attribute__((no_sanitize("integer")))
763void MessageQueue<T, flavor>::commitRead(size_t nBytesRead) {
764 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
765 readPtr += nBytesRead;
766 mReadPtr->store(readPtr, std::memory_order_release);
767}
768
769template <typename T, MQFlavor flavor>
770size_t MessageQueue<T, flavor>::getQuantumSize() const {
771 return mDesc->getQuantum();
772}
773
774template <typename T, MQFlavor flavor>
775size_t MessageQueue<T, flavor>::getQuantumCount() const {
776 return mDesc->getSize() / mDesc->getQuantum();
777}
778
779template <typename T, MQFlavor flavor>
780bool MessageQueue<T, flavor>::isValid() const {
781 return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
782}
783
784template <typename T, MQFlavor flavor>
785void* MessageQueue<T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
786 const native_handle_t* handle = mDesc->getNativeHandle()->handle();
787 auto mGrantors = mDesc->getGrantors();
788 if ((handle == nullptr) || (grantorIdx >= mGrantors.size())) {
789 return nullptr;
790 }
791
792 int fdIndex = mGrantors[grantorIdx].fdIndex;
793 /*
794 * Offset for mmap must be a multiple of PAGE_SIZE.
795 */
796 int mapOffset = (mGrantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
797 int mapLength =
798 mGrantors[grantorIdx].offset - mapOffset + mGrantors[grantorIdx].extent;
799
800 void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED,
801 handle->data[fdIndex], mapOffset);
802 return (address == MAP_FAILED)
803 ? nullptr
804 : reinterpret_cast<uint8_t*>(address) +
805 (mGrantors[grantorIdx].offset - mapOffset);
806}
807
808template <typename T, MQFlavor flavor>
809void MessageQueue<T, flavor>::unmapGrantorDescr(void* address,
810 uint32_t grantorIdx) {
811 auto mGrantors = mDesc->getGrantors();
812 if ((address == nullptr) || (grantorIdx >= mGrantors.size())) {
813 return;
814 }
815
816 int mapOffset = (mGrantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
817 int mapLength =
818 mGrantors[grantorIdx].offset - mapOffset + mGrantors[grantorIdx].extent;
819 void* baseAddress = reinterpret_cast<uint8_t*>(address) -
820 (mGrantors[grantorIdx].offset - mapOffset);
821 if (baseAddress) munmap(baseAddress, mapLength);
822}
823
824} // namespace hardware
825} // namespace android
826#endif // HIDL_MQ_H