diff --git a/src/servers/app/server/BGet++.cpp b/src/servers/app/server/BGet++.cpp index 02cdfe27ba..5bd8e66d72 100644 --- a/src/servers/app/server/BGet++.cpp +++ b/src/servers/app/server/BGet++.cpp @@ -27,6 +27,15 @@ // //------------------------------------------------------------------------------*/ +/* + This class is based on the BGET pool allocator. Original code was in standard + ANSI C with a bunch of static variables. The original code was placed into the + MemPool class and the original allocation, release, and compacting functions + were made into virtual members. MemPool also, unlike the original code, makes + use of malloc() and free() to handle dynamic memory needs. AreaPool is a MemPool + subclass which uses areas to handle memory management needs in large chunks. +*/ + // Buffer allocation size quantum: all buffers allocated are a multiple of this size. ' // This MUST be a power of two. @@ -35,7 +44,8 @@ #include #include #include -#include +#include +#include #include // Declare the interface, including the requested buffer size type, ssize_t. @@ -90,35 +100,6 @@ static struct bfhead freelist = }; -// Total space currently allocated -//static ssize_t totalloc = 0; - -// Number of GetBuffer() and ReleaseBuffer() calls -//static long numget = 0, numrel = 0; - -// Number of pool blocks -//static long numpblk = 0; - - // Number of block gets and rels -//static long numpget = 0, numprel = 0; - -// Number of direct gets and rels -//static long numdget = 0, numdrel = 0; - -// Expansion block size -//static ssize_t exp_incr = 0; - -// 0: no AddToPool calls have been made -// -1: not all pool blocks are the same size -// >0: (common) block size for all AddToPool calls made so far -//static ssize_t pool_len = 0; - -// Automatic expansion block management functions -//static int (*compfcn)(ssize_t sizereq, int sequence) = NULL; -//static void *(*acqfcn)(ssize_t size) = NULL; -//static void (*relfcn)(void *buf) = NULL; - - // Minimum allocation quantum: #define QLSize (sizeof(struct qlinks)) #define SizeQ ((SizeQuant > QLSize) ? SizeQuant : QLSize) @@ -147,17 +128,7 @@ MemPool::~MemPool(void) { } - - - - - - - - - - -// BGET -- Allocate a buffer. +// Allocate a buffer from the available space in the memory pool void *MemPool::GetBuffer(ssize_t requested_size, bool zero) { ssize_t size = requested_size; @@ -372,46 +343,9 @@ void *MemPool::GetBuffer(ssize_t requested_size, bool zero) } -// BGETZ -- Allocate a buffer and clear its contents to zero. We clear -// the entire contents of the buffer to zero, not just the region -// requested by the caller. -/* -void *bgetz(ssize_t size) -{ - char *buf = (char *) GetBuffer(size); - - if (buf != NULL) - { - struct bhead *b; - ssize_t rsize; - - b = BH(buf - sizeof(struct bhead)); - rsize = -(b->bsize); - - if (rsize == 0) - { - struct bdhead *bd; - - bd = BDH(buf - sizeof(struct bdhead)); - rsize = bd->tsize - sizeof(struct bdhead); - } - else - { - rsize -= sizeof(struct bhead); - } - - assert(rsize >= size); - memset(buf, 0, (MemSize) rsize); - } - return ((void *) buf); -} -*/ - -// BGETR -- Reallocate a buffer. This is a minimal implementation, -// simply in terms of ReleaseBuffer() and GetBuffer(). It could be -// enhanced to allow the buffer to grow into adjacent free -// blocks and to avoid moving data unnecessarily. - +// Reallocate a buffer. This is a minimal implementation, simply in terms +// of ReleaseBuffer() and GetBuffer(). It could be enhanced to allow the +// buffer to grow into adjacent free blocks and to avoid moving data unnecessarily. void *MemPool::ReallocateBuffer(void *buf, ssize_t size) { void *nbuf; @@ -588,21 +522,7 @@ void MemPool::ReleaseBuffer(void *buf) } } -/* -// BECTL -- Establish automatic pool expansion control -void bectl( int (*compact) (ssize_t sizereq, int sequence), - void *(*acquire) (ssize_t size), - void (*release) (void *buf), - ssize_t pool_incr ) -{ - compfcn = compact; - acqfcn = acquire; - relfcn = release; - exp_incr = pool_incr; -} -*/ - -// BPOOL -- Add a region of memory to the buffer pool. +// Add a region of memory to the buffer pool. void MemPool::AddToPool(void *buf, ssize_t len) { struct bfhead *b = BFH(buf); @@ -667,7 +587,7 @@ void MemPool::AddToPool(void *buf, ssize_t len) } -// BSTATS -- Return buffer allocation free space statistics. +// Return buffer allocation free space statistics. void MemPool::Stats(ssize_t *curalloc, ssize_t *totfree, ssize_t *maxfree, long *nget, long *nrel) { @@ -693,7 +613,7 @@ void MemPool::Stats(ssize_t *curalloc, ssize_t *totfree, ssize_t *maxfree, } -// BSTATSE -- Return extended statistics +// Return extended statistics void MemPool::ExtendedStats(ssize_t *pool_incr, long *npool, long *npget, long *nprel, long *ndget, long *ndrel) { @@ -707,9 +627,9 @@ void MemPool::ExtendedStats(ssize_t *pool_incr, long *npool, long *npget, long * -// BUFDUMP -- Dump the data in a buffer. This is called with the user -// data pointer, and backs up to the buffer header. It will -// dump either a free block or an allocated one. +// Dump the data in a buffer. This is called with the user data pointer, +// and backs up to the buffer header. It will dump either a free block +// or an allocated one. void MemPool::BufferDump(void *buf) { struct bfhead *b; @@ -772,11 +692,10 @@ void MemPool::BufferDump(void *buf) } } -// BPOOLD -- Dump a buffer pool. The buffer headers are always listed. -// If DUMPALLOC is nonzero, the contents of allocated buffers -// are dumped. If DUMPFREE is nonzero, free blocks are -// dumped as well. If FreeWipe checking is enabled, free -// blocks which have been clobbered will always be dumped. +// Dump a buffer pool. The buffer headers are always listed. If DUMPALLOC is +// nonzero, the contents of allocated buffers are dumped. If DUMPFREE is +// nonzero, free blocks are dumped as well. If FreeWipe checking is enabled, +// free blocks which have been clobbered will always be dumped. void MemPool::PoolDump(void *buf, bool dumpalloc, bool dumpfree) { struct bfhead *b = BFH(buf); @@ -825,7 +744,7 @@ void MemPool::PoolDump(void *buf, bool dumpalloc, bool dumpfree) } } -// BPOOLV -- Validate a buffer pool. +// Validate a buffer pool. int MemPool::Validate(void *buf) { struct bfhead *b = BFH(buf); @@ -879,11 +798,12 @@ int *MemPool::CompactMem(ssize_t sizereq, int sequence) void *MemPool::AcquireMem(ssize_t size) { - return NULL; + return malloc(size); } void MemPool::ReleaseMem(void *buffer) { + free(buffer); } AreaPool::AreaPool(void) @@ -909,13 +829,13 @@ void *AreaPool::AcquireMem(ssize_t size) else areasize=size; } - a=create_area("bitmap_area",(void**)&parea,B_ANY_ADDRESS,areasize, + + a=create_area("AreaPool_area",(void**)&parea,B_ANY_ADDRESS,areasize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA); - if(a==B_BAD_VALUE || - a==B_NO_MEMORY || - a==B_ERROR) + + if(a==B_BAD_VALUE || a==B_NO_MEMORY || a==B_ERROR) { - printf("PANIC: BitmapManager couldn't allocate area!!\n"); + printf("ERROR: AreaPool couldn't allocate area!!\n"); return NULL; } @@ -928,6 +848,7 @@ void AreaPool::ReleaseMem(void *buffer) if(trash==B_ERROR) return; + delete_area(trash); } diff --git a/src/servers/app/server/Jamfile b/src/servers/app/server/Jamfile index a5f8f7b8ef..027a6fd2b1 100644 --- a/src/servers/app/server/Jamfile +++ b/src/servers/app/server/Jamfile @@ -45,6 +45,7 @@ Server app_server : FMWList.cpp PicturePlayer.cpp PNGDump.cpp + RAMLinkMsgReader.cpp # Manager Classes AppServer.cpp diff --git a/src/servers/app/server/RAMLinkMsgReader.cpp b/src/servers/app/server/RAMLinkMsgReader.cpp new file mode 100644 index 0000000000..99ee5d527e --- /dev/null +++ b/src/servers/app/server/RAMLinkMsgReader.cpp @@ -0,0 +1,140 @@ +#include "RAMLinkMsgReader.h" +#include + +RAMLinkMsgReader::RAMLinkMsgReader(int8 *buffer) + : LinkMsgReader(B_ERROR) +{ + SetBuffer(buffer); +} + + +RAMLinkMsgReader::RAMLinkMsgReader(void) + : LinkMsgReader(B_ERROR) +{ + fBuffer=NULL; + fAttachStart=NULL; + fPosition=NULL; + fAttachSize=0; + fCode=B_ERROR; +} + + +RAMLinkMsgReader::~RAMLinkMsgReader(void) +{ + // Note that this class does NOT take responsibility for the buffer it reads from. +} + + + +void RAMLinkMsgReader::SetBuffer(int8 *buffer) +{ + if(!buffer) + { + fBuffer=NULL; + fAttachStart=NULL; + fPosition=NULL; + fAttachSize=0; + fCode=B_ERROR; + return; + } + + fBuffer=buffer; + fPosition=fBuffer+4; + + fCode=*((int32*)fBuffer); + fAttachSize=*( (size_t*) fPosition); + fPosition+=sizeof(size_t); + fAttachStart=fPosition; +} + + +int8 *RAMLinkMsgReader::GetBuffer(void) +{ + return fBuffer; +} + + +size_t RAMLinkMsgReader::GetBufferSize(void) +{ + return fAttachSize; +} + + + +status_t RAMLinkMsgReader::Read(void *data, ssize_t size) +{ + if(!fBuffer || fAttachSize==0) + return B_NO_INIT; + + if(size<1) + return B_BAD_VALUE; + + if(fPosition+size > fAttachStart+fAttachSize) + { + // read past end of buffer + return B_BAD_VALUE; + } + + memcpy(data, fPosition, size); + fPosition+=size; + return B_OK; +} + + +status_t RAMLinkMsgReader::ReadString(char **string) +{ + status_t err; + int32 len = 0; + + err = Read(&len); + if (err < B_OK) + return err; + + if (len) + { + *string = (char *)malloc(len); + if (*string == NULL) + { + fPosition -= sizeof(int32); + return B_NO_MEMORY; + } + + err = Read(*string, len); + if (err < B_OK) + { + free(*string); + *string = NULL; + fPosition -= sizeof(int32); + return err; + } + (*string)[len-1] = '\0'; + return B_OK; + } + else + { + fPosition -= sizeof(int32); + return B_ERROR; + } +} + +// "Forbidden" functions :P +status_t RAMLinkMsgReader::GetNextMessage(int32 *code, bigtime_t timeout) +{ + debugger("RAMLinkMsgReader::GetNextMessage is not permitted"); + return B_ERROR; +} + + +void RAMLinkMsgReader::SetPort(port_id port) +{ + debugger("RAMLinkMsgReader::SetPort is not permitted"); +} + + +port_id RAMLinkMsgReader::GetPort(void) +{ + debugger("RAMLinkMsgReader::GetPort is not permitted"); + return B_ERROR; +} + + diff --git a/src/servers/app/server/RAMLinkMsgReader.h b/src/servers/app/server/RAMLinkMsgReader.h new file mode 100644 index 0000000000..6c3a81168f --- /dev/null +++ b/src/servers/app/server/RAMLinkMsgReader.h @@ -0,0 +1,77 @@ +// Copyright (c) 2001-2002, Haiku +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: RAMLinkMsgReader.h +// Author: DarkWyrm +// Description: Class for reading Link messages from a memory buffer +// +//------------------------------------------------------------------------------ +#ifndef RAM_LINK_MSG_READER_H +#define RAM_LINK_MSG_READER_H + +#include + +/* + This class is somewhat an inheritance hack to avoid some *serious* code + duplication in the app_server. Its only intended use is for reading back + PortLink message sent over an area in cases where it is too large to fit + through a port. + + Expected format: + int32 message code + size_t buffer size + [data buffer] +*/ +class RAMLinkMsgReader : public LinkMsgReader +{ +public: + RAMLinkMsgReader(int8 *buffer); + RAMLinkMsgReader(void); + ~RAMLinkMsgReader(void); + + void SetBuffer(int8 *buffer); + int8 *GetBuffer(void); + size_t GetBufferSize(void); + int32 Code(void) { return fCode; } + + status_t Read(void *data, ssize_t size); + status_t ReadString(char **string); + template status_t Read(Type *data) + { + return Read(data, sizeof(Type)); + } + + // These should never need to be called where this class is used. However, we do + // need to make debugging easier for such contexts... + status_t GetNextMessage(int32 *code, bigtime_t timeout); + void SetPort(port_id port); + port_id GetPort(void); + +protected: + + + int8 *fBuffer, *fAttachStart; + int8 *fPosition; + size_t fAttachSize; + int32 fCode; +}; + +#endif + diff --git a/src/servers/app/server/ServerApp.cpp b/src/servers/app/server/ServerApp.cpp index ea7b1d05ac..fa637b837d 100644 --- a/src/servers/app/server/ServerApp.cpp +++ b/src/servers/app/server/ServerApp.cpp @@ -38,10 +38,12 @@ #include "AppServer.h" #include "BitmapManager.h" +#include "BGet++.h" #include "CursorManager.h" #include "Desktop.h" #include "DisplayDriver.h" #include "FontServer.h" +#include "RAMLinkMsgReader.h" #include "RootLayer.h" #include "ServerApp.h" #include "ServerScreen.h" @@ -92,20 +94,16 @@ ServerApp::ServerApp(port_id sendport, port_id rcvport, port_id clientLooperPort // fMessagePort is the port we receive messages from our BApplication fMessagePort=rcvport; - fAppLink = new BPortLink(fClientAppPort, fMessagePort); + fMsgReader = new LinkMsgReader(fMessagePort); + fMsgSender = new LinkMsgSender(fClientAppPort); fSWindowList=new BList(0); fBitmapList=new BList(0); fPictureList=new BList(0); fIsActive=false; - char *dummy; - fSharedMem=create_area("rw_shared_area",(void**)&dummy,B_ANY_ADDRESS,4096,B_NO_LOCK, - B_READ_AREA|B_WRITE_AREA); + fSharedMem=new AreaPool; - if(fSharedMem<0) - printf("PANIC: Couldn't create shared app_server area!\n"); - ServerCursor *defaultc=cursormanager->GetCursor(B_CURSOR_DEFAULT); fAppCursor=(defaultc)?new ServerCursor(defaultc):NULL; @@ -150,12 +148,15 @@ ServerApp::~ServerApp(void) fPictureList->MakeEmpty(); delete fPictureList; - delete fAppLink; - fAppLink=NULL; + delete fMsgReader; + fMsgReader=NULL; + + delete fMsgSender; + fMsgSender=NULL; + if(fAppCursor) delete fAppCursor; - cursormanager->RemoveAppCursors(fClientTeamID); delete_sem(fLockSem); @@ -165,7 +166,8 @@ ServerApp::~ServerApp(void) thread_info info; if(get_thread_info(fMonitorThreadID,&info)==B_OK) kill_thread(fMonitorThreadID); - delete_area(fSharedMem); + + delete fSharedMem; } /*! @@ -208,10 +210,10 @@ bool ServerApp::PingTarget(void) printf("PANIC: ServerApp %s could not find the app_server port in PingTarget()!\n",fSignature.String()); return false; } - fAppLink->SetSendPort(serverport); - fAppLink->StartMessage(AS_DELETE_APP); - fAppLink->Attach(&fMonitorThreadID,sizeof(thread_id)); - fAppLink->Flush(); + fMsgSender->SetPort(serverport); + fMsgSender->StartMessage(AS_DELETE_APP); + fMsgSender->Attach(&fMonitorThreadID,sizeof(thread_id)); + fMsgSender->Flush(); return false; } return true; @@ -280,7 +282,8 @@ int32 ServerApp::MonitorApp(void *data) // Message-dispatching loop for the ServerApp ServerApp *app = (ServerApp *)data; - BPortLink msgqueue(-1, app->fMessagePort); + LinkMsgReader msgqueue(app->fMessagePort); + bool quitting = false; int32 code; status_t err = B_OK; @@ -288,7 +291,8 @@ int32 ServerApp::MonitorApp(void *data) while(!quitting) { STRACE(("info: ServerApp::MonitorApp listening on port %ld.\n", app->fMessagePort)); - err = msgqueue.GetNextReply(&code); +// err = msgqueue.GetNextReply(&code); + err = msgqueue.GetNextMessage(&code); if (err < B_OK) break; @@ -329,16 +333,16 @@ int32 ServerApp::MonitorApp(void *data) printf("PANIC: ServerApp %s could not find the app_server port!\n",app->fSignature.String()); break; } - app->fAppLink->SetSendPort(serverport); - app->fAppLink->StartMessage(AS_DELETE_APP); - app->fAppLink->Attach(&app->fMonitorThreadID, sizeof(thread_id)); - app->fAppLink->Flush(); + app->fMsgSender->SetPort(serverport); + app->fMsgSender->StartMessage(AS_DELETE_APP); + app->fMsgSender->Attach(&app->fMonitorThreadID, sizeof(thread_id)); + app->fMsgSender->Flush(); break; } default: { STRACE(("ServerApp %s: Got a Message to dispatch\n",app->fSignature.String())); - app->_DispatchMessage(code, msgqueue); + app->DispatchMessage(code, msgqueue); break; } } @@ -358,7 +362,7 @@ int32 ServerApp::MonitorApp(void *data) All attachments are placed in the buffer via a PortLink, so it will be a matter of casting and incrementing an index variable to access them. */ -void ServerApp::_DispatchMessage(int32 code, BPortLink& msg) +void ServerApp::DispatchMessage(int32 code, LinkMsgReader &msg) { LayerData ld; switch(code) @@ -412,18 +416,115 @@ void ServerApp::_DispatchMessage(int32 code, BPortLink& msg) } */ break; } + case AS_AREA_MESSAGE: + { + // This occurs in only one kind of case: a message is too big to send over a port. This + // is really an edge case, so this shouldn't happen *too* often + + // Attached Data: + // 1) area_id id of an area already owned by the server containing the message + // 2) size_t offset of the pointer in the area + // 3) size_t size of the message + + area_id area; + size_t offset; + size_t msgsize; + area_info ai; + int8 *msgpointer; + + msg.Read(&area); + msg.Read(&offset); + msg.Read(&msgsize); + + // Part sanity check, part get base pointer :) + if(get_area_info(area,&ai)!=B_OK) + break; + + msgpointer=(int8*)ai.address + offset; + + RAMLinkMsgReader mlink(msgpointer); + DispatchMessage(mlink.Code(),mlink); + + // This is a very special case in the sense that when ServerMemIO is used for this + // purpose, it will be set to NOT automatically free the memory which it had + // requested. This is the server's job once the message has been dispatched. + fSharedMem->ReleaseBuffer(msgpointer); + + break; + } case AS_ACQUIRE_SERVERMEM: { + // This particular call is more than a bit of a pain in the neck. We are given a + // size of a chunk of memory needed. We need to (1) allocate it, (2) get the area for + // this particular chunk, (3) find the offset in the area for this chunk, and (4) + // tell the client about it. Good thing this particular call isn't used much + // Received from a ServerMemIO object requesting operating memory // Attached Data: // 1) size_t requested size + // 2) port_id reply_port + + size_t memsize; + port_id replyport; + + msg.Read(&memsize); + msg.Read(&replyport); + + // TODO: I wonder if ACQUIRE_SERVERMEM should have a minimum size requirement? + + void *sharedmem=fSharedMem->GetBuffer(memsize); + + BPortLink replylink(replyport); + if(memsize<1 || sharedmem==NULL) + { + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + + area_id owningArea=area_for(sharedmem); + area_info ai; + + if(owningArea==B_ERROR || get_area_info(owningArea,&ai)!=B_OK) + { + replylink.StartMessage(SERVER_FALSE); + replylink.Flush(); + break; + } + + int32 areaoffset=((int32*)sharedmem)-((int32*)ai.address); + STRACE(("Successfully allocated shared memory of size %ld\n",memsize)); + + replylink.StartMessage(SERVER_TRUE); + replylink.Attach(owningArea); + replylink.Attach(areaoffset); + replylink.Flush(); - // TODO: Implement AS_ACQUIRE_SERVERMEM break; } case AS_RELEASE_SERVERMEM: { - // TODO: Implement AS_RELEASE_SERVERMEM + // Received when a ServerMemIO object on destruction + // Attached Data: + // 1) area_id owning area + // 2) int32 area offset + + area_id owningArea; + area_info ai; + int32 areaoffset; + void *sharedmem; + + msg.Read(&owningArea); + msg.Read(&areaoffset); + + if(owningArea<0 || get_area_info(owningArea,&ai)!=B_OK) + break; + + STRACE(("Successfully freed shared memory\n")); + sharedmem=((int32*)ai.address)+areaoffset; + + fSharedMem->ReleaseBuffer(sharedmem); + break; } case AS_UPDATE_DECORATOR: diff --git a/src/servers/app/server/ServerApp.h b/src/servers/app/server/ServerApp.h index 3b4aaefd02..7d49b8f143 100644 --- a/src/servers/app/server/ServerApp.h +++ b/src/servers/app/server/ServerApp.h @@ -30,6 +30,8 @@ #include #include +#include +#include #include "FMWList.h" class AppServer; @@ -39,6 +41,7 @@ class BList; class DisplayDriver; class ServerCursor; class ServerBitmap; +class AreaPool; /*! \class ServerApp ServerApp.h @@ -80,8 +83,8 @@ protected: friend class AppServer; friend class ServerWindow; - void _DispatchMessage(int32 code, BPortLink& link); - ServerBitmap* _FindBitmap(int32 token); +// void DispatchMessage(int32 code, BPortLink& msg); + void DispatchMessage(int32 code, LinkMsgReader &link); port_id fClientAppPort, fMessagePort, @@ -94,7 +97,9 @@ protected: team_id fClientTeamID; - BPortLink *fAppLink; + LinkMsgReader *fMsgReader; + LinkMsgSender *fMsgSender; + BList *fSWindowList, *fBitmapList, *fPictureList; @@ -103,7 +108,7 @@ protected: bool fCursorHidden; bool fIsActive; int32 fHandlerToken; - area_id fSharedMem; + AreaPool *fSharedMem; }; #endif diff --git a/src/servers/app/server/ServerPicture.cpp b/src/servers/app/server/ServerPicture.cpp index 0bb8df3a74..84b0f21b6f 100644 --- a/src/servers/app/server/ServerPicture.cpp +++ b/src/servers/app/server/ServerPicture.cpp @@ -24,7 +24,6 @@ // Description: Server-side counterpart to BPicture // //------------------------------------------------------------------------------ -#include #include "TokenHandler.h" #include "ServerPicture.h" @@ -42,12 +41,8 @@ ServerPicture::ServerPicture(void) if(_area!=B_BAD_VALUE && _area!=B_NO_MEMORY && _area!=B_ERROR) _initialized=true; - - arealink=(_initialized)?new AreaLink(_area):NULL; } ServerPicture::~ServerPicture(void) { - if(arealink) - delete arealink; }