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_AUDIO_FIFO_INDEX_H 18 #define ANDROID_AUDIO_FIFO_INDEX_H 19 20 #include <atomic> 21 #include <stdint.h> 22 #include <time.h> 23 24 /** 25 * An index that may optionally be placed in shared memory. 26 * Must be Plain Old Data (POD), so no virtual methods are allowed. 27 * If in shared memory, exactly one process must explicitly call the constructor via placement new. 28 * \see #audio_utils_fifo_sync 29 */ 30 class audio_utils_fifo_index { 31 32 public: audio_utils_fifo_index()33 audio_utils_fifo_index() : mIndex(0) { } ~audio_utils_fifo_index()34 ~audio_utils_fifo_index() { } 35 36 /** 37 * Load value of index by a simple non-atomic memory read. 38 * 39 * \return Index value 40 */ 41 uint32_t loadSingleThreaded(); 42 43 /** 44 * Load value of index now with memory order 'acquire'. 45 * 46 * \return Index value 47 */ 48 uint32_t loadAcquire(); 49 50 /** 51 * Store new value into index by a simple non-atomic memory write. 52 * 53 * \param value New value to store into index 54 */ 55 void storeSingleThreaded(uint32_t value); 56 57 /** 58 * Store new value into index now with memory order 'release'. 59 * 60 * \param value New value to store into index 61 */ 62 void storeRelease(uint32_t value); 63 64 // TODO op should be set in the constructor. 65 /** 66 * Wait for value of index to change from the specified expected value. 67 * 68 * \param op Either FUTEX_WAIT or FUTEX_WAIT_PRIVATE. 69 * \param expected Current/expected value of index. 70 * \param timeout Indicates the maximum time to block while waiting for value to change. 71 * NULL means to block forever. 72 * Time is expressed as relative CLOCK_MONOTONIC. 73 * We use the Linux kernel representation of time for the very lowest levels, 74 * and save other representations for the APIs that are built on top of this. 75 * This permits APIs to choose the int64_t representation if desired, or the 76 * Linux representation without a double conversion. 77 * 78 * \return Zero for success, or a negative error code as specified at "man 2 futex". 79 */ 80 int wait(int op, uint32_t expected, const struct timespec *timeout); 81 82 // TODO op should be set in the constructor. 83 /** 84 * Wake up any threads waiting for the value of index to change. 85 * 86 * \param op Either FUTEX_WAIT or FUTEX_WAIT_PRIVATE. 87 * \param waiters Maximum number of waiting threads to wake up. 88 * 89 * \return Actual number of threads woken up. 90 */ 91 int wake(int op, int waiters = 1); 92 93 private: 94 // Linux futex is 32 bits regardless of platform. 95 // It would make more sense to declare this as atomic_uint32_t, but there is no such type name. 96 // TODO Support 64-bit index with 32-bit futex in low-order bits. 97 std::atomic_uint_least32_t mIndex; // accessed by both sides using atomic operations 98 // TODO Should be a union with a simple non-atomic variable 99 static_assert(sizeof(mIndex) == sizeof(uint32_t), "mIndex must be 32 bits"); 100 }; 101 102 static_assert(sizeof(audio_utils_fifo_index) == sizeof(uint32_t), 103 "audio_utils_fifo_index must be 32 bits"); 104 105 // ---------------------------------------------------------------------------- 106 107 #if 0 // TODO not currently used, review this code later: bug 150627616 108 109 // TODO 110 // From a design POV, these next two classes should be related. 111 // Extract a base class (that shares their property of being a reference to a fifo index) 112 // This should be good in the case if there is a need for generic manipulations on these references. 113 // Or can we perhaps define a template and make two specializations of it. 114 // This is in the case when compile-time polymorphism is sufficient. 115 116 /** 117 * A reference to an audio_utils_fifo_index with deferred store-release and deferred wake. 118 * 119 * TODO Currently the index and futex share the same 32-bit cell. 120 * In the future, the index may optionally be increased to 64-bits, 121 * and the futex will either be the low-order 32 bits of the index, 122 * or an unrelated 32-bit cell used as a set of event flags. 123 * Both of these will require a change to the API. 124 */ 125 class RefIndexDeferredStoreReleaseDeferredWake 126 { 127 public: 128 RefIndexDeferredStoreReleaseDeferredWake(audio_utils_fifo_index& index); 129 ~RefIndexDeferredStoreReleaseDeferredWake(); 130 131 // Place 'value' into the cache, but do not store it to memory yet. 132 void set(uint32_t value); 133 134 // If there is a new value in the cache, store it now with memory order 'release'. 135 void writeback(); 136 137 // Place 'value' into the cache and then store it with memory order 'release'. 138 void writethrough(uint32_t value); 139 140 // op is FUTEX_WAKE or FUTEX_WAKE_PRIVATE 141 // TODO op should be set in the constructor, and should be abstracted. 142 // waiters is number of waiting threads to wake up 143 void wakeDeferred(int op, int waiters = 1); 144 void wakeNowIfNeeded(); 145 // TODO op should be set in the constructor. 146 void wakeNow(int op, int waiters = 1); 147 148 private: 149 audio_utils_fifo_index& mIndex; // reference to associated index 150 uint32_t mValue; // cached value to be stored 151 bool mWriteback; // whether the cached value needs to be stored 152 int mWaiters; // number of waiters to wake 153 int mWakeOp; // which kind of wake operation to use 154 }; 155 156 /** 157 * A reference to an audio_utils_fifo_index with cached load-acquire, and deferred wait. 158 * 159 * TODO Same as RefIndexDeferredStoreReleaseDeferredWake. 160 */ 161 class RefIndexCachedLoadAcquireDeferredWait 162 { 163 public: 164 RefIndexCachedLoadAcquireDeferredWait(audio_utils_fifo_index& index); 165 ~RefIndexCachedLoadAcquireDeferredWait(); 166 167 // If value is already cached, return the cached value. 168 // Otherwise load now with memory order 'acquire', cache for later use, and return the value. 169 uint32_t get(); 170 171 // If value is already cached, this is a no-op. 172 // Otherwise load now with memory order 'acquire' and cache the value for later use. 173 void prefetch(); 174 175 // Discard any value in the cache. 176 void invalidate(); 177 178 #if 0 179 /** 180 * Load a fresh value for index, ignoring any previously cached information. 181 */ 182 uint32_t readthrough(); 183 #endif 184 185 // TODO This is an immediate wait, but we needed deferred wait 186 /** 187 * Wait for value of index to change from when it was most recently read with get(). 188 * To avoid a race condition, the caller must have already read the index with get(), 189 * and then made the decision to call wait() based on that value. 190 * 191 * \param op Either FUTEX_WAIT or FUTEX_WAIT_PRIVATE. 192 * \param timeout Indicates the maximum time to block while waiting for value to change. 193 * NULL means to block forever. 194 * Time is expressed as relative CLOCK_MONOTONIC. 195 * See above for explanation of why representation is struct timespec. 196 * 197 * \return Zero for success, or a negative error code as specified at "man 2 futex". 198 * \retval -EINVAL caller did not call get() prior to wait() 199 */ 200 int wait(int op, const struct timespec *timeout); 201 202 private: 203 audio_utils_fifo_index& mIndex; // reference to associated index 204 uint32_t mValue; // most recently cached value 205 bool mLoaded; // whether mValue is valid 206 }; 207 208 #endif // 0 209 210 #endif // !ANDROID_AUDIO_FIFO_INDEX_H 211