blob: 9d4188fb2a173807a9f382547a50245fd6576367 [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() :
Hans Boehmf39b5602014-07-16 12:13:16 -070044 mAck(NULL), mCurrent(NULL),
Glenn Kastendc998c82012-03-23 18:53:59 -070045 mMutating(&mStates[0]), mExpecting(NULL),
46 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
54template<typename T> StateQueue<T>::~StateQueue()
55{
56}
57
58// Observer APIs
59
60template<typename T> const T* StateQueue<T>::poll()
61{
Hans Boehmf39b5602014-07-16 12:13:16 -070062 const T *next = (const T *) atomic_load_explicit(&mNext, memory_order_acquire);
63
Glenn Kastendc998c82012-03-23 18:53:59 -070064 if (next != mCurrent) {
65 mAck = next; // no additional barrier needed
66 mCurrent = next;
Glenn Kasten39993082012-05-31 13:40:27 -070067#ifdef STATE_QUEUE_DUMP
68 mObserverDump->mStateChanges++;
69#endif
Glenn Kastendc998c82012-03-23 18:53:59 -070070 }
71 return next;
72}
73
74// Mutator APIs
75
76template<typename T> T* StateQueue<T>::begin()
77{
78 ALOG_ASSERT(!mInMutation, "begin() called when in a mutation");
79 mInMutation = true;
80 return mMutating;
81}
82
83template<typename T> void StateQueue<T>::end(bool didModify)
84{
85 ALOG_ASSERT(mInMutation, "end() called when not in a mutation");
86 ALOG_ASSERT(mIsInitialized || didModify, "first end() must modify for initialization");
87 if (didModify) {
88 mIsDirty = true;
89 mIsInitialized = true;
90 }
91 mInMutation = false;
92}
93
94template<typename T> bool StateQueue<T>::push(StateQueue<T>::block_t block)
95{
96#define PUSH_BLOCK_ACK_NS 3000000L // 3 ms: time between checks for ack in push()
97 // FIXME should be configurable
98 static const struct timespec req = {0, PUSH_BLOCK_ACK_NS};
99
100 ALOG_ASSERT(!mInMutation, "push() called when in a mutation");
101
Glenn Kasten39993082012-05-31 13:40:27 -0700102#ifdef STATE_QUEUE_DUMP
103 if (block == BLOCK_UNTIL_ACKED) {
104 mMutatorDump->mPushAck++;
105 }
106#endif
107
Glenn Kastendc998c82012-03-23 18:53:59 -0700108 if (mIsDirty) {
109
Glenn Kasten39993082012-05-31 13:40:27 -0700110#ifdef STATE_QUEUE_DUMP
111 mMutatorDump->mPushDirty++;
112#endif
113
Glenn Kastendc998c82012-03-23 18:53:59 -0700114 // wait for prior push to be acknowledged
115 if (mExpecting != NULL) {
Glenn Kasten39993082012-05-31 13:40:27 -0700116#ifdef STATE_QUEUE_DUMP
117 unsigned count = 0;
118#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700119 for (;;) {
120 const T *ack = (const T *) mAck; // no additional barrier needed
121 if (ack == mExpecting) {
122 // unnecessary as we're about to rewrite
123 //mExpecting = NULL;
124 break;
125 }
126 if (block == BLOCK_NEVER) {
127 return false;
128 }
Glenn Kasten39993082012-05-31 13:40:27 -0700129#ifdef STATE_QUEUE_DUMP
130 if (count == 1) {
131 mMutatorDump->mBlockedSequence++;
132 }
133 ++count;
134#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700135 nanosleep(&req, NULL);
136 }
Glenn Kasten39993082012-05-31 13:40:27 -0700137#ifdef STATE_QUEUE_DUMP
138 if (count > 1) {
139 mMutatorDump->mBlockedSequence++;
140 }
141#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700142 }
143
144 // publish
Hans Boehmf39b5602014-07-16 12:13:16 -0700145 atomic_store_explicit(&mNext, (uintptr_t)mMutating, memory_order_release);
Glenn Kastendc998c82012-03-23 18:53:59 -0700146 mExpecting = mMutating;
147
148 // copy with circular wraparound
149 if (++mMutating >= &mStates[kN]) {
150 mMutating = &mStates[0];
151 }
152 *mMutating = *mExpecting;
153 mIsDirty = false;
154
155 }
156
157 // optionally wait for this push or a prior push to be acknowledged
158 if (block == BLOCK_UNTIL_ACKED) {
159 if (mExpecting != NULL) {
Glenn Kasten39993082012-05-31 13:40:27 -0700160#ifdef STATE_QUEUE_DUMP
161 unsigned count = 0;
162#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700163 for (;;) {
164 const T *ack = (const T *) mAck; // no additional barrier needed
165 if (ack == mExpecting) {
166 mExpecting = NULL;
167 break;
168 }
Glenn Kasten39993082012-05-31 13:40:27 -0700169#ifdef STATE_QUEUE_DUMP
170 if (count == 1) {
171 mMutatorDump->mBlockedSequence++;
172 }
173 ++count;
174#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700175 nanosleep(&req, NULL);
176 }
Glenn Kasten39993082012-05-31 13:40:27 -0700177#ifdef STATE_QUEUE_DUMP
178 if (count > 1) {
179 mMutatorDump->mBlockedSequence++;
180 }
181#endif
Glenn Kastendc998c82012-03-23 18:53:59 -0700182 }
183 }
184
185 return true;
186}
187
188} // namespace android
189
190// hack for gcc
191#ifdef STATE_QUEUE_INSTANTIATIONS
192#include STATE_QUEUE_INSTANTIATIONS
193#endif