userlibandfileserver/fileserver/smassstorage/inc/rwdrivethread.h
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:26:05 +0100
branchRCL_3
changeset 29 743008598095
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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 the License "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:
// Thread for reading and writing to a drive.
// 
//

/**
 @file
 @internalTechnology
*/

#ifndef __RWDRIVETHREAD_H__
#define __RWDRIVETHREAD_H__

#ifdef MSDC_MULTITHREADED

typedef void (*ProcessWriteCompleteFunc)(TUint8* aAddress, TAny* aPtr);


/**
Class contains buffer for data with associated drive offset and length in bytes.
*/

class TBlockDesc
{
public:

	TBlockDesc();
	void SetPtr(TPtr8& aDes);

	TPtr8 GetReadBuffer();
	TPtr8 GetReadBuffer(TUint aLength, const TInt64& aOffset);

public:
	TInt64 iByteOffset;
	TUint iLength;
	TPtr8 iBuf;
};


/**
Class contains two buffers. Whilst one buffer is being read the
other buffer can be written to. The buffers should be accessed 
by the buffer pointers iDescReadPtr and iDescWritePtr.
*/

class TBlockDescBuffer
{
public:
	TBlockDescBuffer();

	void SwapDesc();
	TInt MaxLength() const {return iDesc2.iBuf.MaxLength();}
	TInt GetBufferNumber(const TPtr8* aBufferPtr) const;
	void SetUpReadBuf(TPtr8& aDes1, TPtr8& aDes2);

public:
	/** Points to block descriptor containing buffer to read from */
	TBlockDesc* iDescReadPtr;
	/** Points to block descriptor containing buffer to write to */
	TBlockDesc* iDescWritePtr;
	
private:
	/** Block descriptor for read/write operations */
	TBlockDesc iDesc1;
	/** Block descriptor for read/write operations */
	TBlockDesc iDesc2;
};


/**
Provides the common thread context used by CReadDriveThread and CWriteDriveThread 
classes.
*/
class CThreadContext : public CBase
{
public:
	static CThreadContext* NewL(const TDesC& aName,
								TThreadFunction aThreadFunction,
								TAny* aOwner);
	~CThreadContext();

private:
	CThreadContext();
	void ConstructL(const TDesC& aName, TThreadFunction aThreadFunction, TAny* aOwner);


public:
	void Resume() {iThread.Resume();}

	TInt MaxBufferLength() const {return iBuffer.MaxLength();} 
	TPtr8 GetReadBuffer();
	TPtr8 GetReadBuffer(TInt aLength);

	TPtrC8 WriteBuf();

public:
	/** Used to tell thread which drive to use */
	CMassStorageDrive* iDrive;
	/** Used by the thread to return error code */
	TInt iError;
	/** CS to regulate read/write buffer access */
	RCriticalSection iCritSect;
	
	/** buffer for reading and writing */
	TBlockDescBuffer iBuffer;

public:
	RThread iThread;
};


/**
Separate disk writer thread, used to implement OUT transfer double-buffering.
*/
class CWriteDriveThread : public CBase
	{
public:
	static CWriteDriveThread* NewL();
	~CWriteDriveThread();

private:
	CWriteDriveThread();
	void ConstructL();

public:
	TBlockDesc* GetReadDesc();

	TInt WriteDriveData(CMassStorageDrive* aDrive, const TInt64& aOffset, TPtrC8& aDes, ProcessWriteCompleteFunc aFunc, TAny* aPtr);

	TUint WriteBufferLength() const {return iThreadContext->iBuffer.iDescWritePtr->iBuf.Length();}
	TUint ReadBufferLength() const {return iThreadContext->iBuffer.iDescReadPtr->iBuf.Length();}

	TInt DeferredError() const {return iThreadContext->iError;}
	void ClearDeferredError() {iThreadContext->iError = KErrNone;}
	void WaitForWriteEmpty();

	TBool IsRecentlyWritten(TInt64 aOffset, TInt aLength);
	inline void SetCommandWrite10(TBool aIsWriteCommand) {iIsCommandWrite10 = aIsWriteCommand;};

private:
	static TInt ThreadFunction(TAny* aSelf);
	TInt WriteToDrive();

public:
	/** Thread context */
	CThreadContext* iThreadContext;

	TInt iWriteCounter;
private:
	/** Semaphore for reading USB */
	RSemaphore iProducerSem;
	/** Semaphore for writing to drive */
	RSemaphore iConsumerSem;
	/* Call back to tell transport that 'transfer' was written and the corresponding buffer can be overwriiten (mainly for SC LDD) */
	ProcessWriteCompleteFunc iCallback;
	TAny* iCallbackParameter;
	/* Flag set to true if the command is Write10. Used in Read10 to ignore pre-read if the previous command was Write10 */
	TBool iIsCommandWrite10;
	};


/**
Separate disk reader thread, used to implement IN transfer double-buffering.
*/
class CReadDriveThread : public CBase
	{
public:
	static CReadDriveThread* NewL();
	~CReadDriveThread();

private:
	CReadDriveThread();
	void ConstructL();

public:
	TBool ReadDriveData(CMassStorageDrive* aDrive, const TInt64& aOffset, TUint32 aLength, TBool aIgnoreCache);
	void DiscardRead();

private:
	static TInt ThreadFunction(TAny* aSelf);
	TInt ReadFromDrive();

public:
	/** Thread context */
	CThreadContext* iThreadContext;
	TBool iCompleted;

private:
	TBool iThreadRunning;
	};


//-----------------------------------------------

/**
Swap the buffer which the read and write buffer pointers are pointing to.
*/
inline void TBlockDescBuffer::SwapDesc()
{
	TBlockDesc* const tmp = iDescReadPtr;
	iDescReadPtr = iDescWritePtr;
	iDescWritePtr = tmp;
}

inline TPtr8 TBlockDesc::GetReadBuffer()
{
	return iBuf.LeftTPtr(iBuf.Length());
}


inline TPtr8 TBlockDesc::GetReadBuffer(TUint aLength, const TInt64& aOffset)
{
	iByteOffset = aOffset;
	iLength = aLength;
	iBuf.SetLength(aLength);
	
	return GetReadBuffer();
}

//-----------------------------------------------

/**
Returns the id of the buffer

@param bufferPtr pointer to the buffer.
@return  returns the buffer ID or -1 if the buffer is not found.
*/
inline TInt TBlockDescBuffer::GetBufferNumber(const TPtr8* aBufferPtr) const
{
	TInt no = -1;
	if (aBufferPtr == &iDesc1.iBuf)
		no = 1;
	else if (aBufferPtr == &iDesc2.iBuf)
		no = 2;
	return no;
}


//-----------------------------------------------

inline TPtr8 CThreadContext::GetReadBuffer()
{
	TInt len = iBuffer.iDescReadPtr->iBuf.Length();
	return iBuffer.iDescReadPtr->iBuf.LeftTPtr(len);
}


inline TPtr8 CThreadContext::GetReadBuffer(TInt aLength)
{
	iBuffer.iDescReadPtr->iBuf.SetLength(aLength);
	return GetReadBuffer();
}


inline TPtrC8 CThreadContext::WriteBuf()
{
	return iBuffer.iDescWritePtr->iBuf;
}

//-----------------------------------------------

inline TBlockDesc* CWriteDriveThread::GetReadDesc()
{
	return iThreadContext->iBuffer.iDescReadPtr;
}

//-----------------------------------------------

#endif //  MSDC_MULTITHREADED

#endif // __RWDRIVETHREAD_H__