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