sl@0: // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include sl@0: #include "d_sharedchunk.h" sl@0: sl@0: static TInt ChunkDestroyedCount=1; // Test counter sl@0: sl@0: // sl@0: // Class definitions sl@0: // sl@0: sl@0: class DSharedChunkFactory : public DLogicalDevice sl@0: { sl@0: public: sl@0: ~DSharedChunkFactory(); sl@0: virtual TInt Install(); sl@0: virtual void GetCaps(TDes8& aDes) const; sl@0: virtual TInt Create(DLogicalChannelBase*& aChannel); sl@0: void LockWait(); sl@0: void LockSignal(); sl@0: private: sl@0: NFastMutex iLock; sl@0: }; sl@0: sl@0: class DSharedChunkChannel : public DLogicalChannelBase sl@0: { sl@0: public: sl@0: DSharedChunkChannel(); sl@0: ~DSharedChunkChannel(); sl@0: virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); sl@0: virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); sl@0: DChunk* OpenChunk(TLinAddr* aKernelAddr=0, TInt* aMaxSize=0); sl@0: inline void LockWait() sl@0: { iFactory->LockWait(); } sl@0: inline void LockSignal() sl@0: { iFactory->LockSignal(); } sl@0: public: sl@0: DSharedChunkFactory* iFactory; sl@0: DChunk* iChunk; sl@0: TLinAddr iKernelAddress; sl@0: TInt iMaxSize; sl@0: sl@0: public: sl@0: /** Require physically contiguous memory */ sl@0: TInt iContiguous; sl@0: /** Caching attribute to create chunks memory */ sl@0: TInt iCacheAttrib; sl@0: }; sl@0: sl@0: class TChunkCleanup : public TDfc sl@0: { sl@0: public: sl@0: TChunkCleanup(DSharedChunkFactory* aFactory); sl@0: ~TChunkCleanup(); sl@0: static void ChunkDestroyed(TChunkCleanup* aSelf); sl@0: void Cancel(); sl@0: public: sl@0: DSharedChunkFactory* iFactory; sl@0: }; sl@0: sl@0: // sl@0: // TChunkCleanup sl@0: // sl@0: sl@0: TChunkCleanup::TChunkCleanup(DSharedChunkFactory* aFactory) sl@0: : TDfc((TDfcFn)TChunkCleanup::ChunkDestroyed,this,Kern::SvMsgQue(),0) sl@0: , iFactory(0) sl@0: { sl@0: aFactory->Open(); sl@0: iFactory = aFactory; sl@0: } sl@0: sl@0: TChunkCleanup::~TChunkCleanup() sl@0: { sl@0: if(iFactory) sl@0: iFactory->Close(0); sl@0: } sl@0: sl@0: void TChunkCleanup::ChunkDestroyed(TChunkCleanup* aSelf) sl@0: { sl@0: DSharedChunkFactory* factory = aSelf->iFactory; sl@0: if(factory) sl@0: { sl@0: factory->LockWait(); sl@0: ++ChunkDestroyedCount; sl@0: factory->LockSignal(); sl@0: } sl@0: delete aSelf; sl@0: } sl@0: sl@0: void TChunkCleanup::Cancel() sl@0: { sl@0: if(iFactory) sl@0: { sl@0: iFactory->Close(0); sl@0: iFactory = 0; sl@0: } sl@0: }; sl@0: sl@0: // sl@0: // DSharedChunkFactory sl@0: // sl@0: sl@0: TInt DSharedChunkFactory::Install() sl@0: { sl@0: return SetName(&KSharedChunkLddName); sl@0: } sl@0: sl@0: DSharedChunkFactory::~DSharedChunkFactory() sl@0: { sl@0: sl@0: } sl@0: sl@0: void DSharedChunkFactory::GetCaps(TDes8& /*aDes*/) const sl@0: { sl@0: // Not used but required as DLogicalDevice::GetCaps is pure virtual sl@0: } sl@0: sl@0: TInt DSharedChunkFactory::Create(DLogicalChannelBase*& aChannel) sl@0: { sl@0: aChannel = NULL; sl@0: DSharedChunkChannel* channel=new DSharedChunkChannel; sl@0: if(!channel) sl@0: return KErrNoMemory; sl@0: channel->iFactory = this; sl@0: aChannel = channel; sl@0: return KErrNone; sl@0: } sl@0: sl@0: void DSharedChunkFactory::LockWait() sl@0: { sl@0: NKern::FMWait(&iLock); sl@0: } sl@0: sl@0: void DSharedChunkFactory::LockSignal() sl@0: { sl@0: NKern::FMSignal(&iLock); sl@0: } sl@0: sl@0: DECLARE_STANDARD_LDD() sl@0: { sl@0: return new DSharedChunkFactory; sl@0: } sl@0: sl@0: // sl@0: // DSharedChunkChannel sl@0: // sl@0: sl@0: TInt DSharedChunkChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/) sl@0: { sl@0: return KErrNone; sl@0: } sl@0: sl@0: DSharedChunkChannel::DSharedChunkChannel() sl@0: :iFactory(0),iChunk(0),iKernelAddress(0),iMaxSize(0), iContiguous(0),iCacheAttrib(0) sl@0: { sl@0: } sl@0: sl@0: DSharedChunkChannel::~DSharedChunkChannel() sl@0: { sl@0: if(iChunk) sl@0: iChunk->Close(0); sl@0: } sl@0: sl@0: DChunk* DSharedChunkChannel::OpenChunk(TLinAddr* aKernelAddr,TInt* aMaxSize) sl@0: { sl@0: __ASSERT_CRITICAL // Thread must be in critical section (to avoid leaking access count on chunk) sl@0: LockWait(); sl@0: DChunk* chunk=iChunk; sl@0: if(chunk) sl@0: if(chunk->Open()!=KErrNone) sl@0: chunk = NULL; sl@0: if(aKernelAddr) sl@0: *aKernelAddr = chunk ? iKernelAddress : NULL; sl@0: if(aMaxSize) sl@0: *aMaxSize = chunk ? iMaxSize : 0; sl@0: LockSignal(); sl@0: return chunk; sl@0: } sl@0: sl@0: TInt DSharedChunkChannel::Request(TInt aFunction, TAny* a1, TAny* a2) sl@0: { sl@0: TInt i1 = (TInt)a1; sl@0: TInt i2 = (TInt)a2; sl@0: sl@0: TInt r=KErrNotSupported; sl@0: sl@0: switch(aFunction) sl@0: { sl@0: sl@0: case RSharedChunkLdd::ECreateChunk: sl@0: { sl@0: if(ChunkDestroyedCount==0) sl@0: NKern::Sleep(NKern::TimerTicks(100)); // Go idle for a while to let chunk cleanup DFCs to be called sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: sl@0: TChunkCleanup* cleanup = new TChunkCleanup(this->iFactory); sl@0: if(!cleanup) sl@0: { sl@0: NKern::ThreadLeaveCS(); sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: // Try and create chunk... sl@0: DChunk* chunk; sl@0: TChunkCreateInfo info; sl@0: sl@0: info.iType = (i1&EMultiple) sl@0: ? TChunkCreateInfo::ESharedKernelMultiple sl@0: : TChunkCreateInfo::ESharedKernelSingle; sl@0: sl@0: info.iMaxSize = i1&~ECreateFlagsMask; sl@0: #ifndef __WINS__ sl@0: info.iMapAttr = (i1&ECached) ? EMapAttrCachedMax sl@0: : EMapAttrFullyBlocking; sl@0: #else sl@0: info.iMapAttr = 0; sl@0: #endif sl@0: sl@0: info.iOwnsMemory = (i1&EOwnsMemory)!=0; sl@0: sl@0: info.iDestroyedDfc = cleanup; sl@0: sl@0: if(i1&EBadType) *(TUint8*)&info.iType = 0xff; sl@0: sl@0: TUint32 mapAttr; sl@0: TUint32 kernAddr; sl@0: r = Kern::ChunkCreate(info, chunk, kernAddr, mapAttr); sl@0: if(r!=KErrNone) sl@0: { sl@0: Kern::Printf("Chunk create failed with reason: %d",r); sl@0: delete cleanup; sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: sl@0: // Setup data members sl@0: LockWait(); sl@0: sl@0: if(iChunk) sl@0: r = KErrAlreadyExists; sl@0: else sl@0: { sl@0: iChunk = chunk; sl@0: iKernelAddress = kernAddr; sl@0: iMaxSize = info.iMaxSize; sl@0: #ifndef __WINS__ sl@0: TUint32 level1Info = mapAttr & EMapAttrL1CacheMask; sl@0: TUint32 level2Info = mapAttr & EMapAttrL2CacheMask; sl@0: TBool chunkIsNotcached = ((level2Info == EMapAttrL2Uncached) && sl@0: ((level1Info == EMapAttrFullyBlocking) || (level1Info == EMapAttrBufferedNC) || sl@0: (level1Info == EMapAttrBufferedC) || (level1Info == EMapAttrL1Uncached))); sl@0: iCacheAttrib = (chunkIsNotcached) ? ENotCached : ECached; sl@0: sl@0: #else sl@0: iCacheAttrib = 0; sl@0: #endif sl@0: ChunkDestroyedCount = 0; sl@0: } sl@0: LockSignal(); sl@0: sl@0: if(r!=KErrNone) sl@0: { sl@0: // There was an error, so discard created chunk sl@0: cleanup->Cancel(); sl@0: Kern::ChunkClose(chunk); sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: // Write back kernel address of chunk sl@0: if(a2) sl@0: kumemput32(a2,(TAny*)&kernAddr,4); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: case RSharedChunkLdd::EGetChunkHandle: sl@0: { sl@0: NKern::ThreadEnterCS(); sl@0: DChunk* chunk=OpenChunk(); sl@0: if(chunk) sl@0: { sl@0: Kern::Printf("We can open a chunk here."); sl@0: r = Kern::MakeHandleAndOpen(0,chunk); sl@0: Kern::Printf("The chunk handle we get is: %d", r); sl@0: chunk->Close(0); sl@0: } sl@0: else sl@0: r = KErrNotFound; sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: case RSharedChunkLdd::ECloseChunkHandle: sl@0: { sl@0: NKern::ThreadEnterCS(); sl@0: r = Kern::CloseHandle(0,i1); sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: case RSharedChunkLdd::ECommitMemory: sl@0: { sl@0: NKern::ThreadEnterCS(); sl@0: TUint32 chunkKernelAddress; sl@0: DChunk* chunk=OpenChunk(&chunkKernelAddress); sl@0: if(chunk) sl@0: { sl@0: TInt type = i1&ECommitTypeMask; sl@0: i1 &= ~ECommitTypeMask; sl@0: iContiguous = type; sl@0: switch(type) sl@0: { sl@0: case ENonContiguous: sl@0: r = Kern::ChunkCommit(chunk,i1,i2); sl@0: break; sl@0: sl@0: case EContiguous: sl@0: { sl@0: TUint32 physAddr=~0u; sl@0: r = Kern::ChunkCommitContiguous(chunk,i1,i2,physAddr); sl@0: if(r!=KErrNone || i2==0) sl@0: break; sl@0: if(physAddr==~0u) sl@0: { r=KErrGeneral; break; } sl@0: sl@0: // Check that ChunkPhysicalAddress returns addresses consistant with the commit sl@0: TUint32 kernAddr; sl@0: TUint32 mapAttr; sl@0: TUint32 physAddr2; sl@0: r = Kern::ChunkPhysicalAddress(chunk, i1, i2, kernAddr, mapAttr, physAddr2); sl@0: if(r==KErrNone) sl@0: if(kernAddr!=chunkKernelAddress+i1 || physAddr2!=physAddr) sl@0: r=KErrGeneral; sl@0: } sl@0: break; sl@0: sl@0: default: sl@0: r = KErrNotSupported; sl@0: break; sl@0: } sl@0: chunk->Close(0); sl@0: } sl@0: else sl@0: r = KErrNotFound; sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: sl@0: case RSharedChunkLdd::ECloseChunk: sl@0: { sl@0: NKern::ThreadEnterCS(); sl@0: sl@0: // Claim ownership of the chunk sl@0: LockWait(); sl@0: DChunk* chunk=iChunk; sl@0: iChunk = 0; sl@0: LockSignal(); sl@0: sl@0: // Close the chunk sl@0: if(chunk) sl@0: r = Kern::ChunkClose(chunk); sl@0: else sl@0: r = KErrNotFound; sl@0: sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: sl@0: case RSharedChunkLdd::ECacheAttribute: sl@0: { sl@0: Kern::Printf("In my shared chunk, the iCacheAttrib is: %d", iCacheAttrib); sl@0: return iCacheAttrib; sl@0: } sl@0: sl@0: case RSharedChunkLdd::EContiguousAttribute: sl@0: { sl@0: Kern::Printf("In my shared chunk, the iContiguous is: %d", iContiguous); sl@0: return iContiguous; sl@0: } sl@0: sl@0: default: sl@0: return KErrNotSupported; sl@0: } sl@0: } sl@0: