blob: fae92e52a2881023645165ef19ec7235bac6c89a [file] [log] [blame]
Jason Samsd19f10d2009-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 Samsd19f10d2009-05-22 14:03:28 -070021
22LocklessCommandFifo::LocklessCommandFifo()
23{
24}
25
26LocklessCommandFifo::~LocklessCommandFifo()
27{
28}
29
30bool LocklessCommandFifo::init(uint32_t sizeInBytes)
31{
32 // Add room for a buffer reset command
33 mBuffer = static_cast<uint8_t *>(malloc(sizeInBytes + 4));
34 if (!mBuffer) {
35 LOGE("LocklessFifo allocation failure");
36 return false;
37 }
38
Jason Sams5f7fc272009-06-18 16:58:42 -070039 if (!mSignalToControl.init() || !mSignalToWorker.init()) {
40 LOGE("Signal setup failed");
Jason Samsd19f10d2009-05-22 14:03:28 -070041 free(mBuffer);
42 return false;
43 }
44
45 mSize = sizeInBytes;
46 mPut = mBuffer;
47 mGet = mBuffer;
48 mEnd = mBuffer + (sizeInBytes) - 1;
49 dumpState("init");
50 return true;
51}
52
53uint32_t LocklessCommandFifo::getFreeSpace() const
54{
55 int32_t freeSpace = 0;
56 //dumpState("getFreeSpace");
57
58 if (mPut >= mGet) {
59 freeSpace = mEnd - mPut;
60 } else {
61 freeSpace = mGet - mPut;
62 }
63
64 if (freeSpace < 0) {
65 freeSpace = 0;
66 }
67
Jason Samse2ae85f2009-06-03 16:04:54 -070068 //LOGE("free %i", freeSpace);
Jason Samsd19f10d2009-05-22 14:03:28 -070069 return freeSpace;
70}
71
72bool LocklessCommandFifo::isEmpty() const
73{
74 return mPut == mGet;
75}
76
77
78void * LocklessCommandFifo::reserve(uint32_t sizeInBytes)
79{
Jason Samse2ae85f2009-06-03 16:04:54 -070080 // Add space for command header and loop token;
81 sizeInBytes += 8;
Jason Samsd19f10d2009-05-22 14:03:28 -070082
83 //dumpState("reserve");
84 if (getFreeSpace() < sizeInBytes) {
85 makeSpace(sizeInBytes);
86 }
87
88 return mPut + 4;
89}
90
91void LocklessCommandFifo::commit(uint32_t command, uint32_t sizeInBytes)
92{
93 //LOGE("commit cmd %i size %i", command, sizeInBytes);
94 //dumpState("commit 1");
95 reinterpret_cast<uint16_t *>(mPut)[0] = command;
96 reinterpret_cast<uint16_t *>(mPut)[1] = sizeInBytes;
97 mPut += ((sizeInBytes + 3) & ~3) + 4;
98 //dumpState("commit 2");
99
Jason Sams5f7fc272009-06-18 16:58:42 -0700100 mSignalToWorker.set();
Jason Samsd19f10d2009-05-22 14:03:28 -0700101}
102
103void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes)
104{
105 commit(command, sizeInBytes);
106 flush();
107}
108
109void LocklessCommandFifo::flush()
110{
111 //dumpState("flush 1");
112 while(mPut != mGet) {
Jason Sams5f7fc272009-06-18 16:58:42 -0700113 mSignalToControl.wait();
Jason Samsd19f10d2009-05-22 14:03:28 -0700114 }
115 //dumpState("flush 2");
116}
117
118const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData)
119{
120 while(1) {
Jason Sams5f7fc272009-06-18 16:58:42 -0700121 //dumpState("get");
Jason Samsd19f10d2009-05-22 14:03:28 -0700122 while(isEmpty()) {
Jason Sams5f7fc272009-06-18 16:58:42 -0700123 mSignalToControl.set();
124 mSignalToWorker.wait();
Jason Samsd19f10d2009-05-22 14:03:28 -0700125 }
126 //dumpState("get 3");
127
128 *command = reinterpret_cast<const uint16_t *>(mGet)[0];
129 *bytesData = reinterpret_cast<const uint16_t *>(mGet)[1];
130 //LOGE("Got %i, %i", *command, *bytesData);
131
132 if (*command) {
133 // non-zero command is valid
134 return mGet+4;
135 }
136
137 // zero command means reset to beginning.
138 mGet = mBuffer;
139 }
140}
141
142void LocklessCommandFifo::next()
143{
144 uint32_t bytes = reinterpret_cast<const uint16_t *>(mGet)[1];
145 mGet += ((bytes + 3) & ~3) + 4;
Jason Sams5f7fc272009-06-18 16:58:42 -0700146 if (isEmpty()) {
147 mSignalToControl.set();
148 }
Jason Samsd19f10d2009-05-22 14:03:28 -0700149 //dumpState("next");
150}
151
152void LocklessCommandFifo::makeSpace(uint32_t bytes)
153{
Jason Samse2ae85f2009-06-03 16:04:54 -0700154 //dumpState("make space");
Jason Samsd19f10d2009-05-22 14:03:28 -0700155 if ((mPut+bytes) > mEnd) {
156 // Need to loop regardless of where get is.
Jason Samse2ae85f2009-06-03 16:04:54 -0700157 while((mGet > mPut) && (mBuffer+4 >= mGet)) {
Jason Samsd19f10d2009-05-22 14:03:28 -0700158 sleep(1);
159 }
160
161 // Toss in a reset then the normal wait for space will do the rest.
162 reinterpret_cast<uint16_t *>(mPut)[0] = 0;
163 reinterpret_cast<uint16_t *>(mPut)[1] = 0;
Jason Samse2ae85f2009-06-03 16:04:54 -0700164 mPut = mBuffer;
Jason Samsd19f10d2009-05-22 14:03:28 -0700165 }
166
167 // it will fit here so we just need to wait for space.
168 while(getFreeSpace() < bytes) {
169 sleep(1);
170 }
171
172}
173
174void LocklessCommandFifo::dumpState(const char *s) const
175{
176 LOGE("%s put %p, get %p, buf %p, end %p", s, mPut, mGet, mBuffer, mEnd);
177}
178
Jason Sams5f7fc272009-06-18 16:58:42 -0700179LocklessCommandFifo::Signal::Signal()
180{
181 mSet = true;
182}
183
184LocklessCommandFifo::Signal::~Signal()
185{
186 pthread_mutex_destroy(&mMutex);
187 pthread_cond_destroy(&mCondition);
188}
189
190bool LocklessCommandFifo::Signal::init()
191{
192 int status = pthread_mutex_init(&mMutex, NULL);
193 if (status) {
194 LOGE("LocklessFifo mutex init failure");
195 return false;
196 }
197
198 status = pthread_cond_init(&mCondition, NULL);
199 if (status) {
200 LOGE("LocklessFifo condition init failure");
201 pthread_mutex_destroy(&mMutex);
202 return false;
203 }
204
205 return true;
206}
207
208void LocklessCommandFifo::Signal::set()
209{
210 int status;
211
212 status = pthread_mutex_lock(&mMutex);
213 if (status) {
214 LOGE("LocklessCommandFifo: error %i locking for set condition.", status);
215 return;
216 }
217
218 mSet = true;
219
220 status = pthread_cond_signal(&mCondition);
221 if (status) {
222 LOGE("LocklessCommandFifo: error %i on set condition.", status);
223 }
224
225 status = pthread_mutex_unlock(&mMutex);
226 if (status) {
227 LOGE("LocklessCommandFifo: error %i unlocking for set condition.", status);
228 }
229}
230
231void LocklessCommandFifo::Signal::wait()
232{
233 int status;
234
235 status = pthread_mutex_lock(&mMutex);
236 if (status) {
237 LOGE("LocklessCommandFifo: error %i locking for condition.", status);
238 return;
239 }
240
241 if (!mSet) {
242 status = pthread_cond_wait(&mCondition, &mMutex);
243 if (status) {
244 LOGE("LocklessCommandFifo: error %i waiting on condition.", status);
245 }
246 }
247 mSet = false;
248
249 status = pthread_mutex_unlock(&mMutex);
250 if (status) {
251 LOGE("LocklessCommandFifo: error %i unlocking for condition.", status);
252 }
253}
Jason Samsd19f10d2009-05-22 14:03:28 -0700254