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