blob: c466b9ff47b9d98f79687149bcac758997c82f9c [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// Constructor and destructor
42
43template<typename T> StateQueue<T>::StateQueue() :
Andy Hungf0859f32023-05-25 16:28:04 -070044 mAck(nullptr), mCurrent(nullptr),
45 mMutating(&mStates[0]), mExpecting(nullptr),
Glenn Kastendc998c82012-03-23 18:53:59 -070046 mInMutation(false), mIsDirty(false), mIsInitialized(false)
Glenn Kasten39993082012-05-31 13:40:27 -070047#ifdef STATE_QUEUE_DUMP
48 , mObserverDump(&mObserverDummyDump), mMutatorDump(&mMutatorDummyDump)
49#endif
Glenn Kastendc998c82012-03-23 18:53:59 -070050{
Dan Albert36802bd2014-11-20 11:31:17 -080051 atomic_init(&mNext, static_cast<uintptr_t>(0));
Glenn Kastendc998c82012-03-23 18:53:59 -070052}
53
Glenn Kastendc998c82012-03-23 18:53:59 -070054// Observer APIs
55
56template<typename T> const T* StateQueue<T>::poll()
57{
Hans Boehmf39b5602014-07-16 12:13:16 -070058 const T *next = (const T *) atomic_load_explicit(&mNext, memory_order_acquire);
59
Glenn Kastendc998c82012-03-23 18:53:59 -070060 if (next != mCurrent) {
61 mAck = next; // no additional barrier needed
62 mCurrent = next;
Glenn Kasten39993082012-05-31 13:40:27 -070063#ifdef STATE_QUEUE_DUMP
64 mObserverDump->mStateChanges++;
65#endif
Glenn Kastendc998c82012-03-23 18:53:59 -070066 }
67 return next;
68}
69
70// Mutator APIs
71
72template<typename T> T* StateQueue<T>::begin()
73{
74 ALOG_ASSERT(!mInMutation, "begin() called when in a mutation");
75 mInMutation = true;
76 return mMutating;
77}
78
79template<typename T> void StateQueue<T>::end(bool didModify)
80{
81 ALOG_ASSERT(mInMutation, "end() called when not in a mutation");
82 ALOG_ASSERT(mIsInitialized || didModify, "first end() must modify for initialization");
83 if (didModify) {
84 mIsDirty = true;
85 mIsInitialized = true;
86 }
87 mInMutation = false;
88}
89
90template<typename T> bool StateQueue<T>::push(StateQueue<T>::block_t block)
91{
92#define PUSH_BLOCK_ACK_NS 3000000L // 3 ms: time between checks for ack in push()
93 // FIXME should be configurable
94 static const struct timespec req = {0, PUSH_BLOCK_ACK_NS};
95
96 ALOG_ASSERT(!mInMutation, "push() called when in a mutation");
97
Glenn Kasten39993082012-05-31 13:40:27 -070098#ifdef STATE_QUEUE_DUMP
99 if (block == BLOCK_UNTIL_ACKED) {
100 mMutatorDump->mPushAck++;
101 }
102#endif
103
Glenn Kastendc998c82012-03-23 18:53:59 -0700104 if (mIsDirty) {
105
Glenn Kasten39993082012-05-31 13:40:27 -0700106#ifdef STATE_QUEUE_DUMP
107 mMutatorDump->mPushDirty++;
108#endif
109
Glenn Kastendc998c82012-03-23 18:53:59 -0700110 // wait for prior push to be acknowledged
Andy Hungf0859f32023-05-25 16:28:04 -0700111 if (mExpecting != nullptr) {
Glenn Kasten39993082012-05-31 13:40:27 -0700112#ifdef STATE_QUEUE_DUMP
113 unsigned count = 0;
114#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700115 for (;;) {
116 const T *ack = (const T *) mAck; // no additional barrier needed
117 if (ack == mExpecting) {
118 // unnecessary as we're about to rewrite
Andy Hungf0859f32023-05-25 16:28:04 -0700119 //mExpecting = nullptr;
Glenn Kastendc998c82012-03-23 18:53:59 -0700120 break;
121 }
122 if (block == BLOCK_NEVER) {
123 return false;
124 }
Glenn Kasten39993082012-05-31 13:40:27 -0700125#ifdef STATE_QUEUE_DUMP
126 if (count == 1) {
127 mMutatorDump->mBlockedSequence++;
128 }
129 ++count;
130#endif
Andy Hungf0859f32023-05-25 16:28:04 -0700131 nanosleep(&req, nullptr);
Glenn Kastendc998c82012-03-23 18:53:59 -0700132 }
Glenn Kasten39993082012-05-31 13:40:27 -0700133#ifdef STATE_QUEUE_DUMP
134 if (count > 1) {
135 mMutatorDump->mBlockedSequence++;
136 }
137#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700138 }
139
140 // publish
Hans Boehmf39b5602014-07-16 12:13:16 -0700141 atomic_store_explicit(&mNext, (uintptr_t)mMutating, memory_order_release);
Glenn Kastendc998c82012-03-23 18:53:59 -0700142 mExpecting = mMutating;
143
144 // copy with circular wraparound
145 if (++mMutating >= &mStates[kN]) {
146 mMutating = &mStates[0];
147 }
148 *mMutating = *mExpecting;
149 mIsDirty = false;
150
151 }
152
153 // optionally wait for this push or a prior push to be acknowledged
154 if (block == BLOCK_UNTIL_ACKED) {
Andy Hungf0859f32023-05-25 16:28:04 -0700155 if (mExpecting != nullptr) {
Glenn Kasten39993082012-05-31 13:40:27 -0700156#ifdef STATE_QUEUE_DUMP
157 unsigned count = 0;
158#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700159 for (;;) {
160 const T *ack = (const T *) mAck; // no additional barrier needed
161 if (ack == mExpecting) {
Andy Hungf0859f32023-05-25 16:28:04 -0700162 mExpecting = nullptr;
Glenn Kastendc998c82012-03-23 18:53:59 -0700163 break;
164 }
Glenn Kasten39993082012-05-31 13:40:27 -0700165#ifdef STATE_QUEUE_DUMP
166 if (count == 1) {
167 mMutatorDump->mBlockedSequence++;
168 }
169 ++count;
170#endif
Andy Hungf0859f32023-05-25 16:28:04 -0700171 nanosleep(&req, nullptr);
Glenn Kastendc998c82012-03-23 18:53:59 -0700172 }
Glenn Kasten39993082012-05-31 13:40:27 -0700173#ifdef STATE_QUEUE_DUMP
174 if (count > 1) {
175 mMutatorDump->mBlockedSequence++;
176 }
177#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700178 }
179 }
180
181 return true;
182}
183
184} // namespace android
185
Andy Hung71ba4b32022-10-06 12:09:49 -0700186// Hack to avoid explicit template instantiation of
187// template class StateQueue<FastCaptureState>;
188// template class StateQueue<FastMixerState>;
Glenn Kastendc998c82012-03-23 18:53:59 -0700189#ifdef STATE_QUEUE_INSTANTIATIONS
Andy Hung71ba4b32022-10-06 12:09:49 -0700190#include STATE_QUEUE_INSTANTIATIONS // NOLINT(bugprone-suspicious-include)
Glenn Kastendc998c82012-03-23 18:53:59 -0700191#endif