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 "shared_memory.h"
17
18 #include <cerrno>
19 #include <cstdlib>
20 #include <cstring>
21 #include <sys/shm.h>
22 #include "hilog_wrapper.h"
23 #include "securec.h"
24
25 namespace OHOS {
26 namespace AAFwk {
27 namespace {
28 constexpr int SHM_KEY_START = 400000; // chosen randomly
29 constexpr int SHM_KEY_END = 500000; // chosen randomly
30 constexpr unsigned int SHM_READ_WRITE_PERMISSIONS = 0666U;
31
32 #ifndef EOK
33 #define EOK (0)
34 #endif
35 }
36
ReleaseShmId(int shmId)37 void SharedMemory::ReleaseShmId(int shmId)
38 {
39 if (shmId == -1) {
40 return;
41 }
42 if (shmctl(shmId, IPC_RMID, nullptr) == -1) {
43 HILOG_ERROR("shmctl IPC_RMID failed: %{public}d.", errno);
44 return;
45 }
46 }
47
PushSharedMemory(const void * data,int size)48 int SharedMemory::PushSharedMemory(const void *data, int size)
49 {
50 // internal call, no need to check null.
51 static int shmKey = SHM_KEY_START;
52 int shmId;
53 while ((shmId = shmget(shmKey, size, SHM_READ_WRITE_PERMISSIONS | IPC_CREAT | IPC_EXCL)) < 0) {
54 if (errno == EEXIST) {
55 ++shmKey;
56 if (shmKey >= SHM_KEY_END) {
57 shmKey = SHM_KEY_START;
58 }
59 continue;
60 }
61 HILOG_ERROR("shmget failed: %{public}d.", errno);
62 return -1;
63 }
64 HILOG_INFO("shmget succeed, shmKey = %{public}d, shmId = %{public}d.", shmKey, shmId);
65
66 void *shared = shmat(shmId, nullptr, 0);
67 if (shared == reinterpret_cast<void *>(-1)) {
68 ReleaseShmId(shmId);
69 HILOG_ERROR("shmat failed: %{public}d.", errno);
70 return -1;
71 }
72
73 int retCode;
74 if ((retCode = memcpy_s(shared, size, data, size)) != EOK) {
75 shmdt(shared);
76 ReleaseShmId(shmId);
77 HILOG_ERROR("memcpy_s failed: %{public}d.", retCode);
78 return -1;
79 }
80
81 if (shmdt(shared) == -1) {
82 ReleaseShmId(shmId);
83 HILOG_ERROR("shmdt failed: %{public}d.", errno);
84 return -1;
85 }
86
87 return shmKey;
88 }
89
PopSharedMemory(int shmKey,int size)90 void* SharedMemory::PopSharedMemory(int shmKey, int size)
91 {
92 if (size <= 0) {
93 HILOG_ERROR("size is invalid: %{public}d.", size);
94 return nullptr;
95 }
96
97 int shmId = shmget(shmKey, 0, 0 | SHM_READ_WRITE_PERMISSIONS);
98 if (shmId == -1) {
99 HILOG_ERROR("shmId is invalid: %{public}d, %{public}d.", shmId, errno);
100 return nullptr;
101 }
102
103 void *shared = shmat(shmId, nullptr, 0);
104 if (shared == reinterpret_cast<void *>(-1)) {
105 HILOG_ERROR("shmat failed %{public}d.", errno);
106 ReleaseShmId(shmId);
107 return nullptr;
108 }
109
110 void *data = reinterpret_cast<void *>(malloc(size));
111 if (data == nullptr) {
112 HILOG_ERROR("malloc failed %{public}d.", errno);
113 return nullptr;
114 }
115 int retCode = memcpy_s(data, size, shared, size);
116 if (retCode != EOK) {
117 shmdt(shared);
118 ReleaseShmId(shmId);
119 HILOG_ERROR("Failed to memory copy, retCode[%{public}d].", retCode);
120 free(data);
121 return nullptr;
122 }
123
124 if (shmdt(shared) == -1) {
125 ReleaseShmId(shmId);
126 HILOG_ERROR("shmdt failed: %{public}d.", errno);
127 free(data);
128 return nullptr;
129 }
130
131 ReleaseShmId(shmId);
132
133 return data;
134 }
135
136 } // namespace AAFwk
137 } // namespace OHOS