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 31namespace OHOS { 32using namespace OHOS::HiviewDFX; 33 34namespace { 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 49constexpr int32_t INVALID_FD = -1; 50constexpr uint32_t MAX_FENCE_NUM = 65535; 51} // namespace 52 53const sptr<SyncFence> SyncFence::INVALID_FENCE = sptr<SyncFence>(new SyncFence(INVALID_FD)); 54const ns_sec_t SyncFence::INVALID_TIMESTAMP = -1; 55const ns_sec_t SyncFence::FENCE_PENDING_TIMESTAMP = INT64_MAX; 56 57SyncFence::SyncFence(int32_t fenceFd) : fenceFd_(fenceFd) 58{ 59} 60 61SyncFence::~SyncFence() 62{ 63} 64 65int32_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 94int32_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 113sptr<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 139ns_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 166std::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 219int32_t SyncFence::Dup() const 220{ 221 return ::dup(fenceFd_); 222} 223 224FenceStatus 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 246int32_t SyncFence::Get() const 247{ 248 return fenceFd_; 249} 250 251bool SyncFence::IsValid() const 252{ 253 return fenceFd_ != -1; 254} 255 256sptr<SyncFence> SyncFence::ReadFromMessageParcel(MessageParcel &parcel) 257{ 258 int32_t fence = parcel.ReadInt32(); 259 if (fence < 0) { 260 return INVALID_FENCE; 261 } 262 263 fence = parcel.ReadFileDescriptor(); 264 265 return sptr<SyncFence>(new SyncFence(fence)); 266} 267 268sptr<SyncFence> SyncFence::InvalidFence() 269{ 270 return sptr<SyncFence>(new SyncFence(-1)); 271} 272 273bool SyncFence::WriteToMessageParcel(MessageParcel &parcel) 274{ 275 int32_t fence = fenceFd_; 276 if (fence >= 0 && fcntl(fence, F_GETFL) == -1 && errno == EBADF) { 277 fence = -1; 278 } 279 280 if (!parcel.WriteInt32(fence)) { 281 return false; 282 } 283 284 if (fence < 0) { 285 UTILS_LOGD("WriteToMessageParcel fence is invalid : %{public}d", fence); 286 return true; 287 } 288 289 if (!parcel.WriteFileDescriptor(fence)) { 290 return false; 291 } 292 return true; 293} 294 295} // namespace OHOS 296