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