• 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/syscall.h>
22 #include <unistd.h>
23 #include "ashmem.h"
24 #include "logging.h"
25 #include "securec.h"
26 
27 namespace {
28 const int HEAD_OFFSET_LEN = 4;
29 constexpr uint32_t TIMEOUT_SEC = 1;
30 const int WAIT_RELEASE_TIMEOUT_US = 10;
31 #ifndef PAGE_SIZE
32 constexpr uint32_t PAGE_SIZE = 4096;
33 #endif
34 }  // namespace
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 = 256;
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 = OHOS::AshmemCreate(name.c_str(), size);
90     CHECK_TRUE(fd >= 0, false, "OHOS::AshmemCreate fail.");
91 
92     int check = OHOS::AshmemSetProt(fd, PROT_READ | PROT_WRITE);
93     if (check < 0) {
94         close(fd);
95         const int bufSize = 256;
96         char buf[bufSize] = {0};
97         strerror_r(errno, buf, bufSize);
98         HILOG_ERROR(LOG_CORE, "OHOS::AshmemSetProt 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 = 256;
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_mutexattr_settype(&muAttr, PTHREAD_MUTEX_RECURSIVE);
130     pthread_mutex_init(&header_->info.mutex_, &muAttr);
131     return true;
132 }
133 
Valid() const134 bool ShareMemoryBlock::Valid() const
135 {
136     return header_ != nullptr;
137 }
138 
ShareMemoryBlock(const std::string & name,uint32_t size)139 ShareMemoryBlock::ShareMemoryBlock(const std::string& name, uint32_t size) : ShareMemoryBlock()
140 {
141     CreateBlock(name, size);
142 }
143 
ShareMemoryBlock(const std::string & name,uint32_t size,int fd)144 ShareMemoryBlock::ShareMemoryBlock(const std::string& name, uint32_t size, int fd) : ShareMemoryBlock()
145 {
146     CreateBlockWithFd(name, size, fd);
147 }
148 
~ShareMemoryBlock()149 ShareMemoryBlock::~ShareMemoryBlock()
150 {
151     ReleaseBlock();
152 }
153 
ReleaseBlock()154 bool ShareMemoryBlock::ReleaseBlock()
155 {
156     if (memorySize_ > 0) {
157         munmap(memoryPoint_, memorySize_);
158         memoryPoint_ = nullptr;
159         memorySize_ = 0;
160     }
161 
162     if (fileDescriptor_ >= 0) {
163         close(fileDescriptor_);
164         fileDescriptor_ = -1;
165     }
166     return true;
167 }
168 
GetCurrentFreeMemory(uint32_t size)169 int8_t* ShareMemoryBlock::GetCurrentFreeMemory(uint32_t size)
170 {
171     CHECK_NOTNULL(header_, nullptr, "header not ready!");
172     uint32_t realSize = size + sizeof(uint32_t) + HEAD_OFFSET_LEN;
173 
174     uint32_t wp = header_->info.writeOffset_;
175     if (wp + realSize > header_->info.memorySize_) {  // 后面部分放不下,从头开始放
176         if (header_->info.readOffset_ == 0) {
177             return nullptr;
178         }
179         *((uint32_t*)(&header_->data[wp])) = 0xffffffff;
180         wp = 0;
181     }
182     if (wp < header_->info.readOffset_ && header_->info.readOffset_ < wp + realSize) {  //
183         return nullptr;
184     }
185 
186     return &header_->data[wp + sizeof(uint32_t)];
187 }
188 
GetFreeMemory(uint32_t size)189 int8_t* ShareMemoryBlock::GetFreeMemory(uint32_t size)
190 {
191     if (reusePloicy_ == ReusePolicy::DROP_NONE) {
192         return GetCurrentFreeMemory(size);
193     }
194     int8_t* ret = nullptr;
195     while (true) {
196         ret = GetCurrentFreeMemory(size);
197         if (ret != nullptr) {
198             break;
199         }
200         if (!Next()) {
201             return nullptr;
202         }
203     }
204     return ret;
205 }
206 
UseFreeMemory(int8_t * pmem,uint32_t size)207 bool ShareMemoryBlock::UseFreeMemory(int8_t* pmem, uint32_t size)
208 {
209     uint32_t wp = pmem - sizeof(uint32_t) - header_->data;
210     *((int*)(&header_->data[wp])) = size;
211 
212     header_->info.writeOffset_ = wp + sizeof(uint32_t) + size;
213     return true;
214 }
215 
PutRaw(const int8_t * data,uint32_t size)216 bool ShareMemoryBlock::PutRaw(const int8_t* data, uint32_t size)
217 {
218     CHECK_NOTNULL(header_, false, "header not ready!");
219     PthreadLocker locker(header_->info.mutex_);
220     int8_t* rawMemory = GetFreeMemory(size);
221     if (rawMemory == nullptr) {
222         HILOG_ERROR(LOG_CORE, "PutRaw not enough space [%d]", size);
223         return false;
224     }
225     if (memcpy_s(rawMemory, size, data, size) != EOK) {
226         HILOG_ERROR(LOG_CORE, "memcpy_s error");
227         return false;
228     }
229 
230     UseFreeMemory(rawMemory, size);
231     ++header_->info.bytesCount_;
232     ++header_->info.chunkCount_;
233     return true;
234 }
235 
PutRawTimeout(const int8_t * data,uint32_t size)236 bool ShareMemoryBlock::PutRawTimeout(const int8_t* data, uint32_t size)
237 {
238     CHECK_NOTNULL(header_, false, "header not ready!");
239 
240     struct timespec time_out;
241     clock_gettime(CLOCK_REALTIME, &time_out);
242     time_out.tv_sec += TIMEOUT_SEC;
243     if (pthread_mutex_timedlock(&header_->info.mutex_, &time_out) != 0) {
244         HILOG_ERROR(LOG_CORE, "PutRawTimeout failed %d", errno);
245         return false;
246     }
247 
248     int8_t* rawMemory = GetFreeMemory(size);
249     if (rawMemory == nullptr) {
250         HILOG_ERROR(LOG_CORE, "PutRaw not enough space [%d]", size);
251         pthread_mutex_unlock(&header_->info.mutex_);
252         return false;
253     }
254     if (memcpy_s(rawMemory, size, data, size) != EOK) {
255         HILOG_ERROR(LOG_CORE, "memcpy_s error");
256         pthread_mutex_unlock(&header_->info.mutex_);
257         return false;
258     }
259 
260     UseFreeMemory(rawMemory, size);
261     ++header_->info.bytesCount_;
262     ++header_->info.chunkCount_;
263 
264     pthread_mutex_unlock(&header_->info.mutex_);
265     return true;
266 }
267 
PutWithPayloadTimeout(const int8_t * header,uint32_t headerSize,const int8_t * payload,uint32_t payloadSize)268 bool ShareMemoryBlock::PutWithPayloadTimeout(const int8_t* header, uint32_t headerSize,
269     const int8_t* payload, uint32_t payloadSize)
270 {
271     CHECK_NOTNULL(header_, false, "header not ready!");
272     struct timespec time_out;
273     clock_gettime(CLOCK_REALTIME, &time_out);
274     time_out.tv_sec += TIMEOUT_SEC;
275     if (pthread_mutex_timedlock(&header_->info.mutex_, &time_out) != 0) {
276         return false;
277     }
278 
279     int8_t* rawMemory = GetFreeMemory(headerSize + payloadSize);
280     if (rawMemory == nullptr) {
281         pthread_mutex_unlock(&header_->info.mutex_);
282         return false;
283     }
284     if (memcpy_s(rawMemory, headerSize, header, headerSize) != EOK) {
285         pthread_mutex_unlock(&header_->info.mutex_);
286         return false;
287     }
288     if (payloadSize > 0) {
289         if (memcpy_s(rawMemory + headerSize, payloadSize, payload, payloadSize) != EOK) {
290             pthread_mutex_unlock(&header_->info.mutex_);
291             return false;
292         }
293     }
294     UseFreeMemory(rawMemory, headerSize + payloadSize);
295     ++header_->info.bytesCount_;
296     ++header_->info.chunkCount_;
297 
298     pthread_mutex_unlock(&header_->info.mutex_);
299     return true;
300 }
301 
302 #ifndef NO_PROTOBUF
PutMessage(const google::protobuf::Message & pmsg,const std::string & pluginName)303 bool ShareMemoryBlock::PutMessage(const google::protobuf::Message& pmsg, const std::string& pluginName)
304 {
305     size_t size = pmsg.ByteSizeLong();
306 
307     CHECK_NOTNULL(header_, false, "header not ready!");
308     PthreadLocker locker(header_->info.mutex_);
309     int8_t* rawMemory = GetFreeMemory(size);
310     if (rawMemory == nullptr) {
311         HILOG_ERROR(LOG_CORE, "%s: PutMessage not enough space [%zu]", pluginName.c_str(), size);
312         return false;
313     }
314 
315     int ret = pmsg.SerializeToArray(rawMemory, size);
316     if (ret <= 0) {
317         HILOG_ERROR(LOG_CORE, "%s: SerializeToArray failed with %d, size: %zu", __func__, ret, size);
318         return false;
319     }
320     UseFreeMemory(rawMemory, size);
321     ++header_->info.bytesCount_;
322     ++header_->info.chunkCount_;
323     return true;
324 }
325 #endif
326 
TakeData(const DataHandler & func)327 bool ShareMemoryBlock::TakeData(const DataHandler& func)
328 {
329     CHECK_NOTNULL(header_, false, "header not ready!");
330     CHECK_TRUE(static_cast<bool>(func), false, "func invalid!");
331 
332     PthreadLocker locker(header_->info.mutex_);
333     auto size = GetDataSize();
334     if (size == 0) {
335         return false;
336     }
337     auto ptr = GetDataPoint();
338     CHECK_TRUE(func(ptr, size), false, "call func FAILED!");
339     CHECK_TRUE(Next(), false, "move read pointer FAILED!");
340     --header_->info.chunkCount_;
341     return true;
342 }
343 
GetDataSize()344 uint32_t ShareMemoryBlock::GetDataSize()
345 {
346     if (header_->info.readOffset_ == header_->info.writeOffset_) {
347         return 0;
348     }
349     uint32_t ret = *((uint32_t*)(&header_->data[header_->info.readOffset_]));
350     if (ret == 0xffffffff) {
351         ret = *((uint32_t*)(&header_->data[0]));
352     }
353     return ret;
354 }
355 
GetDataPoint()356 const int8_t* ShareMemoryBlock::GetDataPoint()
357 {
358     if (*((uint32_t*)(&header_->data[header_->info.readOffset_])) == 0xffffffff) {
359         return &header_->data[HEAD_OFFSET_LEN];
360     }
361     return &header_->data[header_->info.readOffset_ + HEAD_OFFSET_LEN];
362 }
363 
Next()364 bool ShareMemoryBlock::Next()
365 {
366     if (header_->info.readOffset_ == header_->info.writeOffset_) {
367         return false;
368     }
369     uint32_t size = *((uint32_t*)(&header_->data[header_->info.readOffset_]));
370     if (size == 0xffffffff) {
371         size = *((uint32_t*)(&header_->data[0]));
372         header_->info.readOffset_ = size + sizeof(uint32_t);
373     } else {
374         header_->info.readOffset_ += size + sizeof(uint32_t);
375     }
376     return true;
377 }
378 
GetName()379 std::string ShareMemoryBlock::GetName()
380 {
381     return memoryName_;
382 }
383 
GetSize()384 uint32_t ShareMemoryBlock::GetSize()
385 {
386     return memorySize_;
387 }
388 
GetfileDescriptor()389 int ShareMemoryBlock::GetfileDescriptor()
390 {
391     return fileDescriptor_;
392 }
393 
PutWithPayloadSync(const int8_t * header,uint32_t headerSize,const int8_t * payload,uint32_t payloadSize)394 bool ShareMemoryBlock::PutWithPayloadSync(const int8_t* header, uint32_t headerSize,
395     const int8_t* payload, uint32_t payloadSize)
396 {
397     CHECK_NOTNULL(header_, false, "header not ready!");
398     pthread_mutex_lock(&header_->info.mutex_);
399     int8_t* rawMemory = GetFreeMemory(headerSize + payloadSize);
400     if (rawMemory == nullptr) {
401         while (true) {
402             if (rawMemory == nullptr) {
403                 pthread_mutex_unlock(&header_->info.mutex_);
404                 usleep(WAIT_RELEASE_TIMEOUT_US);
405                 pthread_mutex_lock(&header_->info.mutex_);
406                 rawMemory = GetFreeMemory(headerSize + payloadSize);
407                 continue;
408             }
409             break;
410         }
411     }
412     if (memcpy_s(rawMemory, headerSize + payloadSize, header, headerSize) != EOK) {
413         pthread_mutex_unlock(&header_->info.mutex_);
414         return false;
415     }
416     if (payloadSize > 0) {
417         if (memcpy_s(rawMemory + headerSize, payloadSize, payload, payloadSize) != EOK) {
418             pthread_mutex_unlock(&header_->info.mutex_);
419             return false;
420         }
421     }
422     UseFreeMemory(rawMemory, headerSize + payloadSize);
423     ++header_->info.bytesCount_;
424     ++header_->info.chunkCount_;
425     pthread_mutex_unlock(&header_->info.mutex_);
426     return true;
427 }
ClearShareMemoryBlock()428 void ShareMemoryBlock::ClearShareMemoryBlock()
429 {
430     // clear header infos
431     PthreadLocker locker(header_->info.mutex_);
432     header_->info.readOffset_ = 0;
433     header_->info.writeOffset_ = 0;
434     header_->info.bytesCount_ = 0;
435     header_->info.chunkCount_ = 0;
436 }
437