• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
isHandleValidMQDescriptor81     bool isHandleValid() const { return mHandle != nullptr; }
countGrantorsMQDescriptor82     size_t countGrantors() const { return mGrantors.size(); }
83 
grantorsMQDescriptor84     inline const ::android::hardware::hidl_vec<GrantorDescriptor> &grantors() const {
85         return mGrantors;
86     }
87 
grantorsMQDescriptor88     inline ::android::hardware::hidl_vec<GrantorDescriptor> &grantors() {
89         return mGrantors;
90     }
91 
handleMQDescriptor92     inline const ::native_handle_t *handle() const {
93         return mHandle;
94     }
95 
handleMQDescriptor96     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.
alignToWordBoundaryMQDescriptor118     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 
isAlignedToWordBoundaryMQDescriptor134     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>
MQDescriptor(const std::vector<GrantorDescriptor> & grantors,native_handle_t * nhandle,size_t size)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>
MQDescriptor(size_t bufferSize,native_handle_t * nHandle,size_t messageSize,bool configureEventFlag)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>
MQDescriptor(const MQDescriptor<T,flavor> & other)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>
MQDescriptor()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>
~MQDescriptor()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>
getSize()251 size_t MQDescriptor<T, flavor>::getSize() const {
252   return mGrantors[DATAPTRPOS].extent;
253 }
254 
255 template<typename T, MQFlavor flavor>
getQuantum()256 size_t MQDescriptor<T, flavor>::getQuantum() const { return mQuantum; }
257 
258 template<typename T, MQFlavor flavor>
getFlags()259 int32_t MQDescriptor<T, flavor>::getFlags() const { return mFlags; }
260 
261 template<typename T, MQFlavor flavor>
toString(const MQDescriptor<T,flavor> & q)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