diff -r 000000000000 -r 5d03bc08d59c windowing/windowserver/nonnga/CLIENT/RBUFFER.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/windowing/windowserver/nonnga/CLIENT/RBUFFER.CPP Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,439 @@ +// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// RWsBuffer class, handles buffering and flushing of window server commands +// +// + +#include +#include "../SERVER/w32cmd.h" +#include "CLIENT.H" +#include "w32comm.h" + +// Global functions + +GLDEF_C void Assert(TW32Assert aAssert) + { + _LIT(KW32AssertCategory,"W32 Assert"); + User::Panic(KW32AssertCategory,aAssert); + } + +GLDEF_C void Panic(TW32Panic aPanic) + { + _LIT(KW32PanicCategory,"W32"); + User::Panic(KW32PanicCategory,aPanic); + } + +// Public functions + +RWsBuffer::RWsBuffer(RWsSession *aSession) : iSession(aSession), iManager(NULL), + #if defined(__AUTO_FLUSH) + iAutoFlush(ETrue), + #else + iAutoFlush(EFalse), + #endif + iBuf(NULL,0,0), iNext(NULL), iPreviousHandle(0), iBufSize(0), iMaxBufSize(EMinBufferSize), + iDirectAcessCount(0), iInvalidBitmapArray(EFalse) + { + } + +TInt WsFbsDestroyCallBack(TAny* aBitmapHandle) + { + TInt* bitmapHandle=static_cast(aBitmapHandle); + RWsBuffer::FlushAllBuffers(aBitmapHandle ? *bitmapHandle : 0); + + return(0); + } + +void RWsBuffer::SetCallBack() + { + for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext) + if (buffer==this) + return; // Already linked + iNext=(RWsBuffer *)Dll::Tls(); + Dll::SetTls(this); + if (iNext==NULL) // First connection so set callback + RFbsSession::GetSession()->SetCallBack(TCallBack(WsFbsDestroyCallBack,NULL)); + } + +void RWsBuffer::CancelCallBack() + { + RWsBuffer *buffer=(RWsBuffer *)Dll::Tls(); + if (buffer==this) + { + Dll::SetTls(iNext); + if (iNext==NULL) + RFbsSession::GetSession()->ResetCallBack(); // Last connection closing so cancel the callback + } + else + { + RWsBuffer *prev; + while(buffer) + { + prev=buffer; + buffer=buffer->iNext; + if (buffer==this) + { + prev->iNext=iNext; + break; + } + } + } + } + +void RWsBuffer::Close() + { + User::Free((TAny *)iBuf.Ptr()); + } + +void RWsBuffer::Destroy() + { + Flush(); + Close(); + delete this; + } + + +TInt RWsBuffer::Flush(const TIpcArgs* aIpcArgs,TBool aRequestFinish) + { + iBitmapArray.Reset(); + iInvalidBitmapArray=EFalse; + if (iBuf.Length()==0) + { + return(KErrNone); + } + TIpcArgs ipcArgs; + if (aIpcArgs!=NULL) + { + ipcArgs=*aIpcArgs; + // check that the caller hasn't used the first slot + ipcArgs.Set(KBufferMessageSlot,TIpcArgs::ENothing); + __ASSERT_ALWAYS(Mem::Compare(REINTERPRET_CAST(const TUint8*, &ipcArgs), sizeof(TIpcArgs), REINTERPRET_CAST(const TUint8*, aIpcArgs), sizeof(TIpcArgs))==0,Panic(EW32PanicUsingReservedIpcSlot)); + } + ipcArgs.Set(KBufferMessageSlot,&iBuf); + TInt ret; + if(aRequestFinish) + ret=iSession->DoFlush(ipcArgs); + else + ret=iSession->DoSyncMsgBuf(ipcArgs); + iBuf.Zero(); + iPreviousHandle=0; + return(ret); + } + +void RWsBuffer::FlushAllBuffers(TInt aBitmapHandle) + { + for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext) + { + if(!aBitmapHandle || buffer->iInvalidBitmapArray || (buffer->iBitmapArray.FindInOrder(aBitmapHandle)!=KErrNotFound)) + + buffer->Flush(); + } + } + +inline void RWsBuffer::SetAndLimitMaxBufSize(TInt aMaxBufSize) + { // apply upper & lower limits to input buffer size + if (aMaxBufSize < EMinBufferSize) + { + iMaxBufSize = EMinBufferSize; + } + else if (aMaxBufSize > EMaxBufferSize) + { + iMaxBufSize = EMaxBufferSize; + } + else + { + iMaxBufSize = aMaxBufSize; + } + } + +void RWsBuffer::SetBufferSizeL(TInt aBufSize) + { + SetAndLimitMaxBufSize(aBufSize); + ReAllocBufferL(iMaxBufSize); + } + +void RWsBuffer::SetMaxBufferSizeL(TInt aMaxBufSize) + { + SetAndLimitMaxBufSize(aMaxBufSize); + + if (iMaxBufSize < iBufSize) + { // shrink to new maximum + ReAllocBufferL(iMaxBufSize); + } + else + { + // initial allocation should be (at least) a quarter of the requested size + TInt minSize = Max( (iMaxBufSize + 3) >> 2, EMinBufferSize); + if (minSize > iBufSize) + { // new or enlarged buffer + ReAllocBufferL(minSize); + } + } + + __ASSERT_DEBUG((iBufSize >= EMinBufferSize) && (iBufSize <= iMaxBufSize), Assert(EW32AssertBufferLogic)); + } + +// Flush() buffer, try to ReAlloc, Leave if the ReAlloc fails. +void RWsBuffer::ReAllocBufferL(TInt aNewSize) + { + if (aNewSize != iBufSize) + { + Flush(); + if (!ReAllocBuffer(aNewSize)) + { + User::LeaveNoMemory(); + } + } + } + +TBool RWsBuffer::ReAllocBuffer(TInt aNewSize) + { + TUint8* ptr = const_cast(iBuf.Ptr()); + __ASSERT_DEBUG((iBufSize == 0) || (ptr != NULL), Assert(EW32AssertBufferLogic)); + const TInt len = iBuf.Length(); + TUint8* newPtr = static_cast(User::ReAlloc(ptr, aNewSize)); + if (newPtr != NULL) + { // realloc was successful + iBuf.Set(newPtr, len, aNewSize); + iBufSize = aNewSize; + return ETrue; + } + return EFalse; + } + +/* Expand the buffer, to allow new drawing command to fit. + + Called either when trying to store additional commands to queue for Wserv, or + the trying to send a command bigger than the current buffer size. + + Failure to expand the buffer is a minor problem in the first case but a big + problem in the second. + + @param aRequiredSpace Size of buffer increase required. + @param aMsgSize If expanding the buffer fails then needs this value to know whether Flush() is good enough. + @return ETrue if there is enough space, EFalse if not. + */ +void RWsBuffer::GrowBuffer(TInt aRequiredSpace, TInt aMsgSize) + { + __ASSERT_DEBUG(iBufSize < iMaxBufSize, Assert(EW32AssertBufferLogic)); + // maximum size will be big enough? + __ASSERT_ALWAYS(aMsgSize <= iMaxBufSize, Panic(EW32PanicDataExceedsBufferLength)); + + // double or quad the current size, then limit it + TInt newSize = Min((iBufSize >= aRequiredSpace) ? iBufSize << 1 : iBufSize << 2, iMaxBufSize); + + if (!ReAllocBuffer(newSize)) + { // OOM error + Flush(); + if (aMsgSize > iBufSize) + { // message is too big for buffer + Panic(EW32PanicDataExceedsBufferLength); + } + } + } + + +TBool RWsBuffer::SetAutoFlush(TBool aState) + { + TBool old; + + old=iAutoFlush; +#if defined(__AUTO_FLUSH) + if (aState) +#else + iAutoFlush=aState; + if (iAutoFlush) +#endif + Flush(); + return(old); + } + +TInt RWsBuffer::DoWrite(TInt aHandle, TUint aOpcode, TBool aFlush, const TIpcArgs* aIpcArgs, const TAny* aData, TInt aLength, const TAny* aData2, TInt aLength2) + { + __ASSERT_DEBUG(((TUint32) aOpcode) < 0x8000, Assert(EW32AssertIllegalOpcode)); + __ASSERT_DEBUG((aLength&0x3) == 0, Assert(EW32AssertOddLengthData)); + TInt xtra(0); + if (aLength2 > 0) + { + xtra = 4 - (aLength2&0x3); // Round data upto a multiple of 4 + if (xtra==4) + { + xtra=0; + } + } + + const TInt msgSize = aLength + aLength2 + xtra + static_cast(sizeof(TWsCmdHeader)); + TInt available = iBuf.MaxLength() - iBuf.Length(); + if (msgSize > available) + { + if (iBufSize >= iMaxBufSize) + { // buffer is maximum size already + Flush(); + } + else + { // try to grow buffer + if ( (iBuf.Length() + msgSize) > iMaxBufSize) + { // growing alone will not make enough extra space + Flush(); + available = iBufSize; + } + + const TInt requiredSpace = msgSize - available; + if (requiredSpace > 0) + { + GrowBuffer(requiredSpace, msgSize); + } + } + } + + TWsCmdHeader cmdHeader; + cmdHeader.iBase.iOpcode = (TInt16)aOpcode; + cmdHeader.iBase.iCmdLength = (TInt16)(aLength + aLength2 + xtra); + + // For performance reasons we only pass in the handle if it is different + // from the previous command + if (aHandle == iPreviousHandle) + { + iBuf.Append((TUint8 *)&cmdHeader.iBase,sizeof(cmdHeader.iBase)); + } + else + { + iPreviousHandle = aHandle; + cmdHeader.iBase.iOpcode|=EWsOpcodeHandle; + cmdHeader.iDestHandle = aHandle; + iBuf.Append((TUint8 *)&cmdHeader,sizeof(cmdHeader)); + } + + if (aLength) + { + iBuf.Append((TUint8 *)aData, aLength); + } + if (aLength2 > 0) + { + iBuf.Append((TUint8 *)aData2, aLength2); + iBuf.AppendFill(0,xtra); + } + + if (aFlush) + { + return Flush(aIpcArgs); + } + return KErrNone; + } + +void RWsBuffer::Write(TInt handle,TUint opcode) + { + DoWrite(handle, opcode, iAutoFlush, NULL); + } + +void RWsBuffer::Write(TInt handle,TUint opcode,const TAny *pData, TInt length) + { + DoWrite(handle, opcode, iAutoFlush, NULL, pData, length); + } + +void RWsBuffer::Write(TInt handle,TUint opcode,const TAny *pData, TInt length,const TAny *pData2, TInt length2) + { + DoWrite(handle, opcode, iAutoFlush, NULL, pData, length, pData2, length2); + } + +TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TIpcArgs* aIpcArgs) + { + return DoWrite(handle, opcode, ETrue, aIpcArgs); + } + +TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TAny *pData, TInt length,const TIpcArgs* aIpcArgs) + { + return DoWrite(handle, opcode, ETrue, aIpcArgs, pData, length); + } + +TInt RWsBuffer::WriteReply(TInt handle,TUint opcode,const TAny *pData,TInt length,const TAny *pData2,TInt length2,const TIpcArgs* aIpcArgs) + { + return DoWrite(handle, opcode, ETrue, aIpcArgs, pData, length, pData2, length2); + } + +TInt RWsBuffer::WriteReplyP(TInt aHandle, TUint aOpcode, const TWriteDescriptorType& aReplyBuffer) + { + TIpcArgs ipcArgs; + aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs); + return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs); + } + +TInt RWsBuffer::WriteReplyP(TInt aHandle,TUint aOpcode,const TAny *aData,TInt aLength,const TWriteDescriptorType& aReplyBuffer) + { + TIpcArgs ipcArgs; + aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs); + return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData, aLength); + } + +TInt RWsBuffer::WriteReplyP(TInt aHandle,TUint aOpcode,const TAny *aData1,TInt aLengthData1,const TAny *aData2,TInt aLengthData2,const TWriteDescriptorType& aReplyBuffer) + { + TIpcArgs ipcArgs; + aReplyBuffer.SetDescriptorOnIpcArgs(ipcArgs); + return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData1, aLengthData1, aData2, aLengthData2); + } + +TInt RWsBuffer::WriteReplyWs(TUint opcode) +// +// Do a WriteReply using the sessions handle +// + { + return(iSession->WriteReply(opcode)); + } + +TInt RWsBuffer::WriteReplyWs(const TAny *pData, TInt aLength, TUint aOpcode) +// +// Do a WriteReply using the sessions handle +// + { + return(iSession->WriteReply(pData,aLength,aOpcode)); + } + +TInt RWsBuffer::WriteReplyWs(const TAny *pData, TInt aLength, const TAny *pData2, TInt aLength2, TUint aOpcode) +// +// Do a WriteReply using the sessions handle +// + { + return(iSession->WriteReply(pData,aLength,pData2,aLength2,aOpcode)); + } + +TInt RWsBuffer::WriteReplyByProvidingRemoteReadAccess(TInt aHandle,TUint aOpcode,const TAny *aData, TInt aLength,const TReadDescriptorType& aRemoteReadBuffer) + { + TIpcArgs ipcArgs; + aRemoteReadBuffer.SetDescriptorOnIpcArgs(ipcArgs); + return DoWrite(aHandle, aOpcode, ETrue, &ipcArgs, aData, aLength); + } + +void RWsBuffer::AddToBitmapArray(TInt aBitmapHandle) + { + if(aBitmapHandle && !iInvalidBitmapArray) + { + if(iBitmapArray.InsertInOrder(aBitmapHandle)==KErrNoMemory) + + iInvalidBitmapArray=ETrue; + } + } + +void RWsBuffer::SetWsGraphicManager(CWsGraphic::CManager* aManager) + { + __ASSERT_DEBUG(!WsGraphicManager(),Panic(EW32PanicGraphicInternal)); + iManager = aManager; + } + +CWsGraphic::CManager* RWsBuffer::WsGraphicManager() + { + for(RWsBuffer *buffer=(RWsBuffer *)Dll::Tls();buffer;buffer=buffer->iNext) + if (buffer->iManager) + return buffer->iManager; + return NULL; // does not yet exist + }