Brian Anderson | 221de2a | 2016-09-21 16:53:28 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 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 | #ifndef ANDROID_FENCE_TIME_H |
| 18 | #define ANDROID_FENCE_TIME_H |
| 19 | |
| 20 | #include <ui/Fence.h> |
| 21 | #include <utils/Flattenable.h> |
| 22 | #include <utils/Timers.h> |
| 23 | |
| 24 | #include <atomic> |
| 25 | #include <mutex> |
| 26 | #include <queue> |
| 27 | |
| 28 | namespace android { |
| 29 | |
| 30 | // A wrapper around fence that only implements isValid and getSignalTime. |
| 31 | // It automatically closes the fence in a thread-safe manner once the signal |
| 32 | // time is known. |
| 33 | class FenceTime { |
| 34 | public: |
| 35 | // An atomic snapshot of the FenceTime that is flattenable. |
| 36 | // |
| 37 | // This class is needed because the FenceTime class may not stay |
| 38 | // consistent for all steps of the flattening process. |
| 39 | // |
| 40 | // Not thread safe. |
| 41 | struct Snapshot : public Flattenable<Snapshot> { |
| 42 | enum class State { |
| 43 | EMPTY, |
| 44 | FENCE, |
| 45 | SIGNAL_TIME, |
| 46 | }; |
| 47 | |
| 48 | Snapshot() = default; // Creates an empty snapshot. |
| 49 | explicit Snapshot(const sp<Fence>& fence); |
| 50 | explicit Snapshot(nsecs_t signalTime); |
| 51 | |
| 52 | // Movable. |
| 53 | Snapshot(Snapshot&& src) = default; |
| 54 | Snapshot& operator=(Snapshot&& src) = default; |
| 55 | // Not copyable. |
| 56 | Snapshot(const Snapshot& src) = delete; |
| 57 | Snapshot& operator=(const Snapshot&& src) = delete; |
| 58 | |
| 59 | // Flattenable implementation. |
| 60 | size_t getFlattenedSize() const; |
| 61 | size_t getFdCount() const; |
| 62 | status_t flatten(void*& buffer, size_t& size, int*& fds, |
| 63 | size_t& count) const; |
| 64 | status_t unflatten(void const*& buffer, size_t& size, int const*& fds, |
| 65 | size_t& count); |
| 66 | |
| 67 | State state{State::EMPTY}; |
| 68 | sp<Fence> fence{Fence::NO_FENCE}; |
| 69 | nsecs_t signalTime{Fence::SIGNAL_TIME_INVALID}; |
| 70 | }; |
| 71 | |
| 72 | static const std::shared_ptr<FenceTime> NO_FENCE; |
| 73 | |
| 74 | explicit FenceTime(const sp<Fence>& fence); |
| 75 | explicit FenceTime(sp<Fence>&& fence); |
| 76 | |
| 77 | // Passing in Fence::SIGNAL_TIME_PENDING is not allowed. |
| 78 | // Doing so will convert the signalTime to Fence::SIGNAL_TIME_INVALID. |
| 79 | explicit FenceTime(nsecs_t signalTime); |
| 80 | |
| 81 | // Do not allow default construction. Share NO_FENCE or explicitly construct |
| 82 | // with Fence::SIGNAL_TIME_INVALID instead. |
| 83 | FenceTime() = delete; |
| 84 | |
| 85 | // Do not allow copy, assign, or move. Use a shared_ptr to share the |
| 86 | // signalTime result. Or use getSnapshot() if a thread-safe copy is really |
| 87 | // needed. |
| 88 | FenceTime(const FenceTime&) = delete; |
| 89 | FenceTime(FenceTime&&) = delete; |
| 90 | FenceTime& operator=(const FenceTime&) = delete; |
| 91 | FenceTime& operator=(FenceTime&&) = delete; |
| 92 | |
| 93 | // This method should only be called when replacing the fence with |
| 94 | // a signalTime. Since this is an indirect way of setting the signal time |
| 95 | // of a fence, the snapshot should come from a trusted source. |
| 96 | void applyTrustedSnapshot(const Snapshot& src); |
| 97 | |
| 98 | bool isValid() const; |
| 99 | |
| 100 | // Attempts to get the timestamp from the Fence if the timestamp isn't |
| 101 | // already cached. Otherwise, it returns the cached value. |
| 102 | nsecs_t getSignalTime(); |
| 103 | |
| 104 | // Gets the cached timestamp without attempting to query the Fence. |
| 105 | nsecs_t getCachedSignalTime() const; |
| 106 | |
| 107 | // Returns a snapshot of the FenceTime in its current state. |
| 108 | Snapshot getSnapshot() const; |
| 109 | |
| 110 | // Override new and delete since this needs 8-byte alignment, which |
| 111 | // is not guaranteed on x86. |
| 112 | static void* operator new(size_t nbytes) noexcept; |
| 113 | static void operator delete(void *p); |
| 114 | |
| 115 | private: |
| 116 | enum class State { |
| 117 | VALID, |
| 118 | INVALID, |
| 119 | }; |
| 120 | |
| 121 | const State mState{State::INVALID}; |
| 122 | |
| 123 | // mMutex guards mFence and mSignalTime. |
| 124 | // mSignalTime is also atomic since it is sometimes read outside the lock |
| 125 | // for quick checks. |
| 126 | mutable std::mutex mMutex; |
| 127 | sp<Fence> mFence{Fence::NO_FENCE}; |
| 128 | std::atomic<nsecs_t> mSignalTime{Fence::SIGNAL_TIME_INVALID}; |
| 129 | }; |
| 130 | |
| 131 | // A queue of FenceTimes that are expected to signal in FIFO order. |
| 132 | // Only maintains a queue of weak pointers so it doesn't keep references |
| 133 | // to Fences on its own. |
| 134 | // |
| 135 | // Can be used to get the signal time of a fence and close its file descriptor |
| 136 | // without making a syscall for every fence later in the timeline. |
| 137 | // Additionally, since the FenceTime caches the timestamp internally, |
| 138 | // other timelines that reference the same FenceTime can avoid the syscall. |
| 139 | // |
| 140 | // FenceTimeline only keeps track of a limited number of entries to avoid |
| 141 | // growing unbounded. Users of FenceTime must make sure they can work even |
| 142 | // if FenceTimeline did nothing. i.e. they should eventually call |
| 143 | // Fence::getSignalTime(), not only Fence::getCachedSignalTime(). |
| 144 | // |
| 145 | // push() and updateSignalTimes() are safe to call simultaneously from |
| 146 | // different threads. |
| 147 | class FenceTimeline { |
| 148 | public: |
| 149 | static constexpr size_t MAX_ENTRIES = 64; |
| 150 | |
| 151 | void push(const std::shared_ptr<FenceTime>& fence); |
| 152 | void updateSignalTimes(); |
| 153 | |
| 154 | private: |
| 155 | mutable std::mutex mMutex; |
| 156 | std::queue<std::weak_ptr<FenceTime>> mQueue; |
| 157 | }; |
| 158 | |
| 159 | }; // namespace android |
| 160 | |
| 161 | #endif // ANDROID_FENCE_TIME_H |