* Implemented a new client allocation method: instead of having all bitmaps of
all teams in serveral server areas, and instead of having to eventually clone
them all several times in BBitmap, we now have one or more areas per team,
and BBitmap will only clone areas once if needed. As a side effect, this
method should be magnitudes faster than the previous version.
* This method is also much more secure: instead of putting the allocation
maintenance structures into those everyone-read-write areas, they are now
separated, so that faulty applications cannot crash the app_server this
way anymore. This should fix bug #172.
* Freeing memory is not yet implemented though! (although all memory will
be freed upon app exit)
* There are now 3 different bitmap allocation strategies: per ClientMemoryAllocator
(ie. via ServerApp), per area (for overlays, not yet implemented), and using
malloc()/free() for server-only bitmaps.
* ServerBitmap now deletes its buffers itself.
* Cleaned up BBitmap and BApplication a bit.
* The test environment currently doesn't build anymore, will fix it next.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16826 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-03-18 16:43:26 +03:00
|
|
|
/*
|
|
|
|
* Copyright 2006, Haiku, Inc. All Rights Reserved.
|
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Axel Dörfler, axeld@pinc-software.de
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
This class manages a pool of areas for one client. The client is supposed
|
|
|
|
to clone these areas into its own address space to access the data.
|
|
|
|
This mechanism is only used for bitmaps for far.
|
|
|
|
|
|
|
|
Note, this class doesn't provide any real locking - you need to have the
|
|
|
|
ServerApp locked when interacting with any method of this class.
|
|
|
|
|
|
|
|
The Lock()/Unlock() methods are needed whenever you access a pointer that
|
|
|
|
lies within an area allocated using this class. This is needed because an
|
|
|
|
area might be temporarily unavailable or might be relocated at any time.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// TODO: right now, areas will always stay static until they are deleted;
|
|
|
|
// locking is not yet done or enforced!
|
|
|
|
|
|
|
|
#include "ClientMemoryAllocator.h"
|
|
|
|
#include "ServerApp.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
|
|
|
typedef block_list::Iterator block_iterator;
|
|
|
|
typedef chunk_list::Iterator chunk_iterator;
|
|
|
|
|
|
|
|
|
|
|
|
ClientMemoryAllocator::ClientMemoryAllocator(ServerApp* application)
|
|
|
|
:
|
|
|
|
fApplication(application),
|
|
|
|
fLock("client memory lock")
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ClientMemoryAllocator::~ClientMemoryAllocator()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
ClientMemoryAllocator::InitCheck()
|
|
|
|
{
|
|
|
|
return fLock.InitCheck() < B_OK ? fLock.InitCheck() : B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
ClientMemoryAllocator::Allocate(size_t size, void** _address, bool& newArea)
|
|
|
|
{
|
|
|
|
// Search best matching free block from the list
|
|
|
|
|
|
|
|
block_iterator iterator = fFreeBlocks.GetIterator();
|
|
|
|
struct block* block;
|
|
|
|
struct block* best = NULL;
|
|
|
|
|
|
|
|
while ((block = iterator.Next()) != NULL) {
|
|
|
|
if (block->size >= size && (best == NULL || block->size < best->size))
|
|
|
|
best = block;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (best == NULL) {
|
|
|
|
// We didn't find a free block - we need to allocate
|
|
|
|
// another chunk, or resize an existing chunk
|
|
|
|
best = _AllocateChunk(size, newArea);
|
|
|
|
if (best == NULL)
|
|
|
|
return NULL;
|
|
|
|
} else
|
|
|
|
newArea = false;
|
|
|
|
|
|
|
|
// We need to split the chunk into two parts: the one to keep
|
|
|
|
// and the one to give away
|
|
|
|
|
|
|
|
if (best->size == size) {
|
|
|
|
// The simple case: the free block has exactly the size we wanted to have
|
|
|
|
fFreeBlocks.Remove(best);
|
|
|
|
*_address = best->base;
|
|
|
|
return best;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: maybe we should have the user reserve memory in its object
|
|
|
|
// for us, so we don't have to do this here...
|
|
|
|
|
|
|
|
struct block* usedBlock = (struct block*)malloc(sizeof(struct block));
|
|
|
|
if (usedBlock == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
usedBlock->base = best->base;
|
|
|
|
usedBlock->size = size;
|
|
|
|
usedBlock->chunk = best->chunk;
|
|
|
|
|
|
|
|
best->base += size;
|
|
|
|
best->size -= size;
|
|
|
|
|
|
|
|
*_address = usedBlock->base;
|
|
|
|
return usedBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
ClientMemoryAllocator::Free(void *cookie)
|
|
|
|
{
|
|
|
|
if (cookie == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// TODO: implement me!!!
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
area_id
|
|
|
|
ClientMemoryAllocator::Area(void* cookie)
|
|
|
|
{
|
|
|
|
struct block* block = (struct block*)cookie;
|
|
|
|
|
|
|
|
if (block != NULL)
|
|
|
|
return block->chunk->area;
|
|
|
|
|
|
|
|
return B_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32
|
|
|
|
ClientMemoryAllocator::AreaOffset(void* cookie)
|
|
|
|
{
|
|
|
|
struct block* block = (struct block*)cookie;
|
|
|
|
|
|
|
|
if (block != NULL)
|
|
|
|
return block->base - block->chunk->base;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
ClientMemoryAllocator::Lock()
|
|
|
|
{
|
|
|
|
return fLock.ReadLock();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
ClientMemoryAllocator::Unlock()
|
|
|
|
{
|
|
|
|
fLock.ReadUnlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct block *
|
|
|
|
ClientMemoryAllocator::_AllocateChunk(size_t size, bool& newArea)
|
|
|
|
{
|
|
|
|
// round up to multiple of page size
|
|
|
|
size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
|
|
|
|
|
|
|
|
// At first, try to resize our existing areas
|
|
|
|
|
|
|
|
chunk_iterator iterator = fChunks.GetIterator();
|
|
|
|
struct chunk* chunk;
|
|
|
|
while ((chunk = iterator.Next()) != NULL) {
|
|
|
|
status_t status = resize_area(chunk->area, chunk->size + size);
|
|
|
|
if (status == B_OK) {
|
|
|
|
newArea = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: resize and relocate while holding the write lock
|
|
|
|
|
|
|
|
struct block* block;
|
|
|
|
uint8* address;
|
|
|
|
|
|
|
|
if (chunk == NULL) {
|
|
|
|
// TODO: temporary measurement as long as resizing areas doesn't
|
|
|
|
// work the way we need (with relocating the area, if needed)
|
|
|
|
if (size < B_PAGE_SIZE * 32)
|
|
|
|
size = B_PAGE_SIZE * 32;
|
|
|
|
|
|
|
|
// create new area for this allocation
|
|
|
|
chunk = (struct chunk*)malloc(sizeof(struct chunk));
|
|
|
|
if (chunk == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
block = (struct block*)malloc(sizeof(struct block));
|
|
|
|
if (block == NULL) {
|
|
|
|
free(chunk);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
char name[B_OS_NAME_LENGTH];
|
2006-03-18 18:48:12 +03:00
|
|
|
#ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST
|
|
|
|
strcpy(name, "client heap");
|
|
|
|
#else
|
* Implemented a new client allocation method: instead of having all bitmaps of
all teams in serveral server areas, and instead of having to eventually clone
them all several times in BBitmap, we now have one or more areas per team,
and BBitmap will only clone areas once if needed. As a side effect, this
method should be magnitudes faster than the previous version.
* This method is also much more secure: instead of putting the allocation
maintenance structures into those everyone-read-write areas, they are now
separated, so that faulty applications cannot crash the app_server this
way anymore. This should fix bug #172.
* Freeing memory is not yet implemented though! (although all memory will
be freed upon app exit)
* There are now 3 different bitmap allocation strategies: per ClientMemoryAllocator
(ie. via ServerApp), per area (for overlays, not yet implemented), and using
malloc()/free() for server-only bitmaps.
* ServerBitmap now deletes its buffers itself.
* Cleaned up BBitmap and BApplication a bit.
* The test environment currently doesn't build anymore, will fix it next.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16826 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-03-18 16:43:26 +03:00
|
|
|
snprintf(name, sizeof(name), "heap:%ld:%s", fApplication->ClientTeam(),
|
|
|
|
fApplication->SignatureLeaf());
|
2006-03-18 18:48:12 +03:00
|
|
|
#endif
|
* Implemented a new client allocation method: instead of having all bitmaps of
all teams in serveral server areas, and instead of having to eventually clone
them all several times in BBitmap, we now have one or more areas per team,
and BBitmap will only clone areas once if needed. As a side effect, this
method should be magnitudes faster than the previous version.
* This method is also much more secure: instead of putting the allocation
maintenance structures into those everyone-read-write areas, they are now
separated, so that faulty applications cannot crash the app_server this
way anymore. This should fix bug #172.
* Freeing memory is not yet implemented though! (although all memory will
be freed upon app exit)
* There are now 3 different bitmap allocation strategies: per ClientMemoryAllocator
(ie. via ServerApp), per area (for overlays, not yet implemented), and using
malloc()/free() for server-only bitmaps.
* ServerBitmap now deletes its buffers itself.
* Cleaned up BBitmap and BApplication a bit.
* The test environment currently doesn't build anymore, will fix it next.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16826 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-03-18 16:43:26 +03:00
|
|
|
area_id area = create_area(name, (void**)&address, B_ANY_ADDRESS, size,
|
|
|
|
B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
|
|
|
|
if (area < B_OK) {
|
|
|
|
free(block);
|
|
|
|
free(chunk);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add chunk to list
|
|
|
|
|
|
|
|
chunk->area = area;
|
|
|
|
chunk->base = address;
|
|
|
|
chunk->size = size;
|
|
|
|
|
|
|
|
fChunks.Add(chunk);
|
|
|
|
newArea = true;
|
|
|
|
} else {
|
|
|
|
// create new free block for this chunk
|
|
|
|
block = (struct block *)malloc(sizeof(struct block));
|
|
|
|
if (block == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
address = chunk->base + chunk->size;
|
|
|
|
chunk->size += size;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add block to free list
|
|
|
|
|
|
|
|
block->chunk = chunk;
|
|
|
|
block->base = address;
|
|
|
|
block->size = size;
|
|
|
|
|
|
|
|
fFreeBlocks.Add(block);
|
|
|
|
|
|
|
|
return block;
|
|
|
|
}
|
|
|
|
|