1 /*
2 * Copyright (c) 2022 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 #ifndef HDI_SHARED_MEM_QUEUE_META_H
16 #define HDI_SHARED_MEM_QUEUE_META_H
17
18 #include <atomic>
19 #include <cstddef>
20 #include <memory>
21 #include <message_parcel.h>
22 #include <unistd.h>
23
24 #ifndef HDF_LOG_TAG
25 #define HDF_LOG_TAG smq
26 #endif
27
28 namespace OHOS {
29 namespace HDI {
30 namespace Base {
31 enum SmqType : uint32_t {
32 SYNCED_SMQ = 0x01,
33 UNSYNC_SMQ = 0x02,
34 };
35
36 struct MemZone {
37 uint32_t size;
38 uint32_t offset;
39 };
40
41 template <typename T>
42 class SharedMemQueueMeta {
43 public:
SharedMemQueueMeta()44 SharedMemQueueMeta() : SharedMemQueueMeta(-1, 0, 0) {};
SharedMemQueueMeta(size_t elementCount,SmqType type)45 SharedMemQueueMeta(size_t elementCount, SmqType type) : SharedMemQueueMeta(-1, elementCount, type) {};
46 SharedMemQueueMeta(int fd, size_t elementCount, SmqType type);
47 SharedMemQueueMeta(const SharedMemQueueMeta<T> &other);
48 ~SharedMemQueueMeta() = default;
49
50 void SetFd(int fd);
51 int GetFd();
52 size_t GetSize();
53 uint32_t GetType();
54 size_t GetElementCount();
55 size_t GetElemenetSize() const;
56 enum MemZoneType : uint32_t {
57 MEMZONE_RPTR = 0,
58 MEMZONE_WPTR,
59 MEMZONE_SYNCER,
60 MEMZONE_DATA,
61 MEMZONE_COUNT,
62 };
63
64 MemZone *GetMemZone(uint32_t type);
65 bool Marshalling(MessageParcel &parcel);
66 static std::shared_ptr<SharedMemQueueMeta<T>> UnMarshalling(MessageParcel &parcel);
67
AlignToWord(size_t num)68 size_t AlignToWord(size_t num)
69 {
70 constexpr uint32_t alignByteSize = 8;
71 return (num + alignByteSize - 1) & (~(alignByteSize - 1));
72 }
73
74 private:
75 int ashmemFd_;
76 size_t size_;
77 size_t elementCount_;
78 size_t elementSize_;
79 SmqType type_;
80 MemZone memzone_[MEMZONE_COUNT];
81 };
82
83 template <typename T>
SharedMemQueueMeta(int fd,size_t elementCount,SmqType type)84 SharedMemQueueMeta<T>::SharedMemQueueMeta(int fd, size_t elementCount, SmqType type)
85 : ashmemFd_(fd), size_(0), elementCount_(elementCount), elementSize_(AlignToWord(sizeof(T))), type_(type)
86 {
87 // max size UIN32_MAX byte
88 if (elementCount_ > UINT32_MAX / elementSize_) {
89 return;
90 }
91
92 size_t dataSize = elementCount_ * elementSize_;
93 size_t memZoneSize[] = {
94 sizeof(uint64_t), // read ptr
95 sizeof(uint64_t), // write ptr
96 sizeof(uint32_t), // sync word
97 dataSize,
98 };
99
100 size_t offset = 0;
101 for (size_t i = 0; i < MEMZONE_COUNT; offset += memZoneSize[i++]) {
102 memzone_[i].offset = AlignToWord(offset);
103 memzone_[i].size = memZoneSize[i];
104 }
105
106 size_ = memzone_[MEMZONE_DATA].offset + memzone_[MEMZONE_DATA].size;
107 }
108
109 template <typename T>
SharedMemQueueMeta(const SharedMemQueueMeta<T> & other)110 SharedMemQueueMeta<T>::SharedMemQueueMeta(const SharedMemQueueMeta<T> &other)
111 {
112 if (ashmemFd_ >= 0) {
113 close(ashmemFd_);
114 }
115
116 ashmemFd_ = dup(other.ashmemFd_);
117 if (ashmemFd_ < 0) {
118 HDF_LOGW("failed to dup ashmem fd for smq");
119 }
120 elementCount_ = other.elementCount_;
121 elementSize_ = other.elementSize_;
122 size_ = other.size_;
123 type_ = other.type_;
124 memcpy(memzone_, other.memzone_, sizeof(memzone_));
125 }
126
127 template <typename T>
SetFd(int fd)128 void SharedMemQueueMeta<T>::SetFd(int fd)
129 {
130 if (ashmemFd_ >= 0) {
131 close(ashmemFd_);
132 }
133 ashmemFd_ = fd;
134 }
135
136 template <typename T>
GetFd()137 int SharedMemQueueMeta<T>::GetFd()
138 {
139 return ashmemFd_;
140 }
141
142 template <typename T>
GetSize()143 size_t SharedMemQueueMeta<T>::GetSize()
144 {
145 return size_;
146 }
147
148 template <typename T>
GetType()149 uint32_t SharedMemQueueMeta<T>::GetType()
150 {
151 return type_;
152 }
153
154 template <typename T>
GetElementCount()155 size_t SharedMemQueueMeta<T>::GetElementCount()
156 {
157 return elementCount_;
158 }
159
160 template <typename T>
GetElemenetSize()161 size_t SharedMemQueueMeta<T>::GetElemenetSize() const
162 {
163 return elementSize_;
164 }
165
166 template <typename T>
GetMemZone(uint32_t type)167 MemZone *SharedMemQueueMeta<T>::GetMemZone(uint32_t type)
168 {
169 if (type >= MEMZONE_COUNT) {
170 return nullptr;
171 }
172
173 return &memzone_[type];
174 }
175
176 template <typename T>
Marshalling(MessageParcel & parcel)177 bool SharedMemQueueMeta<T>::Marshalling(MessageParcel &parcel)
178 {
179 if (!parcel.WriteBuffer(this, sizeof(SharedMemQueueMeta<T>))) {
180 return false;
181 }
182
183 return parcel.WriteFileDescriptor(ashmemFd_);
184 }
185
186 template <typename T>
UnMarshalling(MessageParcel & parcel)187 std::shared_ptr<SharedMemQueueMeta<T>> SharedMemQueueMeta<T>::UnMarshalling(MessageParcel &parcel)
188 {
189 auto readMeta = reinterpret_cast<const SharedMemQueueMeta<T> *>(parcel.ReadBuffer(sizeof(SharedMemQueueMeta<T>)));
190 if (readMeta == nullptr) {
191 HDF_LOGE("read invalid smq meta");
192 return nullptr;
193 }
194
195 auto fd = parcel.ReadFileDescriptor();
196 if (fd < 0) {
197 HDF_LOGE("read invalid smq fd");
198 return nullptr;
199 }
200
201 auto meta = std::make_shared<SharedMemQueueMeta<T>>(*readMeta);
202 meta->SetFd(fd);
203
204 return meta;
205 }
206 } // namespace Base
207 } // namespace HDI
208 } // namespace OHOS
209
210 #ifdef HDF_LOG_TAG
211 #undef HDF_LOG_TAG
212 #endif
213
214 #endif /* HDI_SHARED_MEM_QUEUE_META_H */
215