blob: 8d3b9ff8d385889c888588a0e1c68a8d3c2231cf [file] [log] [blame]
Jon Medhurstaaf37a32013-06-11 12:10:56 +01001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2010-2015. All rights reserved.
Jon Medhurstaaf37a32013-06-11 12:10:56 +01003 *
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 */
8
9#include "Fifo.h"
10
11#include <stdlib.h>
Jon Medhurstaaf37a32013-06-11 12:10:56 +010012
13#include "Logging.h"
14
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
18Fifo::Fifo(int singleBufferSize, int bufferSize, sem_t* readerSem) {
19 mWrite = mRead = mReadCommit = mRaggedEnd = 0;
20 mWrapThreshold = bufferSize;
21 mSingleBufferSize = singleBufferSize;
22 mReaderSem = readerSem;
Jon Medhurst96b56152014-10-30 18:01:15 +000023 mBuffer = (char*)malloc(bufferSize + singleBufferSize);
Jon Medhurstaaf37a32013-06-11 12:10:56 +010024 mEnd = false;
25
26 if (mBuffer == NULL) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010027 logg->logError("failed to allocate %d bytes", bufferSize + singleBufferSize);
Jon Medhurstaaf37a32013-06-11 12:10:56 +010028 handleException();
29 }
30
31 if (sem_init(&mWaitForSpaceSem, 0, 0)) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010032 logg->logError("sem_init() failed");
Jon Medhurstaaf37a32013-06-11 12:10:56 +010033 handleException();
34 }
35}
36
37Fifo::~Fifo() {
38 free(mBuffer);
39 sem_destroy(&mWaitForSpaceSem);
40}
41
42int Fifo::numBytesFilled() const {
43 return mWrite - mRead + mRaggedEnd;
44}
45
46char* Fifo::start() const {
47 return mBuffer;
48}
49
50bool Fifo::isEmpty() const {
51 return mRead == mWrite && mRaggedEnd == 0;
52}
53
54bool Fifo::isFull() const {
55 return willFill(0);
56}
57
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
60bool 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}
72
73// This function will stall until contiguous singleBufferSize bytes are available
74char* Fifo::write(int length) {
75 if (length <= 0) {
76 length = 0;
77 mEnd = true;
78 }
79
80 // update the write pointer
81 mWrite += length;
82
83 // handle the wrap-around
84 if (mWrite >= mWrapThreshold) {
85 mRaggedEnd = mWrite;
86 mWrite = 0;
87 }
88
89 // send a notification that data is ready
90 sem_post(mReaderSem);
91
92 // wait for space
93 while (isFull()) {
94 sem_wait(&mWaitForSpaceSem);
95 }
96
97 return &mBuffer[mWrite];
98}
99
100void Fifo::release() {
101 // update the read pointer now that the data has been handled
102 mRead = mReadCommit;
103
104 // handle the wrap-around
105 if (mRead >= mWrapThreshold) {
106 mRaggedEnd = mRead = mReadCommit = 0;
107 }
108
109 // send a notification that data is free (space is available)
110 sem_post(&mWaitForSpaceSem);
111}
112
113// This function will return null if no data is available
114char* Fifo::read(int *const length) {
115 // wait for data
116 if (isEmpty() && !mEnd) {
117 return NULL;
118 }
119
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
125
126 return &mBuffer[mRead];
127}