diff -r 000000000000 -r dfb7c4ff071f commsfwutils/commsbufs/src/systemsharedasyncalloc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commsfwutils/commsbufs/src/systemsharedasyncalloc.cpp Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,303 @@ +// Copyright (c) 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: +// + +#include "systemsharedbufs.h" +#include "systemsharedasyncalloc.h" +#include "commsbufasyncreqinternal.h" + + +CSystemSharedPoolAsyncAlloc::CSystemSharedPoolAsyncAlloc(CSystemSharedBufPool& aPool, MAsyncAllocNotifier& aNotifier) +: CActive(EPriorityStandard), +iPool(aPool), +iNotifier(aNotifier) + { + CActiveScheduler::Add(this); + } + +CSystemSharedPoolAsyncAlloc::~CSystemSharedPoolAsyncAlloc() + { + Deactivate(); + } + +void CSystemSharedPoolAsyncAlloc::Activate(TInt aFreeBufs) + { + if(!IsActive()) + { + iStatus = KRequestPending; + iPool.Pool().RequestFreeSpaceNotification(aFreeBufs, iStatus); + SetActive(); + } + } + +void CSystemSharedPoolAsyncAlloc::Deactivate() + { + Cancel(); + } + +void CSystemSharedPoolAsyncAlloc::RunL() + { + User::LeaveIfError(iStatus.Int()); + iNotifier.OnCompletion(); + } + +TInt CSystemSharedPoolAsyncAlloc::RunError(TInt aError) + { + iNotifier.OnError(aError); + return KErrNone; + } + +void CSystemSharedPoolAsyncAlloc::DoCancel() + { + iPool.Pool().CancelFreeSpaceNotification(iStatus); + } + +// ------------------------------------------------------------------------- + +CSystemSharedAsyncAlloc* CSystemSharedAsyncAlloc::New(const RPointerArray& aPools) + { + CSystemSharedAsyncAlloc* self = new CSystemSharedAsyncAlloc(); + if(self) + { + if (self->Construct(aPools) == KErrNone) + { + return self; + } + else + { + delete self; + } + } + return NULL; + } + +CSystemSharedAsyncAlloc::CSystemSharedAsyncAlloc() +: CActive(EPriorityStandard), +iRequestState(EMakeRequest), +iSignalled(ETrue) + { + CActiveScheduler::Add(this); + } + +CSystemSharedAsyncAlloc::~CSystemSharedAsyncAlloc() + { + __ASSERT_DEBUG(iAllocsPending.IsEmpty(), User::Invariant()); + Cancel(); + iAsyncAllocPools.ResetAndDestroy(); + iAsyncAllocPools.Close(); + iAsynAllocLock.Close(); + iOwnerThread.Close(); + } + +TInt CSystemSharedAsyncAlloc::Construct(const RPointerArray& aPools) + { + TInt err = KErrNone; + for(TInt i = 0; i < aPools.Count(); ++i) + { + CSystemSharedPoolAsyncAlloc* asyncPool = new CSystemSharedPoolAsyncAlloc(*(aPools[i]), *this); + if(asyncPool) + { + if(iAsyncAllocPools.Append(asyncPool) != KErrNone) + { + delete asyncPool; + err = KErrNoMemory; + break; + } + } + else + { + err = KErrNoMemory; + break; + } + } + if(err == KErrNone) + { + iAllocsPending.SetOffset(_FOFF(CCommsBufAsyncRequest, iLink)); + err = iAsynAllocLock.CreateLocal(); + if(err == KErrNone) + { + TThreadId id = RThread().Id(); + err = iOwnerThread.Open(id); + if(err == KErrNone) + { + // Activate the AO. + ActivateSelf(); + } + } + } + return err; + } + +void CSystemSharedAsyncAlloc::StartRequest(CCommsBufAsyncRequest& aRequest) + { + iAsynAllocLock.Wait(); + if(iAllocsPending.IsEmpty()) + { + // We do not have anything in the pending alloc queue. + // Kick off the AO. + CompleteSelf(); + } + iAllocsPending.AddLast(aRequest); + iAsynAllocLock.Signal(); + } + +void CSystemSharedAsyncAlloc::CancelRequest(CCommsBufAsyncRequest& aRequest) + { + iAsynAllocLock.Wait(); + aRequest.iLink.Deque(); + aRequest.Complete(KErrCancel); + CompleteSelf(); + iAsynAllocLock.Signal(); + } + +void CSystemSharedAsyncAlloc::MakePoolAsyncRequest() + { + iAsynAllocLock.Wait(); + MakePoolRequest(); + ActivateSelf(); + iAsynAllocLock.Signal(); + } + +void CSystemSharedAsyncAlloc::MakePoolRequest() + { + if(!iAllocsPending.IsEmpty()) + { + CCommsBufAsyncRequest* req = iAllocsPending.First(); + for(TInt i = 0; i < iAsyncAllocPools.Count(); ++i) + { + CSystemSharedPoolAsyncAlloc* asyncPool = iAsyncAllocPools[i]; + TInt poolBufSize = asyncPool->iPool.BufSize(); + if(poolBufSize >= req->iMinSize && poolBufSize <= req->iMaxSize) + { + TInt freeBufs = req->iSize / poolBufSize; + freeBufs = ((req->iSize % asyncPool->iPool.BufSize()) == 0) ? freeBufs : (freeBufs + 1); + asyncPool->Activate(freeBufs); + } + } + } + } + +void CSystemSharedAsyncAlloc::CancelAllPoolRequest() + { + for(TInt i = 0; i < iAsyncAllocPools.Count(); ++i) + { + iAsyncAllocPools[i]->Deactivate(); + } + } + +void CSystemSharedAsyncAlloc::CancelPoolAsyncRequest() + { + iAsynAllocLock.Wait(); + CancelAllPoolRequest(); + ActivateSelf(); + if(!iAllocsPending.IsEmpty()) + { + CompleteSelf(); + } + iAsynAllocLock.Signal(); + } + + void CSystemSharedAsyncAlloc::RunL() + { + // + switch(iRequestState) + { + case EMakeRequest: + MakePoolAsyncRequest(); + break; + + case ECancelRequest: + CancelPoolAsyncRequest(); + iRequestState = EMakeRequest; + break; + + default: + // We should never reach here + CommsBuf::Panic(EMBuf_AsyncAllocInvalidState); + break; + } + + } + + void CSystemSharedAsyncAlloc::DoCancel() + { + TRequestStatus* requestStatusPtr = &iStatus; + iOwnerThread.RequestComplete(requestStatusPtr, KErrCancel); + } + +void CSystemSharedAsyncAlloc::ActivateSelf() + { + if(iSignalled) + { + iStatus = KRequestPending; + SetActive(); + iSignalled = EFalse; + } + } + +void CSystemSharedAsyncAlloc::CompleteSelf() + { + if(!iSignalled) + { + TRequestStatus* requestStatusPtr = &iStatus; + iOwnerThread.RequestComplete(requestStatusPtr, KErrNone); + iSignalled = ETrue; + } + } + +void CSystemSharedAsyncAlloc::OnCompletion() + { + CompleteAsyncAllocs(); + } + +void CSystemSharedAsyncAlloc::OnError(TInt aError) + { + // We hit with an error from the system pool. + // complete all alloc request with that error. + CCommsBufAsyncRequest* req; + iAsynAllocLock.Wait(); + if(!iAllocsPending.IsEmpty()) + { + TDblQueIter iter(iAllocsPending); + while (req = iter++, req != NULL) + { + req->Complete(aError); + } + } + iAsynAllocLock.Signal(); + } + +void CSystemSharedAsyncAlloc::CompleteAsyncAllocs() + { + CCommsBufAsyncRequest *req; + + iAsynAllocLock.Wait(); + TDblQueIter iter(iAllocsPending); + while (req = iter++, req != NULL) + { + RCommsBufChain chain; + chain.Alloc(req->iSize, req->iMinSize, req->iMaxSize, req->iAllocator); + if(!chain.IsEmpty()) + { + req->iBufQ.Assign(chain); + req->Complete(KErrNone); + } + } + // We are in the same thread. Cancel the current pool requests. + CancelAllPoolRequest(); + // Make the pool request if needed. + MakePoolRequest(); + iAsynAllocLock.Signal(); + } +