1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "Fence"
18#define ATRACE_TAG ATRACE_TAG_GRAPHICS
19//#define LOG_NDEBUG 0
20
21 // This is needed for stdint.h to define INT64_MAX in C++
22 #define __STDC_LIMIT_MACROS
23
24#include <sync/sync.h>
25#include <ui/Fence.h>
26#include <unistd.h>
27#include <utils/Log.h>
28#include <utils/Trace.h>
29
30namespace android {
31
32const sp<Fence> Fence::NO_FENCE = sp<Fence>(new Fence);
33
34Fence::Fence() :
35    mFenceFd(-1) {
36}
37
38Fence::Fence(int fenceFd) :
39    mFenceFd(fenceFd) {
40}
41
42Fence::~Fence() {
43    if (mFenceFd != -1) {
44        close(mFenceFd);
45    }
46}
47
48status_t Fence::wait(unsigned int timeout) {
49    ATRACE_CALL();
50    if (mFenceFd == -1) {
51        return NO_ERROR;
52    }
53    int err = sync_wait(mFenceFd, timeout);
54    return err < 0 ? -errno : status_t(NO_ERROR);
55}
56
57status_t Fence::waitForever(const char* logname) {
58    ATRACE_CALL();
59    if (mFenceFd == -1) {
60        return NO_ERROR;
61    }
62    unsigned int warningTimeout = 3000;
63    int err = sync_wait(mFenceFd, warningTimeout);
64    if (err < 0 && errno == ETIME) {
65        ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd,
66                warningTimeout);
67        err = sync_wait(mFenceFd, TIMEOUT_NEVER);
68    }
69    return err < 0 ? -errno : status_t(NO_ERROR);
70}
71
72sp<Fence> Fence::merge(const String8& name, const sp<Fence>& f1,
73        const sp<Fence>& f2) {
74    ATRACE_CALL();
75    int result;
76    // Merge the two fences.  In the case where one of the fences is not a
77    // valid fence (e.g. NO_FENCE) we merge the one valid fence with itself so
78    // that a new fence with the given name is created.
79    if (f1->isValid() && f2->isValid()) {
80        result = sync_merge(name.string(), f1->mFenceFd, f2->mFenceFd);
81    } else if (f1->isValid()) {
82        result = sync_merge(name.string(), f1->mFenceFd, f1->mFenceFd);
83    } else if (f2->isValid()) {
84        result = sync_merge(name.string(), f2->mFenceFd, f2->mFenceFd);
85    } else {
86        return NO_FENCE;
87    }
88    if (result == -1) {
89        status_t err = -errno;
90        ALOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)",
91                name.string(), f1->mFenceFd, f2->mFenceFd,
92                strerror(-err), err);
93        return NO_FENCE;
94    }
95    return sp<Fence>(new Fence(result));
96}
97
98int Fence::dup() const {
99    return ::dup(mFenceFd);
100}
101
102nsecs_t Fence::getSignalTime() const {
103    if (mFenceFd == -1) {
104        return -1;
105    }
106
107    struct sync_fence_info_data* finfo = sync_fence_info(mFenceFd);
108    if (finfo == NULL) {
109        ALOGE("sync_fence_info returned NULL for fd %d", mFenceFd);
110        return -1;
111    }
112    if (finfo->status != 1) {
113        sync_fence_info_free(finfo);
114        return INT64_MAX;
115    }
116
117    struct sync_pt_info* pinfo = NULL;
118    uint64_t timestamp = 0;
119    while ((pinfo = sync_pt_info(finfo, pinfo)) != NULL) {
120        if (pinfo->timestamp_ns > timestamp) {
121            timestamp = pinfo->timestamp_ns;
122        }
123    }
124    sync_fence_info_free(finfo);
125
126    return nsecs_t(timestamp);
127}
128
129size_t Fence::getFlattenedSize() const {
130    return 1;
131}
132
133size_t Fence::getFdCount() const {
134    return isValid() ? 1 : 0;
135}
136
137status_t Fence::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
138    if (size < getFlattenedSize() || count < getFdCount()) {
139        return NO_MEMORY;
140    }
141    FlattenableUtils::write(buffer, size, (uint32_t)getFdCount());
142    if (isValid()) {
143        *fds++ = mFenceFd;
144        count--;
145    }
146    return NO_ERROR;
147}
148
149status_t Fence::unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count) {
150    if (mFenceFd != -1) {
151        // Don't unflatten if we already have a valid fd.
152        return INVALID_OPERATION;
153    }
154
155    if (size < 1) {
156        return NO_MEMORY;
157    }
158
159    uint32_t numFds;
160    FlattenableUtils::read(buffer, size, numFds);
161
162    if (numFds > 1) {
163        return BAD_VALUE;
164    }
165
166    if (count < numFds) {
167        return NO_MEMORY;
168    }
169
170    if (numFds) {
171        mFenceFd = *fds++;
172        count--;
173    }
174
175    return NO_ERROR;
176}
177
178} // namespace android
179