1 /*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 /**
17 * @addtogroup DriverHdi
18 * @{
19 *
20 * @brief Provides APIs for a system ability to obtain hardware device interface (HDI) services,
21 * load or unload a device, and listen for service status, and capabilities for the hdi-gen tool to
22 * automatically generate code in interface description language (IDL).
23 *
24 * The HDF and IDL code generated allow the system ability to accesses HDI driver services.
25 *
26 * @since 1.0
27 */
28
29 /**
30 * @file hdi_smq_meta.h
31 *
32 * @brief Defines the metadata struct of the shared memory queue (SMQ) and provides APIs for obtaining
33 * the data struct members and serializing and deserializing the metadata struct.
34 *
35 * @since 1.0
36 */
37
38 #ifndef HDI_SHARED_MEM_QUEUE_META_H
39 #define HDI_SHARED_MEM_QUEUE_META_H
40
41 #include <atomic>
42 #include <cstddef>
43 #include <memory>
44 #include <message_parcel.h>
45 #include <unistd.h>
46 #include "securec.h"
47
48 #ifndef HDF_LOG_TAG
49 #define HDF_LOG_TAG smq
50 #endif
51
52 namespace OHOS {
53 namespace HDI {
54 namespace Base {
55 /**
56 * @brief Enumerates the SMQ types.
57 */
58 enum SmqType : uint32_t {
59 /** SMQ for synchronous communication */
60 SYNCED_SMQ = 0x01,
61 /** SMQ for asynchronous communication */
62 UNSYNC_SMQ = 0x02,
63 };
64
65 /**
66 * @brief Defines the <b>MemZone</b> struct.
67 */
68 struct MemZone {
69 /** Memory zone size */
70 uint32_t size;
71 /** Memory zone offset */
72 uint32_t offset;
73 };
74
75 /**
76 * @brief Defines the metadata template type of the SMQ.
77 */
78 template <typename T>
79 class SharedMemQueueMeta {
80 public:
81 /**
82 * @brief Default constructor used to create a <b>SharedMemQueueMeta</b> object.
83 */
SharedMemQueueMeta()84 SharedMemQueueMeta() : SharedMemQueueMeta(-1, 0, 0) {}
85
86 /**
87 * @brief A constructor used to create a <b>SharedMemQueueMeta</b> object.
88 *
89 * @param elementCount Indicates the queue size.
90 * @param type Indicates the SMQ type.
91 */
SharedMemQueueMeta(size_t elementCount,SmqType type)92 SharedMemQueueMeta(size_t elementCount, SmqType type) : SharedMemQueueMeta(-1, elementCount, type) {}
93
94 /**
95 * @brief A constructor used to create a <b>SharedMemQueueMeta</b> object.
96 *
97 * @param fd Indicates the file descriptor (FD) of the shared memory file.
98 * @param elementCount Indicates the queue size.
99 * @param type Indicates the SMQ type.
100 */
101 SharedMemQueueMeta(int fd, size_t elementCount, SmqType type);
102
103 /**
104 * @brief A constructor used to copy a <b>SharedMemQueueMeta</b> object.
105 *
106 * @param other Indicates the <b>SharedMemQueueMeta</b> object to copy.
107 */
108 SharedMemQueueMeta(const SharedMemQueueMeta<T> &other);
109 ~SharedMemQueueMeta();
110
111 /**
112 * @brief A constructor used to assign values to the <b>SharedMemQueueMeta</b> object.
113 *
114 * @param other Indicates the <b>SharedMemQueueMeta</b> object to copy.
115 */
116 SharedMemQueueMeta &operator=(const SharedMemQueueMeta<T> &other);
117
118 /**
119 * @brief Sets an FD.
120 *
121 * @param fd Indicates the FD to set.
122 */
123 void SetFd(int fd);
124
125 /**
126 * @brief Obtains the FD.
127 *
128 * @return Returns the FD obtained.
129 */
130 int GetFd() const;
131
132 /**
133 * @brief Obtains the shared memory size.
134 *
135 * @return Returns the shared memory size obtained.
136 */
137 size_t GetSize();
138
139 /**
140 * @brief Obtains the SMQ type.
141 *
142 * @return Returns the SMQ type obtained.
143 */
144 uint32_t GetType();
145
146 /**
147 * @brief Obtains the number of elements in the SMQ.
148 *
149 * @return Returns the number of elements in the SMQ obtained.
150 */
151 size_t GetElementCount();
152
153 /**
154 * @brief Obtains the size of a single element in the SMQ.
155 *
156 * @return Returns the size of a single element obtained.
157 */
158 size_t GetElemenetSize() const;
159
160 /**
161 * @brief Enumerates the shared memory zone types.
162 */
163 enum MemZoneType : uint32_t {
164 /** Read pointer */
165 MEMZONE_RPTR,
166 /** Write pointer */
167 MEMZONE_WPTR,
168 /** Syncword */
169 MEMZONE_SYNCER,
170 /** Data */
171 MEMZONE_DATA,
172 /** Number of shared memory zones */
173 MEMZONE_COUNT,
174 };
175
176 /**
177 * @brief Obtains the memory zone of the specified type.
178 *
179 * @param type Indicates the type of the shared memory zone.
180 * @return Returns the shared memory zone obtained.
181 */
182 MemZone *GetMemZone(uint32_t type);
183
184 /**
185 * @brief Writes the SMQ to a <b>MessageParcel</b> object.
186 *
187 * @param parcel Indicates the <b>MessageParcel</b> object.
188 * @return Returns <b>true</b> if the operation is successful; returns <b>false</b> otherwise.
189 */
190 bool Marshalling(MessageParcel &parcel);
191
192 /**
193 * @brief Reads the SMQ from a <b>MessageParcel</b> object.
194 *
195 * @param parcel Indicates the <b>MessageParcel</b> object from which the SMQ is to read.
196 * @return Returns a <b>SharedMemQueueMeta</b> object, which can be used to create an SQM object.
197 */
198 static std::shared_ptr<SharedMemQueueMeta<T>> UnMarshalling(MessageParcel &parcel);
199
200 /**
201 * @brief Aligns the buffer by 8 bytes.
202 *
203 * @param num Indicates the number of bytes for aligning the buffer.
204 * @return Returns the number of bytes after alignment.
205 */
AlignToWord(size_t num)206 size_t AlignToWord(size_t num)
207 {
208 constexpr uint32_t alignByteSize = 8;
209 return (num + alignByteSize - 1) & (~(alignByteSize - 1));
210 }
211
212 private:
213 /** FD of the shared memory file */
214 int ashmemFd_;
215
216 /** Size of the shared memory */
217 size_t size_;
218
219 /** Number of elements in the SMQ */
220 size_t elementCount_;
221
222 /** Size of an element in the SMQ */
223 size_t elementSize_;
224
225 /** SMQ type */
226 SmqType type_;
227
228 /** Number of shared memory zones */
229 MemZone memzone_[MEMZONE_COUNT];
230 };
231
232 /**
233 * @brief A constructor used to assign values to the <b>SharedMemQueueMeta</b> object.
234 *
235 * @param other Indicates the <b>SharedMemQueueMeta</b> object to copy.
236 */
237 template <typename T>
238 SharedMemQueueMeta<T> &SharedMemQueueMeta<T>::operator=(const SharedMemQueueMeta<T> &other)
239 {
240 if (this != &other) {
241 if (ashmemFd_ >= 0) {
242 close(ashmemFd_);
243 }
244 ashmemFd_ = dup(other.ashmemFd_);
245 size_ = other.size_;
246 elementCount_ = other.elementCount_;
247 elementSize_ = other.elementSize_;
248 type_ = other.type_;
249 if (memcpy_s(memzone_, sizeof(memzone_), other.memzone_, sizeof(other.memzone_)) != EOK) {
250 HDF_LOGW("failed to memcpy_s overload memzone_");
251 }
252 }
253
254 return *this;
255 }
256
257 template <typename T>
SharedMemQueueMeta(int fd,size_t elementCount,SmqType type)258 SharedMemQueueMeta<T>::SharedMemQueueMeta(int fd, size_t elementCount, SmqType type)
259 : ashmemFd_(fd), size_(0), elementCount_(elementCount), elementSize_(sizeof(T)), type_(type)
260 {
261 // max size UIN32_MAX byte
262 if (elementCount_ > UINT32_MAX / elementSize_) {
263 return;
264 }
265
266 size_t dataSize = elementCount_ * elementSize_;
267 size_t memZoneSize[] = {
268 sizeof(uint64_t), // read ptr
269 sizeof(uint64_t), // write ptr
270 sizeof(uint32_t), // sync word
271 dataSize,
272 };
273
274 size_t offset = 0;
275 for (size_t i = 0; i < MEMZONE_COUNT; offset += memZoneSize[i++]) {
276 memzone_[i].offset = AlignToWord(offset);
277 memzone_[i].size = memZoneSize[i];
278 }
279
280 size_ = memzone_[MEMZONE_DATA].offset + memzone_[MEMZONE_DATA].size;
281 }
282
283 template <typename T>
SharedMemQueueMeta(const SharedMemQueueMeta<T> & other)284 SharedMemQueueMeta<T>::SharedMemQueueMeta(const SharedMemQueueMeta<T> &other)
285 {
286 ashmemFd_ = dup(other.ashmemFd_);
287 if (ashmemFd_ < 0) {
288 HDF_LOGW("failed to dup ashmem fd for smq");
289 }
290 elementCount_ = other.elementCount_;
291 elementSize_ = other.elementSize_;
292 size_ = other.size_;
293 type_ = other.type_;
294 if (memcpy_s(memzone_, sizeof(memzone_), other.memzone_, sizeof(other.memzone_)) != EOK) {
295 HDF_LOGW("failed to memcpy_s memzone_");
296 }
297 }
298
299 template <typename T>
~SharedMemQueueMeta()300 SharedMemQueueMeta<T>::~SharedMemQueueMeta()
301 {
302 if (ashmemFd_ >= 0) {
303 close(ashmemFd_);
304 }
305 ashmemFd_ = -1;
306 }
307
308 /**
309 * @brief Sets an FD.
310 *
311 * @param fd Indicates the FD to set.
312 */
313 template <typename T>
SetFd(int fd)314 void SharedMemQueueMeta<T>::SetFd(int fd)
315 {
316 if (ashmemFd_ >= 0) {
317 close(ashmemFd_);
318 }
319 ashmemFd_ = fd;
320 }
321
322 /**
323 * @brief Obtains the FD.
324 *
325 * @return Returns the FD obtained.
326 */
327 template <typename T>
GetFd()328 int SharedMemQueueMeta<T>::GetFd() const
329 {
330 return ashmemFd_;
331 }
332
333 /**
334 * @brief Obtains the shared memory size.
335 *
336 * @return Returns the shared memory size obtained.
337 */
338 template <typename T>
GetSize()339 size_t SharedMemQueueMeta<T>::GetSize()
340 {
341 return size_;
342 }
343
344 /**
345 * @brief Obtains the SMQ type.
346 *
347 * @return Returns the SMQ type obtained.
348 */
349 template <typename T>
GetType()350 uint32_t SharedMemQueueMeta<T>::GetType()
351 {
352 return type_;
353 }
354
355 /**
356 * @brief Obtains the number of elements in the SMQ.
357 *
358 * @return Returns the number of elements in the SMQ obtained.
359 */
360 template <typename T>
GetElementCount()361 size_t SharedMemQueueMeta<T>::GetElementCount()
362 {
363 return elementCount_;
364 }
365
366 /**
367 * @brief Obtains the size of a single element in the SMQ.
368 *
369 * @return Returns the size of a single element obtained.
370 */
371 template <typename T>
GetElemenetSize()372 size_t SharedMemQueueMeta<T>::GetElemenetSize() const
373 {
374 return elementSize_;
375 }
376
377 /**
378 * @brief Obtains the memory zone of the specified type.
379 *
380 * @param type Indicates the type of the shared memory zone.
381 * @return Returns the shared memory zone obtained.
382 */
383 template <typename T>
GetMemZone(uint32_t type)384 MemZone *SharedMemQueueMeta<T>::GetMemZone(uint32_t type)
385 {
386 if (type >= MEMZONE_COUNT) {
387 return nullptr;
388 }
389
390 return &memzone_[type];
391 }
392
393 /**
394 * @brief Marshals the SMQ into a <b>MessageParcel</b> object.
395 *
396 * @param parcel Indicates the <b>MessageParcel</b> object after marshalling.
397 * @return Returns <b>true</b> if the operation is successful; returns <b>false</b> otherwise.
398 */
399 template <typename T>
Marshalling(MessageParcel & parcel)400 bool SharedMemQueueMeta<T>::Marshalling(MessageParcel &parcel)
401 {
402 if (!parcel.WriteFileDescriptor(ashmemFd_)) {
403 HDF_LOGE("%{public}s: failed to write ashmemFd_", __func__);
404 return false;
405 }
406
407 if (!parcel.WriteUint64(static_cast<uint64_t>(elementCount_))) {
408 HDF_LOGE("%{public}s: failed to write elementCount_", __func__);
409 return false;
410 }
411
412 if (!parcel.WriteUint32(static_cast<uint32_t>(type_))) {
413 HDF_LOGE("%{public}s: failed to write type_", __func__);
414 return false;
415 }
416
417 return true;
418 }
419
420 /**
421 * @brief Unmarshals the SMQ from a <b>MessageParcel</b> object.
422 *
423 * @param parcel Indicates the <b>MessageParcel</b> object to unmarshal.
424 * @return Returns a <b>SharedMemQueueMeta</b> object, which can be used to create an SQM object.
425 */
426 template <typename T>
UnMarshalling(MessageParcel & parcel)427 std::shared_ptr<SharedMemQueueMeta<T>> SharedMemQueueMeta<T>::UnMarshalling(MessageParcel &parcel)
428 {
429 int fd = parcel.ReadFileDescriptor();
430 if (fd < 0) {
431 HDF_LOGE("read invalid fd of smq");
432 return nullptr;
433 }
434
435 uint64_t readElementCount = 0;
436 if (!parcel.ReadUint64(readElementCount)) {
437 HDF_LOGE("read invalid elementCount of smq");
438 close(fd);
439 return nullptr;
440 }
441 size_t elementCount = static_cast<size_t>(readElementCount);
442
443 uint32_t typecode = 0;
444 if (!parcel.ReadUint32(typecode)) {
445 HDF_LOGE("read invalid typecode of smq");
446 close(fd);
447 return nullptr;
448 }
449 SmqType type = static_cast<SmqType>(typecode);
450 return std::make_shared<SharedMemQueueMeta<T>>(fd, elementCount, type);
451 }
452 } // namespace Base
453 } // namespace HDI
454 } // namespace OHOS
455
456 #ifdef HDF_LOG_TAG
457 #undef HDF_LOG_TAG
458 #endif
459
460 #endif /* HDI_SHARED_MEM_QUEUE_META_H */
461