blob: c3fee5428cb0f6603fb8c1380c5fa63f17eba7c2 [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{
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 Sams732f1c02009-06-18 16:58:42 -070039 if (!mSignalToControl.init() || !mSignalToWorker.init()) {
40 LOGE("Signal setup failed");
Jason Sams326e0dd2009-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 }
Jason Sams326e0dd2009-05-22 14:03:28 -070067 return freeSpace;
68}
69
70bool LocklessCommandFifo::isEmpty() const
71{
72 return mPut == mGet;
73}
74
75
76void * LocklessCommandFifo::reserve(uint32_t sizeInBytes)
77{
Jason Sams565ac362009-06-03 16:04:54 -070078 // Add space for command header and loop token;
79 sizeInBytes += 8;
Jason Sams326e0dd2009-05-22 14:03:28 -070080
81 //dumpState("reserve");
82 if (getFreeSpace() < sizeInBytes) {
83 makeSpace(sizeInBytes);
84 }
85
86 return mPut + 4;
87}
88
89void LocklessCommandFifo::commit(uint32_t command, uint32_t sizeInBytes)
90{
Jason Sams326e0dd2009-05-22 14:03:28 -070091 //dumpState("commit 1");
92 reinterpret_cast<uint16_t *>(mPut)[0] = command;
93 reinterpret_cast<uint16_t *>(mPut)[1] = sizeInBytes;
94 mPut += ((sizeInBytes + 3) & ~3) + 4;
95 //dumpState("commit 2");
Jason Sams732f1c02009-06-18 16:58:42 -070096 mSignalToWorker.set();
Jason Sams326e0dd2009-05-22 14:03:28 -070097}
98
99void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes)
100{
101 commit(command, sizeInBytes);
102 flush();
103}
104
105void LocklessCommandFifo::flush()
106{
107 //dumpState("flush 1");
108 while(mPut != mGet) {
Jason Sams732f1c02009-06-18 16:58:42 -0700109 mSignalToControl.wait();
Jason Sams326e0dd2009-05-22 14:03:28 -0700110 }
111 //dumpState("flush 2");
112}
113
114const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData)
115{
116 while(1) {
Jason Sams732f1c02009-06-18 16:58:42 -0700117 //dumpState("get");
Jason Sams326e0dd2009-05-22 14:03:28 -0700118 while(isEmpty()) {
Jason Sams732f1c02009-06-18 16:58:42 -0700119 mSignalToControl.set();
120 mSignalToWorker.wait();
Jason Sams326e0dd2009-05-22 14:03:28 -0700121 }
Jason Sams326e0dd2009-05-22 14:03:28 -0700122
123 *command = reinterpret_cast<const uint16_t *>(mGet)[0];
124 *bytesData = reinterpret_cast<const uint16_t *>(mGet)[1];
Jason Sams326e0dd2009-05-22 14:03:28 -0700125 if (*command) {
126 // non-zero command is valid
127 return mGet+4;
128 }
129
130 // zero command means reset to beginning.
131 mGet = mBuffer;
132 }
133}
134
135void LocklessCommandFifo::next()
136{
137 uint32_t bytes = reinterpret_cast<const uint16_t *>(mGet)[1];
138 mGet += ((bytes + 3) & ~3) + 4;
Jason Sams732f1c02009-06-18 16:58:42 -0700139 if (isEmpty()) {
140 mSignalToControl.set();
141 }
Jason Sams326e0dd2009-05-22 14:03:28 -0700142 //dumpState("next");
143}
144
145void LocklessCommandFifo::makeSpace(uint32_t bytes)
146{
Jason Sams565ac362009-06-03 16:04:54 -0700147 //dumpState("make space");
Jason Sams326e0dd2009-05-22 14:03:28 -0700148 if ((mPut+bytes) > mEnd) {
149 // Need to loop regardless of where get is.
Jason Sams565ac362009-06-03 16:04:54 -0700150 while((mGet > mPut) && (mBuffer+4 >= mGet)) {
Jason Sams326e0dd2009-05-22 14:03:28 -0700151 sleep(1);
152 }
153
154 // Toss in a reset then the normal wait for space will do the rest.
155 reinterpret_cast<uint16_t *>(mPut)[0] = 0;
156 reinterpret_cast<uint16_t *>(mPut)[1] = 0;
Jason Sams565ac362009-06-03 16:04:54 -0700157 mPut = mBuffer;
Jason Sams326e0dd2009-05-22 14:03:28 -0700158 }
159
160 // it will fit here so we just need to wait for space.
161 while(getFreeSpace() < bytes) {
162 sleep(1);
163 }
164
165}
166
167void LocklessCommandFifo::dumpState(const char *s) const
168{
Jason Sams992a0b72009-06-23 12:22:47 -0700169 LOGV("%s put %p, get %p, buf %p, end %p", s, mPut, mGet, mBuffer, mEnd);
Jason Sams326e0dd2009-05-22 14:03:28 -0700170}
171
Jason Sams732f1c02009-06-18 16:58:42 -0700172LocklessCommandFifo::Signal::Signal()
173{
174 mSet = true;
175}
176
177LocklessCommandFifo::Signal::~Signal()
178{
179 pthread_mutex_destroy(&mMutex);
180 pthread_cond_destroy(&mCondition);
181}
182
183bool LocklessCommandFifo::Signal::init()
184{
185 int status = pthread_mutex_init(&mMutex, NULL);
186 if (status) {
187 LOGE("LocklessFifo mutex init failure");
188 return false;
189 }
190
191 status = pthread_cond_init(&mCondition, NULL);
192 if (status) {
193 LOGE("LocklessFifo condition init failure");
194 pthread_mutex_destroy(&mMutex);
195 return false;
196 }
197
198 return true;
199}
200
201void LocklessCommandFifo::Signal::set()
202{
203 int status;
204
205 status = pthread_mutex_lock(&mMutex);
206 if (status) {
207 LOGE("LocklessCommandFifo: error %i locking for set condition.", status);
208 return;
209 }
210
211 mSet = true;
212
213 status = pthread_cond_signal(&mCondition);
214 if (status) {
215 LOGE("LocklessCommandFifo: error %i on set condition.", status);
216 }
217
218 status = pthread_mutex_unlock(&mMutex);
219 if (status) {
220 LOGE("LocklessCommandFifo: error %i unlocking for set condition.", status);
221 }
222}
223
224void LocklessCommandFifo::Signal::wait()
225{
226 int status;
227
228 status = pthread_mutex_lock(&mMutex);
229 if (status) {
230 LOGE("LocklessCommandFifo: error %i locking for condition.", status);
231 return;
232 }
233
234 if (!mSet) {
235 status = pthread_cond_wait(&mCondition, &mMutex);
236 if (status) {
237 LOGE("LocklessCommandFifo: error %i waiting on condition.", status);
238 }
239 }
240 mSet = false;
241
242 status = pthread_mutex_unlock(&mMutex);
243 if (status) {
244 LOGE("LocklessCommandFifo: error %i unlocking for condition.", status);
245 }
246}
Jason Sams326e0dd2009-05-22 14:03:28 -0700247