diff options
Diffstat (limited to 'tools/gator/daemon/Fifo.cpp')
-rw-r--r-- | tools/gator/daemon/Fifo.cpp | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/tools/gator/daemon/Fifo.cpp b/tools/gator/daemon/Fifo.cpp new file mode 100644 index 000000000000..250a4d023bf2 --- /dev/null +++ b/tools/gator/daemon/Fifo.cpp @@ -0,0 +1,130 @@ +/** + * Copyright (C) ARM Limited 2010-2013. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "Fifo.h" + +#include <stdlib.h> +#ifdef WIN32 +#define valloc malloc +#endif + +#include "Logging.h" + +// bufferSize is the amount of data to be filled +// singleBufferSize is the maximum size that may be filled during a single write +// (bufferSize + singleBufferSize) will be allocated +Fifo::Fifo(int singleBufferSize, int bufferSize, sem_t* readerSem) { + mWrite = mRead = mReadCommit = mRaggedEnd = 0; + mWrapThreshold = bufferSize; + mSingleBufferSize = singleBufferSize; + mReaderSem = readerSem; + mBuffer = (char*)valloc(bufferSize + singleBufferSize); + mEnd = false; + + if (mBuffer == NULL) { + logg->logError(__FILE__, __LINE__, "failed to allocate %d bytes", bufferSize + singleBufferSize); + handleException(); + } + + if (sem_init(&mWaitForSpaceSem, 0, 0)) { + logg->logError(__FILE__, __LINE__, "sem_init() failed"); + handleException(); + } +} + +Fifo::~Fifo() { + free(mBuffer); + sem_destroy(&mWaitForSpaceSem); +} + +int Fifo::numBytesFilled() const { + return mWrite - mRead + mRaggedEnd; +} + +char* Fifo::start() const { + return mBuffer; +} + +bool Fifo::isEmpty() const { + return mRead == mWrite && mRaggedEnd == 0; +} + +bool Fifo::isFull() const { + return willFill(0); +} + +// Determines if the buffer will fill assuming 'additional' bytes will be added to the buffer +// 'full' means there is less than singleBufferSize bytes available contiguously; it does not mean there are zero bytes available +bool Fifo::willFill(int additional) const { + if (mWrite > mRead) { + if (numBytesFilled() + additional < mWrapThreshold) { + return false; + } + } else { + if (numBytesFilled() + additional < mWrapThreshold - mSingleBufferSize) { + return false; + } + } + return true; +} + +// This function will stall until contiguous singleBufferSize bytes are available +char* Fifo::write(int length) { + if (length <= 0) { + length = 0; + mEnd = true; + } + + // update the write pointer + mWrite += length; + + // handle the wrap-around + if (mWrite >= mWrapThreshold) { + mRaggedEnd = mWrite; + mWrite = 0; + } + + // send a notification that data is ready + sem_post(mReaderSem); + + // wait for space + while (isFull()) { + sem_wait(&mWaitForSpaceSem); + } + + return &mBuffer[mWrite]; +} + +void Fifo::release() { + // update the read pointer now that the data has been handled + mRead = mReadCommit; + + // handle the wrap-around + if (mRead >= mWrapThreshold) { + mRaggedEnd = mRead = mReadCommit = 0; + } + + // send a notification that data is free (space is available) + sem_post(&mWaitForSpaceSem); +} + +// This function will return null if no data is available +char* Fifo::read(int *const length) { + // wait for data + if (isEmpty() && !mEnd) { + return NULL; + } + + // obtain the length + do { + mReadCommit = mRaggedEnd ? mRaggedEnd : mWrite; + *length = mReadCommit - mRead; + } while (*length < 0); // plugs race condition without using semaphores + + return &mBuffer[mRead]; +} |