1255a01c7Sbeveloper/*
2255a01c7Sbeveloper * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
3255a01c7Sbeveloper *
4255a01c7Sbeveloper * Permission is hereby granted, free of charge, to any person obtaining
5255a01c7Sbeveloper * a copy of this software and associated documentation files or portions
6255a01c7Sbeveloper * thereof (the "Software"), to deal in the Software without restriction,
7255a01c7Sbeveloper * including without limitation the rights to use, copy, modify, merge,
8255a01c7Sbeveloper * publish, distribute, sublicense, and/or sell copies of the Software,
9255a01c7Sbeveloper * and to permit persons to whom the Software is furnished to do so, subject
10255a01c7Sbeveloper * to the following conditions:
11255a01c7Sbeveloper *
12255a01c7Sbeveloper *  * Redistributions of source code must retain the above copyright notice,
13255a01c7Sbeveloper *    this list of conditions and the following disclaimer.
14255a01c7Sbeveloper *
15255a01c7Sbeveloper *  * Redistributions in binary form must reproduce the above copyright notice
16255a01c7Sbeveloper *    in the  binary, as well as this list of conditions and the following
17255a01c7Sbeveloper *    disclaimer in the documentation and/or other materials provided with
18255a01c7Sbeveloper *    the distribution.
19255a01c7Sbeveloper *
20255a01c7Sbeveloper * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21255a01c7Sbeveloper * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22255a01c7Sbeveloper * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23255a01c7Sbeveloper * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24255a01c7Sbeveloper * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25255a01c7Sbeveloper * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26255a01c7Sbeveloper * THE SOFTWARE.
27255a01c7Sbeveloper *
28255a01c7Sbeveloper */
29255a01c7Sbeveloper
30a2128487SAxel Dörfler
3152a38012Sejakowatz#include <BufferGroup.h>
32a2128487SAxel Dörfler
3352a38012Sejakowatz#include <Buffer.h>
34a2128487SAxel Dörfler
35b84955d4SBarrett#include "MediaDebug.h"
3676669a29Sbeveloper#include "DataExchange.h"
37a2128487SAxel Dörfler#include "SharedBufferList.h"
3852a38012Sejakowatz
3952a38012Sejakowatz
40a2128487SAxel DörflerBBufferGroup::BBufferGroup(size_t size, int32 count, uint32 placement,
41a2128487SAxel Dörfler	uint32 lock)
4252a38012Sejakowatz{
4352a38012Sejakowatz	CALLED();
44280c64a9SDario Casalinuovo	fInitError = _Init();
45280c64a9SDario Casalinuovo	if (fInitError != B_OK)
4652a38012Sejakowatz		return;
479dec2310SAxel Dörfler
4852a38012Sejakowatz	// This one is easy. We need to create "count" BBuffers,
499dec2310SAxel Dörfler	// each one "size" bytes large. They all go into one
5052a38012Sejakowatz	// area, with "placement" and "lock" attributes.
5152a38012Sejakowatz	// The BBuffers created will clone the area, and
5252a38012Sejakowatz	// then we delete our area. This way BBuffers are
5352a38012Sejakowatz	// independent from the BBufferGroup
5452a38012Sejakowatz
5552a38012Sejakowatz	// don't allow all placement parameter values
5652a38012Sejakowatz	if (placement != B_ANY_ADDRESS && placement != B_ANY_KERNEL_ADDRESS) {
57a2128487SAxel Dörfler		ERROR("BBufferGroup: placement != B_ANY_ADDRESS "
58332cc6bcSAxel Dörfler			"&& placement != B_ANY_KERNEL_ADDRESS (0x%#" B_PRIx32 ")\n",
59332cc6bcSAxel Dörfler			placement);
6052a38012Sejakowatz		placement = B_ANY_ADDRESS;
6152a38012Sejakowatz	}
629dec2310SAxel Dörfler
6352a38012Sejakowatz	// first we roundup for a better placement in memory
64a2128487SAxel Dörfler	size_t allocSize = (size + 63) & ~63;
6552a38012Sejakowatz
6652a38012Sejakowatz	// now we create the area
67a2128487SAxel Dörfler	size_t areaSize
68a2128487SAxel Dörfler		= ((allocSize * count) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
69a2128487SAxel Dörfler
70a2128487SAxel Dörfler	void* startAddress;
71a2128487SAxel Dörfler	area_id bufferArea = create_area("some buffers area", &startAddress,
72964cab46SAugustin Cavalier		placement, areaSize, lock, B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA);
73a2128487SAxel Dörfler	if (bufferArea < 0) {
74a2128487SAxel Dörfler		ERROR("BBufferGroup: failed to allocate %ld bytes area\n", areaSize);
75a2128487SAxel Dörfler		fInitError = (status_t)bufferArea;
7652a38012Sejakowatz		return;
7752a38012Sejakowatz	}
78a2128487SAxel Dörfler
79a2128487SAxel Dörfler	buffer_clone_info info;
8052a38012Sejakowatz
819dec2310SAxel Dörfler	for (int32 i = 0; i < count; i++) {
82a2128487SAxel Dörfler		info.area = bufferArea;
83a2128487SAxel Dörfler		info.offset = i * allocSize;
84a2128487SAxel Dörfler		info.size = size;
85a2128487SAxel Dörfler
86a2128487SAxel Dörfler		fInitError = AddBuffer(info);
87a2128487SAxel Dörfler		if (fInitError != B_OK)
8852a38012Sejakowatz			break;
8952a38012Sejakowatz	}
9052a38012Sejakowatz
91a2128487SAxel Dörfler	delete_area(bufferArea);
9252a38012Sejakowatz}
9352a38012Sejakowatz
94a2128487SAxel Dörfler
9552a38012SejakowatzBBufferGroup::BBufferGroup()
9652a38012Sejakowatz{
9752a38012Sejakowatz	CALLED();
98280c64a9SDario Casalinuovo	fInitError = _Init();
99280c64a9SDario Casalinuovo	if (fInitError != B_OK)
10052a38012Sejakowatz		return;
1019dec2310SAxel Dörfler
10252a38012Sejakowatz	// this one simply creates an empty BBufferGroup
10352a38012Sejakowatz}
10452a38012Sejakowatz
10552a38012Sejakowatz
106a2128487SAxel DörflerBBufferGroup::BBufferGroup(int32 count, const media_buffer_id* buffers)
10752a38012Sejakowatz{
10852a38012Sejakowatz	CALLED();
109280c64a9SDario Casalinuovo	fInitError = _Init();
110280c64a9SDario Casalinuovo	if (fInitError != B_OK)
11152a38012Sejakowatz		return;
1129dec2310SAxel Dörfler
113280c64a9SDario Casalinuovo	// This one creates "BBuffer"s from "media_buffer_id"s passed
11452a38012Sejakowatz	// by the application.
11552a38012Sejakowatz
116a2128487SAxel Dörfler	buffer_clone_info info;
11752a38012Sejakowatz
1189dec2310SAxel Dörfler	for (int32 i = 0; i < count; i++) {
119a2128487SAxel Dörfler		info.buffer = buffers[i];
120a2128487SAxel Dörfler
121a2128487SAxel Dörfler		fInitError = AddBuffer(info);
122a2128487SAxel Dörfler		if (fInitError != B_OK)
12352a38012Sejakowatz			break;
12452a38012Sejakowatz	}
12552a38012Sejakowatz}
12652a38012Sejakowatz
12752a38012Sejakowatz
12852a38012SejakowatzBBufferGroup::~BBufferGroup()
12952a38012Sejakowatz{
13052a38012Sejakowatz	CALLED();
1319dec2310SAxel Dörfler	if (fBufferList != NULL)
1329dec2310SAxel Dörfler		fBufferList->DeleteGroupAndPut(fReclaimSem);
133a2128487SAxel Dörfler
134a2128487SAxel Dörfler	delete_sem(fReclaimSem);
13552a38012Sejakowatz}
13652a38012Sejakowatz
13752a38012Sejakowatz
13852a38012Sejakowatzstatus_t
13952a38012SejakowatzBBufferGroup::InitCheck()
14052a38012Sejakowatz{
14152a38012Sejakowatz	CALLED();
14252a38012Sejakowatz	return fInitError;
14352a38012Sejakowatz}
14452a38012Sejakowatz
14552a38012Sejakowatz
14652a38012Sejakowatzstatus_t
147a2128487SAxel DörflerBBufferGroup::AddBuffer(const buffer_clone_info& info, BBuffer** _buffer)
14852a38012Sejakowatz{
14952a38012Sejakowatz	CALLED();
15052a38012Sejakowatz	if (fInitError != B_OK)
15152a38012Sejakowatz		return B_NO_INIT;
15252a38012Sejakowatz
1531cc20d82SDario Casalinuovo	status_t status = fBufferList->AddBuffer(fReclaimSem, info, _buffer);
154a2128487SAxel Dörfler	if (status != B_OK) {
155a2128487SAxel Dörfler		ERROR("BBufferGroup: error when adding buffer\n");
156a2128487SAxel Dörfler		return status;
15752a38012Sejakowatz	}
158a2128487SAxel Dörfler	atomic_add(&fBufferCount, 1);
15952a38012Sejakowatz	return B_OK;
16052a38012Sejakowatz}
16152a38012Sejakowatz
16252a38012Sejakowatz
163a2128487SAxel DörflerBBuffer*
164a2128487SAxel DörflerBBufferGroup::RequestBuffer(size_t size, bigtime_t timeout)
16552a38012Sejakowatz{
16652a38012Sejakowatz	CALLED();
16752a38012Sejakowatz	if (fInitError != B_OK)
16852a38012Sejakowatz		return NULL;
16952a38012Sejakowatz
17052a38012Sejakowatz	if (size <= 0)
17152a38012Sejakowatz		return NULL;
1729dec2310SAxel Dörfler
173280c64a9SDario Casalinuovo	BBuffer *buffer = NULL;
174280c64a9SDario Casalinuovo	fRequestError = fBufferList->RequestBuffer(fReclaimSem, fBufferCount,
175280c64a9SDario Casalinuovo		size, 0, &buffer, timeout);
17652a38012Sejakowatz
177280c64a9SDario Casalinuovo	return fRequestError == B_OK ? buffer : NULL;
17852a38012Sejakowatz}
17952a38012Sejakowatz
18052a38012Sejakowatz
18152a38012Sejakowatzstatus_t
182a2128487SAxel DörflerBBufferGroup::RequestBuffer(BBuffer* buffer, bigtime_t timeout)
18352a38012Sejakowatz{
18452a38012Sejakowatz	CALLED();
18552a38012Sejakowatz	if (fInitError != B_OK)
18652a38012Sejakowatz		return B_NO_INIT;
1879dec2310SAxel Dörfler
18852a38012Sejakowatz	if (buffer == NULL)
18952a38012Sejakowatz		return B_BAD_VALUE;
19052a38012Sejakowatz
191280c64a9SDario Casalinuovo	fRequestError = fBufferList->RequestBuffer(fReclaimSem, fBufferCount, 0, 0,
192a2128487SAxel Dörfler		&buffer, timeout);
1939dec2310SAxel Dörfler
194280c64a9SDario Casalinuovo	return fRequestError;
19552a38012Sejakowatz}
19652a38012Sejakowatz
19752a38012Sejakowatz
19852a38012Sejakowatzstatus_t
19952a38012SejakowatzBBufferGroup::RequestError()
20052a38012Sejakowatz{
20152a38012Sejakowatz	CALLED();
20252a38012Sejakowatz	if (fInitError != B_OK)
20352a38012Sejakowatz		return B_NO_INIT;
20452a38012Sejakowatz
20552a38012Sejakowatz	return fRequestError;
20652a38012Sejakowatz}
20752a38012Sejakowatz
20852a38012Sejakowatz
20952a38012Sejakowatzstatus_t
210a2128487SAxel DörflerBBufferGroup::CountBuffers(int32* _count)
21152a38012Sejakowatz{
21252a38012Sejakowatz	CALLED();
21352a38012Sejakowatz	if (fInitError != B_OK)
21452a38012Sejakowatz		return B_NO_INIT;
21552a38012Sejakowatz
216a2128487SAxel Dörfler	*_count = fBufferCount;
21752a38012Sejakowatz	return B_OK;
21852a38012Sejakowatz}
21952a38012Sejakowatz
22052a38012Sejakowatz
22152a38012Sejakowatzstatus_t
222a2128487SAxel DörflerBBufferGroup::GetBufferList(int32 bufferCount, BBuffer** _buffers)
22352a38012Sejakowatz{
22452a38012Sejakowatz	CALLED();
22552a38012Sejakowatz	if (fInitError != B_OK)
22652a38012Sejakowatz		return B_NO_INIT;
2279dec2310SAxel Dörfler
228a2128487SAxel Dörfler	if (bufferCount <= 0 || bufferCount > fBufferCount)
22952a38012Sejakowatz		return B_BAD_VALUE;
23052a38012Sejakowatz
231a2128487SAxel Dörfler	return fBufferList->GetBufferList(fReclaimSem, bufferCount, _buffers);
23252a38012Sejakowatz}
23352a38012Sejakowatz
23452a38012Sejakowatz
23552a38012Sejakowatzstatus_t
23652a38012SejakowatzBBufferGroup::WaitForBuffers()
23752a38012Sejakowatz{
23852a38012Sejakowatz	CALLED();
23952a38012Sejakowatz	if (fInitError != B_OK)
24052a38012Sejakowatz		return B_NO_INIT;
24152a38012Sejakowatz
2429dec2310SAxel Dörfler	// TODO: this function is not really useful anyway, and will
243a2128487SAxel Dörfler	// not work exactly as documented, but it is close enough
24452a38012Sejakowatz
24552a38012Sejakowatz	if (fBufferCount < 0)
24652a38012Sejakowatz		return B_BAD_VALUE;
24752a38012Sejakowatz	if (fBufferCount == 0)
24852a38012Sejakowatz		return B_OK;
24952a38012Sejakowatz
250a2128487SAxel Dörfler	// We need to wait until at least one buffer belonging to this group is
251a2128487SAxel Dörfler	// reclaimed.
252a2128487SAxel Dörfler	// This has happened when can aquire "fReclaimSem"
25352a38012Sejakowatz
25452a38012Sejakowatz	status_t status;
255a2128487SAxel Dörfler	while ((status = acquire_sem(fReclaimSem)) == B_INTERRUPTED)
25652a38012Sejakowatz		;
257a2128487SAxel Dörfler	if (status != B_OK)
25852a38012Sejakowatz		return status;
2599dec2310SAxel Dörfler
260a2128487SAxel Dörfler	// we need to release the "fReclaimSem" now, else we would block
261a2128487SAxel Dörfler	// requesting of new buffers
26252a38012Sejakowatz
26352a38012Sejakowatz	return release_sem(fReclaimSem);
26452a38012Sejakowatz}
26552a38012Sejakowatz
26652a38012Sejakowatz
26752a38012Sejakowatzstatus_t
26852a38012SejakowatzBBufferGroup::ReclaimAllBuffers()
26952a38012Sejakowatz{
27052a38012Sejakowatz	CALLED();
27152a38012Sejakowatz	if (fInitError != B_OK)
27252a38012Sejakowatz		return B_NO_INIT;
27352a38012Sejakowatz
274a2128487SAxel Dörfler	// because additional BBuffers might get added to this group betweeen
2759dec2310SAxel Dörfler	// acquire and release
27652a38012Sejakowatz	int32 count = fBufferCount;
27752a38012Sejakowatz
27852a38012Sejakowatz	if (count < 0)
27952a38012Sejakowatz		return B_BAD_VALUE;
28052a38012Sejakowatz	if (count == 0)
28152a38012Sejakowatz		return B_OK;
28252a38012Sejakowatz
28352a38012Sejakowatz	// we need to wait until all BBuffers belonging to this group are reclaimed.
284a2128487SAxel Dörfler	// this has happened when the "fReclaimSem" can be aquired "fBufferCount"
285a2128487SAxel Dörfler	// times
28652a38012Sejakowatz
2878bffda16SDario Casalinuovo	status_t status = B_ERROR;
288a2128487SAxel Dörfler	do {
2898bffda16SDario Casalinuovo		status = acquire_sem_etc(fReclaimSem, count, B_RELATIVE_TIMEOUT, 0);
290a2128487SAxel Dörfler	} while (status == B_INTERRUPTED);
2919dec2310SAxel Dörfler
292a2128487SAxel Dörfler	if (status != B_OK)
29352a38012Sejakowatz		return status;
2949dec2310SAxel Dörfler
295a2128487SAxel Dörfler	// we need to release the "fReclaimSem" now, else we would block
296a2128487SAxel Dörfler	// requesting of new buffers
29752a38012Sejakowatz
29852a38012Sejakowatz	return release_sem_etc(fReclaimSem, count, 0);
29952a38012Sejakowatz}
30052a38012Sejakowatz
30152a38012Sejakowatz
302a2128487SAxel Dörfler//	#pragma mark - deprecated BeOS R4 API
303a2128487SAxel Dörfler
30452a38012Sejakowatz
30552a38012Sejakowatzstatus_t
306a2128487SAxel DörflerBBufferGroup::AddBuffersTo(BMessage* message, const char* name, bool needLock)
30752a38012Sejakowatz{
30852a38012Sejakowatz	CALLED();
30952a38012Sejakowatz	if (fInitError != B_OK)
31052a38012Sejakowatz		return B_NO_INIT;
3119dec2310SAxel Dörfler
31252a38012Sejakowatz	// BeOS R4 legacy API. Implemented as a wrapper around GetBufferList
31352a38012Sejakowatz	// "needLock" is ignored, GetBufferList will do locking
31452a38012Sejakowatz
31552a38012Sejakowatz	if (message == NULL)
31652a38012Sejakowatz		return B_BAD_VALUE;
31752a38012Sejakowatz
31852a38012Sejakowatz	if (name == NULL || strlen(name) == 0)
31952a38012Sejakowatz		return B_BAD_VALUE;
3209dec2310SAxel Dörfler
321f50d7408SDario Casalinuovo	BBuffer* buffers[fBufferCount];
322f50d7408SDario Casalinuovo	status_t status = GetBufferList(fBufferCount, buffers);
323a2128487SAxel Dörfler	if (status != B_OK)
324f50d7408SDario Casalinuovo		return status;
3259dec2310SAxel Dörfler
326f50d7408SDario Casalinuovo	for (int32 i = 0; i < fBufferCount; i++) {
327a2128487SAxel Dörfler		status = message->AddInt32(name, int32(buffers[i]->ID()));
328a2128487SAxel Dörfler		if (status != B_OK)
329f50d7408SDario Casalinuovo			return status;
330a2128487SAxel Dörfler	}
331a2128487SAxel Dörfler
332f50d7408SDario Casalinuovo	return B_OK;
33352a38012Sejakowatz}
33452a38012Sejakowatz
335a2128487SAxel Dörfler
336a2128487SAxel Dörfler//	#pragma mark - private methods
337a2128487SAxel Dörfler
338a2128487SAxel Dörfler
339a2128487SAxel Dörfler/* not implemented */
340a2128487SAxel Dörfler//BBufferGroup::BBufferGroup(const BBufferGroup &)
341a2128487SAxel Dörfler//BBufferGroup & BBufferGroup::operator=(const BBufferGroup &)
342a2128487SAxel Dörfler
343a2128487SAxel Dörfler
344a2128487SAxel Dörflerstatus_t
345a2128487SAxel DörflerBBufferGroup::_Init()
346a2128487SAxel Dörfler{
347a2128487SAxel Dörfler	CALLED();
3489dec2310SAxel Dörfler
349a2128487SAxel Dörfler	// some defaults in case we drop out early
350280c64a9SDario Casalinuovo	fBufferList = NULL;
351a2128487SAxel Dörfler	fRequestError = B_ERROR;
352a2128487SAxel Dörfler	fBufferCount = 0;
353a2128487SAxel Dörfler
354a2128487SAxel Dörfler	// Create the reclaim semaphore
355a2128487SAxel Dörfler	// This is also used as a system wide unique identifier for this group
356a2128487SAxel Dörfler	fReclaimSem = create_sem(0, "buffer reclaim sem");
357280c64a9SDario Casalinuovo	if (fReclaimSem < 0) {
358a2128487SAxel Dörfler		ERROR("BBufferGroup::InitBufferGroup: couldn't create fReclaimSem\n");
359280c64a9SDario Casalinuovo		return (status_t)fReclaimSem;
360a2128487SAxel Dörfler	}
361a2128487SAxel Dörfler
3622f9ed888SAxel Dörfler	fBufferList = BPrivate::SharedBufferList::Get();
363a2128487SAxel Dörfler	if (fBufferList == NULL) {
3649dec2310SAxel Dörfler		ERROR("BBufferGroup::InitBufferGroup: SharedBufferList::Get() "
365a2128487SAxel Dörfler			"failed\n");
366280c64a9SDario Casalinuovo		return B_ERROR;
367a2128487SAxel Dörfler	}
368a2128487SAxel Dörfler
369280c64a9SDario Casalinuovo	return B_OK;
370a2128487SAxel Dörfler}
371a2128487SAxel Dörfler
372