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 20 namespace android { 21 22 #ifdef STATE_QUEUE_DUMP 23 // The StateQueueObserverDump and StateQueueMutatorDump keep 24 // a cache of StateQueue statistics that can be logged by dumpsys. 25 // Each individual native word-sized field is accessed atomically. But the 26 // overall structure is non-atomic, that is there may be an inconsistency between fields. 27 // No barriers or locks are used for either writing or reading. 28 // Only POD types are permitted, and the contents shouldn't be trusted (i.e. do range checks). 29 // It has a different lifetime than the StateQueue, and so it can't be a member of StateQueue. 30 31 struct StateQueueObserverDump { 32 StateQueueObserverDump() : mStateChanges(0) { } 33 /*virtual*/ ~StateQueueObserverDump() { } 34 unsigned mStateChanges; // incremented each time poll() detects a state change 35 void dump(int fd); 36 }; 37 38 struct StateQueueMutatorDump { 39 StateQueueMutatorDump() : mPushDirty(0), mPushAck(0), mBlockedSequence(0) { } 40 /*virtual*/ ~StateQueueMutatorDump() { } 41 unsigned mPushDirty; // incremented each time push() is called with a dirty state 42 unsigned mPushAck; // incremented each time push(BLOCK_UNTIL_ACKED) is called 43 unsigned mBlockedSequence; // incremented before and after each time that push() 44 // blocks for more than one PUSH_BLOCK_ACK_NS; 45 // if odd, then mutator is currently blocked inside push() 46 void dump(int fd); 47 }; 48 #endif 49 50 // manages a FIFO queue of states 51 template<typename T> class StateQueue { 52 53 public: 54 StateQueue(); 55 virtual ~StateQueue(); 56 57 // Observer APIs 58 59 // Poll for a state change. Returns a pointer to a read-only state, 60 // or NULL if the state has not been initialized yet. 61 // If a new state has not pushed by mutator since the previous poll, 62 // then the returned pointer will be unchanged. 63 // The previous state pointer is guaranteed to still be valid; 64 // this allows the observer to diff the previous and new states. 65 const T* poll(); 66 67 // Mutator APIs 68 69 // Begin a mutation. Returns a pointer to a read/write state, except the 70 // first time it is called the state is write-only and _must_ be initialized. 71 // Mutations cannot be nested. 72 // If the state is dirty and has not been pushed onto the state queue yet, then 73 // this new mutation will be squashed together with the previous one. 74 T* begin(); 75 76 // End the current mutation and indicate whether caller modified the state. 77 // If didModify is true, then the state is marked dirty (in need of pushing). 78 // There is no rollback option because modifications are done in place. 79 // Does not automatically push the new state onto the state queue. 80 void end(bool didModify = true); 81 82 // Push a new state, if any, out to the observer via the state queue. 83 // For BLOCK_NEVER, returns: 84 // true if not dirty, or dirty and pushed successfully 85 // false if dirty and not pushed because that would block; remains dirty 86 // For BLOCK_UNTIL_PUSHED and BLOCK_UNTIL_ACKED, always returns true. 87 // No-op if there are no pending modifications (not dirty), except 88 // for BLOCK_UNTIL_ACKED it will wait until a prior push has been acknowledged. 89 // Must not be called in the middle of a mutation. 90 enum block_t { 91 BLOCK_NEVER, // do not block 92 BLOCK_UNTIL_PUSHED, // block until there's a slot available for the push 93 BLOCK_UNTIL_ACKED, // also block until the push is acknowledged by the observer 94 }; 95 bool push(block_t block = BLOCK_NEVER); 96 97 // Return whether the current state is dirty (modified and not pushed). 98 bool isDirty() const { return mIsDirty; } 99 100 #ifdef STATE_QUEUE_DUMP 101 // Register location of observer dump area 102 void setObserverDump(StateQueueObserverDump *dump) 103 { mObserverDump = dump != NULL ? dump : &mObserverDummyDump; } 104 105 // Register location of mutator dump area 106 void setMutatorDump(StateQueueMutatorDump *dump) 107 { mMutatorDump = dump != NULL ? dump : &mMutatorDummyDump; } 108 #endif 109 110 private: 111 static const unsigned kN = 4; // values != 4 are not supported by this code 112 T mStates[kN]; // written by mutator, read by observer 113 114 // "volatile" is meaningless with SMP, but here it indicates that we're using atomic ops 115 volatile const T* mNext; // written by mutator to advance next, read by observer 116 volatile const T* mAck; // written by observer to acknowledge advance of next, read by mutator 117 118 // only used by observer 119 const T* mCurrent; // most recent value returned by poll() 120 121 // only used by mutator 122 T* mMutating; // where updates by mutator are done in place 123 const T* mExpecting; // what the mutator expects mAck to be set to 124 bool mInMutation; // whether we're currently in the middle of a mutation 125 bool mIsDirty; // whether mutating state has been modified since last push 126 bool mIsInitialized; // whether mutating state has been initialized yet 127 128 #ifdef STATE_QUEUE_DUMP 129 StateQueueObserverDump mObserverDummyDump; // default area for observer dump if not set 130 StateQueueObserverDump* mObserverDump; // pointer to active observer dump, always non-NULL 131 StateQueueMutatorDump mMutatorDummyDump; // default area for mutator dump if not set 132 StateQueueMutatorDump* mMutatorDump; // pointer to active mutator dump, always non-NULL 133 #endif 134 135 }; // class StateQueue 136 137 } // namespace android 138 139 #endif // ANDROID_AUDIO_STATE_QUEUE_H 140