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> |
Brian Anderson | 3da8d27 | 2016-07-28 16:20:47 -0700 | [diff] [blame] | 27 | #include <unordered_map> |
Brian Anderson | 221de2a | 2016-09-21 16:53:28 -0700 | [diff] [blame] | 28 | |
| 29 | namespace android { |
| 30 | |
Brian Anderson | 3da8d27 | 2016-07-28 16:20:47 -0700 | [diff] [blame] | 31 | class FenceToFenceTimeMap; |
| 32 | |
Brian Anderson | 221de2a | 2016-09-21 16:53:28 -0700 | [diff] [blame] | 33 | // A wrapper around fence that only implements isValid and getSignalTime. |
| 34 | // It automatically closes the fence in a thread-safe manner once the signal |
| 35 | // time is known. |
| 36 | class FenceTime { |
Brian Anderson | 3da8d27 | 2016-07-28 16:20:47 -0700 | [diff] [blame] | 37 | friend class FenceToFenceTimeMap; |
Brian Anderson | 221de2a | 2016-09-21 16:53:28 -0700 | [diff] [blame] | 38 | public: |
| 39 | // An atomic snapshot of the FenceTime that is flattenable. |
| 40 | // |
| 41 | // This class is needed because the FenceTime class may not stay |
| 42 | // consistent for all steps of the flattening process. |
| 43 | // |
| 44 | // Not thread safe. |
| 45 | struct Snapshot : public Flattenable<Snapshot> { |
| 46 | enum class State { |
| 47 | EMPTY, |
| 48 | FENCE, |
| 49 | SIGNAL_TIME, |
| 50 | }; |
| 51 | |
| 52 | Snapshot() = default; // Creates an empty snapshot. |
| 53 | explicit Snapshot(const sp<Fence>& fence); |
| 54 | explicit Snapshot(nsecs_t signalTime); |
| 55 | |
| 56 | // Movable. |
| 57 | Snapshot(Snapshot&& src) = default; |
| 58 | Snapshot& operator=(Snapshot&& src) = default; |
| 59 | // Not copyable. |
| 60 | Snapshot(const Snapshot& src) = delete; |
| 61 | Snapshot& operator=(const Snapshot&& src) = delete; |
| 62 | |
| 63 | // Flattenable implementation. |
| 64 | size_t getFlattenedSize() const; |
| 65 | size_t getFdCount() const; |
| 66 | status_t flatten(void*& buffer, size_t& size, int*& fds, |
| 67 | size_t& count) const; |
| 68 | status_t unflatten(void const*& buffer, size_t& size, int const*& fds, |
| 69 | size_t& count); |
| 70 | |
| 71 | State state{State::EMPTY}; |
| 72 | sp<Fence> fence{Fence::NO_FENCE}; |
| 73 | nsecs_t signalTime{Fence::SIGNAL_TIME_INVALID}; |
| 74 | }; |
| 75 | |
| 76 | static const std::shared_ptr<FenceTime> NO_FENCE; |
| 77 | |
| 78 | explicit FenceTime(const sp<Fence>& fence); |
| 79 | explicit FenceTime(sp<Fence>&& fence); |
| 80 | |
| 81 | // Passing in Fence::SIGNAL_TIME_PENDING is not allowed. |
| 82 | // Doing so will convert the signalTime to Fence::SIGNAL_TIME_INVALID. |
| 83 | explicit FenceTime(nsecs_t signalTime); |
| 84 | |
| 85 | // Do not allow default construction. Share NO_FENCE or explicitly construct |
| 86 | // with Fence::SIGNAL_TIME_INVALID instead. |
| 87 | FenceTime() = delete; |
| 88 | |
| 89 | // Do not allow copy, assign, or move. Use a shared_ptr to share the |
| 90 | // signalTime result. Or use getSnapshot() if a thread-safe copy is really |
| 91 | // needed. |
| 92 | FenceTime(const FenceTime&) = delete; |
| 93 | FenceTime(FenceTime&&) = delete; |
| 94 | FenceTime& operator=(const FenceTime&) = delete; |
| 95 | FenceTime& operator=(FenceTime&&) = delete; |
| 96 | |
| 97 | // This method should only be called when replacing the fence with |
| 98 | // a signalTime. Since this is an indirect way of setting the signal time |
| 99 | // of a fence, the snapshot should come from a trusted source. |
| 100 | void applyTrustedSnapshot(const Snapshot& src); |
| 101 | |
| 102 | bool isValid() const; |
| 103 | |
| 104 | // Attempts to get the timestamp from the Fence if the timestamp isn't |
| 105 | // already cached. Otherwise, it returns the cached value. |
| 106 | nsecs_t getSignalTime(); |
| 107 | |
| 108 | // Gets the cached timestamp without attempting to query the Fence. |
| 109 | nsecs_t getCachedSignalTime() const; |
| 110 | |
| 111 | // Returns a snapshot of the FenceTime in its current state. |
| 112 | Snapshot getSnapshot() const; |
| 113 | |
Brian Anderson | 3da8d27 | 2016-07-28 16:20:47 -0700 | [diff] [blame] | 114 | void signalForTest(nsecs_t signalTime); |
| 115 | |
Brian Anderson | 221de2a | 2016-09-21 16:53:28 -0700 | [diff] [blame] | 116 | // Override new and delete since this needs 8-byte alignment, which |
| 117 | // is not guaranteed on x86. |
| 118 | static void* operator new(size_t nbytes) noexcept; |
| 119 | static void operator delete(void *p); |
| 120 | |
| 121 | private: |
Brian Anderson | 3da8d27 | 2016-07-28 16:20:47 -0700 | [diff] [blame] | 122 | // For tests only. If forceValidForTest is true, then getSignalTime will |
| 123 | // never return SIGNAL_TIME_INVALID and isValid will always return true. |
| 124 | FenceTime(const sp<Fence>& fence, bool forceValidForTest); |
| 125 | |
Brian Anderson | 221de2a | 2016-09-21 16:53:28 -0700 | [diff] [blame] | 126 | enum class State { |
| 127 | VALID, |
| 128 | INVALID, |
Brian Anderson | 3da8d27 | 2016-07-28 16:20:47 -0700 | [diff] [blame] | 129 | FORCED_VALID_FOR_TEST, |
Brian Anderson | 221de2a | 2016-09-21 16:53:28 -0700 | [diff] [blame] | 130 | }; |
| 131 | |
| 132 | const State mState{State::INVALID}; |
| 133 | |
| 134 | // mMutex guards mFence and mSignalTime. |
| 135 | // mSignalTime is also atomic since it is sometimes read outside the lock |
| 136 | // for quick checks. |
| 137 | mutable std::mutex mMutex; |
| 138 | sp<Fence> mFence{Fence::NO_FENCE}; |
| 139 | std::atomic<nsecs_t> mSignalTime{Fence::SIGNAL_TIME_INVALID}; |
| 140 | }; |
| 141 | |
| 142 | // A queue of FenceTimes that are expected to signal in FIFO order. |
| 143 | // Only maintains a queue of weak pointers so it doesn't keep references |
| 144 | // to Fences on its own. |
| 145 | // |
| 146 | // Can be used to get the signal time of a fence and close its file descriptor |
| 147 | // without making a syscall for every fence later in the timeline. |
| 148 | // Additionally, since the FenceTime caches the timestamp internally, |
| 149 | // other timelines that reference the same FenceTime can avoid the syscall. |
| 150 | // |
| 151 | // FenceTimeline only keeps track of a limited number of entries to avoid |
| 152 | // growing unbounded. Users of FenceTime must make sure they can work even |
| 153 | // if FenceTimeline did nothing. i.e. they should eventually call |
| 154 | // Fence::getSignalTime(), not only Fence::getCachedSignalTime(). |
| 155 | // |
| 156 | // push() and updateSignalTimes() are safe to call simultaneously from |
| 157 | // different threads. |
| 158 | class FenceTimeline { |
| 159 | public: |
| 160 | static constexpr size_t MAX_ENTRIES = 64; |
| 161 | |
| 162 | void push(const std::shared_ptr<FenceTime>& fence); |
| 163 | void updateSignalTimes(); |
| 164 | |
| 165 | private: |
| 166 | mutable std::mutex mMutex; |
| 167 | std::queue<std::weak_ptr<FenceTime>> mQueue; |
| 168 | }; |
| 169 | |
Brian Anderson | 3da8d27 | 2016-07-28 16:20:47 -0700 | [diff] [blame] | 170 | // Used by test code to create or get FenceTimes for a given Fence. |
| 171 | // |
| 172 | // By design, Fences cannot be signaled from user space. However, this class |
| 173 | // allows test code to set the apparent signalTime of a Fence and |
| 174 | // have it be visible to all FenceTimes. Release code should not use |
| 175 | // FenceToFenceTimeMap. |
| 176 | // |
| 177 | // FenceToFenceTimeMap keeps a weak reference to the FenceTime and automatically |
| 178 | // garbage collects entries every time a new FenceTime is created to avoid |
| 179 | // leaks. This prevents us from having to make the Fence destructor |
| 180 | // automatically notify that the underlying fence has been destroyed, which |
| 181 | // would affect release code paths. Garbage collecting so often is inefficient, |
| 182 | // but acceptable for testing. |
| 183 | // |
| 184 | // Since FenceTimes maintain a strong reference to underlying Fences, there |
| 185 | // should not be any aliasing issues where a new Fence happens to have the same |
| 186 | // address as a previous Fence; the previous entry will be garbage collected |
| 187 | // before the new one is added. |
| 188 | class FenceToFenceTimeMap { |
| 189 | public: |
| 190 | // Create a new FenceTime with that wraps the provided Fence. |
| 191 | std::shared_ptr<FenceTime> createFenceTimeForTest(const sp<Fence>& fence); |
| 192 | |
| 193 | // Signals all FenceTimes created through this class that are wrappers |
| 194 | // around |fence|. |
| 195 | void signalAllForTest(const sp<Fence>& fence, nsecs_t signalTime); |
| 196 | |
| 197 | private: |
| 198 | // Cleans up the entries that no longer have a strong reference. |
| 199 | void garbageCollectLocked(); |
| 200 | |
| 201 | mutable std::mutex mMutex; |
| 202 | std::unordered_map<Fence*, std::vector<std::weak_ptr<FenceTime>>> mMap; |
| 203 | }; |
| 204 | |
| 205 | |
Brian Anderson | 221de2a | 2016-09-21 16:53:28 -0700 | [diff] [blame] | 206 | }; // namespace android |
| 207 | |
| 208 | #endif // ANDROID_FENCE_TIME_H |