blob: e896d29207e2ac300caeeb36de15a1246d8bd31b [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#define LOG_TAG "StateQueue"
18//#define LOG_NDEBUG 0
19
Glenn Kasten153b9fe2013-07-15 11:23:36 -070020#include "Configuration.h"
Glenn Kastendc998c82012-03-23 18:53:59 -070021#include <time.h>
22#include <cutils/atomic.h>
23#include <utils/Log.h>
24#include "StateQueue.h"
25
26namespace android {
27
Glenn Kasten39993082012-05-31 13:40:27 -070028#ifdef STATE_QUEUE_DUMP
29void StateQueueObserverDump::dump(int fd)
30{
Elliott Hughes8b5f6422014-05-22 01:22:06 -070031 dprintf(fd, "State queue observer: stateChanges=%u\n", mStateChanges);
Glenn Kasten39993082012-05-31 13:40:27 -070032}
33
34void StateQueueMutatorDump::dump(int fd)
35{
Elliott Hughes8b5f6422014-05-22 01:22:06 -070036 dprintf(fd, "State queue mutator: pushDirty=%u pushAck=%u blockedSequence=%u\n",
Glenn Kasten39993082012-05-31 13:40:27 -070037 mPushDirty, mPushAck, mBlockedSequence);
38}
39#endif
40
Glenn Kastendc998c82012-03-23 18:53:59 -070041// Observer APIs
42
43template<typename T> const T* StateQueue<T>::poll()
44{
Hans Boehmf39b5602014-07-16 12:13:16 -070045 const T *next = (const T *) atomic_load_explicit(&mNext, memory_order_acquire);
46
Glenn Kastendc998c82012-03-23 18:53:59 -070047 if (next != mCurrent) {
48 mAck = next; // no additional barrier needed
49 mCurrent = next;
Glenn Kasten39993082012-05-31 13:40:27 -070050#ifdef STATE_QUEUE_DUMP
51 mObserverDump->mStateChanges++;
52#endif
Glenn Kastendc998c82012-03-23 18:53:59 -070053 }
54 return next;
55}
56
57// Mutator APIs
58
59template<typename T> T* StateQueue<T>::begin()
60{
61 ALOG_ASSERT(!mInMutation, "begin() called when in a mutation");
62 mInMutation = true;
63 return mMutating;
64}
65
66template<typename T> void StateQueue<T>::end(bool didModify)
67{
68 ALOG_ASSERT(mInMutation, "end() called when not in a mutation");
69 ALOG_ASSERT(mIsInitialized || didModify, "first end() must modify for initialization");
70 if (didModify) {
71 mIsDirty = true;
72 mIsInitialized = true;
73 }
74 mInMutation = false;
75}
76
77template<typename T> bool StateQueue<T>::push(StateQueue<T>::block_t block)
78{
79#define PUSH_BLOCK_ACK_NS 3000000L // 3 ms: time between checks for ack in push()
80 // FIXME should be configurable
81 static const struct timespec req = {0, PUSH_BLOCK_ACK_NS};
82
83 ALOG_ASSERT(!mInMutation, "push() called when in a mutation");
84
Glenn Kasten39993082012-05-31 13:40:27 -070085#ifdef STATE_QUEUE_DUMP
86 if (block == BLOCK_UNTIL_ACKED) {
87 mMutatorDump->mPushAck++;
88 }
89#endif
90
Glenn Kastendc998c82012-03-23 18:53:59 -070091 if (mIsDirty) {
92
Glenn Kasten39993082012-05-31 13:40:27 -070093#ifdef STATE_QUEUE_DUMP
94 mMutatorDump->mPushDirty++;
95#endif
96
Glenn Kastendc998c82012-03-23 18:53:59 -070097 // wait for prior push to be acknowledged
Andy Hungf0859f32023-05-25 16:28:04 -070098 if (mExpecting != nullptr) {
Glenn Kasten39993082012-05-31 13:40:27 -070099#ifdef STATE_QUEUE_DUMP
100 unsigned count = 0;
101#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700102 for (;;) {
103 const T *ack = (const T *) mAck; // no additional barrier needed
104 if (ack == mExpecting) {
105 // unnecessary as we're about to rewrite
Andy Hungf0859f32023-05-25 16:28:04 -0700106 //mExpecting = nullptr;
Glenn Kastendc998c82012-03-23 18:53:59 -0700107 break;
108 }
109 if (block == BLOCK_NEVER) {
110 return false;
111 }
Glenn Kasten39993082012-05-31 13:40:27 -0700112#ifdef STATE_QUEUE_DUMP
113 if (count == 1) {
114 mMutatorDump->mBlockedSequence++;
115 }
116 ++count;
117#endif
Andy Hungf0859f32023-05-25 16:28:04 -0700118 nanosleep(&req, nullptr);
Glenn Kastendc998c82012-03-23 18:53:59 -0700119 }
Glenn Kasten39993082012-05-31 13:40:27 -0700120#ifdef STATE_QUEUE_DUMP
121 if (count > 1) {
122 mMutatorDump->mBlockedSequence++;
123 }
124#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700125 }
126
127 // publish
Hans Boehmf39b5602014-07-16 12:13:16 -0700128 atomic_store_explicit(&mNext, (uintptr_t)mMutating, memory_order_release);
Glenn Kastendc998c82012-03-23 18:53:59 -0700129 mExpecting = mMutating;
130
131 // copy with circular wraparound
132 if (++mMutating >= &mStates[kN]) {
133 mMutating = &mStates[0];
134 }
135 *mMutating = *mExpecting;
136 mIsDirty = false;
137
138 }
139
140 // optionally wait for this push or a prior push to be acknowledged
141 if (block == BLOCK_UNTIL_ACKED) {
Andy Hungf0859f32023-05-25 16:28:04 -0700142 if (mExpecting != nullptr) {
Glenn Kasten39993082012-05-31 13:40:27 -0700143#ifdef STATE_QUEUE_DUMP
144 unsigned count = 0;
145#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700146 for (;;) {
147 const T *ack = (const T *) mAck; // no additional barrier needed
148 if (ack == mExpecting) {
Andy Hungf0859f32023-05-25 16:28:04 -0700149 mExpecting = nullptr;
Glenn Kastendc998c82012-03-23 18:53:59 -0700150 break;
151 }
Glenn Kasten39993082012-05-31 13:40:27 -0700152#ifdef STATE_QUEUE_DUMP
153 if (count == 1) {
154 mMutatorDump->mBlockedSequence++;
155 }
156 ++count;
157#endif
Andy Hungf0859f32023-05-25 16:28:04 -0700158 nanosleep(&req, nullptr);
Glenn Kastendc998c82012-03-23 18:53:59 -0700159 }
Glenn Kasten39993082012-05-31 13:40:27 -0700160#ifdef STATE_QUEUE_DUMP
161 if (count > 1) {
162 mMutatorDump->mBlockedSequence++;
163 }
164#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700165 }
166 }
167
168 return true;
169}
170
171} // namespace android
172
Andy Hung528b0502023-05-24 18:30:17 -0700173// Instantiate StateQueue template for the types we need.
174// This needs to be done in the same translation unit as the template
175// method definitions above.
176
177#include "FastCaptureState.h"
178#include "FastMixerState.h"
179
180namespace android {
181template class StateQueue<FastCaptureState>;
182template class StateQueue<FastMixerState>;
183} // namespace android