2 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files or portions
6 * thereof (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so, subject
10 * to the following conditions:
12 * * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright notice
16 * in the binary, as well as this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided with
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31 #include <BufferGroup.h>
36 #include "DataExchange.h"
37 #include "SharedBufferList.h"
40 BBufferGroup::BBufferGroup(size_t size
, int32 count
, uint32 placement
,
45 if (fInitError
!= B_OK
)
48 // This one is easy. We need to create "count" BBuffers,
49 // each one "size" bytes large. They all go into one
50 // area, with "placement" and "lock" attributes.
51 // The BBuffers created will clone the area, and
52 // then we delete our area. This way BBuffers are
53 // independent from the BBufferGroup
55 // don't allow all placement parameter values
56 if (placement
!= B_ANY_ADDRESS
&& placement
!= B_ANY_KERNEL_ADDRESS
) {
57 ERROR("BBufferGroup: placement != B_ANY_ADDRESS "
58 "&& placement != B_ANY_KERNEL_ADDRESS (0x%#" B_PRIx32
")\n",
60 placement
= B_ANY_ADDRESS
;
63 // first we roundup for a better placement in memory
64 size_t allocSize
= (size
+ 63) & ~63;
66 // now we create the area
68 = ((allocSize
* count
) + B_PAGE_SIZE
- 1) & ~(B_PAGE_SIZE
- 1);
71 area_id bufferArea
= create_area("some buffers area", &startAddress
,
72 placement
, areaSize
, lock
, B_READ_AREA
| B_WRITE_AREA
);
74 ERROR("BBufferGroup: failed to allocate %ld bytes area\n", areaSize
);
75 fInitError
= (status_t
)bufferArea
;
79 buffer_clone_info info
;
81 for (int32 i
= 0; i
< count
; i
++) {
82 info
.area
= bufferArea
;
83 info
.offset
= i
* allocSize
;
86 fInitError
= AddBuffer(info
);
87 if (fInitError
!= B_OK
)
91 delete_area(bufferArea
);
95 BBufferGroup::BBufferGroup()
99 if (fInitError
!= B_OK
)
102 // this one simply creates an empty BBufferGroup
106 BBufferGroup::BBufferGroup(int32 count
, const media_buffer_id
* buffers
)
109 fInitError
= _Init();
110 if (fInitError
!= B_OK
)
113 // This one creates "BBuffer"s from "media_buffer_id"s passed
114 // by the application.
116 buffer_clone_info info
;
118 for (int32 i
= 0; i
< count
; i
++) {
119 info
.buffer
= buffers
[i
];
121 fInitError
= AddBuffer(info
);
122 if (fInitError
!= B_OK
)
128 BBufferGroup::~BBufferGroup()
131 if (fBufferList
!= NULL
)
132 fBufferList
->DeleteGroupAndPut(fReclaimSem
);
134 delete_sem(fReclaimSem
);
139 BBufferGroup::InitCheck()
147 BBufferGroup::AddBuffer(const buffer_clone_info
& info
, BBuffer
** _buffer
)
150 if (fInitError
!= B_OK
)
153 status_t status
= fBufferList
->AddBuffer(fReclaimSem
, info
, _buffer
);
154 if (status
!= B_OK
) {
155 ERROR("BBufferGroup: error when adding buffer\n");
158 atomic_add(&fBufferCount
, 1);
164 BBufferGroup::RequestBuffer(size_t size
, bigtime_t timeout
)
167 if (fInitError
!= B_OK
)
173 BBuffer
*buffer
= NULL
;
174 fRequestError
= fBufferList
->RequestBuffer(fReclaimSem
, fBufferCount
,
175 size
, 0, &buffer
, timeout
);
177 return fRequestError
== B_OK
? buffer
: NULL
;
182 BBufferGroup::RequestBuffer(BBuffer
* buffer
, bigtime_t timeout
)
185 if (fInitError
!= B_OK
)
191 fRequestError
= fBufferList
->RequestBuffer(fReclaimSem
, fBufferCount
, 0, 0,
194 return fRequestError
;
199 BBufferGroup::RequestError()
202 if (fInitError
!= B_OK
)
205 return fRequestError
;
210 BBufferGroup::CountBuffers(int32
* _count
)
213 if (fInitError
!= B_OK
)
216 *_count
= fBufferCount
;
222 BBufferGroup::GetBufferList(int32 bufferCount
, BBuffer
** _buffers
)
225 if (fInitError
!= B_OK
)
228 if (bufferCount
<= 0 || bufferCount
> fBufferCount
)
231 return fBufferList
->GetBufferList(fReclaimSem
, bufferCount
, _buffers
);
236 BBufferGroup::WaitForBuffers()
239 if (fInitError
!= B_OK
)
242 // TODO: this function is not really useful anyway, and will
243 // not work exactly as documented, but it is close enough
245 if (fBufferCount
< 0)
247 if (fBufferCount
== 0)
250 // We need to wait until at least one buffer belonging to this group is
252 // This has happened when can aquire "fReclaimSem"
255 while ((status
= acquire_sem(fReclaimSem
)) == B_INTERRUPTED
)
260 // we need to release the "fReclaimSem" now, else we would block
261 // requesting of new buffers
263 return release_sem(fReclaimSem
);
268 BBufferGroup::ReclaimAllBuffers()
271 if (fInitError
!= B_OK
)
274 // because additional BBuffers might get added to this group betweeen
275 // acquire and release
276 int32 count
= fBufferCount
;
283 // we need to wait until all BBuffers belonging to this group are reclaimed.
284 // this has happened when the "fReclaimSem" can be aquired "fBufferCount"
289 status
= acquire_sem_etc(fReclaimSem
, count
, 0, 0);
290 } while (status
== B_INTERRUPTED
);
295 // we need to release the "fReclaimSem" now, else we would block
296 // requesting of new buffers
298 return release_sem_etc(fReclaimSem
, count
, 0);
302 // #pragma mark - deprecated BeOS R4 API
306 BBufferGroup::AddBuffersTo(BMessage
* message
, const char* name
, bool needLock
)
309 if (fInitError
!= B_OK
)
312 // BeOS R4 legacy API. Implemented as a wrapper around GetBufferList
313 // "needLock" is ignored, GetBufferList will do locking
318 if (name
== NULL
|| strlen(name
) == 0)
321 BBuffer
* buffers
[fBufferCount
];
322 status_t status
= GetBufferList(fBufferCount
, buffers
);
326 for (int32 i
= 0; i
< fBufferCount
; i
++) {
327 status
= message
->AddInt32(name
, int32(buffers
[i
]->ID()));
336 // #pragma mark - private methods
339 /* not implemented */
340 //BBufferGroup::BBufferGroup(const BBufferGroup &)
341 //BBufferGroup & BBufferGroup::operator=(const BBufferGroup &)
345 BBufferGroup::_Init()
349 // some defaults in case we drop out early
351 fRequestError
= B_ERROR
;
354 // Create the reclaim semaphore
355 // This is also used as a system wide unique identifier for this group
356 fReclaimSem
= create_sem(0, "buffer reclaim sem");
357 if (fReclaimSem
< 0) {
358 ERROR("BBufferGroup::InitBufferGroup: couldn't create fReclaimSem\n");
359 return (status_t
)fReclaimSem
;
362 fBufferList
= BPrivate::SharedBufferList::Get();
363 if (fBufferList
== NULL
) {
364 ERROR("BBufferGroup::InitBufferGroup: SharedBufferList::Get() "