blob: 019ea72b10290a58a7b3e4a95fc1b4f5d56792a1 [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;
Jason Sams12b14ae2010-03-18 11:39:44 -070020using namespace android::renderscript;
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
Jason Sams12b14ae2010-03-18 11:39:44 -0700131void LocklessCommandFifo::wait()
132{
133 while(isEmpty() && !mInShutdown) {
134 mSignalToControl.set();
135 mSignalToWorker.wait();
136 }
137}
138
Jason Sams326e0dd2009-05-22 14:03:28 -0700139const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData)
140{
141 while(1) {
Jason Sams732f1c02009-06-18 16:58:42 -0700142 //dumpState("get");
Jason Sams12b14ae2010-03-18 11:39:44 -0700143 wait();
Jason Samse514b452009-09-25 14:51:22 -0700144 if (mInShutdown) {
145 *command = 0;
146 *bytesData = 0;
147 return 0;
148 }
149
Jason Sams326e0dd2009-05-22 14:03:28 -0700150 *command = reinterpret_cast<const uint16_t *>(mGet)[0];
151 *bytesData = reinterpret_cast<const uint16_t *>(mGet)[1];
Jason Sams326e0dd2009-05-22 14:03:28 -0700152 if (*command) {
153 // non-zero command is valid
154 return mGet+4;
155 }
Jason Sams8c0ee652009-08-25 14:49:07 -0700156
Jason Sams326e0dd2009-05-22 14:03:28 -0700157 // zero command means reset to beginning.
158 mGet = mBuffer;
159 }
160}
161
162void LocklessCommandFifo::next()
163{
164 uint32_t bytes = reinterpret_cast<const uint16_t *>(mGet)[1];
165 mGet += ((bytes + 3) & ~3) + 4;
Jason Sams732f1c02009-06-18 16:58:42 -0700166 if (isEmpty()) {
167 mSignalToControl.set();
168 }
Jason Sams326e0dd2009-05-22 14:03:28 -0700169 //dumpState("next");
170}
171
Jason Sams8c46b102010-08-18 12:38:03 -0700172bool LocklessCommandFifo::makeSpaceNonBlocking(uint32_t bytes)
173{
174 //dumpState("make space non-blocking");
175 if ((mPut+bytes) > mEnd) {
176 // Need to loop regardless of where get is.
177 if((mGet > mPut) && (mBuffer+4 >= mGet)) {
178 return false;
179 }
180
181 // Toss in a reset then the normal wait for space will do the rest.
182 reinterpret_cast<uint16_t *>(mPut)[0] = 0;
183 reinterpret_cast<uint16_t *>(mPut)[1] = 0;
184 mPut = mBuffer;
185 mSignalToWorker.set();
186 }
187
188 // it will fit here so we just need to wait for space.
189 if(getFreeSpace() < bytes) {
190 return false;
191 }
192
193 return true;
194}
195
Jason Sams326e0dd2009-05-22 14:03:28 -0700196void LocklessCommandFifo::makeSpace(uint32_t bytes)
197{
Jason Sams565ac362009-06-03 16:04:54 -0700198 //dumpState("make space");
Jason Sams326e0dd2009-05-22 14:03:28 -0700199 if ((mPut+bytes) > mEnd) {
200 // Need to loop regardless of where get is.
Jason Sams565ac362009-06-03 16:04:54 -0700201 while((mGet > mPut) && (mBuffer+4 >= mGet)) {
Jason Samsada7f272009-09-24 14:55:38 -0700202 usleep(100);
Jason Sams326e0dd2009-05-22 14:03:28 -0700203 }
204
205 // Toss in a reset then the normal wait for space will do the rest.
206 reinterpret_cast<uint16_t *>(mPut)[0] = 0;
207 reinterpret_cast<uint16_t *>(mPut)[1] = 0;
Jason Sams565ac362009-06-03 16:04:54 -0700208 mPut = mBuffer;
Jason Sams8c46b102010-08-18 12:38:03 -0700209 mSignalToWorker.set();
Jason Sams326e0dd2009-05-22 14:03:28 -0700210 }
211
212 // it will fit here so we just need to wait for space.
213 while(getFreeSpace() < bytes) {
Jason Samsada7f272009-09-24 14:55:38 -0700214 usleep(100);
Jason Sams326e0dd2009-05-22 14:03:28 -0700215 }
Jason Sams8c0ee652009-08-25 14:49:07 -0700216
Jason Sams326e0dd2009-05-22 14:03:28 -0700217}
218
219void LocklessCommandFifo::dumpState(const char *s) const
220{
Jason Sams8c46b102010-08-18 12:38:03 -0700221 LOGV("%s %p put %p, get %p, buf %p, end %p", s, this, mPut, mGet, mBuffer, mEnd);
Jason Sams326e0dd2009-05-22 14:03:28 -0700222}
223