• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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