blob: fe72ddc61c5296f7c3988cf7080fb54fa6e0c5b4 [file] [log] [blame]
Glenn Kastendc998c82012-03-23 18:53:59 -07001/*
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