5012a8fe42
Atomically update put. Change-Id: Id6d4b5c03f5562b3021561e95966a01abd293667
234 lines
5.9 KiB
C++
234 lines
5.9 KiB
C++
/*
|
|
* Copyright (C) 2009 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "rsLocklessFifo.h"
|
|
#include "utils/Timers.h"
|
|
#include "utils/StopWatch.h"
|
|
|
|
using namespace android;
|
|
using namespace android::renderscript;
|
|
|
|
LocklessCommandFifo::LocklessCommandFifo() {
|
|
}
|
|
|
|
LocklessCommandFifo::~LocklessCommandFifo() {
|
|
if (!mInShutdown) {
|
|
shutdown();
|
|
}
|
|
free(mBuffer);
|
|
}
|
|
|
|
void LocklessCommandFifo::shutdown() {
|
|
mInShutdown = true;
|
|
mSignalToWorker.set();
|
|
}
|
|
|
|
bool LocklessCommandFifo::init(uint32_t sizeInBytes) {
|
|
// Add room for a buffer reset command
|
|
mBuffer = static_cast<uint8_t *>(malloc(sizeInBytes + 4));
|
|
if (!mBuffer) {
|
|
LOGE("LocklessFifo allocation failure");
|
|
return false;
|
|
}
|
|
|
|
if (!mSignalToControl.init() || !mSignalToWorker.init()) {
|
|
LOGE("Signal setup failed");
|
|
free(mBuffer);
|
|
return false;
|
|
}
|
|
|
|
mInShutdown = false;
|
|
mSize = sizeInBytes;
|
|
mPut = mBuffer;
|
|
mGet = mBuffer;
|
|
mEnd = mBuffer + (sizeInBytes) - 1;
|
|
//dumpState("init");
|
|
return true;
|
|
}
|
|
|
|
uint32_t LocklessCommandFifo::getFreeSpace() const {
|
|
int32_t freeSpace = 0;
|
|
//dumpState("getFreeSpace");
|
|
|
|
if (mPut >= mGet) {
|
|
freeSpace = mEnd - mPut;
|
|
} else {
|
|
freeSpace = mGet - mPut;
|
|
}
|
|
|
|
if (freeSpace < 0) {
|
|
freeSpace = 0;
|
|
}
|
|
return freeSpace;
|
|
}
|
|
|
|
bool LocklessCommandFifo::isEmpty() const {
|
|
uint32_t p = android_atomic_acquire_load((int32_t *)&mPut);
|
|
return ((uint8_t *)p) == mGet;
|
|
}
|
|
|
|
|
|
void * LocklessCommandFifo::reserve(uint32_t sizeInBytes) {
|
|
// Add space for command header and loop token;
|
|
sizeInBytes += 8;
|
|
|
|
//dumpState("reserve");
|
|
if (getFreeSpace() < sizeInBytes) {
|
|
makeSpace(sizeInBytes);
|
|
}
|
|
|
|
return mPut + 4;
|
|
}
|
|
|
|
void LocklessCommandFifo::commit(uint32_t command, uint32_t sizeInBytes) {
|
|
if (mInShutdown) {
|
|
return;
|
|
}
|
|
//dumpState("commit 1");
|
|
reinterpret_cast<uint16_t *>(mPut)[0] = command;
|
|
reinterpret_cast<uint16_t *>(mPut)[1] = sizeInBytes;
|
|
|
|
int32_t s = ((sizeInBytes + 3) & ~3) + 4;
|
|
android_atomic_add(s, (int32_t *)&mPut);
|
|
//dumpState("commit 2");
|
|
mSignalToWorker.set();
|
|
}
|
|
|
|
void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes) {
|
|
if (mInShutdown) {
|
|
return;
|
|
}
|
|
|
|
//char buf[1024];
|
|
//sprintf(buf, "RenderScript LocklessCommandFifo::commitSync %p %i %i", this, command, sizeInBytes);
|
|
//StopWatch compileTimer(buf);
|
|
commit(command, sizeInBytes);
|
|
flush();
|
|
}
|
|
|
|
void LocklessCommandFifo::flush() {
|
|
//dumpState("flush 1");
|
|
while (mPut != mGet) {
|
|
mSignalToControl.wait();
|
|
}
|
|
//dumpState("flush 2");
|
|
}
|
|
|
|
void LocklessCommandFifo::wait() {
|
|
while (isEmpty() && !mInShutdown) {
|
|
mSignalToControl.set();
|
|
mSignalToWorker.wait();
|
|
}
|
|
}
|
|
|
|
const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData) {
|
|
while (1) {
|
|
//dumpState("get");
|
|
wait();
|
|
if (mInShutdown) {
|
|
*command = 0;
|
|
*bytesData = 0;
|
|
return 0;
|
|
}
|
|
|
|
*command = reinterpret_cast<const uint16_t *>(mGet)[0];
|
|
*bytesData = reinterpret_cast<const uint16_t *>(mGet)[1];
|
|
if (*command) {
|
|
// non-zero command is valid
|
|
return mGet+4;
|
|
}
|
|
|
|
// zero command means reset to beginning.
|
|
mGet = mBuffer;
|
|
}
|
|
}
|
|
|
|
void LocklessCommandFifo::next() {
|
|
uint32_t bytes = reinterpret_cast<const uint16_t *>(mGet)[1];
|
|
|
|
android_atomic_add(((bytes + 3) & ~3) + 4, (int32_t *)&mGet);
|
|
//mGet += ((bytes + 3) & ~3) + 4;
|
|
if (isEmpty()) {
|
|
mSignalToControl.set();
|
|
}
|
|
//dumpState("next");
|
|
}
|
|
|
|
bool LocklessCommandFifo::makeSpaceNonBlocking(uint32_t bytes) {
|
|
//dumpState("make space non-blocking");
|
|
if ((mPut+bytes) > mEnd) {
|
|
// Need to loop regardless of where get is.
|
|
if ((mGet > mPut) || (mBuffer+4 >= mGet)) {
|
|
return false;
|
|
}
|
|
|
|
// Toss in a reset then the normal wait for space will do the rest.
|
|
reinterpret_cast<uint16_t *>(mPut)[0] = 0;
|
|
reinterpret_cast<uint16_t *>(mPut)[1] = 0;
|
|
mPut = mBuffer;
|
|
mSignalToWorker.set();
|
|
}
|
|
|
|
// it will fit here so we just need to wait for space.
|
|
if (getFreeSpace() < bytes) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void LocklessCommandFifo::makeSpace(uint32_t bytes) {
|
|
//dumpState("make space");
|
|
if ((mPut+bytes) > mEnd) {
|
|
// Need to loop regardless of where get is.
|
|
while ((mGet > mPut) || (mBuffer+4 >= mGet)) {
|
|
usleep(100);
|
|
}
|
|
|
|
// Toss in a reset then the normal wait for space will do the rest.
|
|
reinterpret_cast<uint16_t *>(mPut)[0] = 0;
|
|
reinterpret_cast<uint16_t *>(mPut)[1] = 0;
|
|
mPut = mBuffer;
|
|
mSignalToWorker.set();
|
|
}
|
|
|
|
// it will fit here so we just need to wait for space.
|
|
while (getFreeSpace() < bytes) {
|
|
usleep(100);
|
|
}
|
|
|
|
}
|
|
|
|
void LocklessCommandFifo::dumpState(const char *s) const {
|
|
LOGV("%s %p put %p, get %p, buf %p, end %p", s, this, mPut, mGet, mBuffer, mEnd);
|
|
}
|
|
|
|
void LocklessCommandFifo::printDebugData() const {
|
|
dumpState("printing fifo debug");
|
|
const uint32_t *pptr = (const uint32_t *)mGet;
|
|
pptr -= 8 * 4;
|
|
if (mGet < mBuffer) {
|
|
pptr = (const uint32_t *)mBuffer;
|
|
}
|
|
|
|
|
|
for (int ct=0; ct < 16; ct++) {
|
|
LOGV("fifo %p = 0x%08x 0x%08x 0x%08x 0x%08x", pptr, pptr[0], pptr[1], pptr[2], pptr[3]);
|
|
pptr += 4;
|
|
}
|
|
|
|
}
|