diff --git a/headers/private/app/ApplicationPrivate.h b/headers/private/app/ApplicationPrivate.h index 9fa83838fd..1ef0744192 100644 --- a/headers/private/app/ApplicationPrivate.h +++ b/headers/private/app/ApplicationPrivate.h @@ -1,5 +1,5 @@ /* - * Copyright 2001-2005, Haiku. + * Copyright 2001-2006, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -8,12 +8,17 @@ #ifndef _APPLICATION_PRIVATE_H #define _APPLICATION_PRIVATE_H + #include + class BApplication::Private { -public: - static inline BPrivate::PortLink *ServerLink() - { return be_app->fServerLink; } + public: + static inline BPrivate::PortLink *ServerLink() + { return be_app->fServerLink; } + + static inline BPrivate::ServerMemoryAllocator* ServerAllocator() + { return be_app->fServerAllocator; } }; #endif // _APPLICATION_PRIVATE_H diff --git a/headers/private/app/ServerMemoryAllocator.h b/headers/private/app/ServerMemoryAllocator.h new file mode 100644 index 0000000000..58c7245a06 --- /dev/null +++ b/headers/private/app/ServerMemoryAllocator.h @@ -0,0 +1,35 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef SERVER_MEMORY_ALLOCATOR_H +#define SERVER_MEMORY_ALLOCATOR_H + + +#include +#include + +namespace BPrivate { + +class ServerMemoryAllocator { + public: + ServerMemoryAllocator(); + ~ServerMemoryAllocator(); + + status_t InitCheck(); + + status_t AddArea(area_id serverArea, area_id& _localArea, uint8*& _base); + void RemoveArea(area_id serverArea); + + status_t AreaAndBaseFor(area_id serverArea, area_id& area, uint8*& base); + + private: + BList fAreas; +}; + +} // namespace BPrivate + +#endif /* SERVER_MEMORY_ALLOCATOR_H */ diff --git a/headers/private/app/ServerProtocol.h b/headers/private/app/ServerProtocol.h index 6908757127..fab62566fc 100644 --- a/headers/private/app/ServerProtocol.h +++ b/headers/private/app/ServerProtocol.h @@ -318,4 +318,12 @@ enum { AS_LAST_CODE }; +// bitmap allocation types +enum { + kAllocator, + kNewAllocatorArea, + kArea, + kHeap +}; + #endif // APP_SERVER_PROTOCOL_H diff --git a/headers/private/servers/app/BitmapManager.h b/headers/private/servers/app/BitmapManager.h index 12371f5bd5..74ed2ba983 100644 --- a/headers/private/servers/app/BitmapManager.h +++ b/headers/private/servers/app/BitmapManager.h @@ -1,12 +1,12 @@ /* - * Copyright 2001-2005, Haiku. + * Copyright 2001-2006, Haiku. * Distributed under the terms of the MIT License. * * Authors: * DarkWyrm */ -#ifndef BITMAP_MANAGER_H_ -#define BITMAP_MANAGER_H_ +#ifndef BITMAP_MANAGER_H +#define BITMAP_MANAGER_H #include @@ -15,28 +15,25 @@ #include #include -#include "BGet++.h" - +class ClientMemoryAllocator; class ServerBitmap; - class BitmapManager { public: BitmapManager(); virtual ~BitmapManager(); - ServerBitmap* CreateBitmap(BRect bounds, color_space space, - int32 flags, int32 bytesPerRow = -1, - screen_id screen = B_MAIN_SCREEN_ID); + ServerBitmap* CreateBitmap(ClientMemoryAllocator* allocator, BRect bounds, + color_space space, int32 flags, int32 bytesPerRow = -1, + screen_id screen = B_MAIN_SCREEN_ID, + int8* _allocationType = NULL); void DeleteBitmap(ServerBitmap* bitmap); protected: BList fBitmapList; - int8* fBuffer; BLocker fLock; - AreaPool fMemPool; }; extern BitmapManager *gBitmapManager; -#endif /* BITMAP_MANAGER_H_ */ +#endif /* BITMAP_MANAGER_H */ diff --git a/headers/private/servers/app/ServerBitmap.h b/headers/private/servers/app/ServerBitmap.h index 4c7e375fb4..51606a42f8 100644 --- a/headers/private/servers/app/ServerBitmap.h +++ b/headers/private/servers/app/ServerBitmap.h @@ -5,8 +5,8 @@ * Authors: * DarkWyrm */ -#ifndef _SERVER_BITMAP_H_ -#define _SERVER_BITMAP_H_ +#ifndef SERVER_BITMAP_H +#define SERVER_BITMAP_H #include @@ -15,6 +15,7 @@ class BitmapManager; +class ClientMemoryAllocator; /*! \class ServerBitmap ServerBitmap.h @@ -31,11 +32,6 @@ class ServerBitmap { void Acquire(); - inline area_id Area() const - { return fArea; } - inline int32 AreaOffset() const - { return fOffset; } - inline uint8* Bits() const { return fBuffer; } inline uint32 BitsLength() const @@ -59,6 +55,12 @@ class ServerBitmap { inline int32 Token() const { return fToken; } + inline void* AllocationCookie() const + { return fAllocationCookie; } + + area_id Area() const; + uint32 AreaOffset() const; + //! Does a shallow copy of the bitmap passed to it inline void ShallowCopy(const ServerBitmap *from); @@ -84,23 +86,19 @@ protected: virtual ~ServerBitmap(); //! used by the BitmapManager - inline void _SetArea(area_id ID) - { fArea = ID; } - - //! used by the BitmapManager - inline void _SetBuffer(void *ptr) - { fBuffer = (uint8*)ptr; } +// inline void _SetBuffer(void *ptr) +// { fBuffer = (uint8*)ptr; } bool _Release(); void _AllocateBuffer(); - void _FreeBuffer(); void _HandleSpace(color_space space, int32 bytesperline = -1); bool fInitialized; - area_id fArea; + ClientMemoryAllocator* fAllocator; + void* fAllocationCookie; uint8* fBuffer; int32 fReferenceCount; @@ -111,7 +109,6 @@ protected: int32 fFlags; int fBitsPerPixel; int32 fToken; - int32 fOffset; }; class UtilityBitmap : public ServerBitmap { @@ -140,7 +137,6 @@ ServerBitmap::ShallowCopy(const ServerBitmap* from) return; fInitialized = from->fInitialized; - fArea = from->fArea; fBuffer = from->fBuffer; fWidth = from->fWidth; fHeight = from->fHeight; @@ -149,8 +145,6 @@ ServerBitmap::ShallowCopy(const ServerBitmap* from) fFlags = from->fFlags; fBitsPerPixel = from->fBitsPerPixel; fToken = from->fToken; - fOffset = from->fOffset; } - -#endif // _SERVER_BITMAP_H_ +#endif // SERVER_BITMAP_H diff --git a/src/kits/app/Application.cpp b/src/kits/app/Application.cpp index fda5a86234..2e0d18dd6b 100644 --- a/src/kits/app/Application.cpp +++ b/src/kits/app/Application.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2005, Haiku. + * Copyright 2001-2006, Haiku. * Distributed under the terms of the MIT License. * * Authors: @@ -36,6 +36,7 @@ #include #include #include +#include #include using namespace BPrivate; @@ -162,14 +163,14 @@ static void fill_argv_message(BMessage &message); BApplication::BApplication(const char *signature) : BLooper(looper_name_for(signature)) { - InitData(signature, true, NULL); + _InitData(signature, true, NULL); } BApplication::BApplication(const char *signature, status_t *_error) : BLooper(looper_name_for(signature)) { - InitData(signature, true, _error); + _InitData(signature, true, _error); } @@ -177,7 +178,7 @@ BApplication::BApplication(const char *signature, bool initGUI, status_t *_error) : BLooper(looper_name_for(signature)) { - InitData(signature, initGUI, _error); + _InitData(signature, initGUI, _error); } @@ -189,7 +190,7 @@ BApplication::BApplication(BMessage *data) const char *signature = NULL; data->FindString("mime_sig", &signature); - InitData(signature, true, NULL); + _InitData(signature, true, NULL); bigtime_t pulseRate; if (data->FindInt64("_pulse", &pulseRate) == B_OK) @@ -213,7 +214,7 @@ BApplication::~BApplication() Lock(); // tell all loopers(usually windows) to quit. Also, wait for them. - quit_all_windows(true); + _QuitAllWindows(true); // unregister from the roster BRoster::Private().RemoveApp(Team()); @@ -242,7 +243,7 @@ BApplication::operator=(const BApplication &rhs) void -BApplication::InitData(const char *signature, bool initGUI, status_t *_error) +BApplication::_InitData(const char *signature, bool initGUI, status_t *_error) { DBG(OUT("BApplication::InitData(`%s', %p)\n", signature, _error)); // check whether there exists already an application @@ -250,9 +251,9 @@ BApplication::InitData(const char *signature, bool initGUI, status_t *_error) debugger("2 BApplication objects were created. Only one is allowed."); fServerLink = new BPrivate::PortLink(-1, -1); - fServerHeap = NULL; + fServerAllocator = NULL; fInitialWorkspace = 0; - fDraggedMessage = NULL; + //fDraggedMessage = NULL; fReadyToRunCalled = false; // initially, there is no pulse @@ -536,7 +537,7 @@ BApplication::Quit() bool BApplication::QuitRequested() { - return quit_all_windows(false); + return _QuitAllWindows(false); } @@ -693,7 +694,7 @@ BApplication::SetCursor(const BCursor *cursor, bool sync) int32 BApplication::CountWindows() const { - return count_windows(false); + return _CountWindows(false); // we're ignoring menu windows } @@ -701,7 +702,7 @@ BApplication::CountWindows() const BWindow * BApplication::WindowAt(int32 index) const { - return window_at(index, false); + return _WindowAt(index, false); // we're ignoring menu windows } @@ -794,7 +795,7 @@ BApplication::DispatchMessage(BMessage *message, BHandler *handler) switch (message->what) { case B_ARGV_RECEIVED: - do_argv(message); + _ArgvReceived(message); break; case B_REFS_RECEIVED: @@ -974,37 +975,13 @@ BApplication::EndRectTracking() status_t -BApplication::setup_server_heaps() +BApplication::_SetupServerAllocator() { - // TODO: implement? + fServerAllocator = new (std::nothrow) BPrivate::ServerMemoryAllocator(); + if (fServerAllocator == NULL) + return B_NO_MEMORY; - // We may not need to implement this function or the XX_offs_to_ptr functions. - // R5 sets up a couple of areas for various tasks having to do with the - // app_server. Currently (7/29/04), the R1 app_server does not do this and - // may never do this unless a significant need is found for it. --DW - - return B_OK; -} - - -void * -BApplication::rw_offs_to_ptr(uint32 offset) -{ - return NULL; // TODO: implement -} - - -void * -BApplication::ro_offs_to_ptr(uint32 offset) -{ - return NULL; // TODO: implement -} - - -void * -BApplication::global_ro_offs_to_ptr(uint32 offset) -{ - return NULL; // TODO: implement + return fServerAllocator->InitCheck(); } @@ -1012,11 +989,11 @@ status_t BApplication::_InitGUIContext() { // An app_server connection is necessary for a lot of stuff, so get that first. - status_t error = connect_to_app_server(); + status_t error = _ConnectToServer(); if (error != B_OK) return error; - error = setup_server_heaps(); + error = _SetupServerAllocator(); if (error != B_OK) return error; @@ -1030,6 +1007,7 @@ BApplication::_InitGUIContext() B_CURSOR_SYSTEM_DEFAULT = new BCursor(B_HAND_CURSOR); B_CURSOR_I_BEAM = new BCursor(B_I_BEAM_CURSOR); + // TODO: would be nice to get the workspace at launch time from the registrar fInitialWorkspace = current_workspace(); return B_OK; @@ -1037,7 +1015,7 @@ BApplication::_InitGUIContext() status_t -BApplication::connect_to_app_server() +BApplication::_ConnectToServer() { port_id serverPort = find_port(SERVER_PORT_NAME); if (serverPort < B_OK) @@ -1096,7 +1074,7 @@ BApplication::connect_to_app_server() return B_OK; } - +#if 0 void BApplication::send_drag(BMessage *message, int32 vs_token, BPoint offset, BRect dragRect, BHandler *replyTo) @@ -1118,10 +1096,10 @@ BApplication::write_drag(_BSession_ *session, BMessage *message) { // TODO: implement } - +#endif bool -BApplication::window_quit_loop(bool quitFilePanels, bool force) +BApplication::_WindowQuitLoop(bool quitFilePanels, bool force) { BList looperList; { @@ -1173,7 +1151,7 @@ BApplication::window_quit_loop(bool quitFilePanels, bool force) bool -BApplication::quit_all_windows(bool force) +BApplication::_QuitAllWindows(bool force) { AssertLocked(); @@ -1181,9 +1159,9 @@ BApplication::quit_all_windows(bool force) // allowed to lock the application - which would cause a deadlock Unlock(); - bool quit = window_quit_loop(false, force); + bool quit = _WindowQuitLoop(false, force); if (!quit) - quit = window_quit_loop(true, force); + quit = _WindowQuitLoop(true, force); Lock(); @@ -1192,12 +1170,8 @@ BApplication::quit_all_windows(bool force) void -BApplication::do_argv(BMessage *message) +BApplication::_ArgvReceived(BMessage *message) { - // TODO: Consider renaming this function to something - // a bit more descriptive, like "handle_argv_message()", - // or "HandleArgvMessage()" - ASSERT(message != NULL); // build the argv vector @@ -1242,11 +1216,11 @@ BApplication::InitialWorkspace() int32 -BApplication::count_windows(bool includeMenus) const +BApplication::_CountWindows(bool includeMenus) const { int32 count = 0; BList windowList; - if (get_window_list(&windowList, includeMenus) == B_OK) + if (_GetWindowList(&windowList, includeMenus) == B_OK) count = windowList.CountItems(); return count; @@ -1254,11 +1228,11 @@ BApplication::count_windows(bool includeMenus) const BWindow * -BApplication::window_at(uint32 index, bool includeMenus) const +BApplication::_WindowAt(uint32 index, bool includeMenus) const { BList windowList; BWindow *window = NULL; - if (get_window_list(&windowList, includeMenus) == B_OK) { + if (_GetWindowList(&windowList, includeMenus) == B_OK) { if ((int32)index < windowList.CountItems()) window = static_cast(windowList.ItemAt(index)); } @@ -1268,7 +1242,7 @@ BApplication::window_at(uint32 index, bool includeMenus) const status_t -BApplication::get_window_list(BList *list, bool includeMenus) const +BApplication::_GetWindowList(BList *list, bool includeMenus) const { ASSERT(list); @@ -1291,15 +1265,11 @@ BApplication::get_window_list(BList *list, bool includeMenus) const } -int32 -BApplication::async_quit_entry(void *data) -{ - return 0; // TODO: implement? not implemented? -} +// #pragma mark - -// check_app_signature -/*! \brief Checks whether the supplied string is a valid application signature. +/*! + \brief Checks whether the supplied string is a valid application signature. An error message is printed, if the string is no valid app signature. @@ -1308,9 +1278,7 @@ BApplication::async_quit_entry(void *data) - \c B_OK: \a signature is a valid app signature. - \c B_BAD_VALUE: \a signature is \c NULL or no valid app signature. */ - -static -status_t +static status_t check_app_signature(const char *signature) { bool isValid = false; @@ -1328,17 +1296,15 @@ check_app_signature(const char *signature) } -// looper_name_for -/*! \brief Returns the looper name for a given signature. +/*! + \brief Returns the looper name for a given signature. Normally this is "AppLooperPort", but in case of the registrar a special name. \return The looper name. */ - -static -const char * +static const char * looper_name_for(const char *signature) { if (signature && !strcasecmp(signature, kRegistrarSignature)) @@ -1347,12 +1313,10 @@ looper_name_for(const char *signature) } -// fill_argv_message -/*! \brief Fills the passed BMessage with B_ARGV_RECEIVED infos. +/*! + \brief Fills the passed BMessage with B_ARGV_RECEIVED infos. */ - -static -void +static void fill_argv_message(BMessage &message) { message.what = B_ARGV_RECEIVED; diff --git a/src/kits/app/Jamfile b/src/kits/app/Jamfile index 0b18df7844..43afa4ee67 100644 --- a/src/kits/app/Jamfile +++ b/src/kits/app/Jamfile @@ -18,8 +18,8 @@ if $(RUN_WITHOUT_APP_SERVER) != 0 { } UsePrivateHeaders shared app interface ; -UsePrivateHeaders [ FDirName kernel util ] ; # For KMessage.h UsePrivateHeaders [ FDirName servers app ] ; +UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ; SetSubDirSupportedPlatforms haiku libbe_test ; @@ -56,6 +56,7 @@ MergeObject app_kit.o : Server.cpp ServerLink.cpp ServerMemIO.cpp + ServerMemoryAllocator.cpp TokenSpace.cpp TypeConstants.cpp ; diff --git a/src/kits/app/Message.cpp b/src/kits/app/Message.cpp index 774959854c..7069b6b2ab 100644 --- a/src/kits/app/Message.cpp +++ b/src/kits/app/Message.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2005, Haiku Inc. All rights reserved. + * Copyright 2005-2006, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -26,6 +25,7 @@ #include #include #include +#include #include #include diff --git a/src/kits/app/ServerMemoryAllocator.cpp b/src/kits/app/ServerMemoryAllocator.cpp new file mode 100644 index 0000000000..274ca002e1 --- /dev/null +++ b/src/kits/app/ServerMemoryAllocator.cpp @@ -0,0 +1,123 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + +/*! + Note, this class don't provide any locking whatsoever - you are + supposed to have a BPrivate::AppServerLink object around which + does the necessary locking. + However, this is not enforced in the methods here, you have to + take care for yourself! +*/ + +#include "ServerMemoryAllocator.h" + +#include + +#include + + +namespace BPrivate { + +struct area_mapping { + area_id server_area; + area_id local_area; + uint8* local_base; +}; + + +ServerMemoryAllocator::ServerMemoryAllocator() + : + fAreas(4) +{ +} + + +ServerMemoryAllocator::~ServerMemoryAllocator() +{ + for (int32 i = fAreas.CountItems(); i-- > 0;) { + area_mapping* mapping = (area_mapping*)fAreas.ItemAt(i); + + delete_area(mapping->local_area); + delete mapping; + } +} + + +status_t +ServerMemoryAllocator::InitCheck() +{ + return B_OK; +} + + +status_t +ServerMemoryAllocator::AddArea(area_id serverArea, area_id& _area, uint8*& _base) +{ + area_mapping* mapping = new (std::nothrow) area_mapping; + if (mapping == NULL || !fAreas.AddItem(mapping)) { + delete mapping; + return B_NO_MEMORY; + } + + // reserve 128 MB of space for the area + void* base = (void*)0x60000000; + status_t status = _kern_reserve_heap_address_range((addr_t*)&base, + B_BASE_ADDRESS, 128 * 1024 * 1024); + + mapping->local_area = clone_area("server_memory", &base, + status == B_OK ? B_EXACT_ADDRESS : B_BASE_ADDRESS, + B_READ_AREA | B_WRITE_AREA, serverArea); + if (mapping->local_area < B_OK) { + status = mapping->local_area; + delete mapping; + return status; + } + + mapping->server_area = serverArea; + mapping->local_base = (uint8*)base; + + _area = mapping->local_area; + _base = mapping->local_base; + + return B_OK; +} + + +void +ServerMemoryAllocator::RemoveArea(area_id serverArea) +{ + for (int32 i = fAreas.CountItems(); i-- > 0;) { + area_mapping* mapping = (area_mapping*)fAreas.ItemAt(i); + + if (mapping->server_area == serverArea) { + // we found the area we should remove + delete_area(mapping->local_area); + delete mapping; + break; + } + } +} + + +status_t +ServerMemoryAllocator::AreaAndBaseFor(area_id serverArea, area_id& _area, uint8*& _base) +{ + for (int32 i = fAreas.CountItems(); i-- > 0;) { + area_mapping* mapping = (area_mapping*)fAreas.ItemAt(i); + + if (mapping->server_area == serverArea) { + _area = mapping->local_area; + _base = mapping->local_base; + return B_OK; + } + } + + return B_ERROR; +} + +} // namespace BPrivate diff --git a/src/kits/interface/Bitmap.cpp b/src/kits/interface/Bitmap.cpp index 98d2fa390e..8ee838f1bf 100644 --- a/src/kits/interface/Bitmap.cpp +++ b/src/kits/interface/Bitmap.cpp @@ -1,22 +1,20 @@ /* - * Copyright 2001-2005, Haiku Inc. + * Copyright 2001-2006, Haiku Inc. * Distributed under the terms of the MIT License. * * Authors: * Ingo Weinhold (bonefish@users.sf.net) * DarkWyrm * Stephan Aßmus + * Axel Dörfler, axeld@pinc-software.de */ -/** BBitmap objects represent off-screen windows that - * contain bitmap data. - */ +/*! + BBitmap objects represent off-screen windows that + contain bitmap data. +*/ -#include -#include -#include -#include -#include +#include "ColorConversion.h" #include #include @@ -25,11 +23,16 @@ #include #include -#include "ColorConversion.h" - -// Includes to be able to talk to the app_server -#include +#include #include +#include +#include + +#include +#include +#include +#include +#include // get_raw_bytes_per_row @@ -112,7 +115,9 @@ get_bytes_per_row(color_space colorSpace, int32 width) } -// constructor +// #pragma mark - + + /*! \brief Creates and initializes a BBitmap. \param bounds The bitmap dimensions. \param flags Creation flags. @@ -124,7 +129,7 @@ get_bytes_per_row(color_space colorSpace, int32 width) */ BBitmap::BBitmap(BRect bounds, uint32 flags, color_space colorSpace, int32 bytesPerRow, screen_id screenID) - : fBasePtr(NULL), + : fBasePointer(NULL), fSize(0), fColorSpace(B_NO_COLOR_SPACE), fBounds(0, 0, -1, -1), @@ -133,11 +138,11 @@ BBitmap::BBitmap(BRect bounds, uint32 flags, color_space colorSpace, fServerToken(-1), fAreaOffset(-1), fArea(-1), - fOrigArea(-1), + fServerArea(-1), fFlags(0), fInitError(B_NO_INIT) { - InitObject(bounds, colorSpace, flags, bytesPerRow, screenID); + _InitObject(bounds, colorSpace, flags, bytesPerRow, screenID); } // constructor @@ -152,7 +157,7 @@ BBitmap::BBitmap(BRect bounds, uint32 flags, color_space colorSpace, */ BBitmap::BBitmap(BRect bounds, color_space colorSpace, bool acceptsViews, bool needsContiguous) - : fBasePtr(NULL), + : fBasePointer(NULL), fSize(0), fColorSpace(B_NO_COLOR_SPACE), fBounds(0, 0, -1, -1), @@ -161,13 +166,13 @@ BBitmap::BBitmap(BRect bounds, color_space colorSpace, bool acceptsViews, fServerToken(-1), fAreaOffset(-1), fArea(-1), - fOrigArea(-1), + fServerArea(-1), fFlags(0), fInitError(B_NO_INIT) { int32 flags = (acceptsViews ? B_BITMAP_ACCEPTS_VIEWS : 0) | (needsContiguous ? B_BITMAP_IS_CONTIGUOUS : 0); - InitObject(bounds, colorSpace, flags, B_ANY_BYTES_PER_ROW, + _InitObject(bounds, colorSpace, flags, B_ANY_BYTES_PER_ROW, B_MAIN_SCREEN_ID); } @@ -183,7 +188,7 @@ BBitmap::BBitmap(BRect bounds, color_space colorSpace, bool acceptsViews, */ BBitmap::BBitmap(const BBitmap *source, bool acceptsViews, bool needsContiguous) - : fBasePtr(NULL), + : fBasePointer(NULL), fSize(0), fColorSpace(B_NO_COLOR_SPACE), fBounds(0, 0, -1, -1), @@ -192,14 +197,14 @@ BBitmap::BBitmap(const BBitmap *source, bool acceptsViews, fServerToken(-1), fAreaOffset(-1), fArea(-1), - fOrigArea(-1), + fServerArea(-1), fFlags(0), fInitError(B_NO_INIT) { if (source && source->IsValid()) { int32 flags = (acceptsViews ? B_BITMAP_ACCEPTS_VIEWS : 0) | (needsContiguous ? B_BITMAP_IS_CONTIGUOUS : 0); - InitObject(source->Bounds(), source->ColorSpace(), flags, + _InitObject(source->Bounds(), source->ColorSpace(), flags, source->BytesPerRow(), B_MAIN_SCREEN_ID); if (InitCheck() == B_OK) memcpy(Bits(), source->Bits(), BytesPerRow()); @@ -212,7 +217,7 @@ BBitmap::BBitmap(const BBitmap *source, bool acceptsViews, BBitmap::~BBitmap() { delete fWindow; - CleanUp(); + _CleanUp(); } // unarchiving constructor @@ -221,7 +226,7 @@ BBitmap::~BBitmap() */ BBitmap::BBitmap(BMessage *data) : BArchivable(data), - fBasePtr(NULL), + fBasePointer(NULL), fSize(0), fColorSpace(B_NO_COLOR_SPACE), fBounds(0, 0, -1, -1), @@ -230,7 +235,7 @@ BBitmap::BBitmap(BMessage *data) fServerToken(-1), fAreaOffset(-1), fArea(-1), - fOrigArea(-1), + fServerArea(-1), fFlags(0), fInitError(B_NO_INIT) { @@ -246,14 +251,14 @@ BBitmap::BBitmap(BMessage *data) int32 rowBytes = 0; data->FindInt32("_rowbytes", &rowBytes); - InitObject(bounds, cspace, flags, rowBytes, B_MAIN_SCREEN_ID); + _InitObject(bounds, cspace, flags, rowBytes, B_MAIN_SCREEN_ID); if (data->HasData("_data", B_RAW_TYPE) && InitCheck() == B_OK) { - AssertPtr(); + _AssertPointer(); ssize_t size = 0; const void *buffer; if (data->FindData("_data", B_RAW_TYPE, &buffer, &size) == B_OK) - memcpy(fBasePtr, buffer, size); + memcpy(fBasePointer, buffer, size); } if (fFlags & B_BITMAP_ACCEPTS_VIEWS) { @@ -311,8 +316,8 @@ BBitmap::Archive(BMessage *data, bool deep) const // true and it does save all formats as B_RAW_TYPE and it does save // the data even if B_BITMAP_ACCEPTS_VIEWS is set (as opposed to // the BeBook) - const_cast(this)->AssertPtr(); - data->AddData("_data", B_RAW_TYPE, fBasePtr, fSize); + const_cast(this)->_AssertPointer(); + data->AddData("_data", B_RAW_TYPE, fBasePointer, fSize); } return B_OK; @@ -363,7 +368,7 @@ BBitmap::UnlockBits() area_id BBitmap::Area() const { - const_cast(this)->AssertPtr(); + const_cast(this)->_AssertPointer(); return fArea; } @@ -374,8 +379,8 @@ BBitmap::Area() const void * BBitmap::Bits() const { - const_cast(this)->AssertPtr(); - return fBasePtr; + const_cast(this)->_AssertPointer(); + return (void*)fBasePointer; } // BitsLength @@ -501,7 +506,7 @@ status_t BBitmap::ImportBits(const void *data, int32 length, int32 bpr, int32 offset, color_space colorSpace) { - AssertPtr(); + _AssertPointer(); if (InitCheck() != B_OK) return B_NO_INIT; @@ -513,7 +518,7 @@ BBitmap::ImportBits(const void *data, int32 length, int32 bpr, int32 offset, if (bpr < 0) bpr = get_bytes_per_row(colorSpace, width); - return BPrivate::ConvertBits(data, (uint8*)fBasePtr + offset, length, + return BPrivate::ConvertBits(data, (uint8*)fBasePointer + offset, length, fSize - offset, bpr, fBytesPerRow, colorSpace, fColorSpace, width, fBounds.IntegerHeight() + 1); } @@ -545,7 +550,7 @@ status_t BBitmap::ImportBits(const void *data, int32 length, int32 bpr, color_space colorSpace, BPoint from, BPoint to, int32 width, int32 height) { - AssertPtr(); + _AssertPointer(); if (InitCheck() != B_OK) return B_NO_INIT; @@ -556,7 +561,7 @@ BBitmap::ImportBits(const void *data, int32 length, int32 bpr, if (bpr < 0) bpr = get_bytes_per_row(colorSpace, fBounds.IntegerWidth() + 1); - return BPrivate::ConvertBits(data, fBasePtr, length, fSize, bpr, + return BPrivate::ConvertBits(data, fBasePointer, length, fSize, bpr, fBytesPerRow, colorSpace, fColorSpace, from, to, width, height); } @@ -783,6 +788,7 @@ BBitmap::operator=(const BBitmap &) return *this; } +#if 0 // get_shared_pointer /*! \brief ??? */ @@ -791,17 +797,15 @@ BBitmap::get_shared_pointer() const { return NULL; // not implemented } +#endif -// get_server_token -/*! \brief ??? -*/ int32 -BBitmap::get_server_token() const +BBitmap::_ServerToken() const { return fServerToken; } -// InitObject + /*! \brief Initializes the bitmap. \param bounds The bitmap dimensions. \param colorSpace The bitmap's color space. @@ -812,7 +816,7 @@ BBitmap::get_server_token() const \param screenID ??? */ void -BBitmap::InitObject(BRect bounds, color_space colorSpace, uint32 flags, +BBitmap::_InitObject(BRect bounds, color_space colorSpace, uint32 flags, int32 bytesPerRow, screen_id screenID) { //printf("BBitmap::InitObject(bounds: BRect(%.1f, %.1f, %.1f, %.1f), format: %ld, flags: %ld, bpr: %ld\n", @@ -826,7 +830,7 @@ BBitmap::InitObject(BRect bounds, color_space colorSpace, uint32 flags, flags |= B_BITMAP_NO_SERVER_LINK; #endif // RUN_WITHOUT_APP_SERVER - CleanUp(); + _CleanUp(); // check params if (!bounds.IsValid() || !bitmaps_support_space(colorSpace, NULL)) { @@ -857,8 +861,8 @@ BBitmap::InitObject(BRect bounds, color_space colorSpace, uint32 flags, int32 size = bytesPerRow * (bounds.IntegerHeight() + 1); if (flags & B_BITMAP_NO_SERVER_LINK) { - fBasePtr = malloc(size); - if (fBasePtr) { + fBasePointer = (uint8*)malloc(size); + if (fBasePointer) { fSize = size; fColorSpace = colorSpace; fBounds = bounds; @@ -883,34 +887,51 @@ BBitmap::InitObject(BRect bounds, color_space colorSpace, uint32 flags, link.Attach(bytesPerRow); link.Attach(screenID.id); - // Reply Data: - // 1) int32 server token - // 2) area_id id of the area in which the bitmap data resides - // 3) int32 area pointer offset used to calculate fBasePtr - - error = B_ERROR; if (link.FlushWithReply(error) == B_OK && error == B_OK) { // server side success // Get token link.Read(&fServerToken); - link.Read(&fOrigArea); - link.Read(&fAreaOffset); - - if (fOrigArea >= B_OK) { + + int8 allocationType; + link.Read(&allocationType); + + if (allocationType == kArea) { + // TODO: implement me (server-side as well), needed for overlays + fServerArea = B_ERROR; + fAreaOffset = -1; + // that signals the cleanup code to delete our area + fBasePointer = NULL; + } else { + link.Read(&fServerArea); + link.Read(&fAreaOffset); + + BPrivate::ServerMemoryAllocator* allocator + = BApplication::Private::ServerAllocator(); + + if (allocationType == kNewAllocatorArea) + error = allocator->AddArea(fServerArea, fArea, fBasePointer); + else { + error = allocator->AreaAndBaseFor(fServerArea, fArea, fBasePointer); + if (error == B_OK) + fBasePointer += fAreaOffset; + } + } + + if (fServerArea >= B_OK) { fSize = size; fColorSpace = colorSpace; fBounds = bounds; fBytesPerRow = bytesPerRow; fFlags = flags; } else - error = fOrigArea; + error = fServerArea; } if (error < B_OK) { - fBasePtr = NULL; + fBasePointer = NULL; fServerToken = -1; fArea = -1; - fOrigArea = -1; + fServerArea = -1; fAreaOffset = -1; // NOTE: why not "0" in case of error? fFlags = flags; @@ -940,13 +961,13 @@ BBitmap::InitObject(BRect bounds, color_space colorSpace, uint32 flags, informs the server to do so as well (if needed). */ void -BBitmap::CleanUp() +BBitmap::_CleanUp() { - if (fBasePtr == NULL) + if (fBasePointer == NULL) return; if (fFlags & B_BITMAP_NO_SERVER_LINK) { - free(fBasePtr); + free(fBasePointer); } else { BPrivate::AppServerLink link; // AS_DELETE_BITMAP: @@ -955,32 +976,31 @@ BBitmap::CleanUp() link.StartMessage(AS_DELETE_BITMAP); link.Attach(fServerToken); link.Flush(); - - if (fArea >= 0) + + // TODO: we may want to delete parts of the server memory areas here! + + if (fAreaOffset == -1) { + // we own that area, so we have to delete it delete_area(fArea); + } + fArea = -1; fServerToken = -1; fAreaOffset = -1; } - fBasePtr = NULL; + fBasePointer = NULL; } void -BBitmap::AssertPtr() +BBitmap::_AssertPointer() { - if (fBasePtr == NULL && fAreaOffset != -1 && InitCheck() == B_OK) { - // Offset was saved into "fArea" as we can't add - // any member variable due to Binary compatibility - // Get the area in which the data resides - fArea = clone_area("shared bitmap area", (void **)&fBasePtr, B_ANY_ADDRESS, - B_READ_AREA | B_WRITE_AREA, fOrigArea); - - if (fArea >= B_OK) { - // Jump to the location in the area - fBasePtr = (int8 *)fBasePtr + fAreaOffset; - } else - fBasePtr = NULL; + if (fBasePointer == NULL && fServerArea >= B_OK && fAreaOffset == -1) { + // We lazily clone our own areas - if the bitmap is part of the usual + // server memory area, or is a B_BITMAP_NO_SERVER_LINK bitmap, it already + // has its data. + fArea = clone_area("shared bitmap area", (void **)&fBasePointer, B_ANY_ADDRESS, + B_READ_AREA | B_WRITE_AREA, fServerArea); } } diff --git a/src/kits/interface/PrivateScreen.cpp b/src/kits/interface/PrivateScreen.cpp index cebbab6594..99d47380ad 100644 --- a/src/kits/interface/PrivateScreen.cpp +++ b/src/kits/interface/PrivateScreen.cpp @@ -338,7 +338,7 @@ BPrivateScreen::ReadBitmap(BBitmap *bitmap, bool drawCursor, BRect *bounds) BPrivate::AppServerLink link; link.StartMessage(AS_READ_BITMAP); - link.Attach(bitmap->get_server_token()); + link.Attach(bitmap->_ServerToken()); link.Attach(drawCursor); link.Attach(rect); diff --git a/src/kits/interface/View.cpp b/src/kits/interface/View.cpp index db08174242..be49b4df60 100644 --- a/src/kits/interface/View.cpp +++ b/src/kits/interface/View.cpp @@ -1331,7 +1331,7 @@ BView::DragMessage(BMessage *message, BBitmap *image, message->Flatten(buffer, bufferSize); fOwner->fLink->StartMessage(AS_LAYER_DRAG_IMAGE); - fOwner->fLink->Attach(image->get_server_token()); + fOwner->fLink->Attach(image->_ServerToken()); fOwner->fLink->Attach((int32)dragMode); fOwner->fLink->Attach(offset); fOwner->fLink->Attach(bufferSize); @@ -2235,7 +2235,7 @@ BView::DrawBitmapAsync(const BBitmap *bitmap, BRect srcRect, BRect dstRect) check_lock(); fOwner->fLink->StartMessage(AS_LAYER_DRAW_BITMAP); - fOwner->fLink->Attach(bitmap->get_server_token()); + fOwner->fLink->Attach(bitmap->_ServerToken()); fOwner->fLink->Attach(dstRect); fOwner->fLink->Attach(srcRect); @@ -2268,7 +2268,7 @@ BView::DrawBitmapAsync(const BBitmap *bitmap, BPoint where) check_lock(); fOwner->fLink->StartMessage(AS_LAYER_DRAW_BITMAP); - fOwner->fLink->Attach(bitmap->get_server_token()); + fOwner->fLink->Attach(bitmap->_ServerToken()); BRect src = bitmap->Bounds(); BRect dst = src.OffsetToCopy(where); fOwner->fLink->Attach(dst); @@ -4320,7 +4320,7 @@ BView::_SetViewBitmap(const BBitmap* bitmap, BRect srcRect, if (!do_owner_check()) return B_ERROR; - int32 serverToken = bitmap ? bitmap->get_server_token() : -1; + int32 serverToken = bitmap ? bitmap->_ServerToken() : -1; fOwner->fLink->StartMessage(AS_LAYER_SET_VIEW_BITMAP); fOwner->fLink->Attach(serverToken); diff --git a/src/servers/app/BitmapManager.cpp b/src/servers/app/BitmapManager.cpp index ae1f8e3aa5..68ee91aa98 100644 --- a/src/servers/app/BitmapManager.cpp +++ b/src/servers/app/BitmapManager.cpp @@ -1,18 +1,19 @@ /* - * Copyright 2001-2005, Haiku. + * Copyright 2001-2006, Haiku. * Distributed under the terms of the MIT License. * * Authors: * DarkWyrm */ -/** Handler for allocating and freeing area memory for BBitmaps - * on the server side. Utilizes the BGET pool allocator. - * - * Whenever a ServerBitmap associated with a client-side BBitmap needs to be - * created or destroyed, the BitmapManager needs to handle it. It takes care of - * all memory management related to them. - */ +/*! + Handler for allocating and freeing area memory for BBitmaps + on the server side. Utilizes the BGET pool allocator. + + Whenever a ServerBitmap associated with a client-side BBitmap needs to be + created or destroyed, the BitmapManager needs to handle it. It takes care of + all memory management related to them. +*/ #include @@ -23,7 +24,9 @@ #include #include "BitmapManager.h" +#include "ClientMemoryAllocator.h" #include "ServerBitmap.h" +#include "ServerProtocol.h" #include "ServerTokenSpace.h" using std::nothrow; @@ -40,9 +43,7 @@ BitmapManager *gBitmapManager = NULL; BitmapManager::BitmapManager() : fBitmapList(1024), - fBuffer(NULL), - fLock("BitmapManager Lock"), - fMemPool("bitmap pool", BITMAP_AREA_SIZE) + fLock("BitmapManager Lock") { } @@ -53,7 +54,9 @@ BitmapManager::~BitmapManager() int32 count = fBitmapList.CountItems(); for (int32 i = 0; i < count; i++) { if (ServerBitmap* bitmap = (ServerBitmap*)fBitmapList.ItemAt(i)) { - fMemPool.ReleaseBuffer(bitmap->fBuffer); + if (bitmap->AllocationCookie() != NULL) + debugger("We're not supposed to keep our cookies..."); + delete bitmap; } } @@ -70,8 +73,9 @@ BitmapManager::~BitmapManager() \return A new ServerBitmap or NULL if unable to allocate one. */ ServerBitmap* -BitmapManager::CreateBitmap(BRect bounds, color_space space, int32 flags, - int32 bytesPerRow, screen_id screen) +BitmapManager::CreateBitmap(ClientMemoryAllocator* allocator, BRect bounds, + color_space space, int32 flags, int32 bytesPerRow, screen_id screen, + int8* _allocationType) { BAutolock locker(fLock); @@ -86,26 +90,41 @@ if (flags & B_BITMAP_WILL_OVERLAY) if (bitmap == NULL) return NULL; - uint8* buffer = (uint8*)fMemPool.GetBuffer(bitmap->BitsLength()); + void* cookie = NULL; + uint8* buffer = NULL; + + if (allocator != NULL) { + bool newArea; + cookie = allocator->Allocate(bitmap->BitsLength(), (void**)&buffer, newArea); + if (cookie != NULL) { + bitmap->fAllocator = allocator; + bitmap->fAllocationCookie = cookie; + + if (_allocationType) + *_allocationType = newArea ? kNewAllocatorArea : kAllocator; + } + } else { + buffer = (uint8*)malloc(bitmap->BitsLength()); + if (buffer != NULL) { + bitmap->fAllocator = NULL; + bitmap->fAllocationCookie = NULL; + + if (_allocationType) + *_allocationType = kHeap; + } + } if (buffer && fBitmapList.AddItem(bitmap)) { - bitmap->fArea = area_for(buffer); bitmap->fBuffer = buffer; bitmap->fToken = gTokenSpace.NewToken(kBitmapToken, bitmap); bitmap->fInitialized = true; - // calculate area offset - area_info info; - get_area_info(bitmap->fArea, &info); - bitmap->fOffset = buffer - (uint8*)info.address; - if (flags & B_BITMAP_CLEAR_TO_WHITE) { // should work for most colorspaces memset(bitmap->Bits(), 255, bitmap->BitsLength()); } } else { // Allocation failed for buffer or bitmap list - fMemPool.ReleaseBuffer(buffer); delete bitmap; bitmap = NULL; } @@ -119,7 +138,7 @@ if (flags & B_BITMAP_WILL_OVERLAY) \param bitmap The bitmap to delete */ void -BitmapManager::DeleteBitmap(ServerBitmap *bitmap) +BitmapManager::DeleteBitmap(ServerBitmap* bitmap) { if (bitmap == NULL || !bitmap->_Release()) { // there are other references to this bitmap, we don't have to delete it yet @@ -130,9 +149,6 @@ BitmapManager::DeleteBitmap(ServerBitmap *bitmap) if (!locker.IsLocked()) return; - if (fBitmapList.RemoveItem(bitmap)) { - // Server code will require a check to ensure bitmap doesn't have its own area - fMemPool.ReleaseBuffer(bitmap->fBuffer); + if (fBitmapList.RemoveItem(bitmap)) delete bitmap; - } } diff --git a/src/servers/app/ClientMemoryAllocator.cpp b/src/servers/app/ClientMemoryAllocator.cpp new file mode 100644 index 0000000000..441252dc2a --- /dev/null +++ b/src/servers/app/ClientMemoryAllocator.cpp @@ -0,0 +1,234 @@ +/* + * 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 + + +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]; + snprintf(name, sizeof(name), "heap:%ld:%s", fApplication->ClientTeam(), + fApplication->SignatureLeaf()); + 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; +} + diff --git a/src/servers/app/ClientMemoryAllocator.h b/src/servers/app/ClientMemoryAllocator.h new file mode 100644 index 0000000000..f5e9f2c46f --- /dev/null +++ b/src/servers/app/ClientMemoryAllocator.h @@ -0,0 +1,62 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef CLIENT_MEMORY_ALLOCATOR_H +#define CLIENT_MEMORY_ALLOCATOR_H + + +#include "MultiLocker.h" + +#include + + +class ServerApp; +struct chunk; +struct block; + +struct chunk : DoublyLinkedListLinkImpl { + area_id area; + uint8* base; + size_t size; +}; + +struct block : DoublyLinkedListLinkImpl { + struct chunk* chunk; + uint8* base; + size_t size; +}; + +typedef DoublyLinkedList block_list; +typedef DoublyLinkedList chunk_list; + + +class ClientMemoryAllocator { + public: + ClientMemoryAllocator(ServerApp* application); + ~ClientMemoryAllocator(); + + status_t InitCheck(); + + void *Allocate(size_t size, void** _address, bool& newArea); + void Free(void* cookie); + + area_id Area(void* cookie); + uint32 AreaOffset(void* cookie); + + bool Lock(); + void Unlock(); + + private: + struct block *_AllocateChunk(size_t size, bool& newArea); + + ServerApp* fApplication; + MultiLocker fLock; + chunk_list fChunks; + block_list fFreeBlocks; +}; + +#endif /* CLIENT_MEMORY_ALLOCATOR_H */ diff --git a/src/servers/app/Jamfile b/src/servers/app/Jamfile index a8fb3c4a22..84dec4a96d 100644 --- a/src/servers/app/Jamfile +++ b/src/servers/app/Jamfile @@ -3,7 +3,7 @@ SubDir HAIKU_TOP src servers app ; AddResources app_server : app_server.rdef ; UseLibraryHeaders png zlib ; -UsePrivateHeaders app graphics input interface shared [ FDirName servers app ] ; +UsePrivateHeaders app graphics input interface kernel shared [ FDirName servers app ] ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing ] ; UseFreeTypeHeaders ; @@ -14,6 +14,7 @@ Server app_server : AppServer.cpp BGet++.cpp BitmapManager.cpp + ClientMemoryAllocator.cpp ColorSet.cpp CursorData.cpp CursorManager.cpp diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index d9b2f50323..7ecce56a61 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -94,13 +94,14 @@ ServerApp::ServerApp(Desktop* desktop, port_id clientReplyPort, fViewCursor(NULL), fCursorHideLevel(0), fIsActive(false), - fSharedMem("shared memory", 32768) + fSharedMem("shared memory", 32768), + fMemoryAllocator(this) { if (fSignature == "") fSignature = "application/no-signature"; char name[B_OS_NAME_LENGTH]; - snprintf(name, sizeof(name), "a<%s", Signature()); + snprintf(name, sizeof(name), "a<%ld:%s", clientTeam, SignatureLeaf()); fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, name); if (fMessagePort < B_OK) @@ -329,12 +330,7 @@ ServerApp::CurrentCursor() const void ServerApp::_GetLooperName(char* name, size_t length) { -#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST - strlcpy(name, Signature(), length); -#else - strncpy(name, Signature(), length); - name[length - 1] = '\0'; -#endif + snprintf(name, length, "a:%ld:%s", ClientTeam(), SignatureLeaf()); } @@ -729,6 +725,8 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) // First, let's attempt to allocate the bitmap ServerBitmap *bitmap = NULL; + int8 allocationType = kAllocator; + BRect frame; color_space colorSpace; int32 flags, bytesPerRow; @@ -739,8 +737,8 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) link.Read(&flags); link.Read(&bytesPerRow); if (link.Read(&screenID) == B_OK) { - bitmap = gBitmapManager->CreateBitmap(frame, colorSpace, flags, - bytesPerRow, screenID); + bitmap = gBitmapManager->CreateBitmap(&fMemoryAllocator, frame, + colorSpace, flags, bytesPerRow, screenID, &allocationType); } STRACE(("ServerApp %s: Create Bitmap (%.1fx%.1f)\n", @@ -749,8 +747,14 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) if (bitmap != NULL && fBitmapList.AddItem(bitmap)) { fLink.StartMessage(B_OK); fLink.Attach(bitmap->Token()); - fLink.Attach(bitmap->Area()); - fLink.Attach(bitmap->AreaOffset()); + fLink.Attach(allocationType); + + if (allocationType == kArea) { + // TODO: implement me! + } else { + fLink.Attach(fMemoryAllocator.Area(bitmap->AllocationCookie())); + fLink.Attach(fMemoryAllocator.AreaOffset(bitmap->AllocationCookie())); + } } else fLink.StartMessage(B_NO_MEMORY); diff --git a/src/servers/app/ServerApp.h b/src/servers/app/ServerApp.h index c56d6e372a..b0ff645e13 100644 --- a/src/servers/app/ServerApp.h +++ b/src/servers/app/ServerApp.h @@ -13,14 +13,16 @@ #define SERVER_APP_H +#include "ClientMemoryAllocator.h" #include "MessageLooper.h" #include "BGet++.h" -#include - #include #include +#include +#include + class AreaPool; class BMessage; @@ -66,6 +68,7 @@ class ServerApp : public MessageLooper { team_id ClientTeam() const; const char* Signature() const { return fSignature.String(); } + const char* SignatureLeaf() const { return fSignature.String() + 12; } void RemoveWindow(ServerWindow* window); bool InWorkspace(int32 index) const; @@ -132,6 +135,7 @@ class ServerApp : public MessageLooper { bool fIsActive; AreaPool fSharedMem; + ClientMemoryAllocator fMemoryAllocator; }; #endif // SERVER_APP_H diff --git a/src/servers/app/ServerBitmap.cpp b/src/servers/app/ServerBitmap.cpp index 9faa450767..381c3cc281 100644 --- a/src/servers/app/ServerBitmap.cpp +++ b/src/servers/app/ServerBitmap.cpp @@ -8,6 +8,7 @@ #include "ServerBitmap.h" +#include "ClientMemoryAllocator.h" #include "ColorConversion.h" #include @@ -31,7 +32,8 @@ ServerBitmap::ServerBitmap(BRect rect, color_space space, int32 flags, int32 bytesPerRow, screen_id screen) : fInitialized(false), - fArea(B_ERROR), + fAllocator(NULL), + fAllocationCookie(NULL), fBuffer(NULL), fReferenceCount(1), // WARNING: '1' is added to the width and height. @@ -53,10 +55,10 @@ ServerBitmap::ServerBitmap(BRect rect, color_space space, //! Copy constructor does not copy the buffer. ServerBitmap::ServerBitmap(const ServerBitmap* bmp) : fInitialized(false), - fArea(B_ERROR), + fAllocator(NULL), + fAllocationCookie(NULL), fBuffer(NULL), fReferenceCount(1) - // TODO: what about fToken and fOffset ?!? { if (bmp) { fInitialized = bmp->fInitialized; @@ -77,13 +79,14 @@ ServerBitmap::ServerBitmap(const ServerBitmap* bmp) } -/*! - \brief Empty. Defined for subclasses. -*/ ServerBitmap::~ServerBitmap() { - // TODO: Maybe it would be wiser to free the buffer here, - // instead of do that in every subclass ? + if (fAllocator != NULL) + fAllocator->Free(AllocationCookie()); + else if (fAllocationCookie != NULL) + delete_area((area_id)fAllocationCookie); + else + free(fBuffer); } @@ -122,20 +125,6 @@ ServerBitmap::_AllocateBuffer(void) } -/*! - \brief Internal function used by subclasses - - Subclasses should call this to free the internal buffer. -*/ -void -ServerBitmap::_FreeBuffer() -{ - delete[] fBuffer; - fBuffer = NULL; - fInitialized = false; -} - - /*! \brief Internal function used to translate color space values to appropriate internal values. @@ -271,6 +260,29 @@ ServerBitmap::ImportBits(const void *bits, int32 bitsLength, int32 bytesPerRow, } +area_id +ServerBitmap::Area() const +{ + if (fAllocator != NULL) + return fAllocator->Area(AllocationCookie()); + + if (fAllocationCookie != NULL) + return (area_id)fAllocationCookie; + + return B_ERROR; +} + + +uint32 +ServerBitmap::AreaOffset() const +{ + if (fAllocator != NULL) + return fAllocator->AreaOffset(AllocationCookie()); + + return 0; +} + + void ServerBitmap::PrintToStream() { @@ -291,12 +303,13 @@ UtilityBitmap::UtilityBitmap(BRect rect, color_space space, } -UtilityBitmap::UtilityBitmap(const ServerBitmap* bmp) - : ServerBitmap(bmp) +UtilityBitmap::UtilityBitmap(const ServerBitmap* bitmap) + : ServerBitmap(bitmap) { _AllocateBuffer(); - if (bmp->Bits()) - memcpy(Bits(), bmp->Bits(), bmp->BitsLength()); + + if (bitmap->Bits()) + memcpy(Bits(), bitmap->Bits(), bitmap->BitsLength()); } @@ -313,5 +326,4 @@ UtilityBitmap::UtilityBitmap(const uint8* alreadyPaddedData, UtilityBitmap::~UtilityBitmap() { - _FreeBuffer(); } diff --git a/src/servers/app/ServerCursor.cpp b/src/servers/app/ServerCursor.cpp index 1751a203c6..f9a4c7a3fb 100644 --- a/src/servers/app/ServerCursor.cpp +++ b/src/servers/app/ServerCursor.cpp @@ -181,7 +181,6 @@ ServerCursor::ServerCursor(const ServerCursor* cursor) //! Frees the heap space allocated for the cursor's image data ServerCursor::~ServerCursor() { - _FreeBuffer(); } diff --git a/src/tests/servers/app/Jamfile b/src/tests/servers/app/Jamfile index caf768b770..b7750e829b 100644 --- a/src/tests/servers/app/Jamfile +++ b/src/tests/servers/app/Jamfile @@ -6,7 +6,7 @@ SetSubDirSupportedPlatforms libbe_test ; if $(TARGET_PLATFORM) = libbe_test { UseLibraryHeaders agg png zlib ; -UsePrivateHeaders app graphics input interface shared [ FDirName servers app ] ; +UsePrivateHeaders app graphics input interface kernel shared [ FDirName servers app ] ; local appServerDir = [ FDirName $(HAIKU_TOP) src servers app ] ; @@ -52,6 +52,7 @@ SharedLibrary libhwinterfaceimpl.so : SharedLibrary libhaikuappserver.so : Angle.cpp BGet++.cpp + ClientMemoryAllocator.cpp ColorSet.cpp CursorData.cpp CursorManager.cpp