blob: eaaad0207be2acd8fd5d56be10eb1a5d548a4f40 [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 Valsaraju7fd43e32017-01-06 10:19:52 -080034 typedef MQDescriptor<T,flavor> Descriptor;
35
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 */
152
153 bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
154 uint32_t writeNotification, int64_t timeOutNanos = 0,
155 android::hardware::EventFlag* evFlag = nullptr);
156
157 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800158 * Read some data from the FMQ without blocking.
159 *
160 * @param data Pointer to the array to which read data is to be written.
161 * @param count Number of items to be read.
162 *
163 * @return Whether the read was successful.
164 */
165 bool read(T* data, size_t count);
166
167 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800168 * Perform a blocking read operation of 'count' items from the FMQ. Does not
169 * perform a partial read.
170 *
171 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
172 * associated with the FMQ and it is used in that case.
173 *
174 * The application code must ensure that 'evFlag' used by the
175 * reader(s)/writer is based upon the same EventFlag word.
176 *
177 * The method will return false without blocking if any of the following
178 * conditions are true:
179 * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
180 * -If the 'writeNotification' bit mask is zero.
181 * -If 'count' is greater than the FMQ size.
182 *
183 * If FMQ does not contain 'count' items, the eventFlag bit mask
184 * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
185 * wake is called on 'readNotification' (if non-zero).
186 *
187 * @param data Pointer to the array to which read data is to be written.
188 * @param count Number of items to be read.
189 * @param readNotification The EventFlag bit mask to call wake on after
190 * a successful read. No wake is called if 'readNotification' is zero.
191 * @param writeNotification The EventFlag bit mask to call a wait on
192 * if there is insufficient data in the FMQ to be read.
193 * @param timeOutNanos Number of nanoseconds after which the blocking
194 * read attempt is aborted.
195 * @param evFlag The EventFlag object to be used for blocking.
196 *
197 * @return Whether the read was successful.
198 */
199 bool readBlocking(T* data, size_t count, uint32_t readNotification,
200 uint32_t writeNotification, int64_t timeOutNanos = 0,
201 android::hardware::EventFlag* evFlag = nullptr);
202
203 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800204 * Get a pointer to the MQDescriptor object that describes this FMQ.
205 *
206 * @return Pointer to the MQDescriptor associated with the FMQ.
207 */
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800208 const Descriptor* getDesc() const { return mDesc.get(); }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800209
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800210 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800211 * Get a pointer to the EventFlag word if there is one associated with this FMQ.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800212 *
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800213 * @return Pointer to an EventFlag word, will return nullptr if not
214 * configured. This method does not transfer ownership. The EventFlag
215 * word will be unmapped by the MessageQueue destructor.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800216 */
217 std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800218private:
219 struct region {
220 uint8_t* address;
221 size_t length;
222 };
223 struct transaction {
224 region first;
225 region second;
226 };
227
228 size_t writeBytes(const uint8_t* data, size_t size);
229 transaction beginWrite(size_t nBytesDesired) const;
230 void commitWrite(size_t nBytesWritten);
231
232 size_t readBytes(uint8_t* data, size_t size);
233 transaction beginRead(size_t nBytesDesired) const;
234 void commitRead(size_t nBytesRead);
235
236 size_t availableToWriteBytes() const;
237 size_t availableToReadBytes() const;
238
239 MessageQueue(const MessageQueue& other) = delete;
240 MessageQueue& operator=(const MessageQueue& other) = delete;
241 MessageQueue();
242
243 void* mapGrantorDescr(uint32_t grantorIdx);
244 void unmapGrantorDescr(void* address, uint32_t grantorIdx);
245 void initMemory(bool resetPointers);
246
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800247 std::unique_ptr<Descriptor> mDesc;
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800248 uint8_t* mRing = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800249 /*
250 * TODO(b/31550092): Change to 32 bit read and write pointer counters.
251 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800252 std::atomic<uint64_t>* mReadPtr = nullptr;
253 std::atomic<uint64_t>* mWritePtr = nullptr;
254
255 std::atomic<uint32_t>* mEvFlagWord = nullptr;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800256
257 /*
258 * This EventFlag object will be owned by the FMQ and will have the same
259 * lifetime.
260 */
261 android::hardware::EventFlag* mEventFlag = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800262};
263
264template <typename T, MQFlavor flavor>
265void MessageQueue<T, flavor>::initMemory(bool resetPointers) {
266 /*
267 * Verify that the the Descriptor contains the minimum number of grantors
268 * the native_handle is valid and T matches quantum size.
269 */
270 if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800271 (mDesc->countGrantors() < Descriptor::kMinGrantorCount) ||
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800272 (mDesc->getQuantum() != sizeof(T))) {
273 return;
274 }
275
276 if (flavor == kSynchronizedReadWrite) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800277 mReadPtr = reinterpret_cast<std::atomic<uint64_t>*>(
278 mapGrantorDescr(Descriptor::READPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800279 } else {
280 /*
281 * The unsynchronized write flavor of the FMQ may have multiple readers
282 * and each reader would have their own read pointer counter.
283 */
284 mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
285 }
286
287 CHECK(mReadPtr != nullptr);
288
289 mWritePtr =
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800290 reinterpret_cast<std::atomic<uint64_t>*>(mapGrantorDescr(Descriptor::WRITEPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800291 CHECK(mWritePtr != nullptr);
292
293 if (resetPointers) {
294 mReadPtr->store(0, std::memory_order_release);
295 mWritePtr->store(0, std::memory_order_release);
296 } else if (flavor != kSynchronizedReadWrite) {
297 // Always reset the read pointer.
298 mReadPtr->store(0, std::memory_order_release);
299 }
300
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800301 mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr(Descriptor::DATAPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800302 CHECK(mRing != nullptr);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800303
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800304 mEvFlagWord = static_cast<std::atomic<uint32_t>*>(mapGrantorDescr(Descriptor::EVFLAGWORDPOS));
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800305 if (mEvFlagWord != nullptr) {
306 android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
307 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800308}
309
310template <typename T, MQFlavor flavor>
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800311MessageQueue<T, flavor>::MessageQueue(const Descriptor& Desc, bool resetPointers) {
312 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(Desc));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800313 if (mDesc == nullptr) {
314 return;
315 }
316
317 initMemory(resetPointers);
318}
319
320template <typename T, MQFlavor flavor>
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800321MessageQueue<T, flavor>::MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800322 /*
323 * The FMQ needs to allocate memory for the ringbuffer as well as for the
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800324 * read and write pointer counters. If an EventFlag word is to be configured,
325 * we also need to allocate memory for the same/
326 */
327 size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
328 size_t kMetaDataSize = 2 * sizeof(android::hardware::RingBufferPosition);
329
330 if (configureEventFlagWord) {
331 kMetaDataSize+= sizeof(std::atomic<uint32_t>);
332 }
333
334 /*
335 * Ashmem memory region size needs to
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800336 * be specified in page-aligned bytes.
337 */
338 size_t kAshmemSizePageAligned =
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800339 (kQueueSizeBytes + kMetaDataSize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800340
341 /*
342 * Create an ashmem region to map the memory for the ringbuffer,
343 * read counter and write counter.
344 */
345 int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
346 ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
347
348 /*
349 * The native handle will contain the fds to be mapped.
350 */
351 native_handle_t* mqHandle =
352 native_handle_create(1 /* numFds */, 0 /* numInts */);
353 if (mqHandle == nullptr) {
354 return;
355 }
356
357 mqHandle->data[0] = ashmemFd;
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800358 mDesc = std::unique_ptr<Descriptor>(new (std::nothrow) Descriptor(kQueueSizeBytes,
359 mqHandle,
360 sizeof(T),
361 configureEventFlagWord));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800362 if (mDesc == nullptr) {
363 return;
364 }
365 initMemory(true);
366}
367
368template <typename T, MQFlavor flavor>
369MessageQueue<T, flavor>::~MessageQueue() {
370 if (flavor == kUnsynchronizedWrite) {
371 delete mReadPtr;
372 } else {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800373 unmapGrantorDescr(mReadPtr, Descriptor::READPTRPOS);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800374 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800375 if (mWritePtr != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800376 unmapGrantorDescr(mWritePtr, Descriptor::WRITEPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800377 }
378 if (mRing != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800379 unmapGrantorDescr(mRing, Descriptor::DATAPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800380 }
381 if (mEvFlagWord != nullptr) {
Hridya Valsaraju7fd43e32017-01-06 10:19:52 -0800382 unmapGrantorDescr(mEvFlagWord, Descriptor::EVFLAGWORDPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800383 android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
384 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800385}
386
387template <typename T, MQFlavor flavor>
388bool MessageQueue<T, flavor>::write(const T* data) {
389 return write(data, 1);
390}
391
392template <typename T, MQFlavor flavor>
393bool MessageQueue<T, flavor>::read(T* data) {
394 return read(data, 1);
395}
396
397template <typename T, MQFlavor flavor>
398bool MessageQueue<T, flavor>::write(const T* data, size_t count) {
399 /*
400 * If read/write synchronization is not enabled, data in the queue
401 * will be overwritten by a write operation when full.
402 */
403 if ((flavor == kSynchronizedReadWrite && (availableToWriteBytes() < sizeof(T) * count)) ||
404 (count > getQuantumCount()))
405 return false;
406
407 return (writeBytes(reinterpret_cast<const uint8_t*>(data),
408 sizeof(T) * count) == sizeof(T) * count);
409}
410
411template <typename T, MQFlavor flavor>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800412bool MessageQueue<T, flavor>::writeBlocking(const T* data,
413 size_t count,
414 uint32_t readNotification,
415 uint32_t writeNotification,
416 int64_t timeOutNanos,
417 android::hardware::EventFlag* evFlag) {
418 /*
419 * If evFlag is null and the FMQ does not have its own EventFlag object
420 * return false;
421 * If the flavor is kSynchronizedReadWrite and the readNotification
422 * bit mask is zero return false;
423 * If the count is greater than queue size, return false
424 * to prevent blocking until timeOut.
425 */
426 if (evFlag == nullptr) {
427 evFlag = mEventFlag;
428 if (evFlag == nullptr) {
429 return false;
430 }
431 }
432
433 if ((readNotification == 0 && flavor == kSynchronizedReadWrite) ||
434 (count > getQuantumCount())) {
435 return false;
436 }
437
438 /*
439 * There is no need to wait for a readNotification if the flavor
440 * of the queue is kUnsynchronizedWrite or sufficient space to write
441 * is already present in the FMQ. The latter would be the case when
442 * read operations read more number of messages than
443 * write operations write. In other words, a single large read may clear the FMQ
444 * after multiple small writes. This would fail to clear a pending
445 * readNotification bit since EventFlag bits can only be cleared
446 * by a wait() call, however the bit would be correctly cleared by the next
447 * blockingWrite() call.
448 */
449
450 bool result = write(data, count);
451 if (result) {
452 if (writeNotification) {
453 evFlag->wake(writeNotification);
454 }
455 return result;
456 }
457
458 bool endWait = false;
459 while (endWait == false) {
460 uint32_t efState = 0;
461 /*
462 * wait() will return immediately if there was a pending read
463 * notification.
464 */
465 status_t status = evFlag->wait(readNotification, &efState, timeOutNanos);
466 switch(status) {
467 case android::NO_ERROR:
468 /*
469 * If wait() returns NO_ERROR, break and check efState.
470 */
471 break;
472 case android::TIMED_OUT:
473 /*
474 * If wait() returns android::TIMEDOUT, break out of the while loop
475 * and return false;
476 */
477 endWait = true;
478 continue;
479 case -EAGAIN:
480 case -EINTR:
481 /*
482 * For errors -EAGAIN and -EINTR, go back to wait.
483 */
484 continue;
485 default:
486 /*
487 * Throw an error for any other error code since it is unexpected.
488 */
489
490 endWait = true;
491 ALOGE("Unexpected error code from EventFlag Wait %d", status);
492 continue;
493 }
494
495 /*
496 * If the wake() was not due to the readNotification bit or if
497 * there is still insufficient space to write to the FMQ,
498 * keep waiting for another readNotification.
499 */
500 if ((efState & readNotification) && write(data, count)) {
501 if (writeNotification) {
502 evFlag->wake(writeNotification);
503 }
504 result = true;
505 endWait = true;
506 }
507 }
508
509 return result;
510}
511
512template <typename T, MQFlavor flavor>
513bool MessageQueue<T, flavor>::readBlocking(T* data,
514 size_t count,
515 uint32_t readNotification,
516 uint32_t writeNotification,
517 int64_t timeOutNanos,
518 android::hardware::EventFlag* evFlag) {
519 /*
520 * If evFlag is null and the FMQ does not own its own EventFlag object
521 * return false;
522 * If the writeNotification bit mask is zero return false;
523 * If the count is greater than queue size, return false to prevent
524 * blocking until timeOut.
525 */
526 if (evFlag == nullptr) {
527 evFlag = mEventFlag;
528 if (evFlag == nullptr) {
529 return false;
530 }
531 }
532
533 if (writeNotification == 0 || count > getQuantumCount()) {
534 return false;
535 }
536
537 /*
538 * There is no need to wait for a write notification if sufficient
539 * data to read is already present in the FMQ. This would be the
540 * case when read operations read lesser number of messages than
541 * a write operation and multiple reads would be required to clear the queue
542 * after a single write operation. This check would fail to clear a pending
543 * writeNotification bit since EventFlag bits can only be cleared
544 * by a wait() call, however the bit would be correctly cleared by the next
545 * readBlocking() call.
546 */
547
548 bool result = read(data, count);
549 if (result) {
550 if (readNotification) {
551 evFlag->wake(readNotification);
552 }
553 return result;
554 }
555
556 bool endWait = false;
557 while (endWait == false) {
558 uint32_t efState = 0;
559 /*
560 * wait() will return immediately if there was a pending write
561 * notification.
562 */
563 status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos);
564 switch(status) {
565 case android::NO_ERROR:
566 /*
567 * If wait() returns NO_ERROR, break and check efState.
568 */
569 break;
570 case android::TIMED_OUT:
571 /*
572 * If wait() returns android::TIMEDOUT, break out of the while loop
573 * and return false;
574 */
575 endWait = true;
576 continue;
577 case -EAGAIN:
578 case -EINTR:
579 /*
580 * For errors -EAGAIN and -EINTR, go back to wait.
581 */
582 continue;
583 default:
584 /*
585 * Throw an error for any other error code since it is unexpected.
586 */
587
588 endWait = true;
589 ALOGE("Unexpected error code from EventFlag Wait %d", status);
590 continue;
591 }
592
593 /*
594 * If the wake() was not due to the writeNotification bit being set
595 * or if the data in FMQ is still insufficient, go back to waiting
596 * for another write notification.
597 */
598 if ((efState & writeNotification) && read(data, count)) {
599 if (readNotification) {
600 evFlag->wake(readNotification);
601 }
602 result = true;
603 endWait = true;
604 }
605 }
606
607 return result;
608}
609
610template <typename T, MQFlavor flavor>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800611__attribute__((no_sanitize("integer")))
612bool MessageQueue<T, flavor>::read(T* data, size_t count) {
613 if (availableToReadBytes() < sizeof(T) * count) return false;
614 /*
615 * If it is detected that the data in the queue was overwritten
616 * due to the reader process being too slow, the read pointer counter
617 * is set to the same as the write pointer counter to indicate error
618 * and the read returns false;
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -0800619 * Need acquire/release memory ordering for mWritePtr.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800620 */
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -0800621 auto writePtr = mWritePtr->load(std::memory_order_acquire);
622 /*
623 * A relaxed load is sufficient for mReadPtr since there will be no
624 * stores to mReadPtr from a different thread.
625 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800626 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
627
628 if (writePtr - readPtr > mDesc->getSize()) {
629 mReadPtr->store(writePtr, std::memory_order_release);
630 return false;
631 }
632
633 return readBytes(reinterpret_cast<uint8_t*>(data), sizeof(T) * count) ==
634 sizeof(T) * count;
635}
636
637template <typename T, MQFlavor flavor>
638size_t MessageQueue<T, flavor>::availableToWriteBytes() const {
639 return mDesc->getSize() - availableToReadBytes();
640}
641
642template <typename T, MQFlavor flavor>
643size_t MessageQueue<T, flavor>::availableToWrite() const {
644 return availableToWriteBytes()/sizeof(T);
645}
646
647template <typename T, MQFlavor flavor>
648size_t MessageQueue<T, flavor>::availableToRead() const {
649 return availableToReadBytes()/sizeof(T);
650}
651
652template <typename T, MQFlavor flavor>
653size_t MessageQueue<T, flavor>::writeBytes(const uint8_t* data, size_t size) {
654 transaction tx = beginWrite(size);
655 memcpy(tx.first.address, data, tx.first.length);
656 memcpy(tx.second.address, data + tx.first.length, tx.second.length);
657 size_t result = tx.first.length + tx.second.length;
658 commitWrite(result);
659 return result;
660}
661
662/*
663 * The below method does not check for available space since it was already
664 * checked by write() API which invokes writeBytes() which in turn calls
665 * beginWrite().
666 */
667template <typename T, MQFlavor flavor>
668typename MessageQueue<T, flavor>::transaction MessageQueue<T, flavor>::beginWrite(
669 size_t nBytesDesired) const {
670 transaction result;
671 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
672 size_t writeOffset = writePtr % mDesc->getSize();
673 size_t contiguous = mDesc->getSize() - writeOffset;
674 if (contiguous < nBytesDesired) {
675 result = {{mRing + writeOffset, contiguous},
676 {mRing, nBytesDesired - contiguous}};
677 } else {
678 result = {
679 {mRing + writeOffset, nBytesDesired}, {0, 0},
680 };
681 }
682 return result;
683}
684
685template <typename T, MQFlavor flavor>
686__attribute__((no_sanitize("integer")))
687void MessageQueue<T, flavor>::commitWrite(size_t nBytesWritten) {
688 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
689 writePtr += nBytesWritten;
690 mWritePtr->store(writePtr, std::memory_order_release);
691}
692
693template <typename T, MQFlavor flavor>
694size_t MessageQueue<T, flavor>::availableToReadBytes() const {
695 /*
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -0800696 * This method is invoked by implementations of both read() and write() and
697 * hence requries a memory_order_acquired load for both mReadPtr and
698 * mWritePtr.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800699 */
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -0800700 return mWritePtr->load(std::memory_order_acquire) -
701 mReadPtr->load(std::memory_order_acquire);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800702}
703
704template <typename T, MQFlavor flavor>
705size_t MessageQueue<T, flavor>::readBytes(uint8_t* data, size_t size) {
706 transaction tx = beginRead(size);
707 memcpy(data, tx.first.address, tx.first.length);
708 memcpy(data + tx.first.length, tx.second.address, tx.second.length);
709 size_t result = tx.first.length + tx.second.length;
710 commitRead(result);
711 return result;
712}
713
714/*
715 * The below method does not check whether nBytesDesired bytes are available
716 * to read because the check is performed in the read() method before
717 * readBytes() is invoked.
718 */
719template <typename T, MQFlavor flavor>
720typename MessageQueue<T, flavor>::transaction MessageQueue<T, flavor>::beginRead(
721 size_t nBytesDesired) const {
722 transaction result;
723 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
724 size_t readOffset = readPtr % mDesc->getSize();
725 size_t contiguous = mDesc->getSize() - readOffset;
726
727 if (contiguous < nBytesDesired) {
728 result = {{mRing + readOffset, contiguous},
729 {mRing, nBytesDesired - contiguous}};
730 } else {
731 result = {
732 {mRing + readOffset, nBytesDesired}, {0, 0},
733 };
734 }
735
736 return result;
737}
738
739template <typename T, MQFlavor flavor>
740__attribute__((no_sanitize("integer")))
741void MessageQueue<T, flavor>::commitRead(size_t nBytesRead) {
742 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
743 readPtr += nBytesRead;
744 mReadPtr->store(readPtr, std::memory_order_release);
745}
746
747template <typename T, MQFlavor flavor>
748size_t MessageQueue<T, flavor>::getQuantumSize() const {
749 return mDesc->getQuantum();
750}
751
752template <typename T, MQFlavor flavor>
753size_t MessageQueue<T, flavor>::getQuantumCount() const {
754 return mDesc->getSize() / mDesc->getQuantum();
755}
756
757template <typename T, MQFlavor flavor>
758bool MessageQueue<T, flavor>::isValid() const {
759 return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
760}
761
762template <typename T, MQFlavor flavor>
763void* MessageQueue<T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
764 const native_handle_t* handle = mDesc->getNativeHandle()->handle();
765 auto mGrantors = mDesc->getGrantors();
766 if ((handle == nullptr) || (grantorIdx >= mGrantors.size())) {
767 return nullptr;
768 }
769
770 int fdIndex = mGrantors[grantorIdx].fdIndex;
771 /*
772 * Offset for mmap must be a multiple of PAGE_SIZE.
773 */
774 int mapOffset = (mGrantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
775 int mapLength =
776 mGrantors[grantorIdx].offset - mapOffset + mGrantors[grantorIdx].extent;
777
778 void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED,
779 handle->data[fdIndex], mapOffset);
780 return (address == MAP_FAILED)
781 ? nullptr
782 : reinterpret_cast<uint8_t*>(address) +
783 (mGrantors[grantorIdx].offset - mapOffset);
784}
785
786template <typename T, MQFlavor flavor>
787void MessageQueue<T, flavor>::unmapGrantorDescr(void* address,
788 uint32_t grantorIdx) {
789 auto mGrantors = mDesc->getGrantors();
790 if ((address == nullptr) || (grantorIdx >= mGrantors.size())) {
791 return;
792 }
793
794 int mapOffset = (mGrantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
795 int mapLength =
796 mGrantors[grantorIdx].offset - mapOffset + mGrantors[grantorIdx].extent;
797 void* baseAddress = reinterpret_cast<uint8_t*>(address) -
798 (mGrantors[grantorIdx].offset - mapOffset);
799 if (baseAddress) munmap(baseAddress, mapLength);
800}
801
802} // namespace hardware
803} // namespace android
804#endif // HIDL_MQ_H