Merge tag 'v3.10.72' 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
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
18 Fifo::Fifo(int singleBufferSize, int bufferSize, sem_t* readerSem) {
19   mWrite = mRead = mReadCommit = mRaggedEnd = 0;
20   mWrapThreshold = bufferSize;
21   mSingleBufferSize = singleBufferSize;
22   mReaderSem = readerSem;
23   mBuffer = (char*)malloc(bufferSize + singleBufferSize);
24   mEnd = false;
25
26   if (mBuffer == NULL) {
27     logg->logError(__FILE__, __LINE__, "failed to allocate %d bytes", bufferSize + singleBufferSize);
28     handleException();
29   }
30
31   if (sem_init(&mWaitForSpaceSem, 0, 0)) {
32     logg->logError(__FILE__, __LINE__, "sem_init() failed");
33     handleException();
34   }
35 }
36
37 Fifo::~Fifo() {
38   free(mBuffer);
39   sem_destroy(&mWaitForSpaceSem);
40 }
41
42 int Fifo::numBytesFilled() const {
43   return mWrite - mRead + mRaggedEnd;
44 }
45
46 char* Fifo::start() const {
47   return mBuffer;
48 }
49
50 bool Fifo::isEmpty() const {
51   return mRead == mWrite && mRaggedEnd == 0;
52 }
53
54 bool 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
60 bool 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
74 char* 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
100 void 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
114 char* 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 }