132a6e48fSopenharmony_ci/* 232a6e48fSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 332a6e48fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 432a6e48fSopenharmony_ci * you may not use this file except in compliance with the License. 532a6e48fSopenharmony_ci * You may obtain a copy of the License at 632a6e48fSopenharmony_ci * 732a6e48fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 832a6e48fSopenharmony_ci * 932a6e48fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1032a6e48fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1132a6e48fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1232a6e48fSopenharmony_ci * See the License for the specific language governing permissions and 1332a6e48fSopenharmony_ci * limitations under the License. 1432a6e48fSopenharmony_ci */ 1532a6e48fSopenharmony_ci 1632a6e48fSopenharmony_ci#include "sync_fence.h" 1732a6e48fSopenharmony_ci 1832a6e48fSopenharmony_ci#include <cstddef> 1932a6e48fSopenharmony_ci#include <cstdint> 2032a6e48fSopenharmony_ci#include <cstdlib> 2132a6e48fSopenharmony_ci#include <unistd.h> 2232a6e48fSopenharmony_ci#include <errno.h> 2332a6e48fSopenharmony_ci#include <limits> 2432a6e48fSopenharmony_ci#include <securec.h> 2532a6e48fSopenharmony_ci#include <fcntl.h> 2632a6e48fSopenharmony_ci#include <sys/poll.h> 2732a6e48fSopenharmony_ci#include <linux/sync_file.h> 2832a6e48fSopenharmony_ci#include <sys/ioctl.h> 2932a6e48fSopenharmony_ci#include "hilog/log.h" 3032a6e48fSopenharmony_ci 3132a6e48fSopenharmony_cinamespace OHOS { 3232a6e48fSopenharmony_ciusing namespace OHOS::HiviewDFX; 3332a6e48fSopenharmony_ci 3432a6e48fSopenharmony_cinamespace { 3532a6e48fSopenharmony_ci#undef LOG_DOMAIN 3632a6e48fSopenharmony_ci#define LOG_DOMAIN 0xD001400 3732a6e48fSopenharmony_ci#undef LOG_TAG 3832a6e48fSopenharmony_ci#define LOG_TAG "SyncFence" 3932a6e48fSopenharmony_ci 4032a6e48fSopenharmony_ci#define B_CPRINTF(func, fmt, ...) \ 4132a6e48fSopenharmony_ci func(LOG_CORE, "<%{public}d>%{public}s: " fmt, \ 4232a6e48fSopenharmony_ci __LINE__, __func__, ##__VA_ARGS__) 4332a6e48fSopenharmony_ci 4432a6e48fSopenharmony_ci#define UTILS_LOGD(fmt, ...) B_CPRINTF(HILOG_DEBUG, fmt, ##__VA_ARGS__) 4532a6e48fSopenharmony_ci#define UTILS_LOGI(fmt, ...) B_CPRINTF(HILOG_INFO, fmt, ##__VA_ARGS__) 4632a6e48fSopenharmony_ci#define UTILS_LOGW(fmt, ...) B_CPRINTF(HILOG_WARN, fmt, ##__VA_ARGS__) 4732a6e48fSopenharmony_ci#define UTILS_LOGE(fmt, ...) B_CPRINTF(HILOG_ERROR, fmt, ##__VA_ARGS__) 4832a6e48fSopenharmony_ci 4932a6e48fSopenharmony_ciconstexpr int32_t INVALID_FD = -1; 5032a6e48fSopenharmony_ciconstexpr uint32_t MAX_FENCE_NUM = 65535; 5132a6e48fSopenharmony_ci} // namespace 5232a6e48fSopenharmony_ci 5332a6e48fSopenharmony_ciconst sptr<SyncFence> SyncFence::INVALID_FENCE = sptr<SyncFence>(new SyncFence(INVALID_FD)); 5432a6e48fSopenharmony_ciconst ns_sec_t SyncFence::INVALID_TIMESTAMP = -1; 5532a6e48fSopenharmony_ciconst ns_sec_t SyncFence::FENCE_PENDING_TIMESTAMP = INT64_MAX; 5632a6e48fSopenharmony_ci 5732a6e48fSopenharmony_ciSyncFence::SyncFence(int32_t fenceFd) : fenceFd_(fenceFd) 5832a6e48fSopenharmony_ci{ 5932a6e48fSopenharmony_ci} 6032a6e48fSopenharmony_ci 6132a6e48fSopenharmony_ciSyncFence::~SyncFence() 6232a6e48fSopenharmony_ci{ 6332a6e48fSopenharmony_ci} 6432a6e48fSopenharmony_ci 6532a6e48fSopenharmony_ciint32_t SyncFence::Wait(uint32_t timeout) 6632a6e48fSopenharmony_ci{ 6732a6e48fSopenharmony_ci int retCode = -1; 6832a6e48fSopenharmony_ci if (fenceFd_ < 0) { 6932a6e48fSopenharmony_ci return retCode; 7032a6e48fSopenharmony_ci } 7132a6e48fSopenharmony_ci 7232a6e48fSopenharmony_ci struct pollfd pollfds = {0}; 7332a6e48fSopenharmony_ci pollfds.fd = fenceFd_; 7432a6e48fSopenharmony_ci pollfds.events = POLLIN; 7532a6e48fSopenharmony_ci 7632a6e48fSopenharmony_ci do { 7732a6e48fSopenharmony_ci retCode = poll(&pollfds, 1, timeout); 7832a6e48fSopenharmony_ci } while (retCode == -1 && (errno == EINTR || errno == EAGAIN)); 7932a6e48fSopenharmony_ci 8032a6e48fSopenharmony_ci if (retCode == 0) { 8132a6e48fSopenharmony_ci retCode = -1; 8232a6e48fSopenharmony_ci errno = ETIME; 8332a6e48fSopenharmony_ci } else if (retCode > 0) { 8432a6e48fSopenharmony_ci retCode = 0; 8532a6e48fSopenharmony_ci if (pollfds.revents & (POLLERR | POLLNVAL)) { 8632a6e48fSopenharmony_ci retCode = -1; 8732a6e48fSopenharmony_ci errno = EINVAL; 8832a6e48fSopenharmony_ci } 8932a6e48fSopenharmony_ci } 9032a6e48fSopenharmony_ci 9132a6e48fSopenharmony_ci return retCode < 0 ? -errno : 0; 9232a6e48fSopenharmony_ci} 9332a6e48fSopenharmony_ci 9432a6e48fSopenharmony_ciint32_t SyncFence::SyncMerge(const char *name, int32_t fd1, int32_t fd2, int32_t &newFenceFd) 9532a6e48fSopenharmony_ci{ 9632a6e48fSopenharmony_ci struct sync_merge_data syncMergeData = {}; 9732a6e48fSopenharmony_ci syncMergeData.fd2 = fd2; 9832a6e48fSopenharmony_ci if (strcpy_s(syncMergeData.name, sizeof(syncMergeData.name), name)) { 9932a6e48fSopenharmony_ci UTILS_LOGE("SyncMerge ctrcpy fence name failed."); 10032a6e48fSopenharmony_ci return -1; 10132a6e48fSopenharmony_ci } 10232a6e48fSopenharmony_ci int32_t retCode = ioctl(fd1, SYNC_IOC_MERGE, &syncMergeData); 10332a6e48fSopenharmony_ci if (retCode < 0) { 10432a6e48fSopenharmony_ci errno = EINVAL; 10532a6e48fSopenharmony_ci UTILS_LOGE("Fence merge failed, errno: %{public}d, ret: %{public}d.", errno, retCode); 10632a6e48fSopenharmony_ci return -1; 10732a6e48fSopenharmony_ci } 10832a6e48fSopenharmony_ci 10932a6e48fSopenharmony_ci newFenceFd = syncMergeData.fence; 11032a6e48fSopenharmony_ci return 0; 11132a6e48fSopenharmony_ci} 11232a6e48fSopenharmony_ci 11332a6e48fSopenharmony_cisptr<SyncFence> SyncFence::MergeFence(const std::string &name, 11432a6e48fSopenharmony_ci const sptr<SyncFence>& fence1, const sptr<SyncFence>& fence2) 11532a6e48fSopenharmony_ci{ 11632a6e48fSopenharmony_ci int32_t newFenceFd = INVALID_FD; 11732a6e48fSopenharmony_ci int32_t fenceFd1 = fence1->fenceFd_; 11832a6e48fSopenharmony_ci int32_t fenceFd2 = fence2->fenceFd_; 11932a6e48fSopenharmony_ci 12032a6e48fSopenharmony_ci if (fenceFd1 >= 0 && fenceFd2 >= 0) { 12132a6e48fSopenharmony_ci (void)SyncFence::SyncMerge(name.c_str(), fenceFd1, fenceFd2, newFenceFd); 12232a6e48fSopenharmony_ci } else if (fenceFd1 >= 0) { 12332a6e48fSopenharmony_ci (void)SyncFence::SyncMerge(name.c_str(), fenceFd1, fenceFd1, newFenceFd); 12432a6e48fSopenharmony_ci } else if (fenceFd2 >= 0) { 12532a6e48fSopenharmony_ci (void)SyncFence::SyncMerge(name.c_str(), fenceFd2, fenceFd2, newFenceFd); 12632a6e48fSopenharmony_ci } else { 12732a6e48fSopenharmony_ci return INVALID_FENCE; 12832a6e48fSopenharmony_ci } 12932a6e48fSopenharmony_ci 13032a6e48fSopenharmony_ci if (newFenceFd == INVALID_FD) { 13132a6e48fSopenharmony_ci UTILS_LOGE("sync_merge(%{public}s) failed, error: %{public}s (%{public}d)", 13232a6e48fSopenharmony_ci name.c_str(), strerror(errno), errno); 13332a6e48fSopenharmony_ci return INVALID_FENCE; 13432a6e48fSopenharmony_ci } 13532a6e48fSopenharmony_ci 13632a6e48fSopenharmony_ci return sptr<SyncFence>(new SyncFence(newFenceFd)); 13732a6e48fSopenharmony_ci} 13832a6e48fSopenharmony_ci 13932a6e48fSopenharmony_cins_sec_t SyncFence::SyncFileReadTimestamp() 14032a6e48fSopenharmony_ci{ 14132a6e48fSopenharmony_ci std::vector<SyncPointInfo> ptInfos = GetFenceInfo(); 14232a6e48fSopenharmony_ci if (ptInfos.empty()) { 14332a6e48fSopenharmony_ci return FENCE_PENDING_TIMESTAMP; 14432a6e48fSopenharmony_ci } 14532a6e48fSopenharmony_ci size_t signalFenceCount = 0; 14632a6e48fSopenharmony_ci for (const auto &info : ptInfos) { 14732a6e48fSopenharmony_ci if (info.status == SIGNALED) { 14832a6e48fSopenharmony_ci signalFenceCount++; 14932a6e48fSopenharmony_ci } 15032a6e48fSopenharmony_ci } 15132a6e48fSopenharmony_ci if (signalFenceCount == ptInfos.size()) { 15232a6e48fSopenharmony_ci // fence signaled 15332a6e48fSopenharmony_ci uint64_t timestamp = 0; 15432a6e48fSopenharmony_ci for (const auto &ptInfo : ptInfos) { 15532a6e48fSopenharmony_ci if (ptInfo.timestampNs > timestamp) { 15632a6e48fSopenharmony_ci timestamp = ptInfo.timestampNs; 15732a6e48fSopenharmony_ci } 15832a6e48fSopenharmony_ci } 15932a6e48fSopenharmony_ci return static_cast<ns_sec_t>(timestamp); 16032a6e48fSopenharmony_ci } else { 16132a6e48fSopenharmony_ci // fence still active 16232a6e48fSopenharmony_ci return FENCE_PENDING_TIMESTAMP; 16332a6e48fSopenharmony_ci } 16432a6e48fSopenharmony_ci} 16532a6e48fSopenharmony_ci 16632a6e48fSopenharmony_cistd::vector<SyncPointInfo> SyncFence::GetFenceInfo() 16732a6e48fSopenharmony_ci{ 16832a6e48fSopenharmony_ci struct sync_file_info arg; 16932a6e48fSopenharmony_ci struct sync_file_info *infoPtr = nullptr; 17032a6e48fSopenharmony_ci 17132a6e48fSopenharmony_ci errno_t retCode = memset_s(&arg, sizeof(struct sync_file_info), 0, sizeof(struct sync_file_info)); 17232a6e48fSopenharmony_ci if (retCode != EOK) { 17332a6e48fSopenharmony_ci UTILS_LOGE("memset_s error, retCode = %{public}d", retCode); 17432a6e48fSopenharmony_ci return {}; 17532a6e48fSopenharmony_ci } 17632a6e48fSopenharmony_ci int32_t ret = ioctl(fenceFd_, SYNC_IOC_FILE_INFO, &arg); 17732a6e48fSopenharmony_ci if (ret < 0) { 17832a6e48fSopenharmony_ci UTILS_LOGD("GetFenceInfo SYNC_IOC_FILE_INFO ioctl failed, ret: %{public}d", ret); 17932a6e48fSopenharmony_ci return {}; 18032a6e48fSopenharmony_ci } 18132a6e48fSopenharmony_ci if (arg.num_fences <= 0 || arg.num_fences > MAX_FENCE_NUM) { 18232a6e48fSopenharmony_ci UTILS_LOGD("GetFenceInfo arg.num_fences failed, num_fences: %{public}d", arg.num_fences); 18332a6e48fSopenharmony_ci return {}; 18432a6e48fSopenharmony_ci } 18532a6e48fSopenharmony_ci auto sizeMax = std::numeric_limits<size_t>::max(); 18632a6e48fSopenharmony_ci if ((sizeMax - sizeof(struct sync_file_info)) / sizeof(struct sync_fence_info) < arg.num_fences) { 18732a6e48fSopenharmony_ci UTILS_LOGE("GetFenceInfo overflow, num_fences: %{public}d", arg.num_fences); 18832a6e48fSopenharmony_ci return {}; 18932a6e48fSopenharmony_ci } 19032a6e48fSopenharmony_ci size_t syncFileInfoMemSize = sizeof(struct sync_file_info) + sizeof(struct sync_fence_info) * arg.num_fences; 19132a6e48fSopenharmony_ci infoPtr = (struct sync_file_info *)malloc(syncFileInfoMemSize); 19232a6e48fSopenharmony_ci if (infoPtr == nullptr) { 19332a6e48fSopenharmony_ci UTILS_LOGD("GetFenceInfo malloc failed oom"); 19432a6e48fSopenharmony_ci return {}; 19532a6e48fSopenharmony_ci } 19632a6e48fSopenharmony_ci retCode = memset_s(infoPtr, syncFileInfoMemSize, 0, syncFileInfoMemSize); 19732a6e48fSopenharmony_ci if (retCode != 0) { 19832a6e48fSopenharmony_ci UTILS_LOGE("memset_s error, retCode = %{public}d", retCode); 19932a6e48fSopenharmony_ci free(infoPtr); 20032a6e48fSopenharmony_ci return {}; 20132a6e48fSopenharmony_ci } 20232a6e48fSopenharmony_ci infoPtr->num_fences = arg.num_fences; 20332a6e48fSopenharmony_ci infoPtr->sync_fence_info = static_cast<uint64_t>(uintptr_t(infoPtr + 1)); 20432a6e48fSopenharmony_ci ret = ioctl(fenceFd_, SYNC_IOC_FILE_INFO, infoPtr); 20532a6e48fSopenharmony_ci if (ret < 0) { 20632a6e48fSopenharmony_ci UTILS_LOGE("GetTotalFenceInfo SYNC_IOC_FILE_INFO ioctl failed, ret: %{public}d", ret); 20732a6e48fSopenharmony_ci free(infoPtr); 20832a6e48fSopenharmony_ci return {}; 20932a6e48fSopenharmony_ci } 21032a6e48fSopenharmony_ci std::vector<SyncPointInfo> infos; 21132a6e48fSopenharmony_ci const auto fenceInfos = (struct sync_fence_info *)(uintptr_t)(infoPtr->sync_fence_info); 21232a6e48fSopenharmony_ci for (uint32_t i = 0; i < infoPtr->num_fences; i++) { 21332a6e48fSopenharmony_ci infos.push_back(SyncPointInfo { fenceInfos[i].timestamp_ns, static_cast<FenceStatus>(fenceInfos[i].status) }); 21432a6e48fSopenharmony_ci } 21532a6e48fSopenharmony_ci free(infoPtr); 21632a6e48fSopenharmony_ci return infos; 21732a6e48fSopenharmony_ci} 21832a6e48fSopenharmony_ci 21932a6e48fSopenharmony_ciint32_t SyncFence::Dup() const 22032a6e48fSopenharmony_ci{ 22132a6e48fSopenharmony_ci return ::dup(fenceFd_); 22232a6e48fSopenharmony_ci} 22332a6e48fSopenharmony_ci 22432a6e48fSopenharmony_ciFenceStatus SyncFence::GetStatus() 22532a6e48fSopenharmony_ci{ 22632a6e48fSopenharmony_ci if (fenceFd_ < 0) { 22732a6e48fSopenharmony_ci return ERROR; 22832a6e48fSopenharmony_ci } 22932a6e48fSopenharmony_ci std::vector<SyncPointInfo> ptInfos = GetFenceInfo(); 23032a6e48fSopenharmony_ci if (ptInfos.empty()) { 23132a6e48fSopenharmony_ci return ERROR; 23232a6e48fSopenharmony_ci } 23332a6e48fSopenharmony_ci size_t signalFenceCount = 0; 23432a6e48fSopenharmony_ci for (const auto &info : ptInfos) { 23532a6e48fSopenharmony_ci if (info.status == SIGNALED) { 23632a6e48fSopenharmony_ci signalFenceCount++; 23732a6e48fSopenharmony_ci } 23832a6e48fSopenharmony_ci } 23932a6e48fSopenharmony_ci if (signalFenceCount == ptInfos.size()) { 24032a6e48fSopenharmony_ci return SIGNALED; 24132a6e48fSopenharmony_ci } else { 24232a6e48fSopenharmony_ci return ACTIVE; 24332a6e48fSopenharmony_ci } 24432a6e48fSopenharmony_ci} 24532a6e48fSopenharmony_ci 24632a6e48fSopenharmony_ciint32_t SyncFence::Get() const 24732a6e48fSopenharmony_ci{ 24832a6e48fSopenharmony_ci return fenceFd_; 24932a6e48fSopenharmony_ci} 25032a6e48fSopenharmony_ci 25132a6e48fSopenharmony_cibool SyncFence::IsValid() const 25232a6e48fSopenharmony_ci{ 25332a6e48fSopenharmony_ci return fenceFd_ != -1; 25432a6e48fSopenharmony_ci} 25532a6e48fSopenharmony_ci 25632a6e48fSopenharmony_cisptr<SyncFence> SyncFence::ReadFromMessageParcel(MessageParcel &parcel) 25732a6e48fSopenharmony_ci{ 25832a6e48fSopenharmony_ci int32_t fence = parcel.ReadInt32(); 25932a6e48fSopenharmony_ci if (fence < 0) { 26032a6e48fSopenharmony_ci return INVALID_FENCE; 26132a6e48fSopenharmony_ci } 26232a6e48fSopenharmony_ci 26332a6e48fSopenharmony_ci fence = parcel.ReadFileDescriptor(); 26432a6e48fSopenharmony_ci 26532a6e48fSopenharmony_ci return sptr<SyncFence>(new SyncFence(fence)); 26632a6e48fSopenharmony_ci} 26732a6e48fSopenharmony_ci 26832a6e48fSopenharmony_cisptr<SyncFence> SyncFence::InvalidFence() 26932a6e48fSopenharmony_ci{ 27032a6e48fSopenharmony_ci return sptr<SyncFence>(new SyncFence(-1)); 27132a6e48fSopenharmony_ci} 27232a6e48fSopenharmony_ci 27332a6e48fSopenharmony_cibool SyncFence::WriteToMessageParcel(MessageParcel &parcel) 27432a6e48fSopenharmony_ci{ 27532a6e48fSopenharmony_ci int32_t fence = fenceFd_; 27632a6e48fSopenharmony_ci if (fence >= 0 && fcntl(fence, F_GETFL) == -1 && errno == EBADF) { 27732a6e48fSopenharmony_ci fence = -1; 27832a6e48fSopenharmony_ci } 27932a6e48fSopenharmony_ci 28032a6e48fSopenharmony_ci if (!parcel.WriteInt32(fence)) { 28132a6e48fSopenharmony_ci return false; 28232a6e48fSopenharmony_ci } 28332a6e48fSopenharmony_ci 28432a6e48fSopenharmony_ci if (fence < 0) { 28532a6e48fSopenharmony_ci UTILS_LOGD("WriteToMessageParcel fence is invalid : %{public}d", fence); 28632a6e48fSopenharmony_ci return true; 28732a6e48fSopenharmony_ci } 28832a6e48fSopenharmony_ci 28932a6e48fSopenharmony_ci if (!parcel.WriteFileDescriptor(fence)) { 29032a6e48fSopenharmony_ci return false; 29132a6e48fSopenharmony_ci } 29232a6e48fSopenharmony_ci return true; 29332a6e48fSopenharmony_ci} 29432a6e48fSopenharmony_ci 29532a6e48fSopenharmony_ci} // namespace OHOS 296