graphicshwdrivers/surfacemgr/test/testdriver/d_sharedchunk.cpp
author Faisal Memon <faisal.memon@nokia.com>
Fri, 13 Aug 2010 15:24:50 +0100
branchbug235_bringup_0
changeset 147 af143508cc47
parent 0 5d03bc08d59c
permissions -rwxr-xr-x
Prune down surface manager. Interface bit moved to surfacemanager_api. Implementation bit moved to graphics.nokia

// Copyright (c) 2007-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 <kernel/kern_priv.h>
#include "d_sharedchunk.h"

static TInt ChunkDestroyedCount=1;	// Test counter

//
// Class definitions
//

class DSharedChunkFactory : public DLogicalDevice
	{
public:
	~DSharedChunkFactory();
	virtual TInt Install();
	virtual void GetCaps(TDes8& aDes) const;
	virtual TInt Create(DLogicalChannelBase*& aChannel);
	void LockWait();
	void LockSignal();
private:
	NFastMutex iLock;
	};

class DSharedChunkChannel : public DLogicalChannelBase
	{
public:
	DSharedChunkChannel();
	~DSharedChunkChannel();
	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
	DChunk* OpenChunk(TLinAddr* aKernelAddr=0, TInt* aMaxSize=0);
	inline void LockWait()
		{ iFactory->LockWait(); }
	inline void LockSignal()
		{ iFactory->LockSignal(); }
public:
	DSharedChunkFactory*	iFactory;
	DChunk*					iChunk;
	TLinAddr				iKernelAddress;
	TInt					iMaxSize;

public:
	/** Require physically contiguous memory */
	TInt iContiguous;
	/** Caching attribute to create chunks memory */
	TInt iCacheAttrib;
	};

class TChunkCleanup : public TDfc
	{
public:
	TChunkCleanup(DSharedChunkFactory* aFactory);
	~TChunkCleanup();
	static void ChunkDestroyed(TChunkCleanup* aSelf);
	void Cancel();
public:
	DSharedChunkFactory* iFactory;
	};

//
// TChunkCleanup
//

TChunkCleanup::TChunkCleanup(DSharedChunkFactory* aFactory)
	: TDfc((TDfcFn)TChunkCleanup::ChunkDestroyed,this,Kern::SvMsgQue(),0)
	, iFactory(0)
	{
	aFactory->Open();
	iFactory = aFactory;
	}

TChunkCleanup::~TChunkCleanup()
	{
	if(iFactory)
		iFactory->Close(0);
	}

void TChunkCleanup::ChunkDestroyed(TChunkCleanup* aSelf)
	{
	DSharedChunkFactory* factory = aSelf->iFactory;
	if(factory)
		{
		factory->LockWait();
		++ChunkDestroyedCount;
		factory->LockSignal();
		}
	delete aSelf;
	}

void TChunkCleanup::Cancel()
	{
	if(iFactory)
		{
		iFactory->Close(0);
		iFactory = 0;
		}
	};

//
// DSharedChunkFactory
//

TInt DSharedChunkFactory::Install()
	{
	return SetName(&KSharedChunkLddName);
	}

DSharedChunkFactory::~DSharedChunkFactory()
	{

	}

void DSharedChunkFactory::GetCaps(TDes8& /*aDes*/) const
	{
	// Not used but required as DLogicalDevice::GetCaps is pure virtual
	}

TInt DSharedChunkFactory::Create(DLogicalChannelBase*& aChannel)
	{
	aChannel = NULL;
	DSharedChunkChannel* channel=new DSharedChunkChannel;
	if(!channel)
		return KErrNoMemory;
	channel->iFactory = this;
	aChannel = channel;
	return KErrNone;
	}

void DSharedChunkFactory::LockWait()
	{
	NKern::FMWait(&iLock);
	}

void DSharedChunkFactory::LockSignal()
	{
	NKern::FMSignal(&iLock);
	}

DECLARE_STANDARD_LDD()
	{
	return new DSharedChunkFactory;
	}

//
// DSharedChunkChannel
//

TInt DSharedChunkChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
	{
	return KErrNone;
	}

DSharedChunkChannel::DSharedChunkChannel()
:iFactory(0),iChunk(0),iKernelAddress(0),iMaxSize(0), iContiguous(0),iCacheAttrib(0)
	{
	}

DSharedChunkChannel::~DSharedChunkChannel()
	{
	if(iChunk)
		iChunk->Close(0);
	}

DChunk* DSharedChunkChannel::OpenChunk(TLinAddr* aKernelAddr,TInt* aMaxSize)
	{
	__ASSERT_CRITICAL	// Thread must be in critical section (to avoid leaking access count on chunk)
	LockWait();
	DChunk* chunk=iChunk;
	if(chunk)
		if(chunk->Open()!=KErrNone)
			chunk = NULL;
	if(aKernelAddr)
		*aKernelAddr = chunk ? iKernelAddress : NULL;
	if(aMaxSize)
		*aMaxSize = chunk ? iMaxSize : 0;
	LockSignal();
	return chunk;
	}

TInt DSharedChunkChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
	{
	TInt i1 = (TInt)a1;
	TInt i2 = (TInt)a2;

	TInt r=KErrNotSupported;

	switch(aFunction)
		{

	case RSharedChunkLdd::ECreateChunk:
		{
		if(ChunkDestroyedCount==0)
			NKern::Sleep(NKern::TimerTicks(100)); // Go idle for a while to let chunk cleanup DFCs to be called

		NKern::ThreadEnterCS();

		TChunkCleanup* cleanup = new TChunkCleanup(this->iFactory);
		if(!cleanup)
			{
			NKern::ThreadLeaveCS();
			return KErrNoMemory;
			}

		// Try and create chunk...
		DChunk* chunk;
		TChunkCreateInfo info;

		info.iType		 = (i1&EMultiple)
							? TChunkCreateInfo::ESharedKernelMultiple
							: TChunkCreateInfo::ESharedKernelSingle;

		info.iMaxSize	 = i1&~ECreateFlagsMask;
#ifndef __WINS__
		info.iMapAttr = (i1&ECached) ? EMapAttrCachedMax
						 : EMapAttrFullyBlocking;
#else
		info.iMapAttr = 0;
#endif

		info.iOwnsMemory = (i1&EOwnsMemory)!=0;

		info.iDestroyedDfc = cleanup;

		if(i1&EBadType) *(TUint8*)&info.iType = 0xff;

		TUint32 mapAttr;
		TUint32 kernAddr;
		r = Kern::ChunkCreate(info, chunk, kernAddr, mapAttr);
		if(r!=KErrNone)
			{
			Kern::Printf("Chunk create failed with reason: %d",r);
			delete cleanup;
			NKern::ThreadLeaveCS();
			return r;
			}

		// Setup data members
		LockWait();
		
		if(iChunk)
			r = KErrAlreadyExists;
		else
			{
			iChunk = chunk;
			iKernelAddress = kernAddr;
			iMaxSize = info.iMaxSize;
#ifndef __WINS__
			TUint32 level1Info = mapAttr & EMapAttrL1CacheMask;
			TUint32 level2Info = mapAttr & EMapAttrL2CacheMask;
			TBool chunkIsNotcached =  ((level2Info == EMapAttrL2Uncached) &&
			    ((level1Info == EMapAttrFullyBlocking) || (level1Info == EMapAttrBufferedNC) ||
			     (level1Info == EMapAttrBufferedC) || (level1Info == EMapAttrL1Uncached)));
			iCacheAttrib = (chunkIsNotcached) ? ENotCached : ECached;

#else
			iCacheAttrib = 0;
#endif
			ChunkDestroyedCount = 0;
			}
		LockSignal();

		if(r!=KErrNone)
			{
			// There was an error, so discard created chunk
			cleanup->Cancel();
			Kern::ChunkClose(chunk);
			NKern::ThreadLeaveCS();
			return r;
			}

		NKern::ThreadLeaveCS();

		// Write back kernel address of chunk
		if(a2)
			kumemput32(a2,(TAny*)&kernAddr,4);

		return KErrNone;
		}


	case RSharedChunkLdd::EGetChunkHandle:
		{
		NKern::ThreadEnterCS();
		DChunk* chunk=OpenChunk();
		if(chunk)
			{
			Kern::Printf("We can open a chunk here.");
			r = Kern::MakeHandleAndOpen(0,chunk);
			Kern::Printf("The chunk handle we get is: %d", r);
			chunk->Close(0);
			}
		else
			r = KErrNotFound;
		NKern::ThreadLeaveCS();
		return r;
		}


	case RSharedChunkLdd::ECloseChunkHandle:
		{
		NKern::ThreadEnterCS();
		r = Kern::CloseHandle(0,i1);
		NKern::ThreadLeaveCS();
		return r;
		}


	case RSharedChunkLdd::ECommitMemory:
		{
		NKern::ThreadEnterCS();
		TUint32 chunkKernelAddress;
		DChunk* chunk=OpenChunk(&chunkKernelAddress);
		if(chunk)
			{
			TInt type = i1&ECommitTypeMask;
			i1 &= ~ECommitTypeMask;
			iContiguous = type;
			switch(type)
				{
			case ENonContiguous:
				r = Kern::ChunkCommit(chunk,i1,i2);
				break;

			case EContiguous:
				{
				TUint32 physAddr=~0u;
				r = Kern::ChunkCommitContiguous(chunk,i1,i2,physAddr);
				if(r!=KErrNone || i2==0)
					break;
				if(physAddr==~0u)
					{ r=KErrGeneral; break; }

				// Check that ChunkPhysicalAddress returns addresses consistant with the commit
				TUint32 kernAddr;
				TUint32 mapAttr;
				TUint32 physAddr2;
				r = Kern::ChunkPhysicalAddress(chunk, i1, i2, kernAddr, mapAttr, physAddr2);
				if(r==KErrNone)
					if(kernAddr!=chunkKernelAddress+i1 || physAddr2!=physAddr)
						r=KErrGeneral;
				}
				break;

			default:
				r = KErrNotSupported;
				break;
				}
			chunk->Close(0);
			}
		else
			r = KErrNotFound;
		NKern::ThreadLeaveCS();
		return r;
		}

	case RSharedChunkLdd::ECloseChunk:
		{
		NKern::ThreadEnterCS();

		// Claim ownership of the chunk
		LockWait();
		DChunk* chunk=iChunk;
		iChunk = 0;
		LockSignal();

		// Close the chunk
		if(chunk)
			r = Kern::ChunkClose(chunk);
		else
			r = KErrNotFound;

		NKern::ThreadLeaveCS();
		return r;
		}

	case RSharedChunkLdd::ECacheAttribute:
		{
		Kern::Printf("In my shared chunk, the iCacheAttrib is: %d", iCacheAttrib);
		return iCacheAttrib;
		}

	case RSharedChunkLdd::EContiguousAttribute:
		{
		Kern::Printf("In my shared chunk, the iContiguous is: %d", iContiguous);
		return iContiguous;
		}

	default:
		return KErrNotSupported;
		}
	}