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