diff options
Diffstat (limited to 'daemon/Fifo.cpp')
-rw-r--r-- | daemon/Fifo.cpp | 251 |
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 | ||
15 | extern void handleException(); | 15 | extern 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 |
20 | Fifo::Fifo(int singleBufferSize, int bufferSize) { | 20 | Fifo::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 | ||
38 | Fifo::~Fifo() { | 38 | Fifo::~Fifo() { |
39 | free(mBuffer); | 39 | free(mBuffer); |
40 | } | 40 | } |
41 | 41 | ||
42 | int Fifo::numBytesFilled() { | 42 | int Fifo::numBytesFilled() { |
43 | return mWrite - mRead + mRaggedEnd; | 43 | return mWrite - mRead + mRaggedEnd; |
44 | } | 44 | } |
45 | 45 | ||
46 | char* Fifo::start() { | 46 | char* Fifo::start() { |
47 | return mBuffer; | 47 | return mBuffer; |
48 | } | 48 | } |
49 | 49 | ||
50 | bool Fifo::isEmpty() { | 50 | bool Fifo::isEmpty() { |
51 | return mRead == mWrite; | 51 | return mRead == mWrite && mRaggedEnd == 0; |
52 | } | 52 | } |
53 | 53 | ||
54 | bool Fifo::isFull() { | 54 | bool 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 | 60 | bool Fifo::willFill(int additional) { |
61 | bool 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 | 74 | char* Fifo::write(int length) { |
75 | char* 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 | 101 | char* Fifo::read(int* length) { |
102 | char* 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 | } | ||