Home | History | Annotate | Download | only in hidl
      1 /*
      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 _FMSGQ_DESCRIPTOR_H
     18 #define _FMSGQ_DESCRIPTOR_H
     19 
     20 #include <unistd.h>
     21 
     22 #include <cutils/native_handle.h>
     23 #include <hidl/HidlInternal.h>
     24 #include <hidl/HidlSupport.h>
     25 
     26 namespace android {
     27 namespace hardware {
     28 
     29 typedef uint64_t RingBufferPosition;
     30 
     31 struct GrantorDescriptor {
     32     uint32_t flags __attribute__ ((aligned(4)));
     33     uint32_t fdIndex __attribute__ ((aligned(4)));
     34     uint32_t offset __attribute__ ((aligned(4)));
     35     uint64_t extent __attribute__ ((aligned(8)));
     36 };
     37 
     38 static_assert(offsetof(GrantorDescriptor, flags) == 0, "wrong offset");
     39 static_assert(offsetof(GrantorDescriptor, fdIndex) == 4, "wrong offset");
     40 static_assert(offsetof(GrantorDescriptor, offset) == 8, "wrong offset");
     41 static_assert(offsetof(GrantorDescriptor, extent) == 16, "wrong offset");
     42 static_assert(sizeof(GrantorDescriptor) == 24, "wrong size");
     43 static_assert(__alignof(GrantorDescriptor) == 8, "wrong alignment");
     44 
     45 enum MQFlavor : uint32_t {
     46   /*
     47    * kSynchronizedReadWrite represents the wait-free synchronized flavor of the
     48    * FMQ. It is intended to be have a single reader and single writer.
     49    * Attempts to overflow/underflow returns a failure.
     50    */
     51   kSynchronizedReadWrite = 0x01,
     52   /*
     53    * kUnsynchronizedWrite represents the flavor of FMQ where writes always
     54    * succeed. This flavor allows one writer and many readers. A read operation
     55    * can detect an overwrite and reset the read counter.
     56    */
     57   kUnsynchronizedWrite = 0x02
     58 };
     59 
     60 template <typename T, MQFlavor flavor>
     61 struct MQDescriptor {
     62     MQDescriptor(
     63             const std::vector<GrantorDescriptor>& grantors,
     64             native_handle_t* nHandle, size_t size);
     65 
     66     MQDescriptor(size_t bufferSize, native_handle_t* nHandle,
     67                  size_t messageSize, bool configureEventFlag = false);
     68 
     69     MQDescriptor();
     70     ~MQDescriptor();
     71 
     72     explicit MQDescriptor(const MQDescriptor &other);
     73     MQDescriptor &operator=(const MQDescriptor &other) = delete;
     74 
     75     size_t getSize() const;
     76 
     77     size_t getQuantum() const;
     78 
     79     int32_t getFlags() const;
     80 
     81     bool isHandleValid() const { return mHandle != nullptr; }
     82     size_t countGrantors() const { return mGrantors.size(); }
     83 
     84     inline const ::android::hardware::hidl_vec<GrantorDescriptor> &grantors() const {
     85         return mGrantors;
     86     }
     87 
     88     inline ::android::hardware::hidl_vec<GrantorDescriptor> &grantors() {
     89         return mGrantors;
     90     }
     91 
     92     inline const ::native_handle_t *handle() const {
     93         return mHandle;
     94     }
     95 
     96     inline ::native_handle_t *handle() {
     97         return mHandle;
     98     }
     99 
    100     static const size_t kOffsetOfGrantors;
    101     static const size_t kOffsetOfHandle;
    102     enum GrantorType : int { READPTRPOS = 0, WRITEPTRPOS, DATAPTRPOS, EVFLAGWORDPOS };
    103 
    104     /*
    105      * There should at least be GrantorDescriptors for the read counter, write
    106      * counter and data buffer. A GrantorDescriptor for an EventFlag word is
    107      * not required if there is no need for blocking FMQ operations.
    108      */
    109     static constexpr int32_t kMinGrantorCount = DATAPTRPOS + 1;
    110 
    111     /*
    112      * Minimum number of GrantorDescriptors required if EventFlag support is
    113      * needed for blocking FMQ operations.
    114      */
    115     static constexpr int32_t kMinGrantorCountForEvFlagSupport = EVFLAGWORDPOS + 1;
    116 
    117     //TODO(b/34160777) Identify a better solution that supports remoting.
    118     static inline size_t alignToWordBoundary(size_t length) {
    119         constexpr size_t kAlignmentSize = 64;
    120         if (kAlignmentSize % __WORDSIZE != 0) {
    121             details::logAlwaysFatal("Incompatible word size");
    122         }
    123 
    124         /*
    125          * Check if alignment to word boundary would cause an overflow.
    126          */
    127         if (length > SIZE_MAX - kAlignmentSize/8 + 1) {
    128             details::logAlwaysFatal("Queue size too large");
    129         }
    130 
    131         return (length + kAlignmentSize/8 - 1) & ~(kAlignmentSize/8 - 1U);
    132     }
    133 
    134     static inline size_t isAlignedToWordBoundary(size_t offset) {
    135         constexpr size_t kAlignmentSize = 64;
    136         return (offset & (kAlignmentSize/8 - 1)) == 0;
    137     }
    138 private:
    139     ::android::hardware::hidl_vec<GrantorDescriptor> mGrantors;
    140     ::android::hardware::details::hidl_pointer<native_handle_t> mHandle;
    141     uint32_t mQuantum;
    142     uint32_t mFlags;
    143 };
    144 
    145 template<typename T, MQFlavor flavor>
    146 const size_t MQDescriptor<T, flavor>::kOffsetOfGrantors = offsetof(MQDescriptor, mGrantors);
    147 
    148 template<typename T, MQFlavor flavor>
    149 const size_t MQDescriptor<T, flavor>::kOffsetOfHandle = offsetof(MQDescriptor, mHandle);
    150 
    151 /*
    152  * MQDescriptorSync will describe the wait-free synchronized
    153  * flavor of FMQ.
    154  */
    155 template<typename T>
    156 using MQDescriptorSync = MQDescriptor<T, kSynchronizedReadWrite>;
    157 
    158 /*
    159  * MQDescriptorUnsync will describe the unsynchronized write
    160  * flavor of FMQ.
    161  */
    162 template<typename T>
    163 using MQDescriptorUnsync = MQDescriptor<T, kUnsynchronizedWrite>;
    164 
    165 template<typename T, MQFlavor flavor>
    166 MQDescriptor<T, flavor>::MQDescriptor(
    167         const std::vector<GrantorDescriptor>& grantors,
    168         native_handle_t* nhandle,
    169         size_t size)
    170     : mHandle(nhandle),
    171       mQuantum(size),
    172       mFlags(flavor) {
    173     mGrantors.resize(grantors.size());
    174     for (size_t i = 0; i < grantors.size(); ++i) {
    175         if (isAlignedToWordBoundary(grantors[i].offset) == false) {
    176             details::logAlwaysFatal("Grantor offsets need to be aligned");
    177         }
    178         mGrantors[i] = grantors[i];
    179     }
    180 }
    181 
    182 template<typename T, MQFlavor flavor>
    183 MQDescriptor<T, flavor>::MQDescriptor(size_t bufferSize, native_handle_t *nHandle,
    184                                    size_t messageSize, bool configureEventFlag)
    185     : mHandle(nHandle), mQuantum(messageSize), mFlags(flavor) {
    186     /*
    187      * If configureEventFlag is true, allocate an additional spot in mGrantor
    188      * for containing the fd and offset for mmapping the EventFlag word.
    189      */
    190     mGrantors.resize(configureEventFlag? kMinGrantorCountForEvFlagSupport : kMinGrantorCount);
    191 
    192     size_t memSize[] = {
    193         sizeof(RingBufferPosition),  /* memory to be allocated for read pointer counter */
    194         sizeof(RingBufferPosition),  /* memory to be allocated for write pointer counter */
    195         bufferSize,                  /* memory to be allocated for data buffer */
    196         sizeof(std::atomic<uint32_t>)/* memory to be allocated for EventFlag word */
    197     };
    198 
    199     /*
    200      * Create a default grantor descriptor for read, write pointers and
    201      * the data buffer. fdIndex parameter is set to 0 by default and
    202      * the offset for each grantor is contiguous.
    203      */
    204     for (size_t grantorPos = 0, offset = 0;
    205          grantorPos < mGrantors.size();
    206          offset += memSize[grantorPos++]) {
    207         mGrantors[grantorPos] = {
    208             0 /* grantor flags */,
    209             0 /* fdIndex */,
    210             static_cast<uint32_t>(alignToWordBoundary(offset)),
    211             memSize[grantorPos]
    212         };
    213     }
    214 }
    215 
    216 template<typename T, MQFlavor flavor>
    217 MQDescriptor<T, flavor>::MQDescriptor(const MQDescriptor<T, flavor> &other)
    218     : mGrantors(other.mGrantors),
    219       mHandle(nullptr),
    220       mQuantum(other.mQuantum),
    221       mFlags(other.mFlags) {
    222     if (other.mHandle != nullptr) {
    223         mHandle = native_handle_create(
    224                 other.mHandle->numFds, other.mHandle->numInts);
    225 
    226         for (int i = 0; i < other.mHandle->numFds; ++i) {
    227             mHandle->data[i] = dup(other.mHandle->data[i]);
    228         }
    229 
    230         memcpy(&mHandle->data[other.mHandle->numFds],
    231                &other.mHandle->data[other.mHandle->numFds],
    232                other.mHandle->numInts * sizeof(int));
    233     }
    234 }
    235 
    236 template<typename T, MQFlavor flavor>
    237 MQDescriptor<T, flavor>::MQDescriptor() : MQDescriptor(
    238         std::vector<android::hardware::GrantorDescriptor>(),
    239         nullptr /* nHandle */,
    240         0 /* size */) {}
    241 
    242 template<typename T, MQFlavor flavor>
    243 MQDescriptor<T, flavor>::~MQDescriptor() {
    244     if (mHandle != nullptr) {
    245         native_handle_close(mHandle);
    246         native_handle_delete(mHandle);
    247     }
    248 }
    249 
    250 template<typename T, MQFlavor flavor>
    251 size_t MQDescriptor<T, flavor>::getSize() const {
    252   return mGrantors[DATAPTRPOS].extent;
    253 }
    254 
    255 template<typename T, MQFlavor flavor>
    256 size_t MQDescriptor<T, flavor>::getQuantum() const { return mQuantum; }
    257 
    258 template<typename T, MQFlavor flavor>
    259 int32_t MQDescriptor<T, flavor>::getFlags() const { return mFlags; }
    260 
    261 template<typename T, MQFlavor flavor>
    262 std::string toString(const MQDescriptor<T, flavor> &q) {
    263     std::string os;
    264     if (flavor & kSynchronizedReadWrite) {
    265         os += "fmq_sync";
    266     }
    267     if (flavor & kUnsynchronizedWrite) {
    268         os += "fmq_unsync";
    269     }
    270     os += " {"
    271        + toString(q.grantors().size()) + " grantor(s), "
    272        + "size = " + toString(q.getSize())
    273        + ", .handle = " + toString(q.handle())
    274        + ", .quantum = " + toString(q.getQuantum()) + "}";
    275     return os;
    276 }
    277 
    278 }  // namespace hardware
    279 }  // namespace android
    280 
    281 #endif  // FMSGQ_DESCRIPTOR_H
    282