2 // (c) Yuri Kiryanov, openh323@kiryanov.com
3 // for www.Openh323.org by Equivalence
5 // Portions: 1998-1999, Be Incorporated
6 // Be Sample Code License
8 /*----------------------
10 ----------------------
12 Copyright 1991-1999, Be Incorporated.
15 Redistribution and use in source and binary forms, with or without
16 modification, are permitted provided that the following conditions
19 1. Redistributions of source code must retain the above copyright
20 notice, this list of conditions, and the following disclaimer.
22 2. Redistributions in binary form must reproduce the above copyright
23 notice, this list of conditions, and the following disclaimer in the
24 documentation and/or other materials provided with the distribution.
26 3. The name of the author may not be used to endorse or promote products
27 derived from this software without specific prior written permission.
29 THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
30 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
31 OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
33 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
35 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
36 AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
37 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 #include "BlockFIFO.h"
50 #define FPRINTF(x) fprintf x
53 // if we decice to make the FIFO thread safe, use these macros
59 BBlockFIFO::BBlockFIFO(size_t blockSize
, int32 blockCountPerBuffer
, int32 bufferCount
, uint32 placementFlags
, uint32 lockFlags
, const char * name
)
63 sprintf(tname
, "FIFO(0x%6lx,%ld,%ld)", blockSize
, blockCountPerBuffer
, bufferCount
);
66 strncpy(_mName
, name
, 32);
70 _mBlockSize
= blockSize
;
71 _mBufferSize
= blockCountPerBuffer
* blockSize
;
72 _mAreaSize
= _mBufferSize
* bufferCount
;
79 size_t s
= (_mAreaSize
+ B_PAGE_SIZE
-1) & -B_PAGE_SIZE
;
80 if ((blockSize
< 1) || (blockCountPerBuffer
< 1) || (bufferCount
< 2) || (s
< B_PAGE_SIZE
) || (s
> 0x1000000UL
)) {
81 _mInitErr
= B_BAD_VALUE
;
85 _mArea
= create_area(name
, &addr
, placementFlags
, s
, lockFlags
, B_READ_AREA
| B_WRITE_AREA
);
90 _mBuffer
= (char *)addr
;
97 BBlockFIFO::~BBlockFIFO()
99 if (_mArea
> -1) delete_area(_mArea
);
100 if (_mGetSem
> -1) delete_sem(_mGetSem
);
101 if (_mPutSem
> -1) delete_sem(_mPutSem
);
105 BBlockFIFO::InitCheck()
113 if (_mInitErr
< 0) return _mInitErr
;
114 if (_mGetSem
> -1) delete_sem(_mGetSem
);
115 if (_mPutSem
> -1) delete_sem(_mPutSem
);
119 sprintf(name
, "%.27s Get", _mName
);
120 _mGetSem
= create_sem(0, name
);
121 sprintf(name
, "%.27s Put", _mName
);
122 _mPutSem
= create_sem(_mAreaSize
, name
);
123 if (_mGetSem
< 0) _mInitErr
= _mGetSem
;
124 if (_mPutSem
< 0) _mInitErr
= _mPutSem
;
134 BBlockFIFO::SizeAvailableToGet()
136 ENTER_GET
// there's always a race with put, so don't pretend to protect it
137 int32 s
= _mPutOff
- _mGetOff
;
138 if (s
< 0) s
+= _mAreaSize
;
144 BBlockFIFO::SizeAvailableToPut()
146 ENTER_PUT
// there's always a race with get, so don't pretend to protect it
147 int32 s
= _mGetOff
- _mPutOff
;
148 if (s
<= 0) s
+= _mAreaSize
;
154 BBlockFIFO::BeginGet(const void **outData
, size_t requestSize
, bigtime_t timeout
)
156 if (!outData
) { FPRINTF((stderr
, "BAD_VALUE: outData is NULL\n")); return B_BAD_VALUE
; }
158 //FPRINTF((stderr, "requestSize %ld _mBlockSize %ld _mAreaSize %ld _mGetOff %ld\n",
159 // requestSize, _mBlockSize, _mAreaSize, _mGetOff));
160 if (requestSize
> _mBlockSize
) {
161 requestSize
= _mBlockSize
;
163 size_t o
= _mGetOff
+ requestSize
;
164 if (o
> _mAreaSize
) {
167 int32 req
= o
-_mGetOff
;
168 if (_mFlags
& flagEndOfData
) {
169 int32 tg
= _mPutOff
-_mGetOff
;
170 if (tg
< 0) tg
+= _mAreaSize
;
173 if (req
== 0) return 0;
177 status_t err
= acquire_sem_etc(_mGetSem
, req
, B_TIMEOUT
, timeout
);
179 if (((err
== B_TIMED_OUT
) || (err
== B_BAD_SEM_ID
)) && (_mFlags
& flagEndOfData
)) {
180 int32 tg
= _mPutOff
-_mGetOff
;
181 if (tg
< 0) tg
+= _mAreaSize
;
184 if (req
== 0) return 0;
193 *outData
= _mBuffer
+ _mGetOff
;
198 atomic_or(&_mFlags
, flagPendingGet
);
205 if (!(atomic_and(&_mFlags
, ~flagPendingGet
) & flagPendingGet
))
207 int32 o
= _mPendingGet
- _mGetOff
;
208 _mGetOff
= _mPendingGet
;
209 if (o
< 0) o
+= _mAreaSize
;
210 // part of buffer is now free to put into again
211 status_t err
= release_sem_etc(_mPutSem
, o
, B_DO_NOT_RESCHEDULE
);
217 BBlockFIFO::BeginPut(void **outData
, size_t requestSize
, bigtime_t timeout
)
219 if (!outData
) { FPRINTF((stderr
, "BAD_VALUE: outData == NULL\n")); return B_BAD_VALUE
; }
220 if (_mFlags
& flagEndOfData
) { FPRINTF((stderr
, "EPERM: end of data\n")); return EPERM
; }
222 if (requestSize
> _mBufferSize
) {
223 requestSize
= _mBufferSize
;
225 ssize_t o
= _mPutOff
+ requestSize
;
226 if (o
> (ssize_t
)_mAreaSize
) {
229 int32 req
= o
-_mPutOff
;
230 status_t err
= acquire_sem_etc(_mPutSem
, req
, B_TIMEOUT
, timeout
);
233 FPRINTF((stderr
, "BeginPut: acquire_sem_etc() returns %ld (req is %ld)\n", err
, req
));
236 *outData
= _mBuffer
+ _mPutOff
;
237 if (o
== (ssize_t
)_mAreaSize
)
241 atomic_or(&_mFlags
, flagPendingPut
);
246 BBlockFIFO::EndPut(bool atEndOfData
)
248 if (!(atomic_and(&_mFlags
, ~flagPendingPut
) & flagPendingPut
))
250 int32 o
= _mPendingPut
- _mPutOff
;
251 _mPutOff
= _mPendingPut
;
252 if (o
< 0) o
+= _mAreaSize
;
253 // part of buffer is now full to get from again
254 status_t err
= release_sem_etc(_mGetSem
, o
, B_DO_NOT_RESCHEDULE
);
256 atomic_or(&_mFlags
, flagEndOfData
);
257 delete_sem(_mGetSem
);
265 BBlockFIFO::CopyNextBlockOut(void *destination
, size_t requestSize
, bigtime_t timeout
)
267 if (destination
== 0) return B_BAD_VALUE
;
268 if (requestSize
== 0) return 0;
269 char * d
= (char *)destination
;
271 while (requestSize
> 0) {
273 ssize_t got
= BeginGet(&ptr
, requestSize
, timeout
);
274 if (got
< 0) { FPRINTF((stderr
, "BeginGet returns %ld\n", got
)); return (total
> 0 ? total
: got
); }
285 BBlockFIFO::CopyNextBufferIn(const void *source
, size_t requestSize
, bigtime_t timeout
, bool atEndOfData
)
287 if (source
== 0) { FPRINTF((stderr
, "BAD_VALUE: source == NULL\n")); return B_BAD_VALUE
; }
288 if (requestSize
== 0) {
291 atomic_or(&_mFlags
, flagEndOfData
);
292 delete_sem(_mGetSem
);
298 char * s
= (char *)source
;
300 while (requestSize
> 0) {
302 int got
= BeginPut(&ptr
, requestSize
, timeout
);
303 if (got
< 0) return (total
> 0 ? total
: got
);
308 (void)EndPut((requestSize
== 0) ? atEndOfData
: false);