blob: f41b43e7c9a787fff4dd9a126f67563e183e576a [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 {
34 /**
35 * @param Desc MQDescriptor describing the FMQ.
36 * @param resetPointers bool indicating whether the read/write pointers
37 * should be reset or not.
38 */
Hridya Valsaraju7eff3422016-12-27 11:54:13 -080039 MessageQueue(const MQDescriptor<T, flavor>& Desc, bool resetPointers = true);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080040
41 ~MessageQueue();
42
43 /**
44 * This constructor uses Ashmem shared memory to create an FMQ
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -080045 * that can contain a maximum of 'numElementsInQueue' elements of type T.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080046 *
47 * @param numElementsInQueue Capacity of the MessageQueue in terms of T.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -080048 * @param configureEventFlagWord Boolean that specifies if memory should
49 * also be allocated and mapped for an EventFlag word.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080050 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -080051 MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord = false);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080052
53 /**
54 * @return Number of items of type T that can be written into the FMQ
55 * without a read.
56 */
57 size_t availableToWrite() const;
58
59 /**
60 * @return Number of items of type T that are waiting to be read from the
61 * FMQ.
62 */
63 size_t availableToRead() const;
64
65 /**
66 * Returns the size of type T in bytes.
67 *
68 * @param Size of T.
69 */
70 size_t getQuantumSize() const;
71
72 /**
73 * Returns the size of the FMQ in terms of the size of type T.
74 *
75 * @return Number of items of type T that will fit in the FMQ.
76 */
77 size_t getQuantumCount() const;
78
79 /**
80 * @return Whether the FMQ is configured correctly.
81 */
82 bool isValid() const;
83
84 /**
85 * Non-blocking write to FMQ.
86 *
87 * @param data Pointer to the object of type T to be written into the FMQ.
88 *
89 * @return Whether the write was successful.
90 */
91 bool write(const T* data);
92
93 /**
94 * Non-blocking read from FMQ.
95 *
96 * @param data Pointer to the memory where the object read from the FMQ is
97 * copied to.
98 *
99 * @return Whether the read was successful.
100 */
101 bool read(T* data);
102
103 /**
104 * Write some data into the FMQ without blocking.
105 *
106 * @param data Pointer to the array of items of type T.
107 * @param count Number of items in array.
108 *
109 * @return Whether the write was successful.
110 */
111 bool write(const T* data, size_t count);
112
113 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800114 * Perform a blocking write of 'count' items into the FMQ using EventFlags.
115 * Does not support partial writes.
116 *
117 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
118 * associated with the FMQ and it is used in that case.
119 *
120 * The application code must ensure that 'evFlag' used by the
121 * reader(s)/writer is based upon the same EventFlag word.
122 *
123 * The method will return false without blocking if any of the following
124 * conditions are true:
125 * - If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
126 * - If the flavor of the FMQ is synchronized and the 'readNotification' bit mask is zero.
127 * - If 'count' is greater than the FMQ size.
128 *
129 * If the flavor of the FMQ is synchronized and there is insufficient space
130 * available to write into it, the EventFlag bit mask 'readNotification' is
131 * is waited upon.
132 *
133 * Upon a successful write, wake is called on 'writeNotification' (if
134 * non-zero).
135 *
136 * @param data Pointer to the array of items of type T.
137 * @param count Number of items in array.
138 * @param readNotification The EventFlag bit mask to wait on if there is not
139 * enough space in FMQ to write 'count' items.
140 * @param writeNotification The EventFlag bit mask to call wake on
141 * a successful write. No wake is called if 'writeNotification' is zero.
142 * @param timeOutNanos Number of nanoseconds after which the blocking
143 * write attempt is aborted.
144 * @param evFlag The EventFlag object to be used for blocking. If nullptr,
145 * it is checked whether the FMQ owns an EventFlag object and that is used
146 * for blocking instead.
147 *
148 * @return Whether the write was successful.
149 */
150
151 bool writeBlocking(const T* data, size_t count, uint32_t readNotification,
152 uint32_t writeNotification, int64_t timeOutNanos = 0,
153 android::hardware::EventFlag* evFlag = nullptr);
154
155 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800156 * Read some data from the FMQ without blocking.
157 *
158 * @param data Pointer to the array to which read data is to be written.
159 * @param count Number of items to be read.
160 *
161 * @return Whether the read was successful.
162 */
163 bool read(T* data, size_t count);
164
165 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800166 * Perform a blocking read operation of 'count' items from the FMQ. Does not
167 * perform a partial read.
168 *
169 * If 'evFlag' is nullptr, it is checked whether there is an EventFlag object
170 * associated with the FMQ and it is used in that case.
171 *
172 * The application code must ensure that 'evFlag' used by the
173 * reader(s)/writer is based upon the same EventFlag word.
174 *
175 * The method will return false without blocking if any of the following
176 * conditions are true:
177 * -If 'evFlag' is nullptr and the FMQ does not own an EventFlag object.
178 * -If the 'writeNotification' bit mask is zero.
179 * -If 'count' is greater than the FMQ size.
180 *
181 * If FMQ does not contain 'count' items, the eventFlag bit mask
182 * 'writeNotification' is waited upon. Upon a successful read from the FMQ,
183 * wake is called on 'readNotification' (if non-zero).
184 *
185 * @param data Pointer to the array to which read data is to be written.
186 * @param count Number of items to be read.
187 * @param readNotification The EventFlag bit mask to call wake on after
188 * a successful read. No wake is called if 'readNotification' is zero.
189 * @param writeNotification The EventFlag bit mask to call a wait on
190 * if there is insufficient data in the FMQ to be read.
191 * @param timeOutNanos Number of nanoseconds after which the blocking
192 * read attempt is aborted.
193 * @param evFlag The EventFlag object to be used for blocking.
194 *
195 * @return Whether the read was successful.
196 */
197 bool readBlocking(T* data, size_t count, uint32_t readNotification,
198 uint32_t writeNotification, int64_t timeOutNanos = 0,
199 android::hardware::EventFlag* evFlag = nullptr);
200
201 /**
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800202 * Get a pointer to the MQDescriptor object that describes this FMQ.
203 *
204 * @return Pointer to the MQDescriptor associated with the FMQ.
205 */
Hridya Valsaraju7eff3422016-12-27 11:54:13 -0800206 const MQDescriptor<T, flavor>* getDesc() const { return mDesc.get(); }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800207
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800208 /**
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800209 * Get a pointer to the EventFlag word if there is one associated with this FMQ.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800210 *
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800211 * @return Pointer to an EventFlag word, will return nullptr if not
212 * configured. This method does not transfer ownership. The EventFlag
213 * word will be unmapped by the MessageQueue destructor.
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800214 */
215 std::atomic<uint32_t>* getEventFlagWord() const { return mEvFlagWord; }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800216private:
217 struct region {
218 uint8_t* address;
219 size_t length;
220 };
221 struct transaction {
222 region first;
223 region second;
224 };
225
226 size_t writeBytes(const uint8_t* data, size_t size);
227 transaction beginWrite(size_t nBytesDesired) const;
228 void commitWrite(size_t nBytesWritten);
229
230 size_t readBytes(uint8_t* data, size_t size);
231 transaction beginRead(size_t nBytesDesired) const;
232 void commitRead(size_t nBytesRead);
233
234 size_t availableToWriteBytes() const;
235 size_t availableToReadBytes() const;
236
237 MessageQueue(const MessageQueue& other) = delete;
238 MessageQueue& operator=(const MessageQueue& other) = delete;
239 MessageQueue();
240
241 void* mapGrantorDescr(uint32_t grantorIdx);
242 void unmapGrantorDescr(void* address, uint32_t grantorIdx);
243 void initMemory(bool resetPointers);
244
Hridya Valsaraju7eff3422016-12-27 11:54:13 -0800245 std::unique_ptr<MQDescriptor<T, flavor>> mDesc;
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800246 uint8_t* mRing = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800247 /*
248 * TODO(b/31550092): Change to 32 bit read and write pointer counters.
249 */
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800250 std::atomic<uint64_t>* mReadPtr = nullptr;
251 std::atomic<uint64_t>* mWritePtr = nullptr;
252
253 std::atomic<uint32_t>* mEvFlagWord = nullptr;
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800254
255 /*
256 * This EventFlag object will be owned by the FMQ and will have the same
257 * lifetime.
258 */
259 android::hardware::EventFlag* mEventFlag = nullptr;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800260};
261
262template <typename T, MQFlavor flavor>
263void MessageQueue<T, flavor>::initMemory(bool resetPointers) {
264 /*
265 * Verify that the the Descriptor contains the minimum number of grantors
266 * the native_handle is valid and T matches quantum size.
267 */
268 if ((mDesc == nullptr) || !mDesc->isHandleValid() ||
Hridya Valsaraju7eff3422016-12-27 11:54:13 -0800269 (mDesc->countGrantors() < MQDescriptor<T, flavor>::kMinGrantorCount) ||
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800270 (mDesc->getQuantum() != sizeof(T))) {
271 return;
272 }
273
274 if (flavor == kSynchronizedReadWrite) {
275 mReadPtr =
276 reinterpret_cast<std::atomic<uint64_t>*>
Hridya Valsaraju7eff3422016-12-27 11:54:13 -0800277 (mapGrantorDescr(MQDescriptor<T, flavor>::READPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800278 } else {
279 /*
280 * The unsynchronized write flavor of the FMQ may have multiple readers
281 * and each reader would have their own read pointer counter.
282 */
283 mReadPtr = new (std::nothrow) std::atomic<uint64_t>;
284 }
285
286 CHECK(mReadPtr != nullptr);
287
288 mWritePtr =
289 reinterpret_cast<std::atomic<uint64_t>*>
Hridya Valsaraju7eff3422016-12-27 11:54:13 -0800290 (mapGrantorDescr(MQDescriptor<T, flavor>::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
301 mRing = reinterpret_cast<uint8_t*>(mapGrantorDescr
Hridya Valsaraju7eff3422016-12-27 11:54:13 -0800302 (MQDescriptor<T, flavor>::DATAPTRPOS));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800303 CHECK(mRing != nullptr);
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800304
305 mEvFlagWord = static_cast<std::atomic<uint32_t>*>(
Hridya Valsaraju7eff3422016-12-27 11:54:13 -0800306 mapGrantorDescr(MQDescriptor<T, flavor>::EVFLAGWORDPOS));
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800307 if (mEvFlagWord != nullptr) {
308 android::hardware::EventFlag::createEventFlag(mEvFlagWord, &mEventFlag);
309 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800310}
311
312template <typename T, MQFlavor flavor>
Hridya Valsaraju7eff3422016-12-27 11:54:13 -0800313MessageQueue<T, flavor>::MessageQueue(const MQDescriptor<T, flavor>& Desc, bool resetPointers) {
314 mDesc = std::unique_ptr<MQDescriptor<T, flavor>>(new (std::nothrow) MQDescriptor<T, flavor>(Desc));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800315 if (mDesc == nullptr) {
316 return;
317 }
318
319 initMemory(resetPointers);
320}
321
322template <typename T, MQFlavor flavor>
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800323MessageQueue<T, flavor>::MessageQueue(size_t numElementsInQueue, bool configureEventFlagWord) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800324 /*
325 * The FMQ needs to allocate memory for the ringbuffer as well as for the
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800326 * read and write pointer counters. If an EventFlag word is to be configured,
327 * we also need to allocate memory for the same/
328 */
329 size_t kQueueSizeBytes = numElementsInQueue * sizeof(T);
330 size_t kMetaDataSize = 2 * sizeof(android::hardware::RingBufferPosition);
331
332 if (configureEventFlagWord) {
333 kMetaDataSize+= sizeof(std::atomic<uint32_t>);
334 }
335
336 /*
337 * Ashmem memory region size needs to
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800338 * be specified in page-aligned bytes.
339 */
340 size_t kAshmemSizePageAligned =
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800341 (kQueueSizeBytes + kMetaDataSize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800342
343 /*
344 * Create an ashmem region to map the memory for the ringbuffer,
345 * read counter and write counter.
346 */
347 int ashmemFd = ashmem_create_region("MessageQueue", kAshmemSizePageAligned);
348 ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
349
350 /*
351 * The native handle will contain the fds to be mapped.
352 */
353 native_handle_t* mqHandle =
354 native_handle_create(1 /* numFds */, 0 /* numInts */);
355 if (mqHandle == nullptr) {
356 return;
357 }
358
359 mqHandle->data[0] = ashmemFd;
Hridya Valsaraju7eff3422016-12-27 11:54:13 -0800360 mDesc = std::unique_ptr<MQDescriptor<T, flavor>>(
361 new (std::nothrow) MQDescriptor<T, flavor>(kQueueSizeBytes,
Hridya Valsaraju92b79dc2016-12-19 14:57:44 -0800362 mqHandle,
363 sizeof(T),
364 configureEventFlagWord));
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800365 if (mDesc == nullptr) {
366 return;
367 }
368 initMemory(true);
369}
370
371template <typename T, MQFlavor flavor>
372MessageQueue<T, flavor>::~MessageQueue() {
373 if (flavor == kUnsynchronizedWrite) {
374 delete mReadPtr;
375 } else {
Hridya Valsaraju7eff3422016-12-27 11:54:13 -0800376 unmapGrantorDescr(mReadPtr, MQDescriptor<T, flavor>::READPTRPOS);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800377 }
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800378 if (mWritePtr != nullptr) {
379 unmapGrantorDescr(mWritePtr,
Hridya Valsaraju7eff3422016-12-27 11:54:13 -0800380 MQDescriptor<T, flavor>::WRITEPTRPOS);
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800381 }
382 if (mRing != nullptr) {
383 unmapGrantorDescr(mRing, MQDescriptor<T, flavor>::DATAPTRPOS);
384 }
385 if (mEvFlagWord != nullptr) {
386 unmapGrantorDescr(mEvFlagWord, MQDescriptor<T, flavor>::EVFLAGWORDPOS);
387 android::hardware::EventFlag::deleteEventFlag(&mEventFlag);
388 }
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800389}
390
391template <typename T, MQFlavor flavor>
392bool MessageQueue<T, flavor>::write(const T* data) {
393 return write(data, 1);
394}
395
396template <typename T, MQFlavor flavor>
397bool MessageQueue<T, flavor>::read(T* data) {
398 return read(data, 1);
399}
400
401template <typename T, MQFlavor flavor>
402bool MessageQueue<T, flavor>::write(const T* data, size_t count) {
403 /*
404 * If read/write synchronization is not enabled, data in the queue
405 * will be overwritten by a write operation when full.
406 */
407 if ((flavor == kSynchronizedReadWrite && (availableToWriteBytes() < sizeof(T) * count)) ||
408 (count > getQuantumCount()))
409 return false;
410
411 return (writeBytes(reinterpret_cast<const uint8_t*>(data),
412 sizeof(T) * count) == sizeof(T) * count);
413}
414
415template <typename T, MQFlavor flavor>
Hridya Valsarajuf0ffb832016-12-28 08:46:42 -0800416bool MessageQueue<T, flavor>::writeBlocking(const T* data,
417 size_t count,
418 uint32_t readNotification,
419 uint32_t writeNotification,
420 int64_t timeOutNanos,
421 android::hardware::EventFlag* evFlag) {
422 /*
423 * If evFlag is null and the FMQ does not have its own EventFlag object
424 * return false;
425 * If the flavor is kSynchronizedReadWrite and the readNotification
426 * bit mask is zero return false;
427 * If the count is greater than queue size, return false
428 * to prevent blocking until timeOut.
429 */
430 if (evFlag == nullptr) {
431 evFlag = mEventFlag;
432 if (evFlag == nullptr) {
433 return false;
434 }
435 }
436
437 if ((readNotification == 0 && flavor == kSynchronizedReadWrite) ||
438 (count > getQuantumCount())) {
439 return false;
440 }
441
442 /*
443 * There is no need to wait for a readNotification if the flavor
444 * of the queue is kUnsynchronizedWrite or sufficient space to write
445 * is already present in the FMQ. The latter would be the case when
446 * read operations read more number of messages than
447 * write operations write. In other words, a single large read may clear the FMQ
448 * after multiple small writes. This would fail to clear a pending
449 * readNotification bit since EventFlag bits can only be cleared
450 * by a wait() call, however the bit would be correctly cleared by the next
451 * blockingWrite() call.
452 */
453
454 bool result = write(data, count);
455 if (result) {
456 if (writeNotification) {
457 evFlag->wake(writeNotification);
458 }
459 return result;
460 }
461
462 bool endWait = false;
463 while (endWait == false) {
464 uint32_t efState = 0;
465 /*
466 * wait() will return immediately if there was a pending read
467 * notification.
468 */
469 status_t status = evFlag->wait(readNotification, &efState, timeOutNanos);
470 switch(status) {
471 case android::NO_ERROR:
472 /*
473 * If wait() returns NO_ERROR, break and check efState.
474 */
475 break;
476 case android::TIMED_OUT:
477 /*
478 * If wait() returns android::TIMEDOUT, break out of the while loop
479 * and return false;
480 */
481 endWait = true;
482 continue;
483 case -EAGAIN:
484 case -EINTR:
485 /*
486 * For errors -EAGAIN and -EINTR, go back to wait.
487 */
488 continue;
489 default:
490 /*
491 * Throw an error for any other error code since it is unexpected.
492 */
493
494 endWait = true;
495 ALOGE("Unexpected error code from EventFlag Wait %d", status);
496 continue;
497 }
498
499 /*
500 * If the wake() was not due to the readNotification bit or if
501 * there is still insufficient space to write to the FMQ,
502 * keep waiting for another readNotification.
503 */
504 if ((efState & readNotification) && write(data, count)) {
505 if (writeNotification) {
506 evFlag->wake(writeNotification);
507 }
508 result = true;
509 endWait = true;
510 }
511 }
512
513 return result;
514}
515
516template <typename T, MQFlavor flavor>
517bool MessageQueue<T, flavor>::readBlocking(T* data,
518 size_t count,
519 uint32_t readNotification,
520 uint32_t writeNotification,
521 int64_t timeOutNanos,
522 android::hardware::EventFlag* evFlag) {
523 /*
524 * If evFlag is null and the FMQ does not own its own EventFlag object
525 * return false;
526 * If the writeNotification bit mask is zero return false;
527 * If the count is greater than queue size, return false to prevent
528 * blocking until timeOut.
529 */
530 if (evFlag == nullptr) {
531 evFlag = mEventFlag;
532 if (evFlag == nullptr) {
533 return false;
534 }
535 }
536
537 if (writeNotification == 0 || count > getQuantumCount()) {
538 return false;
539 }
540
541 /*
542 * There is no need to wait for a write notification if sufficient
543 * data to read is already present in the FMQ. This would be the
544 * case when read operations read lesser number of messages than
545 * a write operation and multiple reads would be required to clear the queue
546 * after a single write operation. This check would fail to clear a pending
547 * writeNotification bit since EventFlag bits can only be cleared
548 * by a wait() call, however the bit would be correctly cleared by the next
549 * readBlocking() call.
550 */
551
552 bool result = read(data, count);
553 if (result) {
554 if (readNotification) {
555 evFlag->wake(readNotification);
556 }
557 return result;
558 }
559
560 bool endWait = false;
561 while (endWait == false) {
562 uint32_t efState = 0;
563 /*
564 * wait() will return immediately if there was a pending write
565 * notification.
566 */
567 status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos);
568 switch(status) {
569 case android::NO_ERROR:
570 /*
571 * If wait() returns NO_ERROR, break and check efState.
572 */
573 break;
574 case android::TIMED_OUT:
575 /*
576 * If wait() returns android::TIMEDOUT, break out of the while loop
577 * and return false;
578 */
579 endWait = true;
580 continue;
581 case -EAGAIN:
582 case -EINTR:
583 /*
584 * For errors -EAGAIN and -EINTR, go back to wait.
585 */
586 continue;
587 default:
588 /*
589 * Throw an error for any other error code since it is unexpected.
590 */
591
592 endWait = true;
593 ALOGE("Unexpected error code from EventFlag Wait %d", status);
594 continue;
595 }
596
597 /*
598 * If the wake() was not due to the writeNotification bit being set
599 * or if the data in FMQ is still insufficient, go back to waiting
600 * for another write notification.
601 */
602 if ((efState & writeNotification) && read(data, count)) {
603 if (readNotification) {
604 evFlag->wake(readNotification);
605 }
606 result = true;
607 endWait = true;
608 }
609 }
610
611 return result;
612}
613
614template <typename T, MQFlavor flavor>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800615__attribute__((no_sanitize("integer")))
616bool MessageQueue<T, flavor>::read(T* data, size_t count) {
617 if (availableToReadBytes() < sizeof(T) * count) return false;
618 /*
619 * If it is detected that the data in the queue was overwritten
620 * due to the reader process being too slow, the read pointer counter
621 * is set to the same as the write pointer counter to indicate error
622 * and the read returns false;
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -0800623 * Need acquire/release memory ordering for mWritePtr.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800624 */
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -0800625 auto writePtr = mWritePtr->load(std::memory_order_acquire);
626 /*
627 * A relaxed load is sufficient for mReadPtr since there will be no
628 * stores to mReadPtr from a different thread.
629 */
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800630 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
631
632 if (writePtr - readPtr > mDesc->getSize()) {
633 mReadPtr->store(writePtr, std::memory_order_release);
634 return false;
635 }
636
637 return readBytes(reinterpret_cast<uint8_t*>(data), sizeof(T) * count) ==
638 sizeof(T) * count;
639}
640
641template <typename T, MQFlavor flavor>
642size_t MessageQueue<T, flavor>::availableToWriteBytes() const {
643 return mDesc->getSize() - availableToReadBytes();
644}
645
646template <typename T, MQFlavor flavor>
647size_t MessageQueue<T, flavor>::availableToWrite() const {
648 return availableToWriteBytes()/sizeof(T);
649}
650
651template <typename T, MQFlavor flavor>
652size_t MessageQueue<T, flavor>::availableToRead() const {
653 return availableToReadBytes()/sizeof(T);
654}
655
656template <typename T, MQFlavor flavor>
657size_t MessageQueue<T, flavor>::writeBytes(const uint8_t* data, size_t size) {
658 transaction tx = beginWrite(size);
659 memcpy(tx.first.address, data, tx.first.length);
660 memcpy(tx.second.address, data + tx.first.length, tx.second.length);
661 size_t result = tx.first.length + tx.second.length;
662 commitWrite(result);
663 return result;
664}
665
666/*
667 * The below method does not check for available space since it was already
668 * checked by write() API which invokes writeBytes() which in turn calls
669 * beginWrite().
670 */
671template <typename T, MQFlavor flavor>
672typename MessageQueue<T, flavor>::transaction MessageQueue<T, flavor>::beginWrite(
673 size_t nBytesDesired) const {
674 transaction result;
675 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
676 size_t writeOffset = writePtr % mDesc->getSize();
677 size_t contiguous = mDesc->getSize() - writeOffset;
678 if (contiguous < nBytesDesired) {
679 result = {{mRing + writeOffset, contiguous},
680 {mRing, nBytesDesired - contiguous}};
681 } else {
682 result = {
683 {mRing + writeOffset, nBytesDesired}, {0, 0},
684 };
685 }
686 return result;
687}
688
689template <typename T, MQFlavor flavor>
690__attribute__((no_sanitize("integer")))
691void MessageQueue<T, flavor>::commitWrite(size_t nBytesWritten) {
692 auto writePtr = mWritePtr->load(std::memory_order_relaxed);
693 writePtr += nBytesWritten;
694 mWritePtr->store(writePtr, std::memory_order_release);
695}
696
697template <typename T, MQFlavor flavor>
698size_t MessageQueue<T, flavor>::availableToReadBytes() const {
699 /*
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -0800700 * This method is invoked by implementations of both read() and write() and
701 * hence requries a memory_order_acquired load for both mReadPtr and
702 * mWritePtr.
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800703 */
Hridya Valsaraju04cdd2c2016-12-21 08:38:57 -0800704 return mWritePtr->load(std::memory_order_acquire) -
705 mReadPtr->load(std::memory_order_acquire);
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -0800706}
707
708template <typename T, MQFlavor flavor>
709size_t MessageQueue<T, flavor>::readBytes(uint8_t* data, size_t size) {
710 transaction tx = beginRead(size);
711 memcpy(data, tx.first.address, tx.first.length);
712 memcpy(data + tx.first.length, tx.second.address, tx.second.length);
713 size_t result = tx.first.length + tx.second.length;
714 commitRead(result);
715 return result;
716}
717
718/*
719 * The below method does not check whether nBytesDesired bytes are available
720 * to read because the check is performed in the read() method before
721 * readBytes() is invoked.
722 */
723template <typename T, MQFlavor flavor>
724typename MessageQueue<T, flavor>::transaction MessageQueue<T, flavor>::beginRead(
725 size_t nBytesDesired) const {
726 transaction result;
727 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
728 size_t readOffset = readPtr % mDesc->getSize();
729 size_t contiguous = mDesc->getSize() - readOffset;
730
731 if (contiguous < nBytesDesired) {
732 result = {{mRing + readOffset, contiguous},
733 {mRing, nBytesDesired - contiguous}};
734 } else {
735 result = {
736 {mRing + readOffset, nBytesDesired}, {0, 0},
737 };
738 }
739
740 return result;
741}
742
743template <typename T, MQFlavor flavor>
744__attribute__((no_sanitize("integer")))
745void MessageQueue<T, flavor>::commitRead(size_t nBytesRead) {
746 auto readPtr = mReadPtr->load(std::memory_order_relaxed);
747 readPtr += nBytesRead;
748 mReadPtr->store(readPtr, std::memory_order_release);
749}
750
751template <typename T, MQFlavor flavor>
752size_t MessageQueue<T, flavor>::getQuantumSize() const {
753 return mDesc->getQuantum();
754}
755
756template <typename T, MQFlavor flavor>
757size_t MessageQueue<T, flavor>::getQuantumCount() const {
758 return mDesc->getSize() / mDesc->getQuantum();
759}
760
761template <typename T, MQFlavor flavor>
762bool MessageQueue<T, flavor>::isValid() const {
763 return mRing != nullptr && mReadPtr != nullptr && mWritePtr != nullptr;
764}
765
766template <typename T, MQFlavor flavor>
767void* MessageQueue<T, flavor>::mapGrantorDescr(uint32_t grantorIdx) {
768 const native_handle_t* handle = mDesc->getNativeHandle()->handle();
769 auto mGrantors = mDesc->getGrantors();
770 if ((handle == nullptr) || (grantorIdx >= mGrantors.size())) {
771 return nullptr;
772 }
773
774 int fdIndex = mGrantors[grantorIdx].fdIndex;
775 /*
776 * Offset for mmap must be a multiple of PAGE_SIZE.
777 */
778 int mapOffset = (mGrantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
779 int mapLength =
780 mGrantors[grantorIdx].offset - mapOffset + mGrantors[grantorIdx].extent;
781
782 void* address = mmap(0, mapLength, PROT_READ | PROT_WRITE, MAP_SHARED,
783 handle->data[fdIndex], mapOffset);
784 return (address == MAP_FAILED)
785 ? nullptr
786 : reinterpret_cast<uint8_t*>(address) +
787 (mGrantors[grantorIdx].offset - mapOffset);
788}
789
790template <typename T, MQFlavor flavor>
791void MessageQueue<T, flavor>::unmapGrantorDescr(void* address,
792 uint32_t grantorIdx) {
793 auto mGrantors = mDesc->getGrantors();
794 if ((address == nullptr) || (grantorIdx >= mGrantors.size())) {
795 return;
796 }
797
798 int mapOffset = (mGrantors[grantorIdx].offset / PAGE_SIZE) * PAGE_SIZE;
799 int mapLength =
800 mGrantors[grantorIdx].offset - mapOffset + mGrantors[grantorIdx].extent;
801 void* baseAddress = reinterpret_cast<uint8_t*>(address) -
802 (mGrantors[grantorIdx].offset - mapOffset);
803 if (baseAddress) munmap(baseAddress, mapLength);
804}
805
806} // namespace hardware
807} // namespace android
808#endif // HIDL_MQ_H