• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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