blob: c79652016f6efa379bff41d4f91cfeefdc811885 [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;
Jason Sams613cad12009-11-12 15:10:25 -080060 //dumpState("init");
Jason Sams326e0dd2009-05-22 14:03:28 -070061 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 Sams8c401ef2009-10-06 13:58:47 -0700102 if (mInShutdown) {
103 return;
104 }
Jason Sams326e0dd2009-05-22 14:03:28 -0700105 //dumpState("commit 1");
106 reinterpret_cast<uint16_t *>(mPut)[0] = command;
107 reinterpret_cast<uint16_t *>(mPut)[1] = sizeInBytes;
108 mPut += ((sizeInBytes + 3) & ~3) + 4;
109 //dumpState("commit 2");
Jason Sams732f1c02009-06-18 16:58:42 -0700110 mSignalToWorker.set();
Jason Sams326e0dd2009-05-22 14:03:28 -0700111}
112
113void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes)
114{
Jason Sams8c401ef2009-10-06 13:58:47 -0700115 if (mInShutdown) {
116 return;
117 }
Jason Sams326e0dd2009-05-22 14:03:28 -0700118 commit(command, sizeInBytes);
119 flush();
120}
121
122void LocklessCommandFifo::flush()
123{
124 //dumpState("flush 1");
125 while(mPut != mGet) {
Jason Sams732f1c02009-06-18 16:58:42 -0700126 mSignalToControl.wait();
Jason Sams326e0dd2009-05-22 14:03:28 -0700127 }
128 //dumpState("flush 2");
129}
130
131const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData)
132{
133 while(1) {
Jason Sams732f1c02009-06-18 16:58:42 -0700134 //dumpState("get");
Jason Sams8c0ee652009-08-25 14:49:07 -0700135 while(isEmpty() && !mInShutdown) {
Jason Sams732f1c02009-06-18 16:58:42 -0700136 mSignalToControl.set();
137 mSignalToWorker.wait();
Jason Sams326e0dd2009-05-22 14:03:28 -0700138 }
Jason Sams326e0dd2009-05-22 14:03:28 -0700139
Jason Samse514b452009-09-25 14:51:22 -0700140 if (mInShutdown) {
141 *command = 0;
142 *bytesData = 0;
143 return 0;
144 }
145
Jason Sams326e0dd2009-05-22 14:03:28 -0700146 *command = reinterpret_cast<const uint16_t *>(mGet)[0];
147 *bytesData = reinterpret_cast<const uint16_t *>(mGet)[1];
Jason Sams326e0dd2009-05-22 14:03:28 -0700148 if (*command) {
149 // non-zero command is valid
150 return mGet+4;
151 }
Jason Sams8c0ee652009-08-25 14:49:07 -0700152
Jason Sams326e0dd2009-05-22 14:03:28 -0700153 // zero command means reset to beginning.
154 mGet = mBuffer;
155 }
156}
157
158void LocklessCommandFifo::next()
159{
160 uint32_t bytes = reinterpret_cast<const uint16_t *>(mGet)[1];
161 mGet += ((bytes + 3) & ~3) + 4;
Jason Sams732f1c02009-06-18 16:58:42 -0700162 if (isEmpty()) {
163 mSignalToControl.set();
164 }
Jason Sams326e0dd2009-05-22 14:03:28 -0700165 //dumpState("next");
166}
167
168void LocklessCommandFifo::makeSpace(uint32_t bytes)
169{
Jason Sams565ac362009-06-03 16:04:54 -0700170 //dumpState("make space");
Jason Sams326e0dd2009-05-22 14:03:28 -0700171 if ((mPut+bytes) > mEnd) {
172 // Need to loop regardless of where get is.
Jason Sams565ac362009-06-03 16:04:54 -0700173 while((mGet > mPut) && (mBuffer+4 >= mGet)) {
Jason Samsada7f272009-09-24 14:55:38 -0700174 usleep(100);
Jason Sams326e0dd2009-05-22 14:03:28 -0700175 }
176
177 // Toss in a reset then the normal wait for space will do the rest.
178 reinterpret_cast<uint16_t *>(mPut)[0] = 0;
179 reinterpret_cast<uint16_t *>(mPut)[1] = 0;
Jason Sams565ac362009-06-03 16:04:54 -0700180 mPut = mBuffer;
Jason Sams326e0dd2009-05-22 14:03:28 -0700181 }
182
183 // it will fit here so we just need to wait for space.
184 while(getFreeSpace() < bytes) {
Jason Samsada7f272009-09-24 14:55:38 -0700185 usleep(100);
Jason Sams326e0dd2009-05-22 14:03:28 -0700186 }
Jason Sams8c0ee652009-08-25 14:49:07 -0700187
Jason Sams326e0dd2009-05-22 14:03:28 -0700188}
189
190void LocklessCommandFifo::dumpState(const char *s) const
191{
Jason Sams992a0b72009-06-23 12:22:47 -0700192 LOGV("%s put %p, get %p, buf %p, end %p", s, mPut, mGet, mBuffer, mEnd);
Jason Sams326e0dd2009-05-22 14:03:28 -0700193}
194
Jason Sams732f1c02009-06-18 16:58:42 -0700195LocklessCommandFifo::Signal::Signal()
196{
197 mSet = true;
198}
199
200LocklessCommandFifo::Signal::~Signal()
201{
202 pthread_mutex_destroy(&mMutex);
203 pthread_cond_destroy(&mCondition);
204}
205
206bool LocklessCommandFifo::Signal::init()
207{
208 int status = pthread_mutex_init(&mMutex, NULL);
209 if (status) {
210 LOGE("LocklessFifo mutex init failure");
211 return false;
212 }
213
214 status = pthread_cond_init(&mCondition, NULL);
215 if (status) {
216 LOGE("LocklessFifo condition init failure");
217 pthread_mutex_destroy(&mMutex);
218 return false;
219 }
220
221 return true;
222}
223
224void LocklessCommandFifo::Signal::set()
225{
226 int status;
227
228 status = pthread_mutex_lock(&mMutex);
229 if (status) {
230 LOGE("LocklessCommandFifo: error %i locking for set condition.", status);
231 return;
232 }
233
234 mSet = true;
235
236 status = pthread_cond_signal(&mCondition);
237 if (status) {
238 LOGE("LocklessCommandFifo: error %i on set condition.", status);
239 }
240
241 status = pthread_mutex_unlock(&mMutex);
242 if (status) {
243 LOGE("LocklessCommandFifo: error %i unlocking for set condition.", status);
244 }
245}
246
247void LocklessCommandFifo::Signal::wait()
248{
249 int status;
250
251 status = pthread_mutex_lock(&mMutex);
252 if (status) {
253 LOGE("LocklessCommandFifo: error %i locking for condition.", status);
254 return;
255 }
256
257 if (!mSet) {
258 status = pthread_cond_wait(&mCondition, &mMutex);
259 if (status) {
260 LOGE("LocklessCommandFifo: error %i waiting on condition.", status);
261 }
262 }
263 mSet = false;
264
265 status = pthread_mutex_unlock(&mMutex);
266 if (status) {
267 LOGE("LocklessCommandFifo: error %i unlocking for condition.", status);
268 }
269}
Jason Sams326e0dd2009-05-22 14:03:28 -0700270