1 /*
2 * Copyright (c) 2021-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
16 #include "sync_fence.h"
17
18 #include <cstddef>
19 #include <cstdint>
20 #include <cstdlib>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <limits>
24 #include <securec.h>
25 #include <fcntl.h>
26 #include <sys/poll.h>
27 #include <linux/sync_file.h>
28 #include <sys/ioctl.h>
29 #include "hilog/log.h"
30
31 namespace OHOS {
32 using namespace OHOS::HiviewDFX;
33
34 namespace {
35 #undef LOG_DOMAIN
36 #define LOG_DOMAIN 0xD001400
37 #undef LOG_TAG
38 #define LOG_TAG "SyncFence"
39
40 #define B_CPRINTF(func, fmt, ...) \
41 func(LOG_CORE, "<%{public}d>%{public}s: " fmt, \
42 __LINE__, __func__, ##__VA_ARGS__)
43
44 #define UTILS_LOGD(fmt, ...) B_CPRINTF(HILOG_DEBUG, fmt, ##__VA_ARGS__)
45 #define UTILS_LOGI(fmt, ...) B_CPRINTF(HILOG_INFO, fmt, ##__VA_ARGS__)
46 #define UTILS_LOGW(fmt, ...) B_CPRINTF(HILOG_WARN, fmt, ##__VA_ARGS__)
47 #define UTILS_LOGE(fmt, ...) B_CPRINTF(HILOG_ERROR, fmt, ##__VA_ARGS__)
48
49 constexpr int32_t INVALID_FD = -1;
50 constexpr uint32_t MAX_FENCE_NUM = 65535;
51 } // namespace
52
53 const sptr<SyncFence> SyncFence::INVALID_FENCE = sptr<SyncFence>(new SyncFence(INVALID_FD));
54 const ns_sec_t SyncFence::INVALID_TIMESTAMP = -1;
55 const ns_sec_t SyncFence::FENCE_PENDING_TIMESTAMP = INT64_MAX;
56
SyncFence(int32_t fenceFd)57 SyncFence::SyncFence(int32_t fenceFd) : fenceFd_(fenceFd)
58 {
59 }
60
~SyncFence()61 SyncFence::~SyncFence()
62 {
63 }
64
Wait(uint32_t timeout)65 int32_t SyncFence::Wait(uint32_t timeout)
66 {
67 int retCode = -1;
68 if (fenceFd_ < 0) {
69 return retCode;
70 }
71
72 struct pollfd pollfds = {0};
73 pollfds.fd = fenceFd_;
74 pollfds.events = POLLIN;
75
76 do {
77 retCode = poll(&pollfds, 1, timeout);
78 } while (retCode == -1 && (errno == EINTR || errno == EAGAIN));
79
80 if (retCode == 0) {
81 retCode = -1;
82 errno = ETIME;
83 } else if (retCode > 0) {
84 retCode = 0;
85 if (pollfds.revents & (POLLERR | POLLNVAL)) {
86 retCode = -1;
87 errno = EINVAL;
88 }
89 }
90
91 return retCode < 0 ? -errno : 0;
92 }
93
SyncMerge(const char * name,int32_t fd1,int32_t fd2,int32_t & newFenceFd)94 int32_t SyncFence::SyncMerge(const char *name, int32_t fd1, int32_t fd2, int32_t &newFenceFd)
95 {
96 struct sync_merge_data syncMergeData = {};
97 syncMergeData.fd2 = fd2;
98 if (strcpy_s(syncMergeData.name, sizeof(syncMergeData.name), name)) {
99 UTILS_LOGE("SyncMerge ctrcpy fence name failed.");
100 return -1;
101 }
102 int32_t retCode = ioctl(fd1, SYNC_IOC_MERGE, &syncMergeData);
103 if (retCode < 0) {
104 errno = EINVAL;
105 UTILS_LOGE("Fence merge failed, errno: %{public}d, ret: %{public}d.", errno, retCode);
106 return -1;
107 }
108
109 newFenceFd = syncMergeData.fence;
110 return 0;
111 }
112
MergeFence(const std::string & name,const sptr<SyncFence> & fence1,const sptr<SyncFence> & fence2)113 sptr<SyncFence> SyncFence::MergeFence(const std::string &name,
114 const sptr<SyncFence>& fence1, const sptr<SyncFence>& fence2)
115 {
116 int32_t newFenceFd = INVALID_FD;
117 int32_t fenceFd1 = fence1->fenceFd_;
118 int32_t fenceFd2 = fence2->fenceFd_;
119
120 if (fenceFd1 >= 0 && fenceFd2 >= 0) {
121 (void)SyncFence::SyncMerge(name.c_str(), fenceFd1, fenceFd2, newFenceFd);
122 } else if (fenceFd1 >= 0) {
123 (void)SyncFence::SyncMerge(name.c_str(), fenceFd1, fenceFd1, newFenceFd);
124 } else if (fenceFd2 >= 0) {
125 (void)SyncFence::SyncMerge(name.c_str(), fenceFd2, fenceFd2, newFenceFd);
126 } else {
127 return INVALID_FENCE;
128 }
129
130 if (newFenceFd == INVALID_FD) {
131 UTILS_LOGE("sync_merge(%{public}s) failed, error: %{public}s (%{public}d)",
132 name.c_str(), strerror(errno), errno);
133 return INVALID_FENCE;
134 }
135
136 return sptr<SyncFence>(new SyncFence(newFenceFd));
137 }
138
SyncFileReadTimestamp()139 ns_sec_t SyncFence::SyncFileReadTimestamp()
140 {
141 std::vector<SyncPointInfo> ptInfos = GetFenceInfo();
142 if (ptInfos.empty()) {
143 return FENCE_PENDING_TIMESTAMP;
144 }
145 size_t signalFenceCount = 0;
146 for (const auto &info : ptInfos) {
147 if (info.status == SIGNALED) {
148 signalFenceCount++;
149 }
150 }
151 if (signalFenceCount == ptInfos.size()) {
152 // fence signaled
153 uint64_t timestamp = 0;
154 for (const auto &ptInfo : ptInfos) {
155 if (ptInfo.timestampNs > timestamp) {
156 timestamp = ptInfo.timestampNs;
157 }
158 }
159 return static_cast<ns_sec_t>(timestamp);
160 } else {
161 // fence still active
162 return FENCE_PENDING_TIMESTAMP;
163 }
164 }
165
GetFenceInfo()166 std::vector<SyncPointInfo> SyncFence::GetFenceInfo()
167 {
168 struct sync_file_info arg;
169 struct sync_file_info *infoPtr = nullptr;
170
171 errno_t retCode = memset_s(&arg, sizeof(struct sync_file_info), 0, sizeof(struct sync_file_info));
172 if (retCode != EOK) {
173 UTILS_LOGE("memset_s error, retCode = %{public}d", retCode);
174 return {};
175 }
176 int32_t ret = ioctl(fenceFd_, SYNC_IOC_FILE_INFO, &arg);
177 if (ret < 0) {
178 UTILS_LOGD("GetFenceInfo SYNC_IOC_FILE_INFO ioctl failed, ret: %{public}d", ret);
179 return {};
180 }
181 if (arg.num_fences <= 0 || arg.num_fences > MAX_FENCE_NUM) {
182 UTILS_LOGD("GetFenceInfo arg.num_fences failed, num_fences: %{public}d", arg.num_fences);
183 return {};
184 }
185 auto sizeMax = std::numeric_limits<size_t>::max();
186 if ((sizeMax - sizeof(struct sync_file_info)) / sizeof(struct sync_fence_info) < arg.num_fences) {
187 UTILS_LOGE("GetFenceInfo overflow, num_fences: %{public}d", arg.num_fences);
188 return {};
189 }
190 size_t syncFileInfoMemSize = sizeof(struct sync_file_info) + sizeof(struct sync_fence_info) * arg.num_fences;
191 infoPtr = (struct sync_file_info *)malloc(syncFileInfoMemSize);
192 if (infoPtr == nullptr) {
193 UTILS_LOGD("GetFenceInfo malloc failed oom");
194 return {};
195 }
196 retCode = memset_s(infoPtr, syncFileInfoMemSize, 0, syncFileInfoMemSize);
197 if (retCode != 0) {
198 UTILS_LOGE("memset_s error, retCode = %{public}d", retCode);
199 free(infoPtr);
200 return {};
201 }
202 infoPtr->num_fences = arg.num_fences;
203 infoPtr->sync_fence_info = static_cast<uint64_t>(uintptr_t(infoPtr + 1));
204 ret = ioctl(fenceFd_, SYNC_IOC_FILE_INFO, infoPtr);
205 if (ret < 0) {
206 UTILS_LOGE("GetTotalFenceInfo SYNC_IOC_FILE_INFO ioctl failed, ret: %{public}d", ret);
207 free(infoPtr);
208 return {};
209 }
210 std::vector<SyncPointInfo> infos;
211 const auto fenceInfos = (struct sync_fence_info *)(uintptr_t)(infoPtr->sync_fence_info);
212 for (uint32_t i = 0; i < infoPtr->num_fences; i++) {
213 infos.push_back(SyncPointInfo { fenceInfos[i].timestamp_ns, static_cast<FenceStatus>(fenceInfos[i].status) });
214 }
215 free(infoPtr);
216 return infos;
217 }
218
Dup() const219 int32_t SyncFence::Dup() const
220 {
221 return ::dup(fenceFd_);
222 }
223
GetStatus()224 FenceStatus SyncFence::GetStatus()
225 {
226 if (fenceFd_ < 0) {
227 return ERROR;
228 }
229 std::vector<SyncPointInfo> ptInfos = GetFenceInfo();
230 if (ptInfos.empty()) {
231 return ERROR;
232 }
233 size_t signalFenceCount = 0;
234 for (const auto &info : ptInfos) {
235 if (info.status == SIGNALED) {
236 signalFenceCount++;
237 }
238 }
239 if (signalFenceCount == ptInfos.size()) {
240 return SIGNALED;
241 } else {
242 return ACTIVE;
243 }
244 }
245
Get() const246 int32_t SyncFence::Get() const
247 {
248 return fenceFd_;
249 }
250
IsValid() const251 bool SyncFence::IsValid() const
252 {
253 return fenceFd_ != -1;
254 }
255
ReadFromMessageParcel(MessageParcel & parcel,std::function<int (MessageParcel & parcel,std::function<int (Parcel &)> readFdDefaultFunc)> readSafeFdFunc)256 sptr<SyncFence> SyncFence::ReadFromMessageParcel(MessageParcel &parcel,
257 std::function<int(MessageParcel &parcel, std::function<int(Parcel &)>readFdDefaultFunc)>readSafeFdFunc)
258 {
259 int32_t fence = parcel.ReadInt32();
260 if (fence < 0) {
261 return INVALID_FENCE;
262 }
263
264 auto readFdDefaultFunc = [] (Parcel &parcel) -> int {
265 MessageParcel *msgParcel = static_cast<MessageParcel *>(&parcel);
266 return msgParcel->ReadFileDescriptor();
267 };
268 fence = readSafeFdFunc ? readSafeFdFunc(parcel, readFdDefaultFunc) : parcel.ReadFileDescriptor();
269 return sptr<SyncFence>(new SyncFence(fence));
270 }
271
InvalidFence()272 sptr<SyncFence> SyncFence::InvalidFence()
273 {
274 return sptr<SyncFence>(new SyncFence(-1));
275 }
276
WriteToMessageParcel(MessageParcel & parcel)277 bool SyncFence::WriteToMessageParcel(MessageParcel &parcel)
278 {
279 int32_t fence = fenceFd_;
280 if (fence >= 0 && fcntl(fence, F_GETFL) == -1 && errno == EBADF) {
281 fence = -1;
282 }
283
284 if (!parcel.WriteInt32(fence)) {
285 return false;
286 }
287
288 if (fence < 0) {
289 UTILS_LOGD("WriteToMessageParcel fence is invalid : %{public}d", fence);
290 return true;
291 }
292
293 if (!parcel.WriteFileDescriptor(fence)) {
294 return false;
295 }
296 return true;
297 }
298
299 } // namespace OHOS
300