gator: Version 5.14
[android-sdk/arm-ds5-gator.git] / daemon / Fifo.cpp
1 /**
2  * Copyright (C) ARM Limited 2010-2013. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include "Fifo.h"
13 #include "Logging.h"
15 // bufferSize is the amount of data to be filled
16 // singleBufferSize is the maximum size that may be filled during a single write
17 // (bufferSize + singleBufferSize) will be allocated
18 Fifo::Fifo(int singleBufferSize, int bufferSize, sem_t* readerSem) {
19         mWrite = mRead = mReadCommit = mRaggedEnd = 0;
20         mWrapThreshold = bufferSize;
21         mSingleBufferSize = singleBufferSize;
22         mReaderSem = readerSem;
23         mBuffer = (char*)valloc(bufferSize + singleBufferSize);
24         mEnd = false;
26         if (mBuffer == NULL) {
27                 logg->logError(__FILE__, __LINE__, "failed to allocate %d bytes", bufferSize + singleBufferSize);
28                 handleException();
29         }
31         if (sem_init(&mWaitForSpaceSem, 0, 0)) {
32                 logg->logError(__FILE__, __LINE__, "sem_init() failed");
33                 handleException();
34         }
35 }
37 Fifo::~Fifo() {
38         free(mBuffer);
39         sem_destroy(&mWaitForSpaceSem);
40 }
42 int Fifo::numBytesFilled() const {
43         return mWrite - mRead + mRaggedEnd;
44 }
46 char* Fifo::start() const {
47         return mBuffer;
48 }
50 bool Fifo::isEmpty() const {
51         return mRead == mWrite && mRaggedEnd == 0;
52 }
54 bool Fifo::isFull() const {
55         return willFill(0);
56 }
58 // Determines if the buffer will fill assuming 'additional' bytes will be added to the buffer
59 // 'full' means there is less than singleBufferSize bytes available contiguously; it does not mean there are zero bytes available
60 bool Fifo::willFill(int additional) const {
61         if (mWrite > mRead) {
62                 if (numBytesFilled() + additional < mWrapThreshold) {
63                         return false;
64                 }
65         } else {
66                 if (numBytesFilled() + additional < mWrapThreshold - mSingleBufferSize) {
67                         return false;
68                 }
69         }
70         return true;
71 }
73 // This function will stall until contiguous singleBufferSize bytes are available
74 char* Fifo::write(int length) {
75         if (length <= 0) {
76                 length = 0;
77                 mEnd = true;
78         }
80         // update the write pointer
81         mWrite += length;
83         // handle the wrap-around
84         if (mWrite >= mWrapThreshold) {
85                 mRaggedEnd = mWrite;
86                 mWrite = 0;
87         }
89         // send a notification that data is ready
90         sem_post(mReaderSem);
92         // wait for space
93         while (isFull()) {
94                 sem_wait(&mWaitForSpaceSem);
95         }
97         return &mBuffer[mWrite];
98 }
100 void Fifo::release() {
101         // update the read pointer now that the data has been handled
102         mRead = mReadCommit;
104         // handle the wrap-around
105         if (mRead >= mWrapThreshold) {
106                 mRaggedEnd = mRead = mReadCommit = 0;
107         }
109         // send a notification that data is free (space is available)
110         sem_post(&mWaitForSpaceSem);
113 // This function will return null if no data is available
114 char* Fifo::read(int *const length) {
115         // wait for data
116         if (isEmpty() && !mEnd) {
117                 return NULL;
118         }
120         // obtain the length
121         do {
122                 mReadCommit = mRaggedEnd ? mRaggedEnd : mWrite;
123                 *length = mReadCommit - mRead;
124         } while (*length < 0); // plugs race condition without using semaphores
126         return &mBuffer[mRead];