• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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