• Home
  • History
  • Annotate
  • 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 <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