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