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