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