StateQueue.h revision dc998c809e084b617990b281e2ed5271830cc2e0
1/* 2 * Copyright (C) 2012 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_STATE_QUEUE_H 18#define ANDROID_AUDIO_STATE_QUEUE_H 19 20namespace android { 21 22// manages a FIFO queue of states 23template<typename T> class StateQueue { 24 25public: 26 StateQueue(); 27 virtual ~StateQueue(); 28 29 // Observer APIs 30 31 // Poll for a state change. Returns a pointer to a read-only state, 32 // or NULL if the state has not been initialized yet. 33 // If a new state has not pushed by mutator since the previous poll, 34 // then the returned pointer will be unchanged. 35 // The previous state pointer is guaranteed to still be valid; 36 // this allows the observer to diff the previous and new states. 37 const T* poll(); 38 39 // Mutator APIs 40 41 // Begin a mutation. Returns a pointer to a read/write state, except the 42 // first time it is called the state is write-only and _must_ be initialized. 43 // Mutations cannot be nested. 44 // If the state is dirty and has not been pushed onto the state queue yet, then 45 // this new mutation will be squashed together with the previous one. 46 T* begin(); 47 48 // End the current mutation and indicate whether caller modified the state. 49 // If didModify is true, then the state is marked dirty (in need of pushing). 50 // There is no rollback option because modifications are done in place. 51 // Does not automatically push the new state onto the state queue. 52 void end(bool didModify = true); 53 54 // Push a new state, if any, out to the observer via the state queue. 55 // For BLOCK_NEVER, returns: 56 // true if not dirty, or dirty and pushed successfully 57 // false if dirty and not pushed because that would block; remains dirty 58 // For BLOCK_UNTIL_PUSHED and BLOCK_UNTIL_ACKED, always returns true. 59 // No-op if there are no pending modifications (not dirty), except 60 // for BLOCK_UNTIL_ACKED it will wait until a prior push has been acknowledged. 61 // Must not be called in the middle of a mutation. 62 enum block_t { 63 BLOCK_NEVER, // do not block 64 BLOCK_UNTIL_PUSHED, // block until there's a slot available for the push 65 BLOCK_UNTIL_ACKED, // also block until the push is acknowledged by the observer 66 }; 67 bool push(block_t block = BLOCK_NEVER); 68 69 // Return whether the current state is dirty (modified and not pushed). 70 bool isDirty() const { return mIsDirty; } 71 72private: 73 static const unsigned kN = 4; // values != 4 are not supported by this code 74 T mStates[kN]; // written by mutator, read by observer 75 76 // "volatile" is meaningless with SMP, but here it indicates that we're using atomic ops 77 volatile const T* mNext; // written by mutator to advance next, read by observer 78 volatile const T* mAck; // written by observer to acknowledge advance of next, read by mutator 79 80 // only used by observer 81 const T* mCurrent; // most recent value returned by poll() 82 83 // only used by mutator 84 T* mMutating; // where updates by mutator are done in place 85 const T* mExpecting; // what the mutator expects mAck to be set to 86 bool mInMutation; // whether we're currently in the middle of a mutation 87 bool mIsDirty; // whether mutating state has been modified since last push 88 bool mIsInitialized; // whether mutating state has been initialized yet 89 90}; // class StateQueue 91 92} // namespace android 93 94#endif // ANDROID_AUDIO_STATE_QUEUE_H 95