Merge remote-tracking branch 'lsk/v3.10/topic/configs' into linux-linaro-lsk
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / Fifo.cpp
1 /**
2  * Copyright (C) ARM Limited 2010-2014. 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  */
8
9 #include "Fifo.h"
10
11 #include <stdlib.h>
12 #ifdef WIN32
13 #define valloc malloc
14 #endif
15
16 #include "Logging.h"
17
18 // bufferSize is the amount of data to be filled
19 // singleBufferSize is the maximum size that may be filled during a single write
20 // (bufferSize + singleBufferSize) will be allocated
21 Fifo::Fifo(int singleBufferSize, int bufferSize, sem_t* readerSem) {
22   mWrite = mRead = mReadCommit = mRaggedEnd = 0;
23   mWrapThreshold = bufferSize;
24   mSingleBufferSize = singleBufferSize;
25   mReaderSem = readerSem;
26   mBuffer = (char*)valloc(bufferSize + singleBufferSize);
27   mEnd = false;
28
29   if (mBuffer == NULL) {
30     logg->logError(__FILE__, __LINE__, "failed to allocate %d bytes", bufferSize + singleBufferSize);
31     handleException();
32   }
33
34   if (sem_init(&mWaitForSpaceSem, 0, 0)) {
35     logg->logError(__FILE__, __LINE__, "sem_init() failed");
36     handleException();
37   }
38 }
39
40 Fifo::~Fifo() {
41   free(mBuffer);
42   sem_destroy(&mWaitForSpaceSem);
43 }
44
45 int Fifo::numBytesFilled() const {
46   return mWrite - mRead + mRaggedEnd;
47 }
48
49 char* Fifo::start() const {
50   return mBuffer;
51 }
52
53 bool Fifo::isEmpty() const {
54   return mRead == mWrite && mRaggedEnd == 0;
55 }
56
57 bool Fifo::isFull() const {
58   return willFill(0);
59 }
60
61 // Determines if the buffer will fill assuming 'additional' bytes will be added to the buffer
62 // 'full' means there is less than singleBufferSize bytes available contiguously; it does not mean there are zero bytes available
63 bool Fifo::willFill(int additional) const {
64   if (mWrite > mRead) {
65     if (numBytesFilled() + additional < mWrapThreshold) {
66       return false;
67     }
68   } else {
69     if (numBytesFilled() + additional < mWrapThreshold - mSingleBufferSize) {
70       return false;
71     }
72   }
73   return true;
74 }
75
76 // This function will stall until contiguous singleBufferSize bytes are available
77 char* Fifo::write(int length) {
78   if (length <= 0) {
79     length = 0;
80     mEnd = true;
81   }
82
83   // update the write pointer
84   mWrite += length;
85
86   // handle the wrap-around
87   if (mWrite >= mWrapThreshold) {
88     mRaggedEnd = mWrite;
89     mWrite = 0;
90   }
91
92   // send a notification that data is ready
93   sem_post(mReaderSem);
94
95   // wait for space
96   while (isFull()) {
97     sem_wait(&mWaitForSpaceSem);
98   }
99
100   return &mBuffer[mWrite];
101 }
102
103 void Fifo::release() {
104   // update the read pointer now that the data has been handled
105   mRead = mReadCommit;
106
107   // handle the wrap-around
108   if (mRead >= mWrapThreshold) {
109     mRaggedEnd = mRead = mReadCommit = 0;
110   }
111
112   // send a notification that data is free (space is available)
113   sem_post(&mWaitForSpaceSem);
114 }
115
116 // This function will return null if no data is available
117 char* Fifo::read(int *const length) {
118   // wait for data
119   if (isEmpty() && !mEnd) {
120     return NULL;
121   }
122
123   // obtain the length
124   do {
125     mReadCommit = mRaggedEnd ? mRaggedEnd : mWrite;
126     *length = mReadCommit - mRead;
127   } while (*length < 0); // plugs race condition without using semaphores
128
129   return &mBuffer[mRead];
130 }