blob: b0540a6eac4726cc3171fe1c52d838e8c08daa33 [file] [log] [blame]
Jason Sams326e0dd2009-05-22 14:03:28 -07001/*
2 * Copyright (C) 2009 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#include "rsLocklessFifo.h"
18
19using namespace android;
20
Jason Sams326e0dd2009-05-22 14:03:28 -070021
22LocklessCommandFifo::LocklessCommandFifo()
23{
24}
25
26LocklessCommandFifo::~LocklessCommandFifo()
27{
Jason Sams8c0ee652009-08-25 14:49:07 -070028 if (!mInShutdown) {
29 shutdown();
30 }
31 free(mBuffer);
32}
33
34void LocklessCommandFifo::shutdown()
35{
36 mInShutdown = true;
37 mSignalToWorker.set();
Jason Sams326e0dd2009-05-22 14:03:28 -070038}
39
40bool LocklessCommandFifo::init(uint32_t sizeInBytes)
41{
42 // Add room for a buffer reset command
43 mBuffer = static_cast<uint8_t *>(malloc(sizeInBytes + 4));
44 if (!mBuffer) {
45 LOGE("LocklessFifo allocation failure");
46 return false;
47 }
48
Jason Sams732f1c02009-06-18 16:58:42 -070049 if (!mSignalToControl.init() || !mSignalToWorker.init()) {
50 LOGE("Signal setup failed");
Jason Sams326e0dd2009-05-22 14:03:28 -070051 free(mBuffer);
52 return false;
53 }
54
Jason Sams8c0ee652009-08-25 14:49:07 -070055 mInShutdown = false;
Jason Sams326e0dd2009-05-22 14:03:28 -070056 mSize = sizeInBytes;
57 mPut = mBuffer;
58 mGet = mBuffer;
59 mEnd = mBuffer + (sizeInBytes) - 1;
60 dumpState("init");
61 return true;
62}
63
Jason Sams8c0ee652009-08-25 14:49:07 -070064uint32_t LocklessCommandFifo::getFreeSpace() const
Jason Sams326e0dd2009-05-22 14:03:28 -070065{
66 int32_t freeSpace = 0;
67 //dumpState("getFreeSpace");
68
69 if (mPut >= mGet) {
70 freeSpace = mEnd - mPut;
71 } else {
72 freeSpace = mGet - mPut;
73 }
74
75 if (freeSpace < 0) {
76 freeSpace = 0;
77 }
Jason Sams326e0dd2009-05-22 14:03:28 -070078 return freeSpace;
79}
80
81bool LocklessCommandFifo::isEmpty() const
82{
83 return mPut == mGet;
84}
85
86
87void * LocklessCommandFifo::reserve(uint32_t sizeInBytes)
88{
Jason Sams565ac362009-06-03 16:04:54 -070089 // Add space for command header and loop token;
90 sizeInBytes += 8;
Jason Sams326e0dd2009-05-22 14:03:28 -070091
92 //dumpState("reserve");
93 if (getFreeSpace() < sizeInBytes) {
94 makeSpace(sizeInBytes);
95 }
96
97 return mPut + 4;
98}
99
100void LocklessCommandFifo::commit(uint32_t command, uint32_t sizeInBytes)
101{
Jason Sams326e0dd2009-05-22 14:03:28 -0700102 //dumpState("commit 1");
103 reinterpret_cast<uint16_t *>(mPut)[0] = command;
104 reinterpret_cast<uint16_t *>(mPut)[1] = sizeInBytes;
105 mPut += ((sizeInBytes + 3) & ~3) + 4;
106 //dumpState("commit 2");
Jason Sams732f1c02009-06-18 16:58:42 -0700107 mSignalToWorker.set();
Jason Sams326e0dd2009-05-22 14:03:28 -0700108}
109
110void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes)
111{
112 commit(command, sizeInBytes);
113 flush();
114}
115
116void LocklessCommandFifo::flush()
117{
118 //dumpState("flush 1");
119 while(mPut != mGet) {
Jason Sams732f1c02009-06-18 16:58:42 -0700120 mSignalToControl.wait();
Jason Sams326e0dd2009-05-22 14:03:28 -0700121 }
122 //dumpState("flush 2");
123}
124
125const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData)
126{
127 while(1) {
Jason Sams732f1c02009-06-18 16:58:42 -0700128 //dumpState("get");
Jason Sams8c0ee652009-08-25 14:49:07 -0700129 while(isEmpty() && !mInShutdown) {
Jason Sams732f1c02009-06-18 16:58:42 -0700130 mSignalToControl.set();
131 mSignalToWorker.wait();
Jason Sams326e0dd2009-05-22 14:03:28 -0700132 }
Jason Sams326e0dd2009-05-22 14:03:28 -0700133
Jason Samse514b452009-09-25 14:51:22 -0700134 if (mInShutdown) {
135 *command = 0;
136 *bytesData = 0;
137 return 0;
138 }
139
Jason Sams326e0dd2009-05-22 14:03:28 -0700140 *command = reinterpret_cast<const uint16_t *>(mGet)[0];
141 *bytesData = reinterpret_cast<const uint16_t *>(mGet)[1];
Jason Sams326e0dd2009-05-22 14:03:28 -0700142 if (*command) {
143 // non-zero command is valid
144 return mGet+4;
145 }
Jason Sams8c0ee652009-08-25 14:49:07 -0700146
Jason Sams326e0dd2009-05-22 14:03:28 -0700147 // zero command means reset to beginning.
148 mGet = mBuffer;
149 }
150}
151
152void LocklessCommandFifo::next()
153{
154 uint32_t bytes = reinterpret_cast<const uint16_t *>(mGet)[1];
155 mGet += ((bytes + 3) & ~3) + 4;
Jason Sams732f1c02009-06-18 16:58:42 -0700156 if (isEmpty()) {
157 mSignalToControl.set();
158 }
Jason Sams326e0dd2009-05-22 14:03:28 -0700159 //dumpState("next");
160}
161
162void LocklessCommandFifo::makeSpace(uint32_t bytes)
163{
Jason Sams565ac362009-06-03 16:04:54 -0700164 //dumpState("make space");
Jason Sams326e0dd2009-05-22 14:03:28 -0700165 if ((mPut+bytes) > mEnd) {
166 // Need to loop regardless of where get is.
Jason Sams565ac362009-06-03 16:04:54 -0700167 while((mGet > mPut) && (mBuffer+4 >= mGet)) {
Jason Samsada7f272009-09-24 14:55:38 -0700168 usleep(100);
Jason Sams326e0dd2009-05-22 14:03:28 -0700169 }
170
171 // Toss in a reset then the normal wait for space will do the rest.
172 reinterpret_cast<uint16_t *>(mPut)[0] = 0;
173 reinterpret_cast<uint16_t *>(mPut)[1] = 0;
Jason Sams565ac362009-06-03 16:04:54 -0700174 mPut = mBuffer;
Jason Sams326e0dd2009-05-22 14:03:28 -0700175 }
176
177 // it will fit here so we just need to wait for space.
178 while(getFreeSpace() < bytes) {
Jason Samsada7f272009-09-24 14:55:38 -0700179 usleep(100);
Jason Sams326e0dd2009-05-22 14:03:28 -0700180 }
Jason Sams8c0ee652009-08-25 14:49:07 -0700181
Jason Sams326e0dd2009-05-22 14:03:28 -0700182}
183
184void LocklessCommandFifo::dumpState(const char *s) const
185{
Jason Sams992a0b72009-06-23 12:22:47 -0700186 LOGV("%s put %p, get %p, buf %p, end %p", s, mPut, mGet, mBuffer, mEnd);
Jason Sams326e0dd2009-05-22 14:03:28 -0700187}
188
Jason Sams732f1c02009-06-18 16:58:42 -0700189LocklessCommandFifo::Signal::Signal()
190{
191 mSet = true;
192}
193
194LocklessCommandFifo::Signal::~Signal()
195{
196 pthread_mutex_destroy(&mMutex);
197 pthread_cond_destroy(&mCondition);
198}
199
200bool LocklessCommandFifo::Signal::init()
201{
202 int status = pthread_mutex_init(&mMutex, NULL);
203 if (status) {
204 LOGE("LocklessFifo mutex init failure");
205 return false;
206 }
207
208 status = pthread_cond_init(&mCondition, NULL);
209 if (status) {
210 LOGE("LocklessFifo condition init failure");
211 pthread_mutex_destroy(&mMutex);
212 return false;
213 }
214
215 return true;
216}
217
218void LocklessCommandFifo::Signal::set()
219{
220 int status;
221
222 status = pthread_mutex_lock(&mMutex);
223 if (status) {
224 LOGE("LocklessCommandFifo: error %i locking for set condition.", status);
225 return;
226 }
227
228 mSet = true;
229
230 status = pthread_cond_signal(&mCondition);
231 if (status) {
232 LOGE("LocklessCommandFifo: error %i on set condition.", status);
233 }
234
235 status = pthread_mutex_unlock(&mMutex);
236 if (status) {
237 LOGE("LocklessCommandFifo: error %i unlocking for set condition.", status);
238 }
239}
240
241void LocklessCommandFifo::Signal::wait()
242{
243 int status;
244
245 status = pthread_mutex_lock(&mMutex);
246 if (status) {
247 LOGE("LocklessCommandFifo: error %i locking for condition.", status);
248 return;
249 }
250
251 if (!mSet) {
252 status = pthread_cond_wait(&mCondition, &mMutex);
253 if (status) {
254 LOGE("LocklessCommandFifo: error %i waiting on condition.", status);
255 }
256 }
257 mSet = false;
258
259 status = pthread_mutex_unlock(&mMutex);
260 if (status) {
261 LOGE("LocklessCommandFifo: error %i unlocking for condition.", status);
262 }
263}
Jason Sams326e0dd2009-05-22 14:03:28 -0700264