summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/Fifo.cpp')
-rw-r--r--daemon/Fifo.cpp251
1 files changed, 125 insertions, 126 deletions
diff --git a/daemon/Fifo.cpp b/daemon/Fifo.cpp
index bbfc919..191536f 100644
--- a/daemon/Fifo.cpp
+++ b/daemon/Fifo.cpp
@@ -1,126 +1,125 @@
1/** 1/**
2 * Copyright (C) ARM Limited 2010-2012. All rights reserved. 2 * Copyright (C) ARM Limited 2010-2012. All rights reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 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 5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8 8
9#include <stdlib.h> 9#include <stdlib.h>
10#include <string.h> 10#include <string.h>
11#include <unistd.h> 11#include <unistd.h>
12#include "Fifo.h" 12#include "Fifo.h"
13#include "Logging.h" 13#include "Logging.h"
14 14
15extern void handleException(); 15extern void handleException();
16 16
17// bufferSize is the amount of data to be filled 17// bufferSize is the amount of data to be filled
18// singleBufferSize is the maximum size that may be filled during a single write 18// singleBufferSize is the maximum size that may be filled during a single write
19// (bufferSize + singleBufferSize) will be allocated 19// (bufferSize + singleBufferSize) will be allocated
20Fifo::Fifo(int singleBufferSize, int bufferSize) { 20Fifo::Fifo(int singleBufferSize, int bufferSize) {
21 mWrite = mRead = mReadCommit = mRaggedEnd = 0; 21 mWrite = mRead = mReadCommit = mRaggedEnd = 0;
22 mWrapThreshold = bufferSize; 22 mWrapThreshold = bufferSize;
23 mSingleBufferSize = singleBufferSize; 23 mSingleBufferSize = singleBufferSize;
24 mBuffer = (char*)valloc(bufferSize + singleBufferSize); 24 mBuffer = (char*)valloc(bufferSize + singleBufferSize);
25 mEnd = false; 25 mEnd = false;
26 26
27 if (mBuffer == NULL) { 27 if (mBuffer == NULL) {
28 logg->logError(__FILE__, __LINE__, "failed to allocate %d bytes", bufferSize + singleBufferSize); 28 logg->logError(__FILE__, __LINE__, "failed to allocate %d bytes", bufferSize + singleBufferSize);
29 handleException(); 29 handleException();
30 } 30 }
31 31
32 if (sem_init(&mWaitForSpaceSem, 0, 0) || sem_init(&mWaitForDataSem, 0, 0)) { 32 if (sem_init(&mWaitForSpaceSem, 0, 0) || sem_init(&mWaitForDataSem, 0, 0)) {
33 logg->logError(__FILE__, __LINE__, "sem_init() failed"); 33 logg->logError(__FILE__, __LINE__, "sem_init() failed");
34 handleException(); 34 handleException();
35 } 35 }
36} 36}
37 37
38Fifo::~Fifo() { 38Fifo::~Fifo() {
39 free(mBuffer); 39 free(mBuffer);
40} 40}
41 41
42int Fifo::numBytesFilled() { 42int Fifo::numBytesFilled() {
43 return mWrite - mRead + mRaggedEnd; 43 return mWrite - mRead + mRaggedEnd;
44} 44}
45 45
46char* Fifo::start() { 46char* Fifo::start() {
47 return mBuffer; 47 return mBuffer;
48} 48}
49 49
50bool Fifo::isEmpty() { 50bool Fifo::isEmpty() {
51 return mRead == mWrite; 51 return mRead == mWrite && mRaggedEnd == 0;
52} 52}
53 53
54bool Fifo::isFull() { 54bool Fifo::isFull() {
55 return willFill(0); 55 return willFill(0);
56} 56}
57 57
58// Determines if the buffer will fill assuming 'additional' bytes will be added to the buffer 58// Determines if the buffer will fill assuming 'additional' bytes will be added to the buffer
59// comparisons use '<', read and write pointers must never equal when not empty 59// 'full' means there is less than singleBufferSize bytes available contiguously; it does not mean there are zero bytes available
60// 'full' means there is less than singleBufferSize bytes available; it does not mean there are zero bytes available 60bool Fifo::willFill(int additional) {
61bool Fifo::willFill(int additional) { 61 if (mWrite > mRead) {
62 if (mWrite > mRead) { 62 if (numBytesFilled() + additional < mWrapThreshold) {
63 if (numBytesFilled() + additional < mWrapThreshold) { 63 return false;
64 return false; 64 }
65 } 65 } else {
66 } else { 66 if (numBytesFilled() + additional < mWrapThreshold - mSingleBufferSize) {
67 if (numBytesFilled() + additional < mWrapThreshold - mSingleBufferSize) { 67 return false;
68 return false; 68 }
69 } 69 }
70 } 70 return true;
71 return true; 71}
72} 72
73 73// This function will stall until contiguous singleBufferSize bytes are available
74// This function will stall until contiguous singleBufferSize bytes are available 74char* Fifo::write(int length) {
75char* Fifo::write(int length) { 75 if (length <= 0) {
76 if (length <= 0) { 76 length = 0;
77 length = 0; 77 mEnd = true;
78 mEnd = true; 78 }
79 } 79
80 80 // update the write pointer
81 // update the write pointer 81 mWrite += length;
82 mWrite += length; 82
83 83 // handle the wrap-around
84 // handle the wrap-around 84 if (mWrite >= mWrapThreshold) {
85 if (mWrite >= mWrapThreshold) { 85 mRaggedEnd = mWrite;
86 mRaggedEnd = mWrite; 86 mWrite = 0;
87 mWrite = 0; 87 }
88 } 88
89 89 // send a notification that data is ready
90 // send a notification that data is ready 90 sem_post(&mWaitForDataSem);
91 sem_post(&mWaitForDataSem); 91
92 92 // wait for space
93 // wait for space 93 while (isFull()) {
94 while (isFull()) { 94 sem_wait(&mWaitForSpaceSem);
95 sem_wait(&mWaitForSpaceSem); 95 }
96 } 96
97 97 return &mBuffer[mWrite];
98 return &mBuffer[mWrite]; 98}
99} 99
100 100// This function will stall until data is available
101// This function will stall until data is available 101char* Fifo::read(int* length) {
102char* Fifo::read(int* length) { 102 // update the read pointer now that the data has been handled
103 // update the read pointer now that the data has been handled 103 mRead = mReadCommit;
104 mRead = mReadCommit; 104
105 105 // handle the wrap-around
106 // handle the wrap-around 106 if (mRead >= mWrapThreshold) {
107 if (mRead >= mWrapThreshold) { 107 mRaggedEnd = mRead = mReadCommit = 0;
108 mRaggedEnd = mRead = mReadCommit = 0; 108 }
109 } 109
110 110 // send a notification that data is free (space is available)
111 // send a notification that data is free (space is available) 111 sem_post(&mWaitForSpaceSem);
112 sem_post(&mWaitForSpaceSem); 112
113 113 // wait for data
114 // wait for data 114 while (isEmpty() && !mEnd) {
115 while (isEmpty() && !mEnd) { 115 sem_wait(&mWaitForDataSem);
116 sem_wait(&mWaitForDataSem); 116 }
117 } 117
118 118 // obtain the length
119 // obtain the length 119 do {
120 do { 120 mReadCommit = mRaggedEnd ? mRaggedEnd : mWrite;
121 mReadCommit = mRaggedEnd ? mRaggedEnd : mWrite; 121 *length = mReadCommit - mRead;
122 *length = mReadCommit - mRead; 122 } while (*length < 0); // plugs race condition without using semaphores
123 } while (*length < 0); // plugs race condition without using semaphores 123
124 124 return &mBuffer[mRead];
125 return &mBuffer[mRead]; 125}
126}