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