1 /*
2 * Copyright (c) 2021 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 #include "share_memory_block.h"
17
18 #include <cstring>
19 #include <fcntl.h>
20 #include <sys/mman.h>
21 #include <sys/socket.h>
22 #include <sys/syscall.h>
23 #include <sys/un.h>
24 #include <unistd.h>
25
26 #include "logging.h"
27 #include "securec.h"
28
29 namespace {
30 const int HEAD_OFFSET_LEN = 4;
31 #ifndef PAGE_SIZE
32 constexpr uint32_t PAGE_SIZE = 4096;
33 #endif
34 }
35
36 struct PthreadLocker {
PthreadLockerPthreadLocker37 explicit PthreadLocker(pthread_mutex_t& mutex) : mutex_(mutex)
38 {
39 pthread_mutex_lock(&mutex_);
40 }
41
~PthreadLockerPthreadLocker42 ~PthreadLocker()
43 {
44 pthread_mutex_unlock(&mutex_);
45 }
46
47 private:
48 pthread_mutex_t& mutex_;
49 };
50
ShareMemoryBlock()51 ShareMemoryBlock::ShareMemoryBlock()
52 : fileDescriptor_(-1),
53 memoryPoint_(nullptr),
54 memorySize_(0),
55 memoryName_(),
56 header_(nullptr),
57 reusePloicy_(ReusePolicy::DROP_NONE)
58 {
59 }
60
CreateBlockWithFd(std::string name,uint32_t size,int fd)61 bool ShareMemoryBlock::CreateBlockWithFd(std::string name, uint32_t size, int fd)
62 {
63 CHECK_TRUE(fd >= 0, false, "CreateBlock FAIL SYS_memfd_create");
64
65 auto ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
66 if (ptr == MAP_FAILED) {
67 const int bufSize = 1024;
68 char buf[bufSize] = { 0 };
69 strerror_r(errno, buf, bufSize);
70 HILOG_ERROR(LOG_CORE, "CreateBlockWithFd mmap ERR : %s", buf);
71 return false;
72 }
73
74 fileDescriptor_ = fd;
75 memoryPoint_ = ptr;
76 memorySize_ = size;
77
78 memoryName_ = name;
79 header_ = reinterpret_cast<BlockHeader*>(ptr);
80 return true;
81 }
82
CreateBlock(std::string name,uint32_t size)83 bool ShareMemoryBlock::CreateBlock(std::string name, uint32_t size)
84 {
85 HILOG_INFO(LOG_CORE, "CreateBlock %s %d", name.c_str(), size);
86 CHECK_TRUE(size > sizeof(BlockHeader), false, "size %u too less!", size);
87 CHECK_TRUE(size % PAGE_SIZE == 0, false, "size %u not times of %d!", size, PAGE_SIZE);
88
89 int fd = syscall(SYS_memfd_create, name.c_str(), 0);
90 CHECK_TRUE(fd >= 0, false, "CreateBlock FAIL SYS_memfd_create");
91
92 int check = ftruncate(fd, size);
93 if (check < 0) {
94 close(fd);
95 const int bufSize = 1024;
96 char buf[bufSize] = { 0 };
97 strerror_r(errno, buf, bufSize);
98 HILOG_ERROR(LOG_CORE, "CreateBlock ftruncate ERR : %s", buf);
99 return false;
100 }
101
102 auto ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
103 if (ptr == MAP_FAILED) {
104 close(fd);
105 const int bufSize = 1024;
106 char buf[bufSize] = { 0 };
107 strerror_r(errno, buf, bufSize);
108 HILOG_ERROR(LOG_CORE, "CreateBlock mmap ERR : %s", buf);
109 return false;
110 }
111
112 fileDescriptor_ = fd;
113 memoryPoint_ = ptr;
114 memorySize_ = size;
115
116 memoryName_ = name;
117 header_ = reinterpret_cast<BlockHeader*>(ptr);
118
119 // initialize header infos
120 header_->info.readOffset_ = 0;
121 header_->info.writeOffset_ = 0;
122 header_->info.memorySize_ = size - sizeof(BlockHeader);
123 header_->info.bytesCount_ = 0;
124 header_->info.chunkCount_ = 0;
125
126 pthread_mutexattr_t muAttr;
127 pthread_mutexattr_init(&muAttr);
128 pthread_mutexattr_setpshared(&muAttr, PTHREAD_PROCESS_SHARED);
129 pthread_mutex_init(&header_->info.mutex_, &muAttr);
130 return true;
131 }
132
Valid() const133 bool ShareMemoryBlock::Valid() const
134 {
135 return header_ != nullptr;
136 }
137
ShareMemoryBlock(const std::string & name,uint32_t size)138 ShareMemoryBlock::ShareMemoryBlock(const std::string& name, uint32_t size) : ShareMemoryBlock()
139 {
140 CreateBlock(name, size);
141 }
142
ShareMemoryBlock(const std::string & name,uint32_t size,int fd)143 ShareMemoryBlock::ShareMemoryBlock(const std::string& name, uint32_t size, int fd) : ShareMemoryBlock()
144 {
145 CreateBlockWithFd(name, size, fd);
146 }
147
~ShareMemoryBlock()148 ShareMemoryBlock::~ShareMemoryBlock()
149 {
150 ReleaseBlock();
151 }
152
ReleaseBlock()153 bool ShareMemoryBlock::ReleaseBlock()
154 {
155 if (memorySize_ > 0) {
156 munmap(memoryPoint_, memorySize_);
157 memoryPoint_ = nullptr;
158 memorySize_ = 0;
159 }
160
161 if (fileDescriptor_ >= 0) {
162 close(fileDescriptor_);
163 fileDescriptor_ = -1;
164 }
165 return true;
166 }
167
GetCurrentFreeMemory(uint32_t size)168 int8_t* ShareMemoryBlock::GetCurrentFreeMemory(uint32_t size)
169 {
170 CHECK_NOTNULL(header_, nullptr, "header not ready!");
171 uint32_t realSize = size + sizeof(uint32_t) + HEAD_OFFSET_LEN;
172
173 uint32_t wp = header_->info.writeOffset_;
174 if (wp + realSize > header_->info.memorySize_) { // 后面部分放不下,从头开始放
175 if (header_->info.readOffset_ == 0) {
176 return nullptr;
177 }
178 *((uint32_t*)(&header_->data[wp])) = 0xffffffff;
179 wp = 0;
180 }
181 if (wp < header_->info.readOffset_ && header_->info.readOffset_ < wp + realSize) { //
182 return nullptr;
183 }
184
185 return &header_->data[wp + sizeof(uint32_t)];
186 }
187
GetFreeMemory(uint32_t size)188 int8_t* ShareMemoryBlock::GetFreeMemory(uint32_t size)
189 {
190 if (reusePloicy_ == ReusePolicy::DROP_NONE) {
191 return GetCurrentFreeMemory(size);
192 }
193 int8_t* ret = nullptr;
194 while (true) {
195 ret = GetCurrentFreeMemory(size);
196 if (ret != nullptr) {
197 break;
198 }
199 if (!Next()) {
200 return nullptr;
201 }
202 }
203 return ret;
204 }
205
UseFreeMemory(int8_t * pmem,uint32_t size)206 bool ShareMemoryBlock::UseFreeMemory(int8_t* pmem, uint32_t size)
207 {
208 uint32_t wp = pmem - sizeof(uint32_t) - header_->data;
209 *((int*)(&header_->data[wp])) = size;
210
211 header_->info.writeOffset_ = wp + sizeof(uint32_t) + size;
212 return true;
213 }
214
PutRaw(const int8_t * data,uint32_t size)215 bool ShareMemoryBlock::PutRaw(const int8_t* data, uint32_t size)
216 {
217 CHECK_NOTNULL(header_, false, "header not ready!");
218 PthreadLocker locker(header_->info.mutex_);
219 int8_t* rawMemory = GetFreeMemory(size);
220 if (rawMemory == nullptr) {
221 HILOG_INFO(LOG_CORE, "_PutRaw not enough space [%d]", size);
222 return false;
223 }
224 if (memcpy_s(rawMemory, size, data, size) != EOK) {
225 HILOG_ERROR(LOG_CORE, "memcpy_s error");
226 return false;
227 }
228
229 UseFreeMemory(rawMemory, size);
230 ++header_->info.bytesCount_;
231 ++header_->info.chunkCount_;
232 return true;
233 }
234
235 #ifndef NO_PROTOBUF
PutMessage(const google::protobuf::Message & pmsg)236 bool ShareMemoryBlock::PutMessage(const google::protobuf::Message& pmsg)
237 {
238 size_t size = pmsg.ByteSizeLong();
239
240 CHECK_NOTNULL(header_, false, "header not ready!");
241 PthreadLocker locker(header_->info.mutex_);
242 int8_t* rawMemory = GetFreeMemory(size);
243 if (rawMemory == nullptr) {
244 HILOG_INFO(LOG_CORE, "PutMessage not enough space [%zu]", size);
245 return false;
246 }
247
248 pmsg.SerializeToArray(rawMemory, size);
249 UseFreeMemory(rawMemory, size);
250 ++header_->info.bytesCount_;
251 ++header_->info.chunkCount_;
252 return true;
253 }
254 #endif
255
TakeData(const DataHandler & func)256 bool ShareMemoryBlock::TakeData(const DataHandler& func)
257 {
258 CHECK_NOTNULL(header_, false, "header not ready!");
259 CHECK_TRUE(static_cast<bool>(func), false, "func invalid!");
260
261 PthreadLocker locker(header_->info.mutex_);
262 auto size = GetDataSize();
263 if (size == 0) {
264 return false;
265 }
266 auto ptr = GetDataPoint();
267 CHECK_TRUE(func(ptr, size), false, "call func FAILED!");
268 CHECK_TRUE(Next(), false, "move read pointer FAILED!");
269 --header_->info.chunkCount_;
270 return true;
271 }
272
GetDataSize()273 uint32_t ShareMemoryBlock::GetDataSize()
274 {
275 if (header_->info.readOffset_ == header_->info.writeOffset_) {
276 return 0;
277 }
278 uint32_t ret = *((uint32_t*)(&header_->data[header_->info.readOffset_]));
279 if (ret == 0xffffffff) {
280 ret = *((uint32_t*)(&header_->data[0]));
281 }
282 return ret;
283 }
284
GetDataPoint()285 const int8_t* ShareMemoryBlock::GetDataPoint()
286 {
287 if (*((uint32_t*)(&header_->data[header_->info.readOffset_])) == 0xffffffff) {
288 return &header_->data[HEAD_OFFSET_LEN];
289 }
290 return &header_->data[header_->info.readOffset_ + HEAD_OFFSET_LEN];
291 }
292
Next()293 bool ShareMemoryBlock::Next()
294 {
295 if (header_->info.readOffset_ == header_->info.writeOffset_) {
296 return false;
297 }
298 uint32_t size = *((uint32_t*)(&header_->data[header_->info.readOffset_]));
299 if (size == 0xffffffff) {
300 size = *((uint32_t*)(&header_->data[0]));
301 header_->info.readOffset_ = size + sizeof(uint32_t);
302 } else {
303 header_->info.readOffset_ += size + sizeof(uint32_t);
304 }
305 return true;
306 }
307
GetName()308 std::string ShareMemoryBlock::GetName()
309 {
310 return memoryName_;
311 }
312
GetSize()313 uint32_t ShareMemoryBlock::GetSize()
314 {
315 return memorySize_;
316 }
317
GetfileDescriptor()318 int ShareMemoryBlock::GetfileDescriptor()
319 {
320 return fileDescriptor_;
321 }
322