1 /**
2 * Copyright (C) ARM Limited 2010-2012. 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 extern void handleException();
17 // bufferSize is the amount of data to be filled
18 // singleBufferSize is the maximum size that may be filled during a single write
19 // (bufferSize + singleBufferSize) will be allocated
20 Fifo::Fifo(int singleBufferSize, int bufferSize) {
21 mWrite = mRead = mReadCommit = mRaggedEnd = 0;
22 mWrapThreshold = bufferSize;
23 mSingleBufferSize = singleBufferSize;
24 mBuffer = (char*)valloc(bufferSize + singleBufferSize);
25 mEnd = false;
27 if (mBuffer == NULL) {
28 logg->logError(__FILE__, __LINE__, "failed to allocate %d bytes", bufferSize + singleBufferSize);
29 handleException();
30 }
32 if (sem_init(&mWaitForSpaceSem, 0, 0) || sem_init(&mWaitForDataSem, 0, 0)) {
33 logg->logError(__FILE__, __LINE__, "sem_init() failed");
34 handleException();
35 }
36 }
38 Fifo::~Fifo() {
39 free(mBuffer);
40 }
42 int Fifo::numBytesFilled() {
43 return mWrite - mRead + mRaggedEnd;
44 }
46 char* Fifo::start() {
47 return mBuffer;
48 }
50 bool Fifo::isEmpty() {
51 return mRead == mWrite && mRaggedEnd == 0;
52 }
54 bool Fifo::isFull() {
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) {
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(&mWaitForDataSem);
92 // wait for space
93 while (isFull()) {
94 sem_wait(&mWaitForSpaceSem);
95 }
97 return &mBuffer[mWrite];
98 }
100 // This function will stall until data is available
101 char* Fifo::read(int* length) {
102 // update the read pointer now that the data has been handled
103 mRead = mReadCommit;
105 // handle the wrap-around
106 if (mRead >= mWrapThreshold) {
107 mRaggedEnd = mRead = mReadCommit = 0;
108 }
110 // send a notification that data is free (space is available)
111 sem_post(&mWaitForSpaceSem);
113 // wait for data
114 while (isEmpty() && !mEnd) {
115 sem_wait(&mWaitForDataSem);
116 }
118 // obtain the length
119 do {
120 mReadCommit = mRaggedEnd ? mRaggedEnd : mWrite;
121 *length = mReadCommit - mRead;
122 } while (*length < 0); // plugs race condition without using semaphores
124 return &mBuffer[mRead];
125 }