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