From 577f58763be348b31493bc7266dd9f62c4e40f02 Mon Sep 17 00:00:00 2001 From: czeidler Date: Sun, 22 Jan 2012 14:52:46 +1300 Subject: [PATCH] Make it possible to reconnect BBitmap to the app_server. * maintain a list of all BBitmaps * refactor the client memory allocator class, its possible now to just clone existing client area --- headers/os/interface/Bitmap.h | 4 + headers/private/interface/BitmapPrivate.h | 13 ++ src/kits/interface/Bitmap.cpp | 61 ++++++++ src/servers/app/BitmapManager.cpp | 71 ++++++---- src/servers/app/BitmapManager.h | 5 + src/servers/app/ClientMemoryAllocator.cpp | 164 ++++++++++++++-------- src/servers/app/ClientMemoryAllocator.h | 61 ++++++-- src/servers/app/ServerBitmap.cpp | 21 ++- src/servers/app/ServerBitmap.h | 10 +- 9 files changed, 298 insertions(+), 112 deletions(-) diff --git a/headers/os/interface/Bitmap.h b/headers/os/interface/Bitmap.h index 1a45ba75b5..d519166cda 100644 --- a/headers/os/interface/Bitmap.h +++ b/headers/os/interface/Bitmap.h @@ -110,10 +110,12 @@ public: BBitmap& operator=(const BBitmap& source); + class Private; private: friend class BView; friend class BApplication; friend class BPrivate::BPrivateScreen; + friend class Private; virtual status_t Perform(perform_code d, void* arg); virtual void _ReservedBitmap1(); @@ -127,6 +129,8 @@ private: void _CleanUp(); void _AssertPointer(); + void _ReconnectToAppServer(); + private: uint8* fBasePointer; int32 fSize; diff --git a/headers/private/interface/BitmapPrivate.h b/headers/private/interface/BitmapPrivate.h index a91f76fe89..0ae3abe167 100644 --- a/headers/private/interface/BitmapPrivate.h +++ b/headers/private/interface/BitmapPrivate.h @@ -6,6 +6,7 @@ #define _BITMAP_PRIVATE_H +#include #include @@ -16,4 +17,16 @@ struct overlay_client_data { uint8* buffer; }; + +void reconnect_bitmaps_to_app_server(); + + +class BBitmap::Private { +public: + Private(BBitmap* bitmap); + void ReconnectToAppServer(); +private: + BBitmap* fBitmap; +}; + #endif // _BITMAP_PRIVATE_H diff --git a/src/kits/interface/Bitmap.cpp b/src/kits/interface/Bitmap.cpp index c214162092..09feeda5ff 100644 --- a/src/kits/interface/Bitmap.cpp +++ b/src/kits/interface/Bitmap.cpp @@ -32,6 +32,8 @@ #include #include +#include +#include #include #include @@ -42,6 +44,35 @@ using namespace BPrivate; +static BObjectList sBitmapList; +static BLocker sBitmapListLock; + + +void +reconnect_bitmaps_to_app_server() +{ + BAutolock _(sBitmapListLock); + for (int32 i = 0; i < sBitmapList.CountItems(); i++) { + BBitmap::Private bitmap(sBitmapList.ItemAt(i)); + bitmap.ReconnectToAppServer(); + } +} + + +BBitmap::Private::Private(BBitmap* bitmap) + : + fBitmap(bitmap) +{ +} + + +void +BBitmap::Private::ReconnectToAppServer() +{ + fBitmap->_ReconnectToAppServer(); +} + + /*! \brief Returns the number of bytes per row needed to store the actual bitmap data (not including any padding) given a color space and a row width. @@ -1087,6 +1118,9 @@ BBitmap::_InitObject(BRect bounds, color_space colorSpace, uint32 flags, fAreaOffset = -1; // NOTE: why not "0" in case of error? fFlags = flags; + } else { + BAutolock _(sBitmapListLock); + sBitmapList.AddItem(this); } } fWindow = NULL; @@ -1157,6 +1191,9 @@ BBitmap::_CleanUp() fArea = -1; fServerToken = -1; fAreaOffset = -1; + + BAutolock _(sBitmapListLock); + sBitmapList.RemoveItem(this); } fBasePointer = NULL; } @@ -1174,3 +1211,27 @@ BBitmap::_AssertPointer() } } + +void +BBitmap::_ReconnectToAppServer() +{ + BPrivate::AppServerLink link; + + link.StartMessage(AS_RECONNECT_BITMAP); + link.Attach(fBounds); + link.Attach(fColorSpace); + link.Attach(fFlags); + link.Attach(fBytesPerRow); + link.Attach(0); + link.Attach(fArea); + link.Attach(fAreaOffset); + + status_t error; + if (link.FlushWithReply(error) == B_OK && error == B_OK) { + // server side success + // Get token + link.Read(&fServerToken); + + link.Read(&fServerArea); + } +} diff --git a/src/servers/app/BitmapManager.cpp b/src/servers/app/BitmapManager.cpp index 1d31ccae47..dceaf6bed2 100644 --- a/src/servers/app/BitmapManager.cpp +++ b/src/servers/app/BitmapManager.cpp @@ -68,14 +68,8 @@ BitmapManager::BitmapManager() BitmapManager::~BitmapManager() { int32 count = fBitmapList.CountItems(); - for (int32 i = 0; i < count; i++) { - if (ServerBitmap* bitmap = (ServerBitmap*)fBitmapList.ItemAt(i)) { - if (bitmap->AllocationCookie() != NULL) - debugger("We're not supposed to keep our cookies..."); - - delete bitmap; - } - } + for (int32 i = 0; i < count; i++) + delete (ServerBitmap*)fBitmapList.ItemAt(i); } @@ -94,7 +88,6 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, int32 bytesPerRow, int32 screen, uint8* _allocationFlags) { BAutolock locker(fLock); - if (!locker.IsLocked()) return NULL; @@ -112,7 +105,7 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, } } - ServerBitmap* bitmap = new(nothrow) ServerBitmap(bounds, space, flags, + ServerBitmap* bitmap = new(std::nothrow) ServerBitmap(bounds, space, flags, bytesPerRow); if (bitmap == NULL) { if (overlayToken != NULL) @@ -121,11 +114,10 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, return NULL; } - void* cookie = NULL; uint8* buffer = NULL; if (flags & B_BITMAP_WILL_OVERLAY) { - Overlay* overlay = new (std::nothrow) Overlay(hwInterface, bitmap, + Overlay* overlay = new(std::nothrow) Overlay(hwInterface, bitmap, overlayToken); overlay_client_data* clientData = NULL; @@ -134,32 +126,29 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, if (overlay != NULL && overlay->InitCheck() == B_OK) { // allocate client memory to communicate the overlay semaphore // and buffer location to the BBitmap - cookie = allocator->Allocate(sizeof(overlay_client_data), - (void**)&clientData, newArea); + clientData = (overlay_client_data*)bitmap->fClientMemory.Allocate( + allocator, sizeof(overlay_client_data), newArea); } - if (cookie != NULL) { + if (clientData != NULL) { overlay->SetClientData(clientData); - bitmap->fAllocator = allocator; - bitmap->fAllocationCookie = cookie; + bitmap->fMemory = &bitmap->fClientMemory; bitmap->SetOverlay(overlay); bitmap->fBytesPerRow = overlay->OverlayBuffer()->bytes_per_row; buffer = (uint8*)overlay->OverlayBuffer()->buffer; if (_allocationFlags) *_allocationFlags = kFramebuffer | (newArea ? kNewAllocatorArea : 0); - } else { + } else delete overlay; - allocator->Free(cookie); - } } else if (allocator != NULL) { // standard bitmaps bool newArea; - cookie = allocator->Allocate(bitmap->BitsLength(), (void**)&buffer, newArea); - if (cookie != NULL) { - bitmap->fAllocator = allocator; - bitmap->fAllocationCookie = cookie; + buffer = (uint8*)bitmap->fClientMemory.Allocate(allocator, + bitmap->BitsLength(), newArea); + if (buffer != NULL) { + bitmap->fMemory = &bitmap->fClientMemory; if (_allocationFlags) *_allocationFlags = kAllocator | (newArea ? kNewAllocatorArea : 0); @@ -168,8 +157,7 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, // server side only bitmaps buffer = (uint8*)malloc(bitmap->BitsLength()); if (buffer != NULL) { - bitmap->fAllocator = NULL; - bitmap->fAllocationCookie = NULL; + bitmap->fMemory = NULL; if (_allocationFlags) *_allocationFlags = kHeap; @@ -202,6 +190,37 @@ BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, } +ServerBitmap* +BitmapManager::CloneFromClient(area_id clientArea, int32 areaOffset, + BRect bounds, color_space space, uint32 flags, int32 bytesPerRow) +{ + BAutolock locker(fLock); + if (!locker.IsLocked()) + return NULL; + ServerBitmap* bitmap = new(std::nothrow) ServerBitmap(bounds, space, flags, + bytesPerRow); + if (bitmap == NULL) + return NULL; + + ClonedAreaMemory* memory = new(std::nothrow) ClonedAreaMemory; + if (memory == NULL) { + delete bitmap; + return NULL; + } + int8* buffer = (int8*)memory->Clone(clientArea, areaOffset); + if (buffer == NULL) { + delete bitmap; + delete memory; + return NULL; + } + + bitmap->fMemory = memory; + bitmap->fBuffer = memory->Address(); + bitmap->fToken = gTokenSpace.NewToken(kBitmapToken, bitmap); + return bitmap; +} + + /*! \brief Called when a ServerBitmap is deleted. */ void diff --git a/src/servers/app/BitmapManager.h b/src/servers/app/BitmapManager.h index 9459e9adbe..1b454e0125 100644 --- a/src/servers/app/BitmapManager.h +++ b/src/servers/app/BitmapManager.h @@ -33,6 +33,11 @@ public: int32 screen = B_MAIN_SCREEN_ID.id, uint8* _allocationFlags = NULL); + ServerBitmap* CloneFromClient(area_id clientArea, + int32 areaOffset, BRect bounds, + color_space space, uint32 flags, + int32 bytesPerRow = -1); + void BitmapRemoved(ServerBitmap* bitmap); void SuspendOverlays(); diff --git a/src/servers/app/ClientMemoryAllocator.cpp b/src/servers/app/ClientMemoryAllocator.cpp index 5f43539c73..e7ff90af68 100644 --- a/src/servers/app/ClientMemoryAllocator.cpp +++ b/src/servers/app/ClientMemoryAllocator.cpp @@ -35,8 +35,7 @@ typedef chunk_list::Iterator chunk_iterator; ClientMemoryAllocator::ClientMemoryAllocator(ServerApp* application) : - fApplication(application), - fLock("client memory lock") + fApplication(application) { } @@ -64,15 +63,8 @@ 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) +ClientMemoryAllocator::Allocate(size_t size, block** _address, bool& newArea) { // Search best matching free block from the list @@ -100,8 +92,8 @@ ClientMemoryAllocator::Allocate(size_t size, void** _address, bool& newArea) 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; + *_address = best; + return best->base; } // TODO: maybe we should have the user reserve memory in its object @@ -118,19 +110,17 @@ ClientMemoryAllocator::Allocate(size_t size, void** _address, bool& newArea) best->base += size; best->size -= size; - *_address = usedBlock->base; - return usedBlock; + *_address = usedBlock; + return usedBlock->base; } void -ClientMemoryAllocator::Free(void* cookie) +ClientMemoryAllocator::Free(block* freeBlock) { - if (cookie == NULL) + if (freeBlock == NULL) return; - struct block* freeBlock = (struct block*)cookie; - // search for an adjacent free block block_iterator iterator = fFreeBlocks.GetIterator(); @@ -185,49 +175,9 @@ ClientMemoryAllocator::Free(void* cookie) } -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(); -} - - void ClientMemoryAllocator::Dump() { - AutoReadLocker locker(fLock); - debug_printf("Application %ld, %s: chunks:\n", fApplication->ClientTeam(), fApplication->Signature()); @@ -333,3 +283,101 @@ ClientMemoryAllocator::_AllocateChunk(size_t size, bool& newArea) return block; } + +ClientMemory::ClientMemory() + : + fBlock(NULL) +{ +} + + +ClientMemory::~ClientMemory() +{ + if (fBlock != NULL) + fAllocator->Free(fBlock); +} + + +void* +ClientMemory::Allocate(ClientMemoryAllocator* allocator, size_t size, + bool& newArea) +{ + fAllocator = allocator; + return fAllocator->Allocate(size, &fBlock, newArea); +} + + +area_id +ClientMemory::Area() +{ + if (fBlock != NULL) + return fBlock->chunk->area; + return B_ERROR; +} + + +uint8* +ClientMemory::Address() +{ + if (fBlock != NULL) + return fBlock->base; + return 0; +} + + +uint32 +ClientMemory::AreaOffset() +{ + if (fBlock != NULL) + return fBlock->base - fBlock->chunk->base; + return 0; +} + + +ClonedAreaMemory::ClonedAreaMemory() + : + fClonedArea(-1), + fOffset(0), + fBase(NULL) +{ +} + + +ClonedAreaMemory::~ClonedAreaMemory() +{ + if (fClonedArea >= 0) + delete_area(fClonedArea); +} + + +void* +ClonedAreaMemory::Clone(area_id area, uint32 offset) +{ + fClonedArea = clone_area("server_memory", (void**)&fBase, B_ANY_ADDRESS, + B_READ_AREA | B_WRITE_AREA, area); + if (fBase == NULL) + return NULL; + fOffset = offset; + return Address(); +} + + +area_id +ClonedAreaMemory::Area() +{ + return fClonedArea; +} + + +uint8* +ClonedAreaMemory::Address() +{ + return fBase + fOffset; +} + + +uint32 +ClonedAreaMemory::AreaOffset() +{ + return fOffset; +} diff --git a/src/servers/app/ClientMemoryAllocator.h b/src/servers/app/ClientMemoryAllocator.h index 726ecd7d65..6092b68824 100644 --- a/src/servers/app/ClientMemoryAllocator.h +++ b/src/servers/app/ClientMemoryAllocator.h @@ -39,17 +39,9 @@ public: ClientMemoryAllocator(ServerApp* application); ~ClientMemoryAllocator(); - status_t InitCheck(); - - void* Allocate(size_t size, void** _address, + void* Allocate(size_t size, block** _address, bool& newArea); - void Free(void* cookie); - - area_id Area(void* cookie); - uint32 AreaOffset(void* cookie); - - bool Lock(); - void Unlock(); + void Free(block* cookie); void Dump(); @@ -58,10 +50,57 @@ private: private: ServerApp* fApplication; - MultiLocker fLock; chunk_list fChunks; block_list fFreeBlocks; }; +class AreaMemory { +public: + virtual ~AreaMemory() {} + + virtual area_id Area() = 0; + virtual uint8* Address() = 0; + virtual uint32 AreaOffset() = 0; +}; + + +class ClientMemory : public AreaMemory { +public: + ClientMemory(); + + virtual ~ClientMemory(); + + void* Allocate(ClientMemoryAllocator* allocator, + size_t size, bool& newArea); + + virtual area_id Area(); + virtual uint8* Address(); + virtual uint32 AreaOffset(); + +private: + ClientMemoryAllocator* fAllocator; + block* fBlock; +}; + + +/*! Just clones an existing area. */ +class ClonedAreaMemory : public AreaMemory{ +public: + ClonedAreaMemory(); + virtual ~ClonedAreaMemory(); + + void* Clone(area_id area, uint32 offset); + + virtual area_id Area(); + virtual uint8* Address(); + virtual uint32 AreaOffset(); + +private: + area_id fClonedArea; + uint32 fOffset; + uint8* fBase; +}; + + #endif /* CLIENT_MEMORY_ALLOCATOR_H */ diff --git a/src/servers/app/ServerBitmap.cpp b/src/servers/app/ServerBitmap.cpp index 89358d2fcf..be3806fdb3 100644 --- a/src/servers/app/ServerBitmap.cpp +++ b/src/servers/app/ServerBitmap.cpp @@ -59,8 +59,7 @@ using namespace BPrivate; ServerBitmap::ServerBitmap(BRect rect, color_space space, uint32 flags, int32 bytesPerRow, screen_id screen) : - fAllocator(NULL), - fAllocationCookie(NULL), + fMemory(NULL), fOverlay(NULL), fBuffer(NULL), // WARNING: '1' is added to the width and height. @@ -84,8 +83,7 @@ ServerBitmap::ServerBitmap(BRect rect, color_space space, uint32 flags, //! Copy constructor does not copy the buffer. ServerBitmap::ServerBitmap(const ServerBitmap* bitmap) : - fAllocator(NULL), - fAllocationCookie(NULL), + fMemory(NULL), fOverlay(NULL), fBuffer(NULL), fOwner(NULL) @@ -108,9 +106,10 @@ ServerBitmap::ServerBitmap(const ServerBitmap* bitmap) ServerBitmap::~ServerBitmap() { - if (fAllocator != NULL) - fAllocator->Free(AllocationCookie()); - else + if (fMemory != NULL) { + if (fMemory != &fClientMemory) + delete fMemory; + } else delete[] fBuffer; delete fOverlay; @@ -162,8 +161,8 @@ ServerBitmap::ImportBits(const void *bits, int32 bitsLength, int32 bytesPerRow, area_id ServerBitmap::Area() const { - if (fAllocator != NULL) - return fAllocator->Area(AllocationCookie()); + if (fMemory != NULL) + return fMemory->Area(); return B_ERROR; } @@ -172,8 +171,8 @@ ServerBitmap::Area() const uint32 ServerBitmap::AreaOffset() const { - if (fAllocator != NULL) - return fAllocator->AreaOffset(AllocationCookie()); + if (fMemory != NULL) + return fMemory->AreaOffset(); return 0; } diff --git a/src/servers/app/ServerBitmap.h b/src/servers/app/ServerBitmap.h index f087dfa7da..e3b4b36757 100644 --- a/src/servers/app/ServerBitmap.h +++ b/src/servers/app/ServerBitmap.h @@ -16,9 +16,10 @@ #include +#include "ClientMemoryAllocator.h" + class BitmapManager; -class ClientMemoryAllocator; class HWInterface; class Overlay; class ServerApp; @@ -60,9 +61,6 @@ public: inline int32 Token() const { return fToken; } - inline void* AllocationCookie() const - { return fAllocationCookie; } - area_id Area() const; uint32 AreaOffset() const; @@ -96,8 +94,8 @@ protected: void AllocateBuffer(); protected: - ClientMemoryAllocator* fAllocator; - void* fAllocationCookie; + ClientMemory fClientMemory; + AreaMemory* fMemory; ::Overlay* fOverlay; uint8* fBuffer;