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.h
31  *
32  * @brief Provides APIs for the shared memory queue (SMQ).
33  * The SMQ is a common mechanism for inter-process communication. The SMQ must comply with the IDL syntax.
34  * You only need to define the SMQ struct in IDL for the service module.
35  * The HDI module provides common operations for reading and writing the SMQ.
36  *
37  * @since 1.0
38  */
39 
40 #ifndef HDI_SHARED_MEM_QUEUE_INF_H
41 #define HDI_SHARED_MEM_QUEUE_INF_H
42 
43 #include <ashmem.h>
44 #include <atomic>
45 #include <cerrno>
46 #include <datetime_ex.h>
47 #include <hdf_base.h>
48 #include <hdf_log.h>
49 #include <base/hdi_smq_meta.h>
50 #include <base/hdi_smq_syncer.h>
51 #include <memory>
52 #include <securec.h>
53 #include <cstdint>
54 #include <cstring>
55 #include <sys/mman.h>
56 
57 #ifndef PAGE_SIZE
58 #define PAGE_SIZE 4096
59 #endif
60 
61 #ifndef HDF_LOG_TAG
62 #define HDF_LOG_TAG smq
63 #endif
64 
65 namespace OHOS {
66 namespace HDI {
67 namespace Base {
68 /**
69  * @brief Defines the <b>SharedMemQueue</b> class.
70  *
71  * The SMQ is a message queue used for simplex communication between processes.
72  * It allows data write from one end and read at the other end, in either blocking or non-blocking mode.
73  */
74 template <typename T>
75 class SharedMemQueue {
76 public:
77     /**
78      * @brief A constructor used to create a <b>SharedMemQueue</b> object.
79      *
80      * @param elementCount Indicates the queue size, that is, the maximum number of elements allowed in the queue.
81      * @param type Indicates whether the SMQ is synchronous (<b>SYNCED_SMQ</b>) or asynchronous (<b>UNSYNC_SMQ</b>).
82      */
83     SharedMemQueue(uint32_t elementCount, SmqType type);
84 
85     /**
86      * @brief A function used to copy the <b>SharedMemQueue</b> object.
87      */
88     explicit SharedMemQueue(const SharedMemQueueMeta<T> &meta);
89     ~SharedMemQueue();
90 
91     /**
92      * @brief Writes an array of elements to the SMQ in blocking mode.
93      *
94      * When the SMQ is full, this API is blocked until the queue is writeable.
95      *
96      * @param data Indicates the pointer to the array of elements to write.
97      * @param count Indicates the number of elements to write.
98      * @return Returns <b>0</b> if the operation is successful; returns a non-zero value otherwise.
99      */
100     int Write(const T *data, size_t count);
101 
102     /**
103      * @brief Reads an array of elements from the SMQ in blocking mode.
104      *
105      * When the SMQ is empty, this API is blocked until the queue is readable.
106      *
107      * @param data Indicates the pointer to the buffer for storing the elements read.
108      * @param count Indicates the number of elements to read.
109      * @return Returns <b>0</b> if the operation is successful; returns a non-zero value otherwise.
110      */
111     int Read(T *data, size_t count);
112 
113     /**
114      * @brief Writes a single element to the SMQ in blocking mode.
115      *
116      * When the SMQ is full, this API is blocked until the queue is writeable.
117      *
118      * @param data Indicates the pointer to the single element to write.
119      * @return Returns <b>0</b> if the operation is successful; returns a non-zero value otherwise.
120      */
121     int Write(const T *data);
122 
123     /**
124      * @brief Reads a single element from the SMQ in blocking mode.
125      *
126      * When the SMQ is empty, this API is blocked until the queue is readable.
127      *
128      * @param data Indicates the pointer to the buffer for storing the single element read.
129      * @return Returns <b>0</b> if the operation is successful; returns a non-zero value otherwise.
130      */
131     int Read(T *data);
132 
133     /**
134      * @brief Writes a fixed number of elements to the SMQ in blocking mode.
135      *
136      * When the SMQ is full, this API is blocked until the queue is writeable or the write operation times out.
137      *
138      * @param data Indicates the pointer to the array of elements to write.
139      * @param count Indicates the number of elements to write.
140      * @param waitTimeNanoSec Indicates the write operation timeout period, in nanoseconds.
141      * @return Returns <b>0</b> if the operation is successful; returns a non-zero value otherwise.
142      */
143     int Write(const T *data, size_t count, int64_t waitTimeNanoSec);
144 
145     /**
146      * @brief Reads a fixed number of elements from the SMQ in blocking mode.
147      *
148      * When the number of elements in the SMQ is less than the number of elements to read,
149      * this API is blocked until the queue is readable or the read operation times out.
150      *
151      * @param data Indicates the pointer to the buffer for storing the elements read.
152      * @param count Indicates the number of elements to read.
153      * @param waitTimeNanoSec Indicates the read operation timeout period, in nanoseconds.
154      * @return Returns <b>0</b> if the operation is successful; returns a non-zero value otherwise.
155      */
156     int Read(T *data, size_t count, int64_t waitTimeNanoSec);
157 
158     /**
159      * @brief Writes a single element to the SMQ in non-blocking mode.
160      *
161      * When the SMQ queue is full, the SMPQ overflows. The overflowed element will be overwritten.
162      *
163      * @param data Indicates the pointer to the single element to write.
164      * @return Returns <b>0</b> if the operation is successful; returns a non-zero value otherwise.
165      */
166     int WriteNonBlocking(const T *data);
167 
168     /**
169      * @brief Reads a single element from the SMQ in non-blocking mode.
170      *
171      * @param data Indicates the pointer to the buffer for storing the element read.
172      * @return Returns <b>0</b> if the operation is successful; returns a non-zero value otherwise.
173      */
174     int ReadNonBlocking(T *data);
175 
176     /**
177      * @brief Writes a fixed number of elements to the SMQ in non-blocking mode.
178      *
179      * When the SMQ is full, the SMQ overflows. The overflowed elements will be overwritten.
180      *
181      * @param data Indicates the pointer to the elements to write.
182      * @param count Indicates the number of elements to write.
183      * @return Returns <b>0</b> if the operation is successful; returns a non-zero value otherwise.
184      */
185     int WriteNonBlocking(const T *data, size_t count);
186 
187     /**
188      * @brief Reads a fixed number of elements from the SMQ in non-blocking mode.
189      *
190      * If the SMQ queue does not have sufficient elements to read, a failure is returned immediately.
191      *
192      * @param data Indicates the pointer to the buffer for storing the data read.
193      * The number of elements that can be held in the buffer must be greater than the number of elements read.
194      * @param count Indicates the number of elements to read.
195      * @return Returns <b>0</b> if the operation is successful; returns a non-zero value otherwise.
196      */
197     int ReadNonBlocking(T *data, size_t count);
198 
199     /**
200      * @brief Obtains the number of elements that can be written to the SMQ.
201      *
202      * @return Returns the number of elements that can be written to the SMQ.
203      */
204     size_t GetAvalidWriteSize();
205 
206     /**
207      * @brief Obtains the number of elements that can be read from the SMQ.
208      *
209      * @return Returns the number of elements that can be read from the SMQ.
210      */
211     size_t GetAvalidReadSize();
212 
213     /**
214      * @brief Obtains the size of the SMQ, in bytes.
215      *
216      * @return Returns the number of bytes occupied by the SMQ.
217      */
218     size_t GetSize();
219 
220     /**
221      * @brief Obtains the metadata object.
222      *
223      * @return Returns the metadata object obtained.
224      */
225     std::shared_ptr<SharedMemQueueMeta<T>> GetMeta();
226 
227     /**
228      * @brief Checks whether the SMQ object is valid.
229      *
230      * @return Returns <b>true</b> if the object is valid; returns <b>false</b> otherwise.
231      */
232     bool IsGood();
233 
234     /**
235      * @brief Obtains the current timestamp, in nanoseconds.
236      *
237      * @return Returns the timestamp obtained.
238      */
GetNanoTime()239     static inline int64_t GetNanoTime()
240     {
241         struct timespec ts;
242         clock_gettime(CLOCK_MONOTONIC, &ts);
243         return (ts.tv_sec * SEC_TO_NANOSEC + ts.tv_nsec);
244     }
245 
246 private:
247     void Init(bool resetWriteOffset);
248     uintptr_t MapMemZone(uint32_t zoneType);
249     void UnMapMemZone(void *addr, uint32_t zoneType);
250     size_t Align(size_t num, size_t alignSize);
251 
252     int32_t status = HDF_FAILURE;
253     uint8_t *queueBuffer_ = nullptr;
254     std::atomic<uint64_t> *readOffset_ = nullptr;
255     std::atomic<uint64_t> *writeOffset_ = nullptr;
256     std::atomic<uint32_t> *syncerPtr_ = nullptr;
257     std::unique_ptr<SharedMemQueueSyncer> syncer_ = nullptr;
258     std::shared_ptr<SharedMemQueueMeta<T>> meta_ = nullptr;
259 };
260 
261 template <typename T>
SharedMemQueue(uint32_t elementCount,SmqType type)262 SharedMemQueue<T>::SharedMemQueue(uint32_t elementCount, SmqType type)
263 {
264     if (elementCount == 0 || elementCount > UINT16_MAX) {
265         HDF_LOGE("invalid elementCount for smq:%{public}u", elementCount);
266         return;
267     }
268 
269     meta_ = std::make_shared<SharedMemQueueMeta<T>>(elementCount, type);
270     HDF_LOGI("create SharedMemQueue, count=%{public}u, size=%{public}zu", elementCount, meta_->GetSize());
271     int ashmemFd = AshmemCreate("hdi_smq", Align(meta_->GetSize(), PAGE_SIZE));
272     if (ashmemFd < 0) {
273         HDF_LOGE("failed to create ashmem");
274         return;
275     }
276     meta_->SetFd(ashmemFd);
277     Init(true);
278 }
279 
280 template <typename T>
SharedMemQueue(const SharedMemQueueMeta<T> & meta)281 SharedMemQueue<T>::SharedMemQueue(const SharedMemQueueMeta<T> &meta)
282 {
283     meta_ = std::make_shared<SharedMemQueueMeta<T>>(meta);
284     Init(false);
285 }
286 
287 template <typename T>
~SharedMemQueue()288 SharedMemQueue<T>::~SharedMemQueue()
289 {
290     if (meta_ != nullptr && meta_->GetType() == SYNCED_SMQ && readOffset_ != nullptr) {
291         UnMapMemZone(readOffset_, SharedMemQueueMeta<T>::MemZoneType::MEMZONE_RPTR);
292     } else {
293         delete readOffset_;
294         readOffset_ = nullptr;
295     }
296 
297     if (writeOffset_ != nullptr) {
298         UnMapMemZone(writeOffset_, SharedMemQueueMeta<T>::MEMZONE_WPTR);
299     }
300 
301     if (syncerPtr_ != nullptr) {
302         UnMapMemZone(syncerPtr_, SharedMemQueueMeta<T>::MEMZONE_SYNCER);
303     }
304 
305     if (queueBuffer_ != nullptr) {
306         UnMapMemZone(queueBuffer_, SharedMemQueueMeta<T>::MEMZONE_DATA);
307     }
308 }
309 
310 template <typename T>
Init(bool resetWriteOffset)311 void SharedMemQueue<T>::Init(bool resetWriteOffset)
312 {
313     if (meta_ == nullptr) {
314         HDF_LOGE("invalid smq meta for init");
315         return;
316     }
317 
318     if (meta_->GetType() == SYNCED_SMQ) {
319         readOffset_ = reinterpret_cast<std::atomic<uint64_t> *>(MapMemZone(SharedMemQueueMeta<T>::MEMZONE_RPTR));
320     } else {
321         readOffset_ = new std::atomic<uint64_t>;
322     }
323 
324     if (readOffset_ == nullptr) {
325         HDF_LOGE("failed to map read offset");
326         return;
327     }
328 
329     writeOffset_ = reinterpret_cast<std::atomic<uint64_t> *>(MapMemZone(SharedMemQueueMeta<T>::MEMZONE_WPTR));
330     if (writeOffset_ == nullptr) {
331         HDF_LOGE("failed to map write offset");
332         return;
333     }
334 
335     syncerPtr_ = reinterpret_cast<std::atomic<uint32_t> *>(MapMemZone(SharedMemQueueMeta<T>::MEMZONE_SYNCER));
336     if (syncerPtr_ == nullptr) {
337         HDF_LOGE("failed to map sync ptr");
338         return;
339     }
340 
341     queueBuffer_ = reinterpret_cast<uint8_t *>(MapMemZone(SharedMemQueueMeta<T>::MEMZONE_DATA));
342     if (queueBuffer_ == nullptr) {
343         HDF_LOGE("failed to map queue buffer");
344         return;
345     }
346 
347     syncer_ = std::make_unique<SharedMemQueueSyncer>(syncerPtr_);
348 
349     if (resetWriteOffset) {
350         writeOffset_->store(0, std::memory_order_release);
351     }
352     readOffset_->store(0, std::memory_order_release);
353     HDF_LOGI("smq init succ");
354     status = HDF_SUCCESS;
355 }
356 
357 template <typename T>
MapMemZone(uint32_t zoneType)358 uintptr_t SharedMemQueue<T>::MapMemZone(uint32_t zoneType)
359 {
360     auto memzone = meta_->GetMemZone(zoneType);
361     if (memzone == nullptr) {
362         HDF_LOGE("invalid smq mem zone type %{public}u", zoneType);
363         return reinterpret_cast<uintptr_t>(nullptr);
364     }
365 
366     int offset = (static_cast<int>(memzone->offset) / PAGE_SIZE) * PAGE_SIZE;
367     int length = static_cast<int>(memzone->offset) - offset + static_cast<int>(memzone->size);
368 
369     void *ptr = mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, meta_->GetFd(), offset);
370     if (ptr == MAP_FAILED) {
371         HDF_LOGE(
372             "failed to map memzone %{public}u, size %{public}u, offset %{public}u , fd %{public}d, errnor=%{public}d",
373             zoneType, length, offset, meta_->GetFd(), errno);
374         return reinterpret_cast<uintptr_t>(nullptr);
375     }
376     return (reinterpret_cast<uintptr_t>(ptr) + (static_cast<int>(memzone->offset) - offset));
377 }
378 
379 template <typename T>
UnMapMemZone(void * addr,uint32_t zoneType)380 void SharedMemQueue<T>::UnMapMemZone(void *addr, uint32_t zoneType)
381 {
382     auto memzone = meta_->GetMemZone(zoneType);
383     if (memzone == nullptr) {
384         return;
385     }
386     int offset = (static_cast<int>(memzone->offset) / PAGE_SIZE) * PAGE_SIZE;
387     int length = static_cast<int>(memzone->offset) - offset + static_cast<int>(memzone->size);
388     uint8_t *ptr = reinterpret_cast<uint8_t *>(addr) - (static_cast<int>(memzone->offset) - offset);
389     if (ptr == nullptr) {
390         return;
391     }
392     munmap(ptr, length);
393 }
394 
395 template <typename T>
IsGood()396 bool SharedMemQueue<T>::IsGood()
397 {
398     return status == HDF_SUCCESS;
399 }
400 
401 template <typename T>
Align(size_t num,size_t alignSize)402 size_t SharedMemQueue<T>::Align(size_t num, size_t alignSize)
403 {
404     if (alignSize < 1 || num > (SIZE_MAX - alignSize)) {
405         HDF_LOGE("Invalid parameter num or alignSize");
406         return 0;
407     }
408     return (num + alignSize - 1) & ~(alignSize - 1);
409 }
410 
411 template <typename T>
Write(const T * data,size_t count)412 int SharedMemQueue<T>::Write(const T *data, size_t count)
413 {
414     return Write(data, count, 0);
415 }
416 
417 template <typename T>
Read(T * data,size_t count)418 int SharedMemQueue<T>::Read(T *data, size_t count)
419 {
420     return Read(data, count, 0);
421 }
422 
423 template <typename T>
Write(const T * data)424 int SharedMemQueue<T>::Write(const T *data)
425 {
426     return Write(data, 1, 0);
427 }
428 
429 template <typename T>
Read(T * data)430 int SharedMemQueue<T>::Read(T *data)
431 {
432     return Read(data, 1, 0);
433 }
434 
435 template <typename T>
Write(const T * data,size_t count,int64_t waitTimeNanoSec)436 int SharedMemQueue<T>::Write(const T *data, size_t count, int64_t waitTimeNanoSec)
437 {
438     if (meta_->GetType() != SmqType::SYNCED_SMQ) {
439         HDF_LOGE("unsynecd smq not support blocking write");
440         return HDF_ERR_NOT_SUPPORT;
441     }
442 
443     if (WriteNonBlocking(data, count) == 0) {
444         return syncer_->Wake(SharedMemQueueSyncer::SYNC_WORD_READ);
445     }
446 
447     int ret = 0;
448     auto startTime = GetNanoTime();
449     int64_t currentTime = startTime;
450     while (true) {
451         if (waitTimeNanoSec != 0) {
452             currentTime = GetNanoTime();
453             waitTimeNanoSec -= (currentTime - startTime);
454             startTime = currentTime;
455             if (waitTimeNanoSec <= 0) {
456                 ret = WriteNonBlocking(data, count);
457                 break;
458             }
459         }
460         ret = syncer_->Wait(SharedMemQueueSyncer::SYNC_WORD_WRITE, waitTimeNanoSec);
461         if (ret != 0 && ret != -ETIMEDOUT) {
462             break;
463         }
464 
465         ret = WriteNonBlocking(data, count);
466         if (ret == 0) {
467             break;
468         }
469     }
470 
471     if (ret == 0) {
472         ret = syncer_->Wake(SharedMemQueueSyncer::SYNC_WORD_READ);
473     } else {
474         HDF_LOGE("failed to write %{public}zu, ret=%{public}d", count, ret);
475     }
476 
477     return ret;
478 }
479 
480 template <typename T>
Read(T * data,size_t count,int64_t waitTimeNanoSec)481 int SharedMemQueue<T>::Read(T *data, size_t count, int64_t waitTimeNanoSec)
482 {
483     if (meta_->GetType() != SmqType::SYNCED_SMQ) {
484         HDF_LOGE("unsynecd smq not support blocking read");
485         return HDF_ERR_NOT_SUPPORT;
486     }
487 
488     if (ReadNonBlocking(data, count) == 0) {
489         return syncer_->Wake(SharedMemQueueSyncer::SYNC_WORD_WRITE);
490     }
491 
492     int ret = -ENODATA;
493     auto startTime = GetNanoTime();
494     int64_t currentTime;
495     while (true) {
496         if (waitTimeNanoSec != 0) {
497             currentTime = GetNanoTime();
498             waitTimeNanoSec -= (currentTime - startTime);
499             startTime = currentTime;
500             if (waitTimeNanoSec <= 0) {
501                 ret = ReadNonBlocking(data, count);
502                 break;
503             }
504         }
505         ret = syncer_->Wait(SharedMemQueueSyncer::SYNC_WORD_READ, waitTimeNanoSec);
506         if (ret != 0 && ret != -ETIMEDOUT) {
507             break;
508         }
509 
510         ret = ReadNonBlocking(data, count);
511         if (ret == 0) {
512             break;
513         }
514     }
515     if (ret == 0) {
516         ret = syncer_->Wake(SharedMemQueueSyncer::SYNC_WORD_WRITE);
517     } else {
518         HDF_LOGE("failed to read %{public}zu, ret=%{public}d", count, ret);
519     }
520 
521     return ret;
522 }
523 
524 template <typename T>
WriteNonBlocking(const T * data)525 int SharedMemQueue<T>::WriteNonBlocking(const T *data)
526 {
527     return WriteNonBlocking(data, 1);
528 }
529 
530 template <typename T>
ReadNonBlocking(T * data)531 int SharedMemQueue<T>::ReadNonBlocking(T *data)
532 {
533     return ReadNonBlocking(data, 1);
534 }
535 
536 template <typename T>
WriteNonBlocking(const T * data,size_t count)537 int SharedMemQueue<T>::WriteNonBlocking(const T *data, size_t count)
538 {
539     auto avalidWrite = GetAvalidWriteSize();
540     if (count > avalidWrite && meta_->GetType() == SmqType::SYNCED_SMQ) {
541         // synced smq can not overflow write
542         return -E2BIG;
543     }
544 
545     auto wOffset = writeOffset_->load(std::memory_order_acquire);
546     auto rOffset = readOffset_->load(std::memory_order_acquire);
547     uint64_t newWriteOffset;
548     auto qCount = meta_->GetElementCount();
549     if (wOffset + count <= qCount) {
550         if (memcpy_s(queueBuffer_ + (wOffset * sizeof(T)), (qCount - wOffset) * sizeof(T),
551             data, count * sizeof(T)) != EOK) {
552             return HDF_FAILURE;
553         };
554         newWriteOffset = (wOffset + count) % qCount;
555     } else {
556         size_t firstPartSize = qCount - wOffset;
557         size_t secParcSize = count - firstPartSize;
558         if (memcpy_s(queueBuffer_ + (wOffset * sizeof(T)), (qCount - wOffset) * sizeof(T),
559             data, firstPartSize * sizeof(T)) != EOK) {
560             return HDF_FAILURE;
561         }
562         if (memcpy_s(queueBuffer_, qCount * sizeof(T), data + firstPartSize, secParcSize * sizeof(T)) != EOK) {
563             return HDF_FAILURE;
564         }
565         newWriteOffset = secParcSize;
566     }
567 
568     writeOffset_->store(newWriteOffset, std::memory_order_release);
569     if (wOffset < rOffset && newWriteOffset >= rOffset) {
570         HDF_LOGW("warning:smp ring buffer overflow");
571     }
572     return 0;
573 }
574 
575 template <typename T>
ReadNonBlocking(T * data,size_t count)576 int SharedMemQueue<T>::ReadNonBlocking(T *data, size_t count)
577 {
578     if (count == 0) {
579         return -EINVAL;
580     }
581 
582     if (count > GetAvalidReadSize()) {
583         return -ENODATA;
584     }
585 
586     auto qCount = meta_->GetElementCount();
587     auto rOffset = readOffset_->load(std::memory_order_acquire);
588     if (rOffset + count <= qCount) {
589         if (memcpy_s(data, count * sizeof(T), queueBuffer_ + (rOffset * sizeof(T)), count * sizeof(T)) != EOK) {
590             return HDF_FAILURE;
591         }
592         readOffset_->store((rOffset + count) % qCount, std::memory_order_release);
593         return 0;
594     }
595 
596     size_t firstPartSize = qCount - rOffset;
597     size_t secPartSize = count - firstPartSize;
598 
599     if (memcpy_s(data, count * sizeof(T), queueBuffer_ + (rOffset * sizeof(T)), firstPartSize * sizeof(T)) != EOK) {
600         return HDF_FAILURE;
601     }
602     if (memcpy_s(data + firstPartSize, (count - firstPartSize) * sizeof(T),
603         queueBuffer_, secPartSize * sizeof(T)) != EOK) {
604         return HDF_FAILURE;
605     };
606     readOffset_->store(secPartSize, std::memory_order_release);
607 
608     return 0;
609 }
610 
611 template <typename T>
GetAvalidWriteSize()612 size_t SharedMemQueue<T>::GetAvalidWriteSize()
613 {
614     return meta_->GetElementCount() - GetAvalidReadSize();
615 }
616 
617 template <typename T>
GetAvalidReadSize()618 size_t SharedMemQueue<T>::GetAvalidReadSize()
619 {
620     auto wOffset = writeOffset_->load(std::memory_order_acquire);
621     auto rOffset = readOffset_->load(std::memory_order_acquire);
622     auto size = wOffset >= rOffset ? (wOffset - rOffset) : (wOffset + meta_->GetElementCount() - rOffset);
623     return size;
624 }
625 
626 template <typename T>
GetSize()627 size_t SharedMemQueue<T>::GetSize()
628 {
629     return meta_->GetSize();
630 }
631 
632 template <typename T>
GetMeta()633 std::shared_ptr<SharedMemQueueMeta<T>> SharedMemQueue<T>::GetMeta()
634 {
635     return meta_;
636 }
637 } // namespace Base
638 } // namespace HDI
639 } // namespace OHOS
640 
641 #ifdef HDF_LOG_TAG
642 #undef HDF_LOG_TAG
643 #endif
644 
645 #endif /* HDI_SHARED_MEM_QUEUEHDI_INF_H */
646