* Rewrote BBufferGroup header.

* Cleaned up the source file, no functional change (intended).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32139 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-08-05 16:08:47 +00:00
parent 034ea9408b
commit a21284874f
2 changed files with 203 additions and 233 deletions
+31 -45
View File
@@ -1,82 +1,68 @@
/******************************************************************************* /*
/ * Copyright 2009, Haiku Inc. All Rights Reserved.
/ File: BufferGroup.h * Distributed under the terms of the MIT License.
/ */
/ Description: A BBufferGroup organizes sets of BBuffers so that you can request #ifndef _BUFFER_GROUP_H
/ and reclaim them.
/
/ Copyright 1997-98, Be Incorporated, All Rights Reserved
/
*******************************************************************************/
#if !defined(_BUFFER_GROUP_H)
#define _BUFFER_GROUP_H #define _BUFFER_GROUP_H
#include <MediaDefs.h> #include <MediaDefs.h>
class BBuffer; class BBuffer;
struct _shared_buffer_list; struct _shared_buffer_list;
class BBufferGroup
{
public:
BBufferGroup( class BBufferGroup {
size_t size, public:
int32 count = 3, BBufferGroup(size_t size, int32 count = 3,
uint32 placement = B_ANY_ADDRESS, uint32 placement = B_ANY_ADDRESS,
uint32 lock = B_FULL_LOCK); uint32 lock = B_FULL_LOCK);
explicit BBufferGroup(); explicit BBufferGroup();
BBufferGroup( BBufferGroup(int32 count,
int32 count,
const media_buffer_id* buffers); const media_buffer_id* buffers);
~BBufferGroup(); /* BBufferGroup is NOT a virtual class!!! */ ~BBufferGroup();
status_t InitCheck(); status_t InitCheck();
/* use this function to add buffers you created on your own */ status_t AddBuffer(const buffer_clone_info& info,
status_t AddBuffer( BBuffer** _buffer = NULL);
const buffer_clone_info & info,
BBuffer ** out_buffer = NULL);
BBuffer * RequestBuffer( BBuffer* RequestBuffer(size_t size,
size_t size,
bigtime_t timeout = B_INFINITE_TIMEOUT); bigtime_t timeout = B_INFINITE_TIMEOUT);
status_t RequestBuffer( status_t RequestBuffer(BBuffer* buffer,
BBuffer * buffer,
bigtime_t timeout = B_INFINITE_TIMEOUT); bigtime_t timeout = B_INFINITE_TIMEOUT);
status_t RequestError(); /* return last RequestBuffer error, useful if NULL is returned */
status_t CountBuffers( status_t RequestError();
int32 * out_count);
status_t GetBufferList( status_t CountBuffers(int32* _count);
int32 buf_count, status_t GetBufferList(int32 bufferCount,
BBuffer ** out_buffers); BBuffer** _buffers);
status_t WaitForBuffers(); status_t WaitForBuffers();
status_t ReclaimAllBuffers(); status_t ReclaimAllBuffers();
private: private:
/* in BeOS R5 this is a deprecated api, from BeOS R4 times */ // deprecated BeOS R4 API
status_t AddBuffersTo(BMessage * message, const char * name, bool needLock=true); status_t AddBuffersTo(BMessage* message, const char* name,
bool needLock);
status_t InitBufferGroup(); /* used internally */ BBufferGroup(const BBufferGroup& other);
BBufferGroup(const BBufferGroup &); /* not implemented */ BBufferGroup& operator=(const BBufferGroup& other);
BBufferGroup& operator=(const BBufferGroup&); /* not implemented */
status_t _Init();
private:
friend struct _shared_buffer_list; friend struct _shared_buffer_list;
status_t fInitError; status_t fInitError;
status_t fRequestError; status_t fRequestError;
int32 fBufferCount; int32 fBufferCount;
_shared_buffer_list* fBufferList; _shared_buffer_list* fBufferList;
// this is a BBufferGroup specific semaphore used for reclaiming BBuffers of this group
// is also is a system wide unique identifier of this group
sem_id fReclaimSem; sem_id fReclaimSem;
uint32 _reserved_buffer_group_[9]; uint32 _reserved[9];
}; };
#endif /* _BUFFER_GROUP_H */
#endif // _BUFFER_GROUP_H
+146 -162
View File
@@ -27,69 +27,21 @@
* *
*/ */
#include <BufferGroup.h> #include <BufferGroup.h>
#include <Buffer.h> #include <Buffer.h>
#include "debug.h" #include "debug.h"
#include "SharedBufferList.h"
#include "DataExchange.h" #include "DataExchange.h"
#include "SharedBufferList.h"
/*************************************************************
* private BBufferGroup
*************************************************************/
status_t
BBufferGroup::InitBufferGroup()
{
CALLED();
// some defaults
fBufferList = 0;
fReclaimSem = B_ERROR;
fInitError = B_ERROR;
fRequestError = B_ERROR;
fBufferCount = 0;
// create the reclaim semaphore
fReclaimSem = create_sem(0,"buffer reclaim sem");
if (fReclaimSem < B_OK) {
ERROR("BBufferGroup::InitBufferGroup: couldn't create fReclaimSem\n");
fInitError = (status_t)fReclaimSem;
return fInitError;
}
// ask media_server to get the area_id of the shared buffer list
server_get_shared_buffer_area_request area_request;
server_get_shared_buffer_area_reply area_reply;
if (QueryServer(SERVER_GET_SHARED_BUFFER_AREA, &area_request, sizeof(area_request), &area_reply, sizeof(area_reply)) != B_OK) {
ERROR("BBufferGroup::InitBufferGroup: SERVER_GET_SHARED_BUFFER_AREA failed\n");
fInitError = B_ERROR;
return fInitError;
}
ASSERT(area_reply.area > 0);
fBufferList = _shared_buffer_list::Clone(area_reply.area);
if (fBufferList == NULL) {
ERROR("BBufferGroup::InitBufferGroup: _shared_buffer_list::Clone failed\n");
fInitError = B_ERROR;
return fInitError;
}
fInitError = B_OK;
return fInitError;
}
/************************************************************* BBufferGroup::BBufferGroup(size_t size, int32 count, uint32 placement,
* public BBufferGroup
*************************************************************/
BBufferGroup::BBufferGroup(size_t size,
int32 count,
uint32 placement,
uint32 lock) uint32 lock)
{ {
CALLED(); CALLED();
if (InitBufferGroup() != B_OK) if (_Init() != B_OK)
return; return;
// This one is easy. We need to create "count" BBuffers, // This one is easy. We need to create "count" BBuffers,
@@ -99,100 +51,76 @@ BBufferGroup::BBufferGroup(size_t size,
// then we delete our area. This way BBuffers are // then we delete our area. This way BBuffers are
// independent from the BBufferGroup // independent from the BBufferGroup
void *start_addr;
area_id buffer_area;
size_t area_size;
buffer_clone_info bci;
BBuffer *buffer;
// don't allow all placement parameter values // don't allow all placement parameter values
if (placement != B_ANY_ADDRESS && placement != B_ANY_KERNEL_ADDRESS) { if (placement != B_ANY_ADDRESS && placement != B_ANY_KERNEL_ADDRESS) {
ERROR("BBufferGroup: placement != B_ANY_ADDRESS && placement != B_ANY_KERNEL_ADDRESS (0x%08lx)\n",placement); ERROR("BBufferGroup: placement != B_ANY_ADDRESS "
"&& placement != B_ANY_KERNEL_ADDRESS (0x%08lx)\n", placement);
placement = B_ANY_ADDRESS; placement = B_ANY_ADDRESS;
} }
// first we roundup for a better placement in memory // first we roundup for a better placement in memory
int allocsize = (size + 63) & ~63; size_t allocSize = (size + 63) & ~63;
// now we create the area // now we create the area
area_size = ((allocsize * count) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1); size_t areaSize
= ((allocSize * count) + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
buffer_area = create_area("some buffers area", &start_addr,placement,area_size,lock,B_READ_AREA | B_WRITE_AREA); void* startAddress;
if (buffer_area < B_OK) { area_id bufferArea = create_area("some buffers area", &startAddress,
ERROR("BBufferGroup: failed to allocate %ld bytes area\n",area_size); placement, areaSize, lock, B_READ_AREA | B_WRITE_AREA);
fInitError = (status_t)buffer_area; if (bufferArea < 0) {
ERROR("BBufferGroup: failed to allocate %ld bytes area\n", areaSize);
fInitError = (status_t)bufferArea;
return; return;
} }
fBufferCount = count; buffer_clone_info info;
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
bci.area = buffer_area; info.area = bufferArea;
bci.offset = i * allocsize; info.offset = i * allocSize;
bci.size = size; info.size = size;
buffer = new BBuffer(bci);
if (0 == buffer->Data()) { fInitError = AddBuffer(info);
// BBuffer::Data() will return 0 if an error occured if (fInitError != B_OK)
ERROR("BBufferGroup: error while creating buffer\n");
delete buffer;
fInitError = B_ERROR;
break;
}
if (B_OK != fBufferList->AddBuffer(fReclaimSem,buffer)) {
ERROR("BBufferGroup: error when adding buffer\n");
delete buffer;
fInitError = B_ERROR;
break; break;
} }
delete_area(bufferArea);
} }
delete_area(buffer_area);
}
/* explicit */
BBufferGroup::BBufferGroup() BBufferGroup::BBufferGroup()
{ {
CALLED(); CALLED();
if (InitBufferGroup() != B_OK) if (_Init() != B_OK)
return; return;
// this one simply creates an empty BBufferGroup // this one simply creates an empty BBufferGroup
} }
BBufferGroup::BBufferGroup(int32 count, BBufferGroup::BBufferGroup(int32 count, const media_buffer_id* buffers)
const media_buffer_id *buffers)
{ {
CALLED(); CALLED();
if (InitBufferGroup() != B_OK) if (_Init() != B_OK)
return; return;
// XXX we need to make sure that a media_buffer_id is only added once to each group // TODO: we need to make sure that a media_buffer_id is only added
// once to each group
// this one creates "BBuffer"s from "media_buffer_id"s passed // this one creates "BBuffer"s from "media_buffer_id"s passed
// by the application. // by the application.
fBufferCount = count; buffer_clone_info info;
buffer_clone_info bci;
BBuffer *buffer;
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
bci.buffer = buffers[i]; info.buffer = buffers[i];
buffer = new BBuffer(bci);
if (0 == buffer->Data()) { fInitError = AddBuffer(info);
// BBuffer::Data() will return 0 if an error occured if (fInitError != B_OK)
ERROR("BBufferGroup(2): error while creating buffer\n");
delete buffer;
fInitError = B_ERROR;
break; break;
} }
if (B_OK != fBufferList->AddBuffer(fReclaimSem,buffer)) {
ERROR("BBufferGroup(2): error when adding buffer\n");
delete buffer;
fInitError = B_ERROR;
break;
}
}
} }
@@ -201,7 +129,7 @@ BBufferGroup::~BBufferGroup()
CALLED(); CALLED();
if (fBufferList) if (fBufferList)
fBufferList->Terminate(fReclaimSem); fBufferList->Terminate(fReclaimSem);
if (fReclaimSem >= B_OK)
delete_sem(fReclaimSem); delete_sem(fReclaimSem);
} }
@@ -215,41 +143,44 @@ BBufferGroup::InitCheck()
status_t status_t
BBufferGroup::AddBuffer(const buffer_clone_info &info, BBufferGroup::AddBuffer(const buffer_clone_info& info, BBuffer** _buffer)
BBuffer **out_buffer)
{ {
CALLED(); CALLED();
if (fInitError != B_OK) if (fInitError != B_OK)
return B_NO_INIT; return B_NO_INIT;
// XXX we need to make sure that a media_buffer_id is only added once to each group // TODO: we need to make sure that a media_buffer_id is only added
// once to each group
BBuffer *buffer; BBuffer* buffer = new(std::nothrow) BBuffer(info);
buffer = new BBuffer(info); if (buffer == NULL)
if (0 == buffer->Data()) { return B_NO_MEMORY;
// BBuffer::Data() will return 0 if an error occured
ERROR("BBufferGroup::AddBuffer: error while creating buffer\n"); if (buffer->Data() == NULL) {
// BBuffer::Data() will return NULL if an error occured
ERROR("BBufferGroup: error while creating buffer\n");
delete buffer; delete buffer;
return B_ERROR; return B_ERROR;
} }
if (B_OK != fBufferList->AddBuffer(fReclaimSem,buffer)) {
ERROR("BBufferGroup::AddBuffer: error when adding buffer\n"); status_t status = fBufferList->AddBuffer(fReclaimSem, buffer);
if (status != B_OK) {
ERROR("BBufferGroup: error when adding buffer\n");
delete buffer; delete buffer;
fInitError = B_ERROR; return status;
return B_ERROR;
} }
atomic_add(&fBufferCount, 1); atomic_add(&fBufferCount, 1);
if (out_buffer != 0) if (_buffer != NULL)
*out_buffer = buffer; *_buffer = buffer;
return B_OK; return B_OK;
} }
BBuffer* BBuffer*
BBufferGroup::RequestBuffer(size_t size, BBufferGroup::RequestBuffer(size_t size, bigtime_t timeout)
bigtime_t timeout)
{ {
CALLED(); CALLED();
if (fInitError != B_OK) if (fInitError != B_OK)
@@ -262,16 +193,16 @@ BBufferGroup::RequestBuffer(size_t size,
status_t status; status_t status;
buffer = NULL; buffer = NULL;
status = fBufferList->RequestBuffer(fReclaimSem, fBufferCount, size, 0, &buffer, timeout); status = fBufferList->RequestBuffer(fReclaimSem, fBufferCount, size, 0,
&buffer, timeout);
fRequestError = status; fRequestError = status;
return (status == B_OK) ? buffer : NULL; return status == B_OK ? buffer : NULL;
} }
status_t status_t
BBufferGroup::RequestBuffer(BBuffer *buffer, BBufferGroup::RequestBuffer(BBuffer* buffer, bigtime_t timeout)
bigtime_t timeout)
{ {
CALLED(); CALLED();
if (fInitError != B_OK) if (fInitError != B_OK)
@@ -281,7 +212,8 @@ BBufferGroup::RequestBuffer(BBuffer *buffer,
return B_BAD_VALUE; return B_BAD_VALUE;
status_t status; status_t status;
status = fBufferList->RequestBuffer(fReclaimSem, fBufferCount, 0, 0, &buffer, timeout); status = fBufferList->RequestBuffer(fReclaimSem, fBufferCount, 0, 0,
&buffer, timeout);
fRequestError = status; fRequestError = status;
return status; return status;
@@ -300,29 +232,28 @@ BBufferGroup::RequestError()
status_t status_t
BBufferGroup::CountBuffers(int32 *out_count) BBufferGroup::CountBuffers(int32* _count)
{ {
CALLED(); CALLED();
if (fInitError != B_OK) if (fInitError != B_OK)
return B_NO_INIT; return B_NO_INIT;
*out_count = fBufferCount; *_count = fBufferCount;
return B_OK; return B_OK;
} }
status_t status_t
BBufferGroup::GetBufferList(int32 buf_count, BBufferGroup::GetBufferList(int32 bufferCount, BBuffer** _buffers)
BBuffer **out_buffers)
{ {
CALLED(); CALLED();
if (fInitError != B_OK) if (fInitError != B_OK)
return B_NO_INIT; return B_NO_INIT;
if (buf_count <= 0 || buf_count > fBufferCount) if (bufferCount <= 0 || bufferCount > fBufferCount)
return B_BAD_VALUE; return B_BAD_VALUE;
return fBufferList->GetBufferList(fReclaimSem,buf_count,out_buffers); return fBufferList->GetBufferList(fReclaimSem, bufferCount, _buffers);
} }
@@ -333,25 +264,26 @@ BBufferGroup::WaitForBuffers()
if (fInitError != B_OK) if (fInitError != B_OK)
return B_NO_INIT; return B_NO_INIT;
// XXX this function is not really useful anyway, and will // TODO: this function is not really useful anyway, and will
// XXX not work exactly as documented, but it is close enough // not work exactly as documented, but it is close enough
if (fBufferCount < 0) if (fBufferCount < 0)
return B_BAD_VALUE; return B_BAD_VALUE;
if (fBufferCount == 0) if (fBufferCount == 0)
return B_OK; return B_OK;
// we need to wait until at least one buffer belonging to this group is reclaimed. // We need to wait until at least one buffer belonging to this group is
// this has happened when can aquire "fReclaimSem" // reclaimed.
// This has happened when can aquire "fReclaimSem"
status_t status; status_t status;
while (B_INTERRUPTED == (status = acquire_sem(fReclaimSem))) while ((status = acquire_sem(fReclaimSem)) == B_INTERRUPTED)
; ;
if (status != B_OK)
if (status != B_OK) // some error happened
return status; return status;
// we need to release the "fReclaimSem" now, else we would block requesting of new buffers // we need to release the "fReclaimSem" now, else we would block
// requesting of new buffers
return release_sem(fReclaimSem); return release_sem(fReclaimSem);
} }
@@ -364,7 +296,8 @@ BBufferGroup::ReclaimAllBuffers()
if (fInitError != B_OK) if (fInitError != B_OK)
return B_NO_INIT; return B_NO_INIT;
// because additional BBuffers might get added to this group betweeen acquire and release // because additional BBuffers might get added to this group betweeen
// acquire and release
int32 count = fBufferCount; int32 count = fBufferCount;
if (count < 0) if (count < 0)
@@ -373,29 +306,26 @@ BBufferGroup::ReclaimAllBuffers()
return B_OK; return B_OK;
// we need to wait until all BBuffers belonging to this group are reclaimed. // we need to wait until all BBuffers belonging to this group are reclaimed.
// this has happened when the "fReclaimSem" can be aquired "fBufferCount" times // this has happened when the "fReclaimSem" can be aquired "fBufferCount"
// times
status_t status; status_t status;
while (B_INTERRUPTED == (status = acquire_sem_etc(fReclaimSem, count, 0, 0))) do {
; status = acquire_sem_etc(fReclaimSem, count, 0, 0);
} while (status == B_INTERRUPTED);
if (status != B_OK) // some error happened if (status != B_OK)
return status; return status;
// we need to release the "fReclaimSem" now, else we would block requesting of new buffers // we need to release the "fReclaimSem" now, else we would block
// requesting of new buffers
return release_sem_etc(fReclaimSem, count, 0); return release_sem_etc(fReclaimSem, count, 0);
} }
/*************************************************************
* private BBufferGroup
*************************************************************/
/* not implemented */ // #pragma mark - deprecated BeOS R4 API
/*
BBufferGroup::BBufferGroup(const BBufferGroup &)
BBufferGroup & BBufferGroup::operator=(const BBufferGroup &)
*/
status_t status_t
BBufferGroup::AddBuffersTo(BMessage* message, const char* name, bool needLock) BBufferGroup::AddBuffersTo(BMessage* message, const char* name, bool needLock)
@@ -414,21 +344,75 @@ BBufferGroup::AddBuffersTo(BMessage * message, const char * name, bool needLock)
return B_BAD_VALUE; return B_BAD_VALUE;
BBuffer** buffers; BBuffer** buffers;
status_t status;
int32 count; int32 count;
count = fBufferCount; count = fBufferCount;
buffers = new BBuffer * [count]; buffers = new BBuffer * [count];
if (B_OK != (status = GetBufferList(count,buffers))) status_t status = GetBufferList(count, buffers);
if (status != B_OK)
goto end; goto end;
for (int32 i = 0; i < count; i++) for (int32 i = 0; i < count; i++) {
if (B_OK != (status = message->AddInt32(name,int32(buffers[i]->ID())))) status = message->AddInt32(name, int32(buffers[i]->ID()));
if (status != B_OK)
goto end; goto end;
}
end: end:
delete [] buffers; delete [] buffers;
return status; return status;
} }
// #pragma mark - private methods
/* not implemented */
//BBufferGroup::BBufferGroup(const BBufferGroup &)
//BBufferGroup & BBufferGroup::operator=(const BBufferGroup &)
status_t
BBufferGroup::_Init()
{
CALLED();
// some defaults in case we drop out early
fBufferList = 0;
fInitError = B_ERROR;
fRequestError = B_ERROR;
fBufferCount = 0;
// Create the reclaim semaphore
// This is also used as a system wide unique identifier for this group
fReclaimSem = create_sem(0, "buffer reclaim sem");
if (fReclaimSem < B_OK) {
ERROR("BBufferGroup::InitBufferGroup: couldn't create fReclaimSem\n");
fInitError = (status_t)fReclaimSem;
return fInitError;
}
// ask media_server to get the area_id of the shared buffer list
server_get_shared_buffer_area_request areaRequest;
server_get_shared_buffer_area_reply areaReply;
if (QueryServer(SERVER_GET_SHARED_BUFFER_AREA, &areaRequest,
sizeof(areaRequest), &areaReply, sizeof(areaReply)) != B_OK) {
ERROR("BBufferGroup::InitBufferGroup: SERVER_GET_SHARED_BUFFER_AREA "
"failed\n");
fInitError = B_ERROR;
return fInitError;
}
fBufferList = _shared_buffer_list::Clone(areaReply.area);
if (fBufferList == NULL) {
ERROR("BBufferGroup::InitBufferGroup: _shared_buffer_list::Clone "
"failed\n");
fInitError = B_ERROR;
return fInitError;
}
fInitError = B_OK;
return fInitError;
}