201037_09
authorhgs
Mon, 27 Sep 2010 10:52:00 +0100
changeset 273 6a75fa55495f
parent 271 dc268b18d709
child 274 c7e97f847492
201037_09
kernel/eka/bld.inf
kernel/eka/drivers/usbcc/descriptors.cpp
kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.cpp
kernel/eka/eabi/usbdescriptorsu.def
kernel/eka/extension/bld.inf
kernel/eka/include/d32usbdescriptors.h
kernel/eka/include/e32ver.h
kernel/eka/include/nkern/win32/nk_plat.h
kernel/eka/include/usb.h
kernel/eka/nkern/nkern.cpp
kernel/eka/nkern/win32/ncsched.cpp
kernel/eka/nkern/win32/ncthrd.cpp
kernel/eka/nkern/win32/vectors.cpp
kernel/eka/release.txt
kernel/eka/rombuild/alltests.oby
kernel/eka/rombuild/autotest.oby
kernel/eka/rombuild/autotest_e32tests.oby
kernel/eka/rombuild/autotest_f32tests.oby
kernel/eka/rombuild/f32_perf_tests.oby
kernel/eka/rombuild/f32_perf_tests_fat_exfat.oby
kernel/eka/rombuild/f32tests.oby
kernel/eka/rombuild/h4usbmmctest_load.oby
kernel/eka/rombuild/h4usbmmctest_test.oby
kernel/eka/rombuild/h4usbstress.oby
kernel/eka/rombuild/mmctest_load.oby
kernel/eka/rombuild/mmctest_test.oby
kernel/eka/rombuild/mmctest_test_e32tests.oby
kernel/eka/rombuild/mmctest_test_f32tests.oby
kernel/eka/rombuild/nandtest_load.oby
kernel/eka/rombuild/nandtest_test.oby
kernel/eka/rombuild/nandtest_test_e32tests.oby
kernel/eka/rombuild/nandtest_test_f32tests.oby
kerneltest/e32test/active/t_schedrace.cpp
kerneltest/e32test/device/t_usbcsc.cpp
kerneltest/e32test/group/bld.inf
kerneltest/e32test/group/t_schedrace.mmp
kerneltest/e32test/group/t_usb_device.mmp
kerneltest/e32test/group/t_usb_scdevice.mmp
kerneltest/e32test/traces_t_usbcsc/fixed_id.definitions
kerneltest/e32test/usb/t_usb_device/src/activecontrol.cpp
kerneltest/f32test/plugins/version_1/virus/t_vshook.cpp
kerneltest/f32test/plugins/version_1/virus/virusdef.txt
kerneltest/f32test/server/t_fsrv.cpp
package_definition.xml
userlibandfileserver/fileserver/group/release.txt
userlibandfileserver/fileserver/inc/f32fsys.h
userlibandfileserver/fileserver/inc/f32fsys.inl
userlibandfileserver/fileserver/inc/f32ver.h
userlibandfileserver/fileserver/sfile/sf_file.cpp
userlibandfileserver/fileserver/sfile/sf_func.h
userlibandfileserver/fileserver/sfile/sf_main.cpp
userlibandfileserver/fileserver/sfile/sf_notify.cpp
userlibandfileserver/fileserver/sfile/sf_ops.h
userlibandfileserver/fileserver/sfile/sf_plugin.h
userlibandfileserver/fileserver/sfile/sf_plugin_man.cpp
userlibandfileserver/fileserver/sfile/sf_request.cpp
userlibandfileserver/fileserver/sfile/sf_ses.cpp
userlibandfileserver/fileserver/sfile/sf_std.h
userlibandfileserver/fileserver/sfile/sf_std.inl
userlibandfileserver/fileserver/sfile/sf_thread.cpp
userlibandfileserver/fileserver/sfsrv/cl_file.cpp
--- a/kernel/eka/bld.inf	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/bld.inf	Mon Sep 27 10:52:00 2010 +0100
@@ -406,18 +406,6 @@
 include/e32shbufcmn.h							SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(e32shbufcmn.h)
 include/e32shbuf_priv.h							SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(e32shbuf_priv.h)
 
-// Build system extensions
-extension/base_rvct_common.mk					/epoc32/tools/makefile_templates/base/
-extension/bootstrap.flm							/epoc32/tools/makefile_templates/base/
-extension/bootstrap.meta						/epoc32/tools/makefile_templates/base/
-extension/bootstrap.mk							/epoc32/tools/makefile_templates/base/
-extension/bootstrap.xml							/epoc32/tools/makefile_templates/base/
-extension/config.meta							/epoc32/tools/makefile_templates/base/
-extension/config.mk								/epoc32/tools/makefile_templates/base/
-extension/copy_default.meta						/epoc32/tools/makefile_templates/base/
-extension/copy_default.mk						/epoc32/tools/makefile_templates/base/
-extension/genexec.meta							/epoc32/tools/makefile_templates/base/
-extension/genexec.mk							/epoc32/tools/makefile_templates/base/
 
 PRJ_MMPFILES
 
--- a/kernel/eka/drivers/usbcc/descriptors.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/drivers/usbcc/descriptors.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -603,8 +603,11 @@
 	SetBufferPointer(iBuf);
 	iBuf[0] = iBuf.Size();									// bLength
 	iBuf[1] = KUsbDescType_Otg;								// bDescriptorType
-	iBuf[2] = (aHnpSupport ? KUsbOtgAttr_HnpSupp : 0) |
-		(aSrpSupport ? KUsbOtgAttr_SrpSupp : 0);			// bmAttributes
+  // B HNP not supported which is temporarily hard coded here. 
+	iBuf[2] = ( aHnpSupport ? 0 : 0 ) | ( aSrpSupport ? KUsbOtgAttr_SrpSupp : 0 );			// bmAttributes			
+	iBuf[3] = KUsbOtgDesc_bcdOTG & 0x00ff;
+  iBuf[4] = ( KUsbOtgDesc_bcdOTG >> 8 ) & 0x00ff;
+		
 	return KErrNone;
     }
 
--- a/kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -1,4 +1,4 @@
-// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 2007-2010 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"
@@ -1130,7 +1130,7 @@
 	// Only cast if correctly indentified as otg descriptor
 	if(	aOriginal &&
 		aOriginal->ibDescriptorType == EOTG &&
-		aOriginal->ibLength == TUsbOTGDescriptor::KSizeInOctets &&
+		TUsbOTGDescriptor::IsValidOTGDescriptorLength( aOriginal->ibLength ) &&
 		aOriginal->iRecognisedAndParsed == ERecognised)
 		{
 		ret = static_cast<TUsbOTGDescriptor*>(aOriginal);
@@ -1157,7 +1157,17 @@
     // the TPL.
     return (ParseTUint8(iBlob, EbmAttributes) & 0x01) == 0x01;
     }
-	
+
+EXPORT_C TUint16 TUsbOTGDescriptor::BcdOTG() const
+	{
+    TUint16 bcdOTG = 0x0000;
+    if ( iBlob[EbmLength] > TUsbOTGDescriptor::KSizeInOctets )
+	    {
+        bcdOTG = ( iBlob[EbcdOTG] ) | ( iBlob[EbcdOTG + 1] << 8 );
+	    }
+    return bcdOTG;
+	}
+
 /**
 The parsing routine for OTG descriptors.
 
@@ -1167,13 +1177,14 @@
 	{
 	TUsbOTGDescriptor* endDes = NULL;
 
+	TUint8 descriptorLength = aUsbDes[KbLengthOffset];
 	const TInt KMinOTGDesDecisionLength = 2;
 	if(	aUsbDes.Length() >= KMinOTGDesDecisionLength &&
 		aUsbDes[KbDescriptorTypeOffset] == EOTG &&
-		aUsbDes[KbLengthOffset] == TUsbOTGDescriptor::KSizeInOctets)
+		TUsbOTGDescriptor::IsValidOTGDescriptorLength( descriptorLength ) )
 		{
 		// Robustness check - check the length field is valid, and that we have enough data.
-		if(aUsbDes.Length() < TUsbOTGDescriptor::KSizeInOctets)
+		if(aUsbDes.Length() < descriptorLength)
 			{
 			User::Leave(KErrCorrupt);
 			}
@@ -1181,10 +1192,10 @@
 		// Looks ok to be an OTG descriptor.
 		endDes = new(ELeave) TUsbOTGDescriptor;
 		// Set the standard fields
-		endDes->ibLength = TUsbOTGDescriptor::KSizeInOctets;
+		endDes->ibLength = descriptorLength;
 		endDes->ibDescriptorType = EOTG;
 		// Set the blob appropriately
-		endDes->iBlob.Set(aUsbDes.Left(TUsbOTGDescriptor::KSizeInOctets));
+		endDes->iBlob.Set(aUsbDes.Left(descriptorLength));
 
 		// Null the pointers
 		endDes->iFirstChild = NULL;
@@ -1194,7 +1205,7 @@
 		endDes->iRecognisedAndParsed = ERecognised;
 
 		// Update the data-left-to-parse Symbian descriptor
-		aUsbDes.Set(aUsbDes.Mid(TUsbOTGDescriptor::KSizeInOctets));
+		aUsbDes.Set(aUsbDes.Mid(descriptorLength));
 		}
 
 	return endDes;
@@ -1232,6 +1243,20 @@
 		}
 	}
 
+/**
+@internalComponent
+*/
+/*static*/ TBool TUsbOTGDescriptor::IsValidOTGDescriptorLength(TUint8 aLength)
+	{
+    TBool ret = EFalse;
+    const TUint8 KOTG13DescriptorLength = 3; //OTG1.3 
+    const TUint8 KOTG20DescriptorLength = 5; //OTG2.0
+    if ( ( aLength == KOTG13DescriptorLength ) || ( aLength == KOTG20DescriptorLength ) )
+        {
+        ret = ETrue;
+        }
+    return ret;
+	}
 
 // ----------------------
 // TUsbStringDescriptor
--- a/kernel/eka/eabi/usbdescriptorsu.def	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/eabi/usbdescriptorsu.def	Mon Sep 27 10:52:00 2010 +0100
@@ -92,4 +92,4 @@
 	_ZNK17TUsbOTGDescriptor10AttributesEv @ 91 NONAME
 	_ZNK17TUsbOTGDescriptor12HNPSupportedEv @ 92 NONAME
 	_ZNK17TUsbOTGDescriptor12SRPSupportedEv @ 93 NONAME
-
+        _ZNK17TUsbOTGDescriptor6BcdOTGEv @ 94 NONAME
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/extension/bld.inf	Mon Sep 27 10:52:00 2010 +0100
@@ -0,0 +1,27 @@
+// Copyright (c) 2010 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:
+// 
+
+PRJ_EXPORTS
+base_rvct_common.mk					/epoc32/tools/makefile_templates/base/
+bootstrap.flm						/epoc32/tools/makefile_templates/base/
+bootstrap.meta						/epoc32/tools/makefile_templates/base/
+bootstrap.mk						/epoc32/tools/makefile_templates/base/
+bootstrap.xml						/epoc32/tools/makefile_templates/base/
+config.meta							/epoc32/tools/makefile_templates/base/
+config.mk							/epoc32/tools/makefile_templates/base/
+copy_default.meta					/epoc32/tools/makefile_templates/base/
+copy_default.mk						/epoc32/tools/makefile_templates/base/
+genexec.meta						/epoc32/tools/makefile_templates/base/
+genexec.mk							/epoc32/tools/makefile_templates/base/
--- a/kernel/eka/include/d32usbdescriptors.h	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/include/d32usbdescriptors.h	Mon Sep 27 10:52:00 2010 +0100
@@ -1,4 +1,4 @@
-// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 2007-2010 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"
@@ -528,20 +528,24 @@
 	IMPORT_C static TUsbOTGDescriptor* Cast(TUsbGenericDescriptor* aOriginal);
 
 public:
-	static const TInt KSizeInOctets = 3;
+	static const TInt KSizeInOctets = 3; //OTG1.3 otg descriptor length
 	enum TFieldOffsets
 		{
-		EbmAttributes		= 2
+	  EbmLength       = 0,
+		EbmAttributes		= 2,
+		EbcdOTG         = 3
 		};
 
 public:
 	IMPORT_C TUint8 Attributes() const;
     IMPORT_C TBool HNPSupported() const;
     IMPORT_C TBool SRPSupported() const;
+    IMPORT_C TUint16 BcdOTG() const;
 public:
 	static TUsbOTGDescriptor* ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc);
 	virtual TBool IsParent(TUsbGenericDescriptor& aPotentialParent);
 	virtual TBool IsPeer(TUsbGenericDescriptor& aPotentialPeer);
+	static TBool IsValidOTGDescriptorLength(TUint8 aLength);
 	};
 
 
--- a/kernel/eka/include/e32ver.h	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/include/e32ver.h	Mon Sep 27 10:52:00 2010 +0100
@@ -28,7 +28,7 @@
 
 const TInt KE32MajorVersionNumber=2;
 const TInt KE32MinorVersionNumber=0;
-const TInt KE32BuildVersionNumber=4001;
+const TInt KE32BuildVersionNumber=4003;
 
 const TInt KMachineConfigurationMajorVersionNumber=1;
 const TInt KMachineConfigurationMinorVersionNumber=0;
--- a/kernel/eka/include/nkern/win32/nk_plat.h	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/include/nkern/win32/nk_plat.h	Mon Sep 27 10:52:00 2010 +0100
@@ -1,4 +1,4 @@
-// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 1998-2010 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"
@@ -12,7 +12,7 @@
 //
 // Description:
 // e32\include\nkern\win32\nk_plat.h
-// 
+//
 // WARNING: This file contains some APIs which are internal and are subject
 //          to change without notice. Such APIs should therefore not be used
 //          outside the Kernel and Hardware Services package.
@@ -23,20 +23,20 @@
  @internalComponent
 */
 
-#ifndef __NK_WIN32_H__
-#define __NK_WIN32_H__
+#ifndef	__NK_WIN32_H__
+#define	__NK_WIN32_H__
 
-#define _CRTIMP			// we want to use the win32 static runtime library
+#define	_CRTIMP			// we want to use the win32 static runtime library
 
-#define WIN32_LEAN_AND_MEAN
-#define _WIN32_WINNT 0x0400
+#define	WIN32_LEAN_AND_MEAN
+#define	_WIN32_WINNT	0x0400
 #include <windows.h>
 
-typedef void (*TExcHandler)(TAny*,TAny*);
+typedef void (*TExcHandler)(TAny*, TAny*);
 
 struct TWin32ExcInfo
 	{
-	enum {EExcInKernel = 0x1};
+	enum { EExcInKernel = 0x1 };
 public:
 	TExcHandler iHandler;
 	TAny* iParam[2];
@@ -67,20 +67,21 @@
 enum TEmulThreadType
 	{
 	EThreadEvent,	// an 'interrupt' thread, interacts with Win32 events
-	EThreadNKern	// a nKern thread, identified by a NThread control block
+	EThreadNKern	// an nKern thread, identified by an NThread control block
 	};
 
 class NThread : public NThreadBase
 	{
 public:
 	typedef void (*TDivert)();
-	enum TWakeup {ERelease,EResume,EResumeLocked,EIdle,EEscaped,EResumeDiverted};
-	enum TSelectCpu {ECpuAll=-1,ECpuSingle=-2};
+	enum TWakeup { ERelease, EResume, EResumeLocked, EIdle, EEscaped, EResumeDiverted };
+	enum TSelectCpu { ECpuAll = -1, ECpuSingle = -2 };
+
 public:
 	TInt Create(SNThreadCreateInfo& aInfo, TBool aInitial);
 	void Stillborn();
 	void DoForceExit();
-//
+
 	IMPORT_C static void Idle();
 	IMPORT_C static void SetProperties(TBool aTrace, TInt aCpu);
 	TBool WakeUp();
@@ -90,10 +91,10 @@
 
 private:
 	static DWORD WINAPI StartThread(LPVOID aParam);
-//
+
 	static void ExitSync();
 	static void ExitAsync();
-//
+
 	static void Exception();
 	static LONG WINAPI ExceptionFilter(EXCEPTION_POINTERS* aExc);
 
@@ -105,74 +106,75 @@
 public:
 	HANDLE iWinThread;
 	DWORD iWinThreadId;
-	HANDLE iScheduleLock;	// event used for scheduling interlock
-	TBool iDiverted;		// flag to indicate that the thread is being diverted
-	TDivert iDivert;		// function to invoke after reschedule, may be null
-	TAny* iDivertReturn;    // return address from diversion
-	TInt iInKernel;			// flag to indicate if the thread is running 'in' the kernel
-	TWakeup iWakeup;		// indicates how to wake up the thread
+	HANDLE iScheduleLock;		// event used for scheduling interlock
+	volatile TInt iInKernel;	// flag to indicate if the thread is running 'in' the kernel
+	TWakeup iWakeup;			// indicates how to wake up the thread
+	TBool iDiverting;			// flag to indicate that the thread is being diverted
+	TDivert iDivertFn;			// function to invoke after reschedule, may be null
+	TAny* iDivertReturn;    	// return address from diversion
 	TLinAddr iUserStackBase;
 	};
 
 IMPORT_C HANDLE CreateWin32Thread(TEmulThreadType aType, LPTHREAD_START_ROUTINE aThreadFunc, LPVOID aPtr, TBool aRun);
-IMPORT_C void StartOfInterrupt();
-IMPORT_C void EndOfInterrupt();
 
 void SchedulerInit(NThread& aInit);
 void SchedulerRegister(NThread& aSelf);
-NThread* SchedulerThread();
-NThread& CheckedCurrentThread();
 void SchedulerLock();
 void SchedulerUnlock();
 void SchedulerEscape();
 void SchedulerReenter();
-void Win32FindNonPreemptibleFunctions();
+NThread* RunningThread();
+NThread& CheckedCurrentThread();
 
-inline void EnterKernel(TBool aCheck=TRUE)
-	{
-	if (++CheckedCurrentThread().iInKernel==1 && aCheck)
-		{
-		NThread& t = CheckedCurrentThread();
-		__NK_ASSERT_ALWAYS(t.iCsCount==0);
-		__NK_ASSERT_ALWAYS(t.iHeldFastMutex==0);
-		__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked==0);
-		}
-	}
+void EnterKernel(TBool aDiversion = FALSE);
+void LeaveKernel();
+IMPORT_C void StartOfInterrupt();
+IMPORT_C void EndOfInterrupt();
 
-void LeaveKernel();
+void Win32FindNonPreemptibleFunctions();
 
 IMPORT_C TInt __fastcall Dispatch(TInt aFunction, TInt* aArgs);
 
-typedef TInt (__cdecl *TExecHandler)(TInt,TInt,TInt,TInt);
-typedef void (__cdecl *TPreprocessHandler)(TInt*,TUint32);
+typedef TInt (__cdecl* TExecHandler)(TInt, TInt, TInt, TInt);
+typedef void (__cdecl* TPreprocessHandler)(TInt*, TUint32);
 
 // Emulator nKern scheduling data
 class Win32Interrupt
 	{
 public:
 	void Init();
-	TInt Mask();
-	void Restore(TInt aLevel);
-	void Begin();
-	void End();
+	void BeginInterrupt();
+	void EndInterrupt();
+	TInt MaskInterrupts(TBool aPreempt);
+	void RestoreInterruptMask(TInt aLevel);
+	void ForceReschedule();
+
 	inline TBool InInterrupt() const
-		{return iInterrupted!=0;}	
-	void ForceReschedule();
+		{
+		return iInterrupted != 0;
+		}
 	inline TBool InterruptsStatus(TBool aRequest) const
-	{return aRequest?(iLevel==0):(iLevel!=0);}
+		{
+		return aRequest ? (iLevel == 0) : (iLevel != 0);
+		}
+
 private:
-	static void Reschedule(TAny*);
+	static void SchedulerThreadFunction(TAny*);
+
 private:
-	TInt iLock;
-	HANDLE iQ;
-	DWORD iOwner;
-	TInt iLevel;
+	CRITICAL_SECTION iCS;			// protects data below
+	HANDLE iQ;						// semaphore to wait on
+
+	DWORD iOwner;					// controller of the mask
+	TInt iLevel;					// owner's recursion count
+	TInt iWaiting;					// number of waiters
+
 	TBool iRescheduleOnExit;
-	NThread* iInterrupted;
-	NThread iScheduler;
+	NThread* iInterrupted;			// the thread preempted by Begin()
+	NThread iScheduler;				// the dedicated scheduler thread
 	};
 
-extern TBool Win32AtomicSOAW;	// flag to indicate availability of SignalObjectAndWait() API
+extern TBool Win32AtomicSOAW;		// flag to indicate availability of SignalObjectAndWait() API
 extern TBool Win32TraceThreadId;
 extern TInt Win32SingleCpu;
 extern Win32Interrupt Interrupt;
@@ -184,4 +186,60 @@
 
 void FastCounterInit();
 
-#endif
+// Wrappers round Win32 thread control & synchronisation functions ...
+inline void CheckedSuspendThread(HANDLE aWinThread)
+	{
+	TInt suspLevel = (TInt)SuspendThread(aWinThread);
+	__NK_ASSERT_ALWAYS(suspLevel >= 0);
+	}
+
+inline void CheckedResumeThread(HANDLE aWinThread, BOOL once = EFalse)
+	{
+	TInt suspLevel = (TInt)ResumeThread(aWinThread);
+	__NK_ASSERT_ALWAYS(once ? suspLevel == 1 : suspLevel > 0);				// check thread was previously suspended
+	}
+
+inline void CheckedGetThreadContext(HANDLE aWinThread, CONTEXT* aContext)
+	{
+	DWORD r = GetThreadContext(aWinThread, aContext);
+	__NK_ASSERT_ALWAYS(r != 0);
+	}
+
+inline void CheckedSetThreadContext(HANDLE aWinThread, CONTEXT* aContext)
+	{
+	DWORD r = SetThreadContext(aWinThread, aContext);
+	__NK_ASSERT_ALWAYS(r != 0);
+	}
+
+inline void CheckedSetThreadPriority(HANDLE aWinThread, TInt aPriority)
+	{
+	DWORD r = SetThreadPriority(aWinThread, aPriority);
+	__NK_ASSERT_ALWAYS(r != 0);
+	}
+
+inline void CheckedWaitForSingleObject(HANDLE aWaitObject)
+	{
+	DWORD r = WaitForSingleObject(aWaitObject, INFINITE);
+	__NK_ASSERT_ALWAYS(r == WAIT_OBJECT_0);
+	}
+
+inline void CheckedSignalObjectAndWait(HANDLE aToWake, HANDLE aToWaitOn)
+	{
+	DWORD r = SignalObjectAndWait(aToWake, aToWaitOn, INFINITE, FALSE);
+	__NK_ASSERT_ALWAYS(r == WAIT_OBJECT_0);
+	}
+
+inline void CheckedSetEvent(HANDLE aWaitObject)
+	{
+	DWORD r = SetEvent(aWaitObject);
+	__NK_ASSERT_ALWAYS(r != 0);
+	}
+
+inline void CheckedReleaseSemaphore(HANDLE aSemaphore)
+	{
+	DWORD r = ReleaseSemaphore(aSemaphore, 1, NULL);
+	__NK_ASSERT_ALWAYS(r != 0);
+	}
+
+
+#endif	// __NK_WIN32_H__
--- a/kernel/eka/include/usb.h	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/include/usb.h	Mon Sep 27 10:52:00 2010 +0100
@@ -1,4 +1,4 @@
-// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 2002-2010 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"
@@ -84,7 +84,7 @@
 const TUint KUsbDescSize_Config               = 9;
 const TUint KUsbDescSize_Interface            = 9;
 const TUint KUsbDescSize_Endpoint             = 7;
-const TUint KUsbDescSize_Otg                  = 3;
+const TUint KUsbDescSize_Otg                  = 5;
 const TUint KUsbDescSize_DeviceQualifier      = 10;
 const TUint KUsbDescSize_OtherSpeedConfig     = 9;
 const TUint KUsbDescSize_InterfaceAssociation = 8;
@@ -137,6 +137,7 @@
 const TUint8 KUsbOtgAttr_B_HnpEnable     = 0x04;
 const TUint8 KUsbOtgAttr_A_HnpSupport    = 0x08;
 const TUint8 KUsbOtgAttr_A_AltHnpSupport = 0x10;
+const TUint16 KUsbOtgDesc_bcdOTG         = 0x0200;
 
 //
 // Feature Settings
--- a/kernel/eka/nkern/nkern.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/nkern/nkern.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -1,4 +1,4 @@
-// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 1998-2010 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"
@@ -201,6 +201,7 @@
 	NKern::Lock();
 	TheScheduler.iLock.Signal();
 	NKern::Unlock();
+	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"NKern::UnlockSystem");
 	}
 
 
@@ -446,6 +447,7 @@
 	NKern::Lock();
 	pC->iRequestSemaphore.Wait();
 	NKern::Unlock();
+	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"NKern::WaitForAnyRequest");
 	}
 #endif
 
@@ -508,6 +510,7 @@
 	NKern::Lock();
 	aSem->Signal();
 	NKern::Unlock();
+	CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR,"NKern::FSSignal(NFastSemaphore*)");
 	}
 
 
@@ -524,6 +527,7 @@
  */
 EXPORT_C void NKern::FSSignal(NFastSemaphore* aSem, NFastMutex* aMutex)
 	{
+	CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR,"NKern::FSSignal(NFastSemaphore*, NFastMutex*)");
 	if (!aMutex)
 		aMutex=&TheScheduler.iLock;
 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::FSSignal %m +FM %M",aSem,aMutex));
@@ -531,6 +535,7 @@
 	aSem->Signal();
 	aMutex->Signal();
 	NKern::Unlock();
+	CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR,"NKern::FSSignal(NFastSemaphore*, NFastMutex*)");
 	}
 
 
@@ -555,6 +560,7 @@
 	NKern::Lock();
 	aSem->SignalN(aCount);
 	NKern::Unlock();
+	CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR,"NKern::FSSignalN(NFastSemaphore*, TInt)");
 	}
 
 
@@ -572,6 +578,7 @@
  */
 EXPORT_C void NKern::FSSignalN(NFastSemaphore* aSem, TInt aCount, NFastMutex* aMutex)
 	{
+	CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR,"NKern::FSSignalN(NFastSemaphore*, TInt, NFastMutex*)");
 	if (!aMutex)
 		aMutex=&TheScheduler.iLock;
 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::FSSignalN %m %d + FM %M",aSem,aCount,aMutex));
@@ -579,6 +586,7 @@
 	aSem->SignalN(aCount);
 	aMutex->Signal();
 	NKern::Unlock();
+	CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR,"NKern::FSSignalN(NFastSemaphore*, TInt, NFastMutex*)");
 	}
 
 
--- a/kernel/eka/nkern/win32/ncsched.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/nkern/win32/ncsched.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -12,7 +12,7 @@
 //
 // Description:
 // e32\nkern\win32\ncsched.cpp
-// 
+//
 //
 
 // NThreadBase member data
@@ -21,33 +21,35 @@
 #include <e32cmn.h>
 #include <e32cmn_private.h>
 #include "nk_priv.h"
+#include <emulator.h>
 
-#ifdef __EMI_SUPPORT__
+#ifdef	__EMI_SUPPORT__
 extern void EMI_AddTaskSwitchEvent(TAny* aPrevious, TAny* aNext);
 extern void EMI_CheckDfcTag(TAny* aNext);
 #endif
 typedef void (*ProcessHandler)(TAny* aAddressSpace);
 
-static DWORD TlsIndex = TLS_OUT_OF_INDEXES;
-
 static NThreadBase* SelectThread(TScheduler& aS)
 //
 // Select the next thread to run.
 // This is the heart of the rescheduling algorithm.
+// This should be essentially the same as the EPOC32 version!
 //
 	{
 	NThreadBase* t = static_cast<NThreadBase*>(aS.First());
+
+#ifdef	_DEBUG
 	__NK_ASSERT_DEBUG(t);
-#ifdef _DEBUG
 	if (t->iHeldFastMutex)
 		{
-		__KTRACE_OPT(KSCHED2,DEBUGPRINT("Resched init->%T, Holding %M",t,t->iHeldFastMutex));
+		__KTRACE_OPT(KSCHED2, DEBUGPRINT("Resched init->%T, Holding %M", t, t->iHeldFastMutex));
 		}
 	else
 		{
-		__KTRACE_OPT(KSCHED2,DEBUGPRINT("Resched init->%T",t));
+		__KTRACE_OPT(KSCHED2, DEBUGPRINT("Resched init->%T", t));
 		}
-#endif
+#endif	// _DEBUG
+
 	if (t->iTime == 0 && !t->Alone())
 		{
 		// round robin
@@ -59,11 +61,13 @@
 			t->iHeldFastMutex->iWaiting = 1;
 			return t;
 			}
+
 		t->iTime = t->iTimeslice;		// reset old thread time slice
 		t = static_cast<NThreadBase*>(t->iNext);					// next thread
 		aS.iQueue[t->iPriority] = t;		// make it first in list
-		__KTRACE_OPT(KSCHED2,DEBUGPRINT("RoundRobin->%T",t));
+		__KTRACE_OPT(KSCHED2, DEBUGPRINT("RoundRobin->%T", t));
 		}
+
 	if (t->iHeldFastMutex)
 		{
 		if (t->iHeldFastMutex == &aS.iLock)
@@ -71,20 +75,22 @@
 			// thread holds system lock: use it
 			return t;
 			}
+
 		if ((t->i_ThrdAttr & KThreadAttImplicitSystemLock) != 0 && aS.iLock.iHoldingThread)
 			t->iHeldFastMutex->iWaiting = 1;
+
 		__NK_ASSERT_DEBUG((t->i_ThrdAttr & KThreadAttAddressSpace) == 0);
-/*
+		/*
 		Check for an address space change. Not implemented for Win32, but useful as
 		documentaiton of the algorithm.
 
 		if ((t->i_ThrdAttr & KThreadAttAddressSpace) != 0 && t->iAddressSpace != aS.iAddressSpace)
 			t->iHeldFastMutex->iWaiting = 1;
-*/
+		*/
 		}
 	else if (t->iWaitFastMutex && t->iWaitFastMutex->iHoldingThread)
 		{
-		__KTRACE_OPT(KSCHED2,DEBUGPRINT("Resched inter->%T, Blocked on %M",t->iWaitFastMutex->iHoldingThread,t->iWaitFastMutex));
+		__KTRACE_OPT(KSCHED2, DEBUGPRINT("Resched inter->%T, Blocked on %M", t->iWaitFastMutex->iHoldingThread, t->iWaitFastMutex));
 		t = t->iWaitFastMutex->iHoldingThread;
 		}
 	else if (t->i_ThrdAttr & KThreadAttImplicitSystemLock)
@@ -94,12 +100,13 @@
 			{
 			// system lock held, switch to that thread
 			t = aS.iLock.iHoldingThread;
-			__KTRACE_OPT(KSCHED2,DEBUGPRINT("Resched inter->%T (IMP SYS)",t));
+			__KTRACE_OPT(KSCHED2, DEBUGPRINT("Resched inter->%T (IMP SYS)", t));
 			t->iHeldFastMutex->iWaiting = 1;	// aS.iLock.iWaiting = 1;
 			return t;
 			}
+
 		__NK_ASSERT_DEBUG((t->i_ThrdAttr & KThreadAttAddressSpace) == 0);
-/*
+		/*
 		Check for an address space change. Not implemented for Win32, but useful as
 		documentaiton of the algorithm.
 
@@ -108,109 +115,99 @@
 			// what do we do now?
 			__NK_ASSERT_DEBUG(FALSE);
 			}
-*/
+		*/
 		}
+
 	return t;
 	}
 
 // from NThread
 #undef i_ThrdAttr
 
-TBool NThread::WakeUp()
+// From here on it's all emulator (i.e. Win32) specific; there isn't any EPOC32 equivalent for most of it.
 //
-// Wake up the thread. What to do depends on whether we were preempted or voluntarily
-// rescheduled.
+// The emulator uses one Win32 thread for each Symbian thread; these are the ones scheduled by the Symbian
+// nanokernel in the algorithm above. Only one such thread will be running at a time; the others will be
+// waiting on their individual scheduler locks, thus simulating a single-threaded architecture.
 //
-// Return TRUE if we need to immediately reschedule again because we had to unlock
-// the kernel but there are DFCs pending. In this case, the thread does not wake up.
+// In addition, there are some more Win32 threads used to handle timers, interrupts and the like. These
+// are not under control of the Symbian scheduler. They are given higher priority than the Symbian threads,
+// so they can run preemptively under control of the Win32 scheduler. However, they must call functions
+// from the Win32Interrupt class before using any Symbian OS calls, so that the current Symbian thread can
+// be suspended during the 'virtual interrupt'.
+
+static DWORD TlsIndex = TLS_OUT_OF_INDEXES;
+
+void SchedulerInit(NThread& aInit)
 //
-// NB. kernel is locked
+// Initialise the win32 nKern scheduler
 //
 	{
-	switch (iWakeup)
+	DWORD procaffin, sysaffin;
+	if (GetProcessAffinityMask(GetCurrentProcess(), &procaffin, &sysaffin))
 		{
-	default:
-		FAULT();
-	case EIdle:
-		__NK_ASSERT_ALWAYS(TheScheduler.iCurrentThread == this);
-		__NK_ASSERT_ALWAYS(SetEvent(iScheduleLock));
-		break;
-	case ERelease:
-		TheScheduler.iCurrentThread = this;
-		__NK_ASSERT_ALWAYS(SetEvent(iScheduleLock));
-		break;
-	case EResumeLocked:
-		// The thread is Win32 suspended and must be resumed.
-		//
-		// A newly created thread does not need the kernel unlocked so we can
-		// just resume the suspended thread
-		//
-		__KTRACE_OPT(KSCHED,DEBUGPRINT("Win32Resume->%T",this));
-		iWakeup = ERelease;
-		TheScheduler.iCurrentThread = this;
-		if (TheScheduler.iProcessHandler)
-			(*ProcessHandler(TheScheduler.iProcessHandler))(iAddressSpace); // new thread will need to have its static data updated
-		__NK_ASSERT_ALWAYS(TInt(ResumeThread(iWinThread)) > 0);	// check thread was previously suspended
-		break;
-	case EResumeDiverted:
-		// The thread is Win32 suspended and must be resumed.
-		//
-		// The thread needs to be diverted, and does not need the kernel
-		// unlocked.
-		//
-		// It's safe the divert the thread here because we called
-		// IsSafeToPreempt() when we suspended it - otherwise the diversion
-		// could get lost.
-		//
-		__KTRACE_OPT(KSCHED,DEBUGPRINT("Win32Resume->%T (Resuming diverted thread)",this));
-		iWakeup = ERelease;
-		ApplyDiversion();
-		TheScheduler.iCurrentThread = this;
-		__NK_ASSERT_ALWAYS(TInt(ResumeThread(iWinThread)) == 1);
-		break;
-	case EResume:
-		// The thread is Win32 suspended and must be resumed.
-		//
-		// the complication here is that we have to unlock the kernel on behalf of the
-		// pre-empted thread. This means that we have to check to see if there are more DFCs
-		// pending or a reschedule required, as we unlock the kernel. That check is
-		// carried out with interrupts disabled.
-		//
-		// If so, we go back around the loop in this thread context
-		//
-		// Otherwise, we unlock the kernel (having marked us as not-preempted),
-		// enable interrupts and then resume the thread. If pre-emption occurs before the thread
-		// is resumed, it is the new thread that is pre-empted, not the running thread, so we are guaranteed
-		// to be able to call ResumeThread. If pre-emption occurs, and we are rescheduled to run before
-		// that occurs, we will once again be running with the kernel locked and the other thread will
-		// have been re-suspended by Win32: so all is well.
-		//		
-		{
-		__KTRACE_OPT(KSCHED,DEBUGPRINT("Win32Resume->%T",this));
-		TInt irq = NKern::DisableAllInterrupts();
-		if (TheScheduler.iDfcPendingFlag || TheScheduler.iRescheduleNeededFlag)
+		DWORD cpu;
+		switch (Win32SingleCpu)
 			{
-			// we were interrrupted... back to the top
-			TheScheduler.iRescheduleNeededFlag = TRUE;	// ensure we do the reschedule
-			return TRUE;
+		default:
+			// bind the emulator to a nominated CPU on the host PC
+			cpu = (1 << Win32SingleCpu);
+			if (!(sysaffin & cpu))
+				cpu = procaffin;	// CPU selection invalid
+			break;
+
+		case NThread::ECpuSingle:
+			// bind the emulator to a single CPU on the host PC, pick one
+			cpu = procaffin ^ (procaffin & (procaffin - 1));
+			break;
+
+		case NThread::ECpuAll:
+			// run the emulator on all CPUs on the host PC
+			cpu = sysaffin;
+			break;
 			}
-		iWakeup = ERelease;
-		TheScheduler.iCurrentThread = this;
-		if (TheScheduler.iProcessHandler)
-			(*ProcessHandler(TheScheduler.iProcessHandler))(iAddressSpace); // threads resumed after interrupt or locks need to have static data updated
+
+		SetProcessAffinityMask(GetCurrentProcess(), cpu);
+		}
+
+	// identify whether we can use the atomic SignalObjectAndWait API in Win32 for rescheduling
+	Win32AtomicSOAW = (SignalObjectAndWait(aInit.iScheduleLock, aInit.iScheduleLock, INFINITE, FALSE) == WAIT_OBJECT_0);
+
+	// allocate the TLS used for thread identification, and set it for the init thread
+	TlsIndex = TlsAlloc();
+	__NK_ASSERT_ALWAYS(TlsIndex != TLS_OUT_OF_INDEXES);
+	SchedulerRegister(aInit);
 
-		if (iInKernel == 0 && iUserModeCallbacks != NULL)
-			ApplyDiversion();
-		else 
-			TheScheduler.iKernCSLocked = 0;		// have to unlock the kernel on behalf of the new thread
-		
-		TheScheduler.iCurrentThread = this;
-		NKern::RestoreInterrupts(irq);
-		__NK_ASSERT_ALWAYS(TInt(ResumeThread(iWinThread)) > 0);	// check thread was previously suspended
-		}
-		break;
-		}
-	return FALSE;
+	Win32FindNonPreemptibleFunctions();
+	Interrupt.Init();
+	}
+
+void SchedulerRegister(NThread& aSelf)
+	{
+	TlsSetValue(TlsIndex, &aSelf);
+	}
+
+inline NThread* RunningThread()
+// Returns the NThread actually running
+	{
+	if (TlsIndex == TLS_OUT_OF_INDEXES)
+		return NULL;				// not yet initialised
+	else
+		return static_cast<NThread*>(TlsGetValue(TlsIndex));
+	}
+
+inline TBool IsScheduledThread()
+// True if the NThread actually running is the scheduled one (not an interrupt thread or similar)
+	{
+	return RunningThread() == TheScheduler.iCurrentThread;
+	}
+
+inline NThread& CheckedCurrentThread()
+// Returns the NThread actually running, checking that it's the scheduled one (not an interrupt thread or similar)
+	{
+	NThread* t = RunningThread();
+	__NK_ASSERT_ALWAYS(t == TheScheduler.iCurrentThread);
+	return *t;
 	}
 
 static void ThreadExit(NThread& aCurrent, NThread& aNext)
@@ -218,8 +215,8 @@
 // The final context switch of a thread.
 // Wake up the next thread and then destroy this one's Win32 resources.
 //
-// Return without terminating if we need to immediately reschedule again because
-// we had to unlock the kernel but there are DFCs pending.
+// Return without terminating if we need to immediately reschedule again
+// because we had to unlock the kernel but there are DFCs pending.
 //
 	{
 	// the thread is dead
@@ -238,9 +235,9 @@
 	ExitThread(0);		// does not return
 	}
 
-#ifdef MONITOR_THREAD_CPU_TIME
+#ifdef	MONITOR_THREAD_CPU_TIME
 static inline void UpdateThreadCpuTime(NThread& aCurrent, NThread& aNext)
-	{	
+	{
 	TUint32 timestamp = NKern::FastCounter();
 	if (aCurrent.iLastStartTime)
 		aCurrent.iTotalCpuTime += timestamp - aCurrent.iLastStartTime;
@@ -248,9 +245,9 @@
 	}
 #else
 static inline void UpdateThreadCpuTime(NThread& /*aCurrent*/, NThread& /*aNext*/)
-	{	
+	{
 	}
-#endif
+#endif	// MONITOR_THREAD_CPU_TIME
 
 static void SwitchThreads(NThread& aCurrent, NThread& aNext)
 //
@@ -259,27 +256,88 @@
 // optimise the signal-and-wait
 //
 	{
+	__NK_ASSERT_ALWAYS(InterruptsStatus(ETrue));
 	UpdateThreadCpuTime(aCurrent, aNext);
+
 	if (aCurrent.iNState == NThread::EDead)
+		{
 		ThreadExit(aCurrent, aNext);
-	else if (Win32AtomicSOAW && aNext.iWakeup==NThread::ERelease)
+		// Yes, this is reachable!
+		}
+	else if (Win32AtomicSOAW && aNext.iWakeup == NThread::ERelease)
 		{
-		// special case optimization for normally blocked threads using atomic Win32 primitive
+		// special case optimization for normally scheduled threads using atomic Win32 primitive
 		TheScheduler.iCurrentThread = &aNext;
-		DWORD result=SignalObjectAndWait(aNext.iScheduleLock,aCurrent.iScheduleLock, INFINITE, FALSE);
-		if (result != WAIT_OBJECT_0)
-			{
-			__NK_ASSERT_ALWAYS(result == 0xFFFFFFFF);
-			KPrintf("SignalObjectAndWait() failed with %d (%T->%T)",GetLastError(),&aCurrent,&aNext);
-			FAULT();
-			}
+		CheckedSignalObjectAndWait(aNext.iScheduleLock, aCurrent.iScheduleLock);
+		}
+	else if (aNext.WakeUp())
+		{
+		// We didn't wake the target thread; instead we need to re-reschedule in this thread
+		__NK_ASSERT_ALWAYS(InterruptsStatus(EFalse));
+		return;
 		}
 	else
 		{
-		if (aNext.WakeUp())
-			return;			// need to re-reschedule in this thread
-		__NK_ASSERT_ALWAYS(WaitForSingleObject(aCurrent.iScheduleLock, INFINITE) == WAIT_OBJECT_0);
+		// Target thread woken, now wait to be rescheduled
+		CheckedWaitForSingleObject(aCurrent.iScheduleLock);
 		}
+
+	__NK_ASSERT_ALWAYS(InterruptsStatus(ETrue));
+	}
+
+void TScheduler::Reschedule()
+//
+// Enter with kernel locked, exit with kernel unlocked, interrupts disabled.
+// If the thread is dead do not return, but terminate the thread.
+//
+	{
+	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
+	NThread& me = *static_cast<NThread*>(TheScheduler.iCurrentThread);
+
+	for (;;)
+		{
+		NKern::DisableAllInterrupts();
+		if (TheScheduler.iDfcPendingFlag)
+			TheScheduler.QueueDfcs();
+
+		// Exit from this loop when further rescheduling is no longer needed
+		if (!TheScheduler.iRescheduleNeededFlag)
+			break;
+
+		// Choose the next thread to run, using the Symbian scheduler
+		TheScheduler.iRescheduleNeededFlag = FALSE;
+		NKern::EnableAllInterrupts();
+		NThread* t = static_cast<NThread*>(SelectThread(TheScheduler));
+		__KTRACE_OPT(KSCHED, DEBUGPRINT("Reschedule->%T (%08x%08x)", t, TheScheduler.iPresent[1], TheScheduler.iPresent[0]));
+
+#ifdef	__EMI_SUPPORT__
+		EMI_AddTaskSwitchEvent(&me, t);
+		EMI_CheckDfcTag(t);
+#endif
+#ifdef	BTRACE_CPU_USAGE
+		if (TheScheduler.iCpuUsageFilter)
+			TheScheduler.iBTraceHandler(BTRACE_HEADER_C(4, BTrace::ECpuUsage, BTrace::ENewThreadContext), 0, (TUint32)t, 0, 0, 0, 0, 0);
+#endif
+
+		// SwitchThreads() can return immediately, if it turns out that another reschedule is
+		// necessary; otherwise, this thread will be descheduled in favour of the one selected
+		// above, and SwitchThreads() will only return when this thread is next selected
+		SwitchThreads(me, *t);
+
+		// When we start again, we should check for being forced to exit; otherwise go round the
+		// loop again to see whether another reschedule is called for (e.g. if there are new DFCs).
+		NThread::TDivert divertToExit = me.iDivertFn;
+		me.iDivertFn = NULL;
+		if (divertToExit)
+			divertToExit();
+		}
+
+	// interrupts are disabled, the kernel is still locked
+	if (TheScheduler.iProcessHandler)
+		(*ProcessHandler(TheScheduler.iProcessHandler))(me.iAddressSpace);		// thread will need to have its static data updated
+
+	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
+	TheScheduler.iKernCSLocked = 0;
 	}
 
 void TScheduler::YieldTo(NThreadBase*)
@@ -292,50 +350,121 @@
 	TScheduler::Reschedule();
 	}
 
-void TScheduler::Reschedule()
+TBool NThread::WakeUp()
+//
+// Wake up the thread. What to do depends on whether it was preempted or voluntarily
+// rescheduled.
+//
+// On entry, the kernel is locked, and interrupts may be enabled or disabled.
 //
-// Enter with kernel locked, exit with kernel unlocked, interrupts disabled.
-// If the thread is dead do not return, but terminate the thread.
+// The return value is TRUE if the caller should immediately reschedule again because we
+// needed to unlock the kernel in order to resume the thread but there were DFCs pending.
+// In this case, the thread is not woken, the kernel remains locked, and the return is
+// made with interrupts disabled (whether or not they were on entry).
+//
+// Otherise, the target thread is woken up (in any of several different ways), and the
+// the return value is FALSE. In that case the interrupt status is unchanged; and the
+// kernel may or not still be locked.
 //
 	{
-	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
-	NThread& me = *static_cast<NThread*>(TheScheduler.iCurrentThread);
-	for (;;)
+	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked > 0);
+	__NK_ASSERT_ALWAYS(RunningThread() != this);		// Can't wake self!
+
+	switch (iWakeup)
 		{
-		NKern::DisableAllInterrupts();
-		if (TheScheduler.iDfcPendingFlag)
-			TheScheduler.QueueDfcs();
-		if (!TheScheduler.iRescheduleNeededFlag)
-			break;
-		NKern::EnableAllInterrupts();
-		TheScheduler.iRescheduleNeededFlag = FALSE;
-		NThread* t = static_cast<NThread*>(SelectThread(TheScheduler));
-		__KTRACE_OPT(KSCHED,DEBUGPRINT("Reschedule->%T (%08x%08x)",t,TheScheduler.iPresent[1],TheScheduler.iPresent[0]));
-#ifdef __EMI_SUPPORT__
-		EMI_AddTaskSwitchEvent(&me,t);
-		EMI_CheckDfcTag(t);
-#endif
-#ifdef BTRACE_CPU_USAGE
-		if(TheScheduler.iCpuUsageFilter)
-			TheScheduler.iBTraceHandler(BTRACE_HEADER_C(4,BTrace::ECpuUsage,BTrace::ENewThreadContext),0,(TUint32)t,0,0,0,0,0);
-#endif
-		SwitchThreads(me, *t);
+	default:
+		FAULT();
+
+	case EIdle:
+		// The thread is waiting on its scheduler lock, in Idle()
+		__NK_ASSERT_ALWAYS(TheScheduler.iCurrentThread == this);
+		CheckedSetEvent(iScheduleLock);
+		break;
+
+	case ERelease:
+		// The thread is waiting on its scheduler lock
+		TheScheduler.iCurrentThread = this;
+		CheckedSetEvent(iScheduleLock);
+		break;
+
+	case EResumeLocked:
+		// The thread is Win32 suspended and must be resumed.
+		//
+		// A newly created thread does not need the kernel unlocked so we can
+		// just resume it; OTOH it will need to have its static data updated ...
+		//
+		__KTRACE_OPT(KSCHED, DEBUGPRINT("Win32ResumeLocked->%T", this));
+		iWakeup = ERelease;
+		TheScheduler.iCurrentThread = this;
+		if (TheScheduler.iProcessHandler)
+			(*ProcessHandler(TheScheduler.iProcessHandler))(iAddressSpace);
+		CheckedResumeThread(iWinThread);
+		break;
+
+	case EResumeDiverted:
+		// The thread is Win32 suspended and must be resumed.
+		//
+		// It does not need the kernel unlocked, but does have a diversion pending. We
+		// know it's safe to divert the thread here because we called IsSafeToPreempt()
+		// when we suspended it - otherwise the diversion could get lost.
+		//
+		__KTRACE_OPT(KSCHED, DEBUGPRINT("Win32Resume->%T (Resuming diverted thread)", this));
+		iWakeup = ERelease;
+		TheScheduler.iCurrentThread = this;
+		ApplyDiversion();
+		CheckedResumeThread(iWinThread, ETrue);
+		break;
 
-		// we have just been scheduled to run... check for diversion/new Dfcs
-		NThread::TDivert divert = me.iDivert;
-		if (divert)
+	case EResume:
+		// The thread is Win32 suspended and must be resumed.
+		//
+		// The complication here is that we have to unlock the kernel on behalf of the
+		// pre-empted thread. Before doing so, we have to check whether there are DFCs
+		// or a reschedule pending; if so, we don't unlock the kernel or wake the target
+		// thread, but instead return TRUE, so that our caller (usually SwitchThreads()
+		// above) knows to return and go round the TScheduler::Reschedule() loop again.
+		//
+		TInt irq = NKern::DisableAllInterrupts();
+		if (TheScheduler.iRescheduleNeededFlag || TheScheduler.iDfcPendingFlag)
 			{
-			// diversion (e.g. force exit)
-			me.iDivert = NULL;
-			divert();						// does not return
+			__KTRACE_OPT(KSCHED, DEBUGPRINT("Win32Resume->%T preempted", this));
+			TheScheduler.iRescheduleNeededFlag = TRUE;	// ensure we do the reschedule
+			return TRUE;
 			}
+
+		// Otherwise we mark the thread as not-preempted, unlock the kernel, restore
+		// interrupts, and resume the thread.
+		__KTRACE_OPT(KSCHED, DEBUGPRINT("Win32Resume->%T", this));
+		iWakeup = ERelease;
+		TheScheduler.iCurrentThread = this;
+		if (TheScheduler.iProcessHandler)
+			(*ProcessHandler(TheScheduler.iProcessHandler))(iAddressSpace); // threads resumed after interrupt or locks need to have static data updated
+		TheScheduler.iKernCSLocked = 0;
+
+		// If there are callbacks waiting, and the thread is in user mode, divert it to
+		// pick up its callbacks (we know this is safe because we called IsSafeToPreempt()
+		// when we suspended it - otherwise the diversion could get lost.
+		if (iUserModeCallbacks != NULL && !iInKernel)
+			{
+			TheScheduler.iKernCSLocked = 1;					// prevent further pre-emption
+			ApplyDiversion();
+			}
+
+		// If pre-emption occurs before the thread is resumed, it is the new thread that
+		// is pre-empted, not the running thread, so we are guaranteed to be able to call
+		// ResumeThread. If pre-emption occurs, and we are rescheduled to run before that
+		// occurs, we will once again be running with the kernel locked and the other
+		// thread will have been re-suspended by Win32: so all is well.
+		//
+		NKern::RestoreInterrupts(irq);
+		CheckedResumeThread(iWinThread);
+		break;
 		}
-	if (TheScheduler.iProcessHandler)
-		(*ProcessHandler(TheScheduler.iProcessHandler))(me.iAddressSpace);
-	// interrrupts are disabled, the kernel is still locked
-	TheScheduler.iKernCSLocked = 0;
+
+	return FALSE;
 	}
 
+
 /**	Put the emulator into 'idle'.
 	This is called by the idle thread when there is nothing else to do.
 
@@ -351,7 +480,8 @@
 	{
 	NThread& me = *static_cast<NThread*>(TheScheduler.iCurrentThread);
 	me.iWakeup = EIdle;
-	__NK_ASSERT_ALWAYS(WaitForSingleObject(me.iScheduleLock, INFINITE) == WAIT_OBJECT_0);
+	CheckedWaitForSingleObject(me.iScheduleLock);
+
 	// something happened, and we've been prodded by an interrupt
 	// the kernel was locked by the interrupt, and now reschedule
 	me.iWakeup = ERelease;
@@ -359,146 +489,83 @@
 	NKern::EnableAllInterrupts();
 	}
 
-void SchedulerInit(NThread& aInit)
-//
-// Initialise the win32 nKern scheduler
-//
+
+void EnterKernel(TBool aDiversion)
 	{
-	DWORD procaffin,sysaffin;
-	if (GetProcessAffinityMask(GetCurrentProcess(),&procaffin,&sysaffin))
+	NThread& t = CheckedCurrentThread();
+	volatile TInt& inKernel = t.iInKernel;
+	__NK_ASSERT_DEBUG(inKernel >= 0);
+
+	// This code has to be re-entrant, because a thread that's in the process
+	// of entering the kernel may be preempted; then if it isn't yet marked
+	// as 'in the kernel' it can be diverted through EnterKernel()/LeaveKernel()
+	// in order to execute user-mode callbacks.  However this is all in the
+	// same thread context, so it doesn't need any special synchronisation.
+	// The moment of 'entering' the kernel is deemed to occur when the new value
+	// of iInKernel is written back to the NThread object.
+	if (inKernel++ == 0)
 		{
-		DWORD cpu;
-		switch (Win32SingleCpu)
+		// preamble when coming from userspace
+		__NK_ASSERT_ALWAYS(InterruptsStatus(ETrue));
+		__NK_ASSERT_ALWAYS(t.iHeldFastMutex == 0);
+		if (aDiversion)
 			{
-		default:
-			// bind the emulator to a nominated CPU on the host PC
-			cpu = (1<<Win32SingleCpu);
-			if (!(sysaffin & cpu))
-				cpu = procaffin;	// CPU selection invalid
-			break;
-		case NThread::ECpuSingle:
-			// bind the emulator to a single CPU on the host PC, pick one
-			cpu = procaffin ^ (procaffin & (procaffin-1));
-			break;
-		case NThread::ECpuAll:
-			// run the emulator on all CPUs on the host PC
-			cpu=sysaffin;
-			break;
+			// Forced entry, to make thread exit or run user-mode callbacks
+			// If exiting, iCsCount will have been set to 1 to prevent preemption
+			// Otherwise it must be 0, as in the non-diversion case
+			__NK_ASSERT_ALWAYS(t.iCsCount <= 1);
+			__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
 			}
-		SetProcessAffinityMask(GetCurrentProcess(), cpu);
+		else
+			{
+			__NK_ASSERT_ALWAYS(t.iCsCount == 0);
+			__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 0);
+			}
 		}
-	// identify if we can use the atomic SignalObjectAndWait API in Win32 for rescheduling
-	Win32AtomicSOAW = (SignalObjectAndWait(aInit.iScheduleLock, aInit.iScheduleLock, INFINITE, FALSE) == WAIT_OBJECT_0);
-	//
-	// allocate the TLS used for thread identification, and set it for the init thread
-	TlsIndex = TlsAlloc();
-	__NK_ASSERT_ALWAYS(TlsIndex != TLS_OUT_OF_INDEXES);
-	SchedulerRegister(aInit);
-	//
-	Interrupt.Init();
-
-	Win32FindNonPreemptibleFunctions();
-	}
-
-void SchedulerRegister(NThread& aSelf)
-	{
-	TlsSetValue(TlsIndex,&aSelf);
-	}
-
-NThread* SchedulerThread()
-	{
-	if (TlsIndex != TLS_OUT_OF_INDEXES)
-		return static_cast<NThread*>(TlsGetValue(TlsIndex));
-	else
-		return NULL;  // not yet initialised
 	}
 
-inline TBool IsScheduledThread()
-	{
-	return SchedulerThread() == TheScheduler.iCurrentThread;
-	}
-	
-NThread& CheckedCurrentThread()
+void LeaveKernel()
 	{
-	NThread* t = SchedulerThread();
-	__NK_ASSERT_ALWAYS(t == TheScheduler.iCurrentThread);
-	return *t;
-	}
-
+	NThread& t = CheckedCurrentThread();
+	volatile TInt& inKernel = t.iInKernel;
+	__NK_ASSERT_DEBUG(inKernel > 0);
 
-/**	Disable normal 'interrupts'.
+	// This code has to be re-entrant, because a thread that's in the process
+	// of leaving the kernel may be preempted; then if it isn't still marked
+	// as 'in the kernel' it can be diverted through EnterKernel()/LeaveKernel()
+	// in order to execute user-mode callbacks.  However this is all in the
+	// same thread context, so it doesn't need any special synchronisation.
+	// The moment of 'leaving' the kernel is deemed to occur when the new value
+	// of iInKernel is written back to the NThread object.
+	if (inKernel == 1)
+		{
+		// postamble when about to return to userspace
+		__NK_ASSERT_ALWAYS(t.iCsCount == 0);
+		__NK_ASSERT_ALWAYS(t.iHeldFastMutex == 0);
+		__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 0);
+		NKern::DisableAllInterrupts();
+		t.CallUserModeCallbacks();
+		NKern::EnableAllInterrupts();
+		}
 
-	@param	aLevel Ignored
-	@return	Cookie to be passed into RestoreInterrupts()
- */
-EXPORT_C TInt NKern::DisableInterrupts(TInt /*aLevel*/)
-	{
-	return Interrupt.Mask();
+	inKernel -= 1;
 	}
 
-
-/**	Disable all maskable 'interrupts'.
-
-	@return	Cookie to be passed into RestoreInterrupts()
- */
-EXPORT_C TInt NKern::DisableAllInterrupts()
-	{
-	return Interrupt.Mask();
-	}
-
-
-/**	Enable all maskable 'interrupts'
-
-	@internalComponent
- */
-EXPORT_C void NKern::EnableAllInterrupts()
-	{
-	Interrupt.Restore(0);
-	}
-
-
-/** Restore interrupt mask to state preceding a DisableInterrupts() call
-
-	@param	aLevel Cookie returned by Disable(All)Interrupts()
- */
-EXPORT_C void NKern::RestoreInterrupts(TInt aLevel)
-	{
-	Interrupt.Restore(aLevel);
-	}
-
-
-/**	Unlocks the kernel.
-
-	Decrements iKernCSLocked; if it becomes zero and IDFCs or a reschedule are
-	pending, calls the scheduler to process them.
+/**	Locks the kernel and returns a pointer to the current thread
+	Increments iKernCSLocked, thereby deferring IDFCs and preemption.
 
     @pre    Call either in a thread or an IDFC context.
     @pre    Do not call from an ISR.
 	@pre	Do not call from bare Win32 threads.
  */
-EXPORT_C void NKern::Unlock()
-//
-// using this coding sequence it is possible to call Reschedule unnecessarily
-// if we are preempted after testing the flags (lock is zero at this point).
-// However, in the common case this is much faster because 'disabling interrupts'
-// can be very expensive.
-//
+EXPORT_C NThread* NKern::LockC()
 	{
-	CHECK_PRECONDITIONS(MASK_NOT_ISR,"NKern::Unlock");	
-	__ASSERT_WITH_MESSAGE_DEBUG(IsScheduledThread(),"Do not call from bare Win32 threads","NKern::Unlock");	// check that we are a scheduled thread
-	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked > 0);	// Can't unlock if it isn't locked!
-	if (--TheScheduler.iKernCSLocked == 0)
-		{
-		if (TheScheduler.iRescheduleNeededFlag || TheScheduler.iDfcPendingFlag)
-			{
-			TheScheduler.iKernCSLocked = 1;
-			TScheduler::Reschedule();
-			NKern::EnableAllInterrupts();
-			}
-		}
+	CHECK_PRECONDITIONS(MASK_NOT_ISR, "NKern::LockC");
+	__ASSERT_WITH_MESSAGE_ALWAYS(IsScheduledThread(), "Do not call from bare Win32 threads", "NKern::LockC");	// check that we are a scheduled thread
+	++TheScheduler.iKernCSLocked;
+	return (NThread*)TheScheduler.iCurrentThread;
 	}
 
-
 /**	Locks the kernel.
 
 	Increments iKernCSLocked, thereby deferring IDFCs and preemption.
@@ -509,25 +576,43 @@
  */
 EXPORT_C void NKern::Lock()
 	{
-	CHECK_PRECONDITIONS(MASK_NOT_ISR,"NKern::Lock");		
-	__ASSERT_WITH_MESSAGE_ALWAYS(IsScheduledThread(),"Do not call from bare Win32 threads","NKern::Lock");	// check that we are a scheduled thread
+	CHECK_PRECONDITIONS(MASK_NOT_ISR, "NKern::Lock");
+	__ASSERT_WITH_MESSAGE_ALWAYS(IsScheduledThread(), "Do not call from bare Win32 threads", "NKern::Lock");	// check that we are a scheduled thread
 	++TheScheduler.iKernCSLocked;
 	}
 
+/**	Unlocks the kernel.
 
-/**	Locks the kernel and returns a pointer to the current thread
-	Increments iKernCSLocked, thereby deferring IDFCs and preemption.
+	Decrements iKernCSLocked; if it would become zero and IDFCs or a reschedule are
+	pending, calls the scheduler to process them.
 
     @pre    Call either in a thread or an IDFC context.
     @pre    Do not call from an ISR.
 	@pre	Do not call from bare Win32 threads.
  */
-EXPORT_C NThread* NKern::LockC()
+EXPORT_C void NKern::Unlock()
 	{
-	CHECK_PRECONDITIONS(MASK_NOT_ISR,"NKern::Lock");		
-	__ASSERT_WITH_MESSAGE_ALWAYS(IsScheduledThread(),"Do not call from bare Win32 threads","NKern::Lock");	// check that we are a scheduled thread
-	++TheScheduler.iKernCSLocked;
-	return (NThread*)TheScheduler.iCurrentThread;
+	// check that the caller is the scheduled thread
+	__ASSERT_WITH_MESSAGE_DEBUG(IsScheduledThread(), "Do not call from bare Win32 threads", "NKern::Unlock");
+	CHECK_PRECONDITIONS(MASK_NOT_ISR, "NKern::Unlock");
+	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked > 0);	// Can't unlock if it isn't locked!
+
+	// Rather than decrementing the lock before testing the flags, and then
+	// re-incrementing it in order to call Reschedule() -- which would
+	// leave a window for preemption -- we can test the flags first, and then
+	// see whether the lock count is 1 ...
+	if ((TheScheduler.iRescheduleNeededFlag || TheScheduler.iDfcPendingFlag) &&
+			TheScheduler.iKernCSLocked == 1)
+		{
+		// Reschedule() returns with the kernel unlocked, but interrupts disabled
+		TScheduler::Reschedule();
+		NKern::EnableAllInterrupts();
+		}
+	else
+		{
+		// All other cases - just decrement the lock count
+		TheScheduler.iKernCSLocked -= 1;
+		}
 	}
 
 
@@ -537,26 +622,100 @@
 	calls the scheduler to process the IDFCs and possibly reschedule.
 
 	@return	Nonzero if a reschedule actually occurred, zero if not.
-	
+
     @pre    Call either in a thread or an IDFC context.
     @pre    Do not call from an ISR.
 	@pre	Do not call from bare Win32 threads.
  */
 EXPORT_C TInt NKern::PreemptionPoint()
 	{
-	CHECK_PRECONDITIONS(MASK_NOT_ISR,"NKern::PreemptionPoint");		
-	__ASSERT_WITH_MESSAGE_DEBUG(IsScheduledThread(),"Do not call from bare Win32 threads","NKern::PreemptionPoint");	// check that we are a scheduled thread
-	if (TheScheduler.iKernCSLocked == 1 && 
-		(TheScheduler.iRescheduleNeededFlag || TheScheduler.iDfcPendingFlag))
+	// check that the caller is the scheduled thread
+	__ASSERT_WITH_MESSAGE_DEBUG(IsScheduledThread(), "Do not call from bare Win32 threads", "NKern::PreemptionPoint");
+	CHECK_PRECONDITIONS(MASK_NOT_ISR, "NKern::PreemptionPoint");
+
+	if ((TheScheduler.iRescheduleNeededFlag || TheScheduler.iDfcPendingFlag) &&
+			TheScheduler.iKernCSLocked == 1)
 		{
+		// Reschedule() returns with the kernel unlocked, but interrupts disabled
 		TScheduler::Reschedule();
 		TheScheduler.iKernCSLocked = 1;
 		NKern::EnableAllInterrupts();
 		return TRUE;
 		}
+
 	return FALSE;
 	}
 
+/**	Return the current processor context type
+	(thread, IDFC, interrupt or escaped thread)
+
+	@return	A value from NKern::TContext enumeration (including EEscaped)
+	@pre	Any context
+
+	@see	NKern::TContext
+ */
+EXPORT_C TInt NKern::CurrentContext()
+	{
+	NThread* t = RunningThread();
+
+	if (!t)
+		return NKern::EInterrupt;
+
+	if (TheScheduler.iInIDFC)
+		return NKern::EIDFC;
+
+	if (t->iWakeup == NThread::EEscaped)
+		return NKern::EEscaped;
+
+	__NK_ASSERT_ALWAYS(NKern::Crashed() || t == TheScheduler.iCurrentThread);
+	return NKern::EThread;
+	}
+
+
+/**	Disable normal 'interrupts'.
+
+	@param	aLevel Ignored
+    @pre    Call in a Symbian (thread, IDFC, ISR) context.
+	@pre	Do not call from bare Win32 threads.
+	@return	Cookie to be passed into RestoreInterrupts()
+ */
+EXPORT_C TInt NKern::DisableInterrupts(TInt /*aLevel*/)
+	{
+	return Interrupt.MaskInterrupts(EFalse);
+	}
+
+/** Restore interrupt mask to state preceding a DisableInterrupts() call
+
+	@param	aLevel Cookie returned by Disable(All)Interrupts()
+    @pre    Call in a Symbian (thread, IDFC, ISR) context.
+	@pre	Do not call from bare Win32 threads.
+ */
+EXPORT_C void NKern::RestoreInterrupts(TInt aLevel)
+	{
+	Interrupt.RestoreInterruptMask(aLevel);
+	}
+
+/**	Disable all maskable 'interrupts'.
+
+    @pre    Call in a Symbian (thread, IDFC, ISR) context.
+	@pre	Do not call from bare Win32 threads.
+	@return	Cookie to be passed into RestoreInterrupts()
+ */
+EXPORT_C TInt NKern::DisableAllInterrupts()
+	{
+	return Interrupt.MaskInterrupts(EFalse);
+	}
+
+/**	Enable all maskable 'interrupts'
+
+	@internalComponent
+    @pre    Call in a Symbian (thread, IDFC, ISR) context.
+	@pre	Do not call from bare Win32 threads.
+ */
+EXPORT_C void NKern::EnableAllInterrupts()
+	{
+	Interrupt.RestoreInterruptMask(0);
+	}
 
 /**	Mark the start of an 'interrupt' in the Win32 emulator.
 	This must be called in interrupt threads before using any other kernel APIs,
@@ -566,11 +725,11 @@
  */
 EXPORT_C void StartOfInterrupt()
 	{
-	__ASSERT_WITH_MESSAGE_DEBUG(!IsScheduledThread(),"Win32 'interrupt' thread context","StartOfInterrupt");	// check that we are a scheduled thread
-	Interrupt.Begin();
+	// check that the caller is not a scheduled thread
+	__ASSERT_WITH_MESSAGE_DEBUG(!IsScheduledThread(), "Win32 'interrupt' thread context", "StartOfInterrupt");
+	Interrupt.BeginInterrupt();
 	}
 
-
 /**	Mark the end of an 'interrupt' in the Win32 emulator.
 	This checks to see if we need to reschedule.
 
@@ -578,166 +737,277 @@
  */
 EXPORT_C void EndOfInterrupt()
 	{
-	__ASSERT_WITH_MESSAGE_DEBUG(!IsScheduledThread(),"Win32 'interrupt' thread context","EndOfInterrupt");	// check that we are a scheduled thread
-	Interrupt.End();
+	// check that the caller is not a scheduled thread
+	__ASSERT_WITH_MESSAGE_DEBUG(!IsScheduledThread(), "Win32 'interrupt' thread context", "EndOfInterrupt");
+	Interrupt.EndInterrupt();
 	}
 
 
+// The Win32Interrupt class manages virtual interrupts from Win32 event threads
+
 void Win32Interrupt::Init()
 	{
-	iQ=CreateSemaphoreA(NULL, 0, KMaxTInt, NULL);
+	InitializeCriticalSection(&iCS);
+	iQ = CreateSemaphoreA(NULL, 0, KMaxTInt, NULL);
 	__NK_ASSERT_ALWAYS(iQ);
-	//
+
 	// create the NThread which exists solely to service reschedules for interrupts
 	// this makes the End() much simpler as it merely needs to kick this thread
 	SNThreadCreateInfo ni;
 	memclr(&ni, sizeof(ni));
-	ni.iFunction=&Reschedule;
-	ni.iTimeslice=-1;
-	ni.iPriority=1;
+	ni.iFunction = &SchedulerThreadFunction;
+	ni.iTimeslice = -1;
+	ni.iPriority = 1;
 	NKern::ThreadCreate(&iScheduler, ni);
 	NKern::Lock();
 	TScheduler::YieldTo(&iScheduler);
-	Restore(0);
+	RestoreInterruptMask(0);
 	}
 
-TInt Win32Interrupt::Mask()
+void Win32Interrupt::BeginInterrupt()
 	{
-	if (!iQ)
-		return 0;				// interrupt scheme not enabled yet
-	DWORD id=GetCurrentThreadId();
-	if (__e32_atomic_add_ord32(&iLock, 1))
-		{
-		if (id==iOwner)
-			return iLevel++;
-		__NK_ASSERT_ALWAYS(WaitForSingleObject(iQ,INFINITE) == WAIT_OBJECT_0);
-		iRescheduleOnExit=IsScheduledThread() &&
-				(TheScheduler.iRescheduleNeededFlag || TheScheduler.iDfcPendingFlag);
-		}
-	else
-		iRescheduleOnExit=FALSE;
-	__NK_ASSERT_ALWAYS(iOwner==0 && iLevel==0);
-	iOwner=id;
-	iLevel=1;
-	return 0;
+	__NK_ASSERT_ALWAYS(!IsScheduledThread());				// check that we aren't a scheduled thread
+	MaskInterrupts(ETrue);									// suspend scheduled thread and set mask
+#ifdef	BTRACE_CPU_USAGE
+	BTrace0(BTrace::ECpuUsage, BTrace::EIrqStart);
+#endif
 	}
 
-void Win32Interrupt::Restore(TInt aLevel)
+void Win32Interrupt::EndInterrupt()
 	{
-	if (!iQ)
-		return;				// interrupt scheme not enabled yet
-	DWORD id=GetCurrentThreadId();
-	for (;;)
+	NThread* pC = iInterrupted;
+	iInterrupted = 0;
+	__NK_ASSERT_ALWAYS(pC == TheScheduler.iCurrentThread);	// unchanged since BeginInterrupt()
+	__NK_ASSERT_ALWAYS(!IsScheduledThread());				// check that we aren't a scheduled thread
+	__NK_ASSERT_ALWAYS(iOwner == GetCurrentThreadId());		// check we are the interrupting thread
+	__NK_ASSERT_ALWAYS(InterruptsStatus(EFalse));
+	__NK_ASSERT_ALWAYS(iLevel == 1);						// DSG: is this correct?
+
+	if (TheScheduler.iKernCSLocked)
+		{
+		// No rescheduling allowed; just resume the interrupted thread
+		NKern::EnableAllInterrupts();
+		CheckedResumeThread(pC->iWinThread);
+		return;
+		}
+
+	__NK_ASSERT_ALWAYS(iLevel == 1);						// DSG: is this correct?
+	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 0);
+
+	TBool diversionUnsafe = EFalse;							// Optimistic assumption until checked
+	if (TheScheduler.iRescheduleNeededFlag || TheScheduler.iDfcPendingFlag)
 		{
-		__NK_ASSERT_ALWAYS(id == iOwner);
-		TInt count = iLevel - aLevel;
-		if (count <= 0)
-			return;						// alredy restored to that level
-		TBool reschedule = FALSE;
-		iLevel = aLevel;		// update this value before releasing the lock
-		if (aLevel == 0)
+		switch (pC->iWakeup)
 			{
-			// we release the lock
-			iOwner = 0;
-			if (iRescheduleOnExit && TheScheduler.iKernCSLocked == 0)
-				reschedule = TRUE;		// need to trigger reschedule on full release
+		default:
+			FAULT();
+
+		case NThread::EIdle:
+			// wake up the Idle thread, it will always reschedule immediately
+			TheScheduler.iKernCSLocked = 1;					// prevent further pre-emption
+			if (pC->WakeUp())
+				FAULT();									// this can't happen
+			NKern::EnableAllInterrupts();
+			CheckedResumeThread(pC->iWinThread);
+			return;
+
+		case NThread::ERelease:
+			if (pC->IsSafeToPreempt())
+				{
+				// pre-empt the current thread and poke the 'scheduler' thread
+				UpdateThreadCpuTime(*pC, iScheduler);
+				pC->iWakeup = NThread::EResume;				// how to wake this thread later
+				TheScheduler.iKernCSLocked = 1;				// prevent further pre-emption
+				RescheduleNeeded();
+				NKern::EnableAllInterrupts();
+				if (iScheduler.WakeUp())
+					FAULT();								// this can't happen
+				return;
+				}
+
+			diversionUnsafe = ETrue;						// don't consider diverting
+			break;
 			}
-		// now release the lock
-		if (__e32_atomic_add_ord32(&iLock, TUint32(-count)) == (TUint32)count)
-			{	// fully released, check for reschedule
-			if (!reschedule)
-				return;
+		}
+
+#ifdef	BTRACE_CPU_USAGE
+	// no thread reschedle, so emit trace...
+	BTrace0(BTrace::ECpuUsage, BTrace::EIrqEnd);
+#endif
+
+	// If there are callbacks waiting, and the thread is in user mode, and it's at a
+	// point where it can safely be preempted, then divert it to pick up its callbacks
+	if (pC->iUserModeCallbacks != NULL && !pC->iInKernel && !diversionUnsafe)
+		if (pC->IsSafeToPreempt())
+			{
+			TheScheduler.iKernCSLocked = 1;
+			pC->ApplyDiversion();
 			}
-		else
-			{	// not fully released
-			if (aLevel == 0)
-				__NK_ASSERT_ALWAYS(ReleaseSemaphore(iQ,1,NULL));
-			return;
-			}
-		// unlocked everything but a reschedule may be required
-		TheScheduler.iKernCSLocked = 1;
-		TScheduler::Reschedule();
-		// return with the kernel unlocked, but interrupts disabled
-		// instead of going recursive with a call to EnableAllInterrupts() we iterate
-		aLevel=0;
-		}
+
+	NKern::EnableAllInterrupts();
+	CheckedResumeThread(pC->iWinThread);
 	}
 
-void Win32Interrupt::Begin()
+
+TInt Win32Interrupt::MaskInterrupts(TBool aPreempt)
 	{
-	Mask();
-	__NK_ASSERT_ALWAYS(iInterrupted==0);	// check we haven't done this already
-	__NK_ASSERT_ALWAYS(!IsScheduledThread());	// check that we aren't a scheduled thread
-	NThread* pC;
-	for (;;)
+	if (!iQ)
+		return 0;									// interrupt scheme not enabled yet
+
+	EnterCriticalSection(&iCS); 					// Win32 critical section, not a Symbian one
+
+	DWORD id = GetCurrentThreadId();
+	if (iOwner == id)
+		{
+		// The easiest case: we already own the mask, so just increment the level.
+		// The requirement for rescheduling on exit is unaffected.
+		__NK_ASSERT_ALWAYS(!aPreempt);
+		TInt r = iLevel++;
+		LeaveCriticalSection(&iCS);
+		return r;
+		}
+
+	if (!iOwner && !aPreempt)
 		{
-		pC=static_cast<NThread*>(TheScheduler.iCurrentThread);
-		DWORD r=SuspendThread(pC->iWinThread);
-		if (pC == TheScheduler.iCurrentThread)
+		// Another easy case; we've been called from a Symbian thread, and there's
+		// no contention, so we can just take ownership of the interrupt mask. No
+		// rescheduling is required on exit (but this may change) ...
+		__NK_ASSERT_ALWAYS(iLevel == 0);
+		TInt r = iLevel++;
+		iOwner = id;
+		iRescheduleOnExit = EFalse;
+		LeaveCriticalSection(&iCS);
+		return r;
+		}
+
+	if (iOwner)
+		{
+		// Someone else owns it; if we've been called from an interrupt thread,
+		// this could be another interrupt thread or a Symbian thread. If we're
+		// being called from a Symbian thread, the owner must be another Symbian
+		// thread, because a Symbian thread can't preempt an interrupt thread.
+		//
+		// In either case, we can increment the count of waiters, then wait for the
+		// curent holder to release it. Note that another (interrupt) thread could
+		// also do this, and then the order in which they get to run is undefined.
+		iWaiting += 1;
+
+		do
 			{
-			// there was no race while suspending the thread, so we can carry on
-			__NK_ASSERT_ALWAYS(r != 0xffffffff);
-			break;
+			__NK_ASSERT_ALWAYS(iWaiting > 0);
+			LeaveCriticalSection(&iCS);
+			CheckedWaitForSingleObject(iQ);
+			EnterCriticalSection(&iCS);
+			__NK_ASSERT_ALWAYS(iWaiting > 0);
 			}
-		// We suspended the thread while doing a context switch, resume it and try again
-		if (r != 0xffffffff)
-			__NK_ASSERT_ALWAYS(TInt(ResumeThread(pC->iWinThread)) > 0);	// check thread was previously suspended
+		while (iOwner);
+
+		iWaiting -= 1;
+		iRescheduleOnExit = IsScheduledThread() && (TheScheduler.iRescheduleNeededFlag || TheScheduler.iDfcPendingFlag);
 		}
-#ifdef BTRACE_CPU_USAGE
-	BTrace0(BTrace::ECpuUsage,BTrace::EIrqStart);
-#endif
-	iInterrupted = pC;
+
+	// Nobody now controls the interrupt mask ...
+	__NK_ASSERT_ALWAYS(iOwner == 0 && iLevel == 0);
+
+	if (aPreempt)
+		{
+		// ... but in this case, we've been called from an interrupt thread and
+		// a Symbian thread may still be running -- yes, even though all emulator
+		// threads are normally bound to a single CPU!
+		//
+		// To ensure that such a thread doesn't see an inconsistent state, we
+		// have to suspend it before we actually take ownership, as it could
+		// examine the interrupt state at any time, without taking any locks.
+
+		__NK_ASSERT_ALWAYS(iInterrupted == 0);		// we haven't done this already
+		NThread* pC;
+		for (;;)
+			{
+			pC = static_cast<NThread*>(TheScheduler.iCurrentThread);
+			CheckedSuspendThread(pC->iWinThread);
+			if (pC == TheScheduler.iCurrentThread)
+				break;								// no change of thread, so ok to proceed
+
+			// We suspended the thread while doing a (Symbian) context switch!
+			// The scheduler state might be inconsistent if we left it like that,
+			// so instead we'll resume it, then try again ...
+			CheckedResumeThread(pC->iWinThread);
+			}
+
+		__NK_ASSERT_ALWAYS(iInterrupted == 0);
+		iInterrupted = pC;
+		}
+
+	// Now we can assert ownership of the interrupt mask.
+	__NK_ASSERT_ALWAYS(iOwner == 0 && iLevel == 0);
+	TInt r = iLevel++;
+	iOwner = id;
+	LeaveCriticalSection(&iCS);
+	return r;
 	}
 
-void Win32Interrupt::End()
+void Win32Interrupt::RestoreInterruptMask(TInt aLevel)
 	{
-	__NK_ASSERT_ALWAYS(iOwner == GetCurrentThreadId());	// check we are the interrupting thread
-	NThread* pC = iInterrupted;
-	__NK_ASSERT_ALWAYS(pC==TheScheduler.iCurrentThread);
-	iInterrupted = 0;
-	if (iLock == 1 && TheScheduler.iKernCSLocked == 0 &&
-		(TheScheduler.iRescheduleNeededFlag || TheScheduler.iDfcPendingFlag) &&
-		pC->IsSafeToPreempt())
+	if (!iQ)
+		return;										// interrupt scheme not enabled yet
+
+	DWORD id = GetCurrentThreadId();
+	EnterCriticalSection(&iCS); 					// Win32 critical section, not a Symbian one
+
+	for (;;)
 		{
-		TheScheduler.iKernCSLocked = 1;		// prevent further pre-emption
-		if (pC->iWakeup == NThread::EIdle)
+		__NK_ASSERT_ALWAYS(id == iOwner);			// only the current owner may do this
+		TInt count = iLevel - aLevel;
+		if (count <= 0)
+			break;									// already restored to that level
+
+		iLevel = aLevel;							// update the recursion level first
+		if (aLevel > 0)
 			{
-			// wake up the NULL thread, it will always reschedule immediately
-			pC->WakeUp();
+			// The easiest case: we're still holding ownership, so there's nothing to do
+			break;
 			}
-		else
+
+		iOwner = 0;									// give up ownership
+		if (iWaiting)
 			{
-			// pre-empt the current thread and poke the 'scheduler' thread
-			__NK_ASSERT_ALWAYS(pC->iWakeup == NThread::ERelease);
-			pC->iWakeup = NThread::EResume;
-			UpdateThreadCpuTime(*pC, iScheduler);
-			RescheduleNeeded();
-			NKern::EnableAllInterrupts();
-			iScheduler.WakeUp();
-			return;
+			// Someone else is waiting for control of the interrupt mask.
+			// They may preempt us as soon as we exit the critical section
+			// (at the end of this function)
+			CheckedReleaseSemaphore(iQ);
+			break;
 			}
-		}
-	else
-		{
-		// no thread reschedle, so emit trace...
-#ifdef BTRACE_CPU_USAGE
-		BTrace0(BTrace::ECpuUsage,BTrace::EIrqEnd);
-#endif
+
+		// Lock fully released, no-one waiting, so see whether we need to reschedule
+		if (TheScheduler.iKernCSLocked || !iRescheduleOnExit)
+			break;
+
+		// Interrupt mask fully unlocked, but reschedule required ...
+		TheScheduler.iKernCSLocked = 1;
+		LeaveCriticalSection(&iCS);
+		TScheduler::Reschedule();
+		EnterCriticalSection(&iCS);
+
+		// Note: TScheduler::Reschedule() above calls MaskInterrupts() -- which changes
+		// the state of most of our member data. It returns with the kernel unlocked,
+		// but interrupts still disabled. Hence we will have reacquired ownership of the
+		// interrupt mask, and must release it again.  Instead of going recursive with a
+		// call to EnableAllInterrupts() we iterate; we'll get out of this loop eventually,
+		// because iRescheduleOnExit is updated by MaskInterrupts() ...
+		aLevel = 0;
 		}
 
-	if (((NThread*)pC)->iInKernel == 0 &&		// thread is running in user mode
-		pC->iUserModeCallbacks != NULL && 		// and has callbacks queued
-		TheScheduler.iKernCSLocked == 0 &&		// and is not currently processing a diversion
-		pC->IsSafeToPreempt())					// and can be safely prempted at this point
-		{
-		TheScheduler.iKernCSLocked = 1;
-		pC->ApplyDiversion();
-		}
-	NKern::EnableAllInterrupts();
-	__NK_ASSERT_ALWAYS(TInt(ResumeThread(pC->iWinThread)) > 0);	// check thread was previously suspended
+	LeaveCriticalSection(&iCS);
 	}
 
-void Win32Interrupt::Reschedule(TAny*)
+void Win32Interrupt::ForceReschedule()
+	{
+	RescheduleNeeded();
+	if (iScheduler.WakeUp())
+		FAULT();											// this can't happen
+	}
+
+void Win32Interrupt::SchedulerThreadFunction(TAny*)
 //
 // The entry-point for the interrupt-rescheduler thread.
 //
@@ -751,25 +1021,62 @@
 	FAULT();
 	}
 
-void Win32Interrupt::ForceReschedule()
+
+//
+// We need a global lock in the emulator to avoid scheduling reentrancy problems with the host
+// in particular, some host API calls acquire host mutexes, preempting such services results
+// in suspension of those threads which can cause deadlock if another thread requires that host
+// mutex.
+//
+// Because thread dreaction and code loading also require the same underlying mutex (used
+// by NT to protect DLL entrypoint calling), this would be rather complex with a fast mutex.
+// For now, keep it simple and use the preemption lock. Note that this means that the
+// MS timer DFC may be significantly delayed when loading large DLL trees, for example.
+//
+
+void SchedulerLock()
+//
+// Acquire the global lock. May be called before scheduler running, so handle that case
+//
 	{
-	RescheduleNeeded();
-	iScheduler.WakeUp();
+	if (TheScheduler.iCurrentThread)
+		{
+		EnterKernel();
+		NKern::Lock();
+		}
 	}
 
+void SchedulerUnlock()
+//
+// Release the global lock. May be called before scheduler running, so handle that case
+//
+	{
+	if (TheScheduler.iCurrentThread)
+		{
+		NKern::Unlock();
+		LeaveKernel();
+		}
+	}
+
+
+// This function allows a thread to escape from the Symbian scheduling domain to
+// become an ordinary Win32 thread for a while, in cases where it is necessary
+// to use Win32 APIs that are incompatible with the Symbian threading model.
+// AFAICS this is not currently used!
 void SchedulerEscape()
 	{
-	NThread& me=CheckedCurrentThread();
+	NThread& me = CheckedCurrentThread();
 	EnterKernel();
-	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked==0);	// Can't call Escape() with the Emulator/kernel already locked
+	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 0);	// Can't call Escape() with the Emulator/kernel already locked
 	NKern::ThreadEnterCS();
 	NKern::Lock();
-	me.iNState=NThreadBase::EBlocked;
+	me.iNState = NThreadBase::EBlocked;
 	TheScheduler.Remove(&me);
-	me.iWakeup=NThread::EEscaped;
-	SetThreadPriority(me.iWinThread,THREAD_PRIORITY_ABOVE_NORMAL);
-	Interrupt.ForceReschedule();	// schedules some other thread so we can carry on outside the scheduler domain
-	// this will change the value of iCurrentThread to ensure the 'escaped' invariants are set
+	me.iWakeup = NThread::EEscaped;
+	SetThreadPriority(me.iWinThread, THREAD_PRIORITY_ABOVE_NORMAL);
+	Interrupt.ForceReschedule();
+	// This schedules some other thread so we can carry on outside the scheduler domain.
+	// It will change the value of iCurrentThread to ensure the 'escaped' invariants are set
 	}
 
 void ReenterDfc(TAny* aPtr)
@@ -781,15 +1088,15 @@
 
 void SchedulerReenter()
 	{
-	NThread* me=SchedulerThread();
+	NThread* me = RunningThread();
 	__NK_ASSERT_ALWAYS(me);
 	__NK_ASSERT_ALWAYS(me->iWakeup == NThread::EEscaped);
 	TDfc idfc(&ReenterDfc, me);
 	StartOfInterrupt();
 	idfc.Add();
 	EndOfInterrupt();
-	SetThreadPriority(me->iWinThread,THREAD_PRIORITY_NORMAL);
-	__NK_ASSERT_ALWAYS(WaitForSingleObject(me->iScheduleLock, INFINITE) == WAIT_OBJECT_0);
+	SetThreadPriority(me->iWinThread, THREAD_PRIORITY_NORMAL);
+	CheckedWaitForSingleObject(me->iScheduleLock);
 	// when released, the kernel is locked and handed over to us
 	// need to complete the reschedule protocol in this thread now
 	TScheduler::Reschedule();
@@ -799,27 +1106,6 @@
 	}
 
 
-/**	Return the current processor context type
-	(thread, IDFC, interrupt or escaped thread)
-
-	@return	A value from NKern::TContext enumeration (including EEscaped)
-	@pre	Any context
-
-	@see	NKern::TContext
- */
-EXPORT_C TInt NKern::CurrentContext()
-	{
-	NThread* t = SchedulerThread();
-	if (!t)
-		return NKern::EInterrupt;
-	if (TheScheduler.iInIDFC)
-		return NKern::EIDFC;
-	if (t->iWakeup == NThread::EEscaped)
-		return NKern::EEscaped;
-	__NK_ASSERT_ALWAYS(NKern::Crashed() || t == TheScheduler.iCurrentThread);
-	return NKern::EThread;
-	}
-
 //
 // We use SuspendThread and ResumeThread to preempt threads.  This can cause
 // deadlock if the thread is using windows synchronisation primitives (eg
@@ -838,31 +1124,26 @@
 // Uncomment the following line to turn on tracing when we examine the call stack
 // #define DUMP_STACK_BACKTRACE
 
-#ifdef DUMP_STACK_BACKTRACE
+#ifdef	DUMP_STACK_BACKTRACE
 
 #include <psapi.h>
 
 typedef BOOL (WINAPI GMIFunc)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb);
-typedef BOOL (WINAPI EPMFunc)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded);
+typedef BOOL (WINAPI EPMFunc)(HANDLE hProcess, HMODULE* lphModule, DWORD cb, LPDWORD lpcbNeeded);
 typedef DWORD (WINAPI GMBNFunc)(HANDLE hProcess, HMODULE hModule, LPSTR lpBaseName, DWORD nSize);
 
 void PrintAllModuleInfo()
 	{
 	HMODULE psapiLibrary = LoadLibraryA("psapi.dll");
 	__NK_ASSERT_ALWAYS(psapiLibrary != NULL);
-
 	EPMFunc* epmFunc = (EPMFunc*)GetProcAddress(psapiLibrary, "EnumProcessModules");
 	__NK_ASSERT_ALWAYS(epmFunc != NULL);
-	
 	GMIFunc* gmiFunc = (GMIFunc*)GetProcAddress(psapiLibrary, "GetModuleInformation");
 	__NK_ASSERT_ALWAYS(gmiFunc != NULL);
-	
 	GMBNFunc* gmbnFunc = (GMBNFunc*)GetProcAddress(psapiLibrary, "GetModuleBaseNameA");
 	__NK_ASSERT_ALWAYS(gmbnFunc != NULL);
-
 	const TInt maxModules = 256;
 	HMODULE modules[maxModules];
-
 	DWORD spaceNeeded;
 	BOOL r = epmFunc(GetCurrentProcess(), modules, sizeof(HMODULE) * maxModules, &spaceNeeded);
 	__NK_ASSERT_ALWAYS(r);
@@ -871,16 +1152,13 @@
 	for (TUint i = 0 ; i < spaceNeeded / sizeof(HMODULE) ; ++i)
 		{
 		HMODULE library = modules[i];
-		
 		const TUint maxNameLen = 64;
 		char name[maxNameLen];
 		WORD len = gmbnFunc(GetCurrentProcess(), library, name, sizeof(name));
 		__NK_ASSERT_ALWAYS(len > 0 && len < maxNameLen);
-		
 		MODULEINFO info;
 		r = gmiFunc(GetCurrentProcess(), library, &info, sizeof(info));
 		__NK_ASSERT_ALWAYS(r);
-		
 		DEBUGPRINT("Module %s found at %08x to %08x", name, (TUint)info.lpBaseOfDll, (TUint)info.lpBaseOfDll + info.SizeOfImage);
 		}
 
@@ -888,7 +1166,7 @@
 	__NK_ASSERT_ALWAYS(r);
 	}
 
-#endif
+#endif	// DUMP_STACK_BACKTRACE
 
 const TInt KWin32NonPreemptibleFunctionCount = 2;
 
@@ -908,21 +1186,19 @@
 
 TWin32FunctionInfo Win32FindExportedFunction(const char* aFunctionName, ...)
 	{
-	const char *libname;
-	HMODULE library = NULL;
-
 	va_list arg;
 	va_start(arg, aFunctionName);
+	HMODULE library = NULL;
+	const char* libname;
 
 	// Loop through arguments until we find a library we can get a handle to.  List of library names
 	// is NULL-terminated.
-	while ((libname = va_arg(arg, const char *)) != NULL)
+	while ((libname = va_arg(arg, const char*)) != NULL)
 		{
 		library = GetModuleHandleA(libname);
 		if (library != NULL)
 			break;
 		}
-
 	va_end(arg);
 
 	// Make sure we did get a valid library
@@ -933,22 +1209,19 @@
 	__NK_ASSERT_ALWAYS(start != 0);
 
 	// Now have to check all other exports to find the end of the function
-	TUint end = 0xffffffff;
-	TInt i = 1;
-	for (;;)
+	TUint end = ~0u;
+	for (TInt i = 1; ; ++i)
 		{
 		TUint addr = (TUint)GetProcAddress(library, MAKEINTRESOURCEA(i));
 		if (!addr)
 			break;
 		if (addr > start && addr < end)
 			end = addr;
-		++i;
 		}
-	__NK_ASSERT_ALWAYS(end != 0xffffffff);
-	
+	__NK_ASSERT_ALWAYS(end != ~0u);
 	TWin32FunctionInfo result = { start, end - start };
-	
-#ifdef DUMP_STACK_BACKTRACE
+
+#ifdef	DUMP_STACK_BACKTRACE
 	DEBUGPRINT("Function %s found at %08x to %08x", aFunctionName, start, end);
 #endif
 	
@@ -957,7 +1230,7 @@
 
 void Win32FindNonPreemptibleFunctions()
 	{
-#ifdef DUMP_STACK_BACKTRACE
+#ifdef	DUMP_STACK_BACKTRACE
 	PrintAllModuleInfo();
 #endif
 
@@ -966,7 +1239,7 @@
 	Win32NonPreemptibleFunctions[i++] = Win32FindExportedFunction("KiUserExceptionDispatcher", "ntdll.dll", NULL);
 	__NK_ASSERT_ALWAYS(i == KWin32NonPreemptibleFunctionCount);
 	}
-	
+
 TBool Win32IsThreadInNonPreemptibleFunction(HANDLE aWinThread, TLinAddr aStackTop)
 	{
 	const TInt KMaxSearchDepth = 16;		 // 12 max observed while handling exceptions
@@ -974,24 +1247,23 @@
 	const TInt KMaxFrameSize = 4096;
 
 	CONTEXT c;
- 	c.ContextFlags=CONTEXT_FULL;
-	GetThreadContext(aWinThread, &c);
-
+	c.ContextFlags = CONTEXT_CONTROL;
+	CheckedGetThreadContext(aWinThread, &c);
 	TUint eip = c.Eip;
 	TUint ebp = c.Ebp;
 	TUint lastEbp = c.Esp;
 
-	#ifdef DUMP_STACK_BACKTRACE
+#ifdef	DUMP_STACK_BACKTRACE
 	DEBUGPRINT("Stack backtrace for thread %x", aWinThread);
-	#endif	
+#endif
 
 	// Walk the call stack
 	for (TInt i = 0 ; i < KMaxSearchDepth ; ++i)
 		{
-		#ifdef DUMP_STACK_BACKTRACE
+#ifdef	DUMP_STACK_BACKTRACE
 		DEBUGPRINT("  %08x", eip);
-		#endif
-		
+#endif
+
 		for (TInt j = 0 ; j < KWin32NonPreemptibleFunctionCount ; ++j)
 			{
 			const TWin32FunctionInfo& info = Win32NonPreemptibleFunctions[j];
@@ -1001,7 +1273,7 @@
 				return TRUE;
 				}
 			}
-		
+
 		// Check frame pointer is valid before dereferencing it
 		if (TUint(aStackTop - ebp) > KMaxStackSize || TUint(ebp - lastEbp) > KMaxFrameSize || ebp & 3)
 			break;
@@ -1011,7 +1283,7 @@
 		ebp = frame[0];
 		eip = frame[1];
 		}
-	
+
 	return FALSE;
 	}
 
@@ -1020,20 +1292,3 @@
 	return !Win32IsThreadInNonPreemptibleFunction(iWinThread, iUserStackBase);
 	}
 
-void LeaveKernel()
-	{
-	TInt& k=CheckedCurrentThread().iInKernel;
-	__NK_ASSERT_DEBUG(k>0);
-	if (k==1)  // just about to leave kernel
-		{
-		NThread& t = CheckedCurrentThread();
-		__NK_ASSERT_ALWAYS(t.iCsCount==0);
-		__NK_ASSERT_ALWAYS(t.iHeldFastMutex==0);
-		__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked==0);
-		NKern::DisableAllInterrupts();
-		t.CallUserModeCallbacks();
-		NKern::EnableAllInterrupts();
-		}
-	--k;
-	}
-
--- a/kernel/eka/nkern/win32/ncthrd.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/nkern/win32/ncthrd.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -1,4 +1,4 @@
-// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 1998-2010 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"
@@ -12,7 +12,7 @@
 //
 // Description:
 // e32\nkern\win32\ncthrd.cpp
-// 
+//
 //
 
 // NThreadBase member data
@@ -21,6 +21,11 @@
 #include "nk_priv.h"
 #include <emulator.h>
 
+#if		defined(__CW32__) && defined(__MWERKS__) && (__MWERKS__ < 0x3200)
+// Early versions didn't support try/except :(
+#error	"This compiler is no longer supported, because it doesn't provide C++ exception generation and handling"
+#endif
+
 extern "C" void ExcFault(TAny*);
 
 // initial Win32 thread stack size
@@ -36,31 +41,298 @@
 	NFastMutex iHandoff;
 	};
 
+
+/** Set some global properties of the emulator
+	Called by the Win32 base port during boot.
+
+	@param	aTrace TRUE means trace Win32 thread ID for every thread created
+	@param	aSingleCpu TRUE means lock the emulator process to a single CPU
+
+	@internalTechnology
+ */
+EXPORT_C void NThread::SetProperties(TBool aTrace, TInt aSingleCpu)
+	{
+	Win32TraceThreadId = aTrace;
+	Win32SingleCpu = aSingleCpu;
+	}
+
+
+
+void NThread__HandleException(TWin32ExcInfo aExc)
+//
+// Final stage NKern exception handler.
+//
+// The first stage of exception processing (in ExceptionHandler()) entered the
+// kernel and locked it, so we have to undo those two operations before returning.
+// However, if the kernel was already locked when the exception occurred, it is
+// a fatal condition and the system will be faulted.
+//
+// Note that the parameter struct is passed by value, this allows for direct
+// access to the exception context created on the call stack by NThread::Exception().
+//
+	{
+	NKern::Unlock();
+	if (TheScheduler.iKernCSLocked)
+		ExcFault(&aExc);
+
+	// Complete the exception data. Note that the call to EnterKernel() in
+	// ExceptionHandler() will have incremented iInKernel after the exception
+	// occurred.
+	NThread* me = static_cast<NThread*>(TheScheduler.iCurrentThread);
+	__NK_ASSERT_DEBUG(me->iInKernel);
+	aExc.iFlags = me->iInKernel == 1 ? 0 : TWin32ExcInfo::EExcInKernel;
+	aExc.iHandler = NULL;
+
+	// run NThread exception handler in 'kernel' mode
+	me->iHandlers->iExceptionHandler(&aExc, me);
+	LeaveKernel();
+
+	// If a 'user' handler is set by the kernel handler, run it
+	if (aExc.iHandler)
+		aExc.iHandler(aExc.iParam[0], aExc.iParam[1]);
+	}
+
+__NAKED__ void NThread::Exception()
+//
+// Trampoline to nKern exception handler
+// Must preserve all registers in the structure defined by TWin32Exc
+//
+// This is an intermediate layer, to which control has been diverted by
+// NThread::ExceptionHandler(). It constructs a TWin32Exc structure on
+// the stack and passes it NThread__ExceptionHandler().
+//
+// At this point we are no longer in Win32 exception context.
+//
+	{
+	// this is the TWin32Exc structure
+	__asm push Win32ExcAddress			// save return address followed by EBP first to help debugger
+	__asm push ebp
+	__asm mov ebp, esp
+	__asm push cs
+	__asm pushfd
+	__asm push gs
+	__asm push fs
+	__asm push es
+	__asm push ds
+	__asm push ss
+	__asm push edi
+	__asm push esi
+	__asm lea esi, [ebp+8]
+	__asm push esi						// original esp
+	__asm push ebx
+	__asm push edx
+	__asm push ecx
+	__asm push eax
+	__asm push Win32ExcDataAddress
+	__asm push Win32ExcCode
+	__asm sub esp, 20					// struct init completed by NThread__HandleException()
+
+	__asm call NThread__HandleException
+
+	__asm add esp, 28
+	__asm pop eax
+	__asm pop ecx
+	__asm pop edx
+	__asm pop ebx
+	__asm pop esi						// original ESP - ignore
+	__asm pop esi
+	__asm pop edi
+	__asm pop ebp						// original SS - ignore
+	__asm pop ds
+	__asm pop es
+	__asm pop fs
+	__asm pop gs
+	__asm popfd
+	__asm pop ebp						// original CS - ignore
+	__asm pop ebp
+	__asm ret
+	}
+
+// From e32/commmon/win32/seh.cpp
+extern DWORD CallFinalSEHHandler(EXCEPTION_RECORD* aException, CONTEXT* aContext);
+
+extern void DivertHook();
+
+DWORD NThread::ExceptionHandler(EXCEPTION_RECORD* aException, CONTEXT* aContext)
+//
+// Win32 exception handler for EPOC threads
+//
+// This is the outermost wrapper, called from ExceptionFilter() of via manual
+// interception of the Win32 exception mechanism if using a really old compiler
+//
+	{
+	if (aException->ExceptionCode == EXCEPTION_BREAKPOINT)
+		{
+		// Hardcoded breakpoint
+		//
+		// Jump directly to NT's default unhandled exception handler which will
+		// either display a dialog, directly invoke the JIT debugger or do nothing
+		// dependent upon the AeDebug and ErrorMode registry settings.
+		//
+		// Note this handler is always installed on the SEH chain and is always
+		// the last handler on this chain, as it is installed by NT in kernel32.dll
+		// before invoking the Win32 thread function.
+		return CallFinalSEHHandler(aException, aContext);
+		}
+
+	// deal with conflict between preemption and diversion
+	// the diversion will have been applied to the pre-exception context, not
+	// the current context, and thus will get 'lost'. Wake-up of a pre-empted
+	// thread with a diversion will not unlock the kernel, so we need to deal
+	// with the possibility that the kernel may be locked if a diversion exists
+	NThread& me = *static_cast<NThread*>(TheScheduler.iCurrentThread);
+	if (me.iDiverting && me.iDivertFn)
+		{
+		// The thread is being forced to exit - run the diversion outside of Win32 exception handler
+		__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
+		aContext->Eip = (TUint32)&DivertHook;
+		}
+	else
+		{
+		if (me.iDiverting)
+			{
+			// The thread is being prodded to pick up its callbacks.  This will happen when the
+			// exception handler calls LeaveKernel(), so we can remove the diversion
+			__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
+			if (aException->ExceptionAddress == &DivertHook)
+				aException->ExceptionAddress = me.iDivertReturn;
+			me.iDivertReturn = NULL;
+			me.iDiverting = EFalse;
+			EnterKernel(TRUE);
+			}
+		else
+			{
+			EnterKernel();
+			TheScheduler.iKernCSLocked = 1;	// prevent pre-emption
+			}
+
+		// If the kernel was already locked, this will be detected in the next stage handler
+		// (NThread::Exception()), which we arrange to run outside the Win32 exception context
+		Win32ExcAddress = aException->ExceptionAddress;
+		Win32ExcDataAddress = (TAny*)aException->ExceptionInformation[1];
+		Win32ExcCode = aException->ExceptionCode;
+		aContext->Eip = (TUint32)&Exception;
+		}
+
+	return ExceptionContinueExecution;
+	}
+
+LONG WINAPI NThread::ExceptionFilter(EXCEPTION_POINTERS* aExc)
+//
+// Filter wrapper for main Win32 exception handler
+//
+	{
+	LONG ret = EXCEPTION_CONTINUE_SEARCH;
+
+	switch (ExceptionHandler(aExc->ExceptionRecord, aExc->ContextRecord))
+		{
+	case ExceptionContinueExecution:
+		ret = EXCEPTION_CONTINUE_EXECUTION;
+		break;
+		
+	case ExceptionContinueSearch:
+	default:
+		break;
+		}
+
+	return ret;
+	}
+
+
+DWORD WINAPI NThread::StartThread(LPVOID aParam)
+//
+// Win32 thread function for nKern threads.
+//
+// The thread first enters this function after the nScheduler has resumed
+// it, following the context switch induced by the hand-off mutex.
+//
+// The parameter block for this thread needs to be copied into its
+// own context, before releasing the mutex and handing control back to
+// the creating thread.
+//
+	{
+	SCreateThread* init = static_cast<SCreateThread*>(aParam);
+	NThread& me = *static_cast<NThread*>(init->iHandoff.iHoldingThread);
+	me.iWinThreadId = GetCurrentThreadId();
+	SchedulerRegister(me);
+#ifdef BTRACE_FAST_MUTEX
+	BTraceContext4(BTrace::EFastMutex, BTrace::EFastMutexWait, &init->iHandoff);
+#endif
+	NKern::Unlock();
+
+	// intercept win32 exceptions in a debuggabble way
+	__try
+		{
+		// save the thread entry point and parameter block
+		const SNThreadCreateInfo& info = *init->iInfo;
+		NThreadFunction threadFunction = info.iFunction;
+		TUint8 parameterBlock[KMaxParameterBlock];
+		TAny* parameter = (TAny*)info.iParameterBlock;
+
+		if (info.iParameterBlockSize)
+			{
+			__NK_ASSERT_DEBUG(TUint(info.iParameterBlockSize) <= TUint(KMaxParameterBlock));
+			memcpy(parameterBlock, info.iParameterBlock, info.iParameterBlockSize);
+			parameter = parameterBlock;
+			}
+
+
+		// Calculate stack base
+		me.iUserStackBase = (((TLinAddr)&parameterBlock) + 0xfff) & ~0xfff;
+
+		// some useful diagnostics for debugging
+		if (Win32TraceThreadId)
+			KPrintf("Thread %T created @ 0x%x - Win32 Thread ID 0x%x", init->iHandoff.iHoldingThread, init->iHandoff.iHoldingThread, GetCurrentThreadId());
+
+#ifdef MONITOR_THREAD_CPU_TIME
+		me.iLastStartTime = 0;  // Don't count NThread setup in cpu time
+#endif
+
+		// start-up complete, release the handoff mutex, which will re-suspend us
+		NKern::FMSignal(&init->iHandoff);
+
+		// thread has been resumed: invoke the thread function
+		threadFunction(parameter);
+		}
+	__except (ExceptionFilter(GetExceptionInformation()))
+		{
+		// Do nothing - filter does all the work and hooks into EPOC
+		// h/w exception mechanism if necessary by thread diversion
+		}
+
+	NKern::Exit();
+	return 0;
+	}
+
+
+
 /**
  * Set the Win32 thread priority based on the thread type.
- * Interrupt/Event threads must be able to preempt normal nKern threads,
- * so they get a higher priority.
+ * Interrupt/Event threads must be able to preempt normal
+ * nKern threads, so they get a higher (Win32) priority.
  */
 static void SetPriority(HANDLE aThread, TEmulThreadType aType)
 	{
 	TInt p;
+
 	switch (aType)
 		{
 	default:
 		FAULT();
+
 	case EThreadEvent:
 		p = THREAD_PRIORITY_ABOVE_NORMAL;
 		break;
+
 	case EThreadNKern:
 		p = THREAD_PRIORITY_NORMAL;
 		break;
 		}
 
-	__NK_ASSERT_ALWAYS(SetThreadPriority(aThread, p));
+	CheckedSetThreadPriority(aThread, p);
 	SetThreadPriorityBoost(aThread, TRUE);		// disable priority boost (for NT)
 	}
 
-
 /**	Create a Win32 thread for use in the emulator.
 
 	@param	aType Type of thread (Event or NKern) - determines Win32 priority
@@ -91,115 +363,6 @@
 	return handle;
 	}
 
-
-/** Set some global properties of the emulator
-	Called by the Win32 base port during boot.
-
-	@param	aTrace TRUE means trace Win32 thread ID for every thread created
-	@param	aSingleCpu TRUE means lock the emulator process to a single CPU
-
-	@internalTechnology
- */
-EXPORT_C void NThread::SetProperties(TBool aTrace, TInt aSingleCpu)
-	{
-	Win32TraceThreadId = aTrace;
-	Win32SingleCpu = aSingleCpu;
-	}
-
-#if defined(__CW32__) && __MWERKS__ < 0x3200
-DWORD NThread__ExceptionHandler(EXCEPTION_RECORD* aException, TAny* /*aRegistrationRecord*/, CONTEXT* aContext)
-//
-// Hook into exception handling for old version of CW
-//
-	{
-	return NThread::ExceptionHandler(aException, aContext);
-	}
-#endif // old __CW32__
-
-DWORD WINAPI NThread::StartThread(LPVOID aParam)
-//
-// Win32 thread function for nKern threads.
-//
-// The thread first enters this function after the nScheduler has resumed
-// it, following the context switch induced by the hand-off mutex.
-//
-// The parameter block for this thread needs to be copied into its
-// own context, before releasing the mutex and handing control back to
-// the creating thread.
-//
-	{
-	SCreateThread* init = static_cast<SCreateThread*>(aParam);
-	NThread& me=*static_cast<NThread*>(init->iHandoff.iHoldingThread);
-	me.iWinThreadId = GetCurrentThreadId();
-	SchedulerRegister(me);
-#ifdef BTRACE_FAST_MUTEX
-	BTraceContext4(BTrace::EFastMutex,BTrace::EFastMutexWait,&init->iHandoff);
-#endif
-	NKern::Unlock();
-
-#if defined(__CW32__) && __MWERKS__ < 0x3200
-	// intercept the win32 exception mechanism manually
-    asm {
-    	push	ebp
-    	mov		eax, -1
-    	push	eax
-    	push	eax
-    	push	offset NThread__ExceptionHandler
-    	push	fs:[0]
-    	mov		fs:[0], esp
-
-		// realign the stack
-    	sub		esp, 0x20
-    	and		esp, ~0x1f
-		}
-#else // ! old __CW32__
-	// intercept win32 exceptions in a debuggabble way
-__try {
-#endif // old __CW32__
-
-	// save the thread entry point and parameter block
-	const SNThreadCreateInfo& info = *init->iInfo;
-	TUint8 parameterBlock[KMaxParameterBlock];
-	TAny* parameter=(TAny*)info.iParameterBlock;
-	if (info.iParameterBlockSize)
-		{
-		__NK_ASSERT_DEBUG(TUint(info.iParameterBlockSize)<=TUint(KMaxParameterBlock));
-		parameter=parameterBlock;
-		memcpy(parameterBlock,info.iParameterBlock,info.iParameterBlockSize);
-		}
-	NThreadFunction threadFunction=info.iFunction;
-
-	// Calculate stack base
-	me.iUserStackBase = (((TLinAddr)&parameterBlock)+0xfff)&~0xfff; // base address of stack
-
-	// some useful diagnostics for debugging
-	if (Win32TraceThreadId)
-		KPrintf("Thread %T created @ 0x%x - Win32 Thread ID 0x%x",init->iHandoff.iHoldingThread,init->iHandoff.iHoldingThread,GetCurrentThreadId());
-
-#ifdef MONITOR_THREAD_CPU_TIME
-	me.iLastStartTime = 0;  // Don't count NThread setup in cpu time
-#endif
- 
-	// start-up complete, release the handoff mutex, which will re-suspend us
-	NKern::FMSignal(&init->iHandoff);
-
-	// thread has been resumed: invoke the thread function
-	threadFunction(parameter);
-
-#if !defined(__CW32__) || __MWERKS__ >= 0x3200
-	// handle win32 exceptions
-} __except (ExceptionFilter(GetExceptionInformation())) {
-	// Do nothing - filter does all the work and hooks
-	// into EPOC h/w exception mechanism if necessary
-	// by thread diversion
-}
-#endif // !old __CW32__
-
-	NKern::Exit();
-
-	return 0;
-	}
-
 static HANDLE InitThread()
 //
 // Set up the initial thread and return the thread handle
@@ -207,7 +370,8 @@
 	{
 	HANDLE p = GetCurrentProcess();
 	HANDLE me;
-	__NK_ASSERT_ALWAYS(DuplicateHandle(p, GetCurrentThread(), p, &me, 0, FALSE, DUPLICATE_SAME_ACCESS));
+	DWORD r = DuplicateHandle(p, GetCurrentThread(), p, &me, 0, FALSE, DUPLICATE_SAME_ACCESS);
+	__NK_ASSERT_ALWAYS(r != 0);						// r is zero on error
 	SetPriority(me, EThreadNKern);
 	return me;
 	}
@@ -218,11 +382,11 @@
 	iWinThreadId = 0;
 	iScheduleLock = NULL;
 	iInKernel = 1;
-	iDivert = NULL;
+	iDivertFn = NULL;
 	iWakeup = aInitial ? ERelease : EResumeLocked;	// mark new threads as created (=> win32 suspend)
 
-	TInt r=NThreadBase::Create(aInfo,aInitial);
-	if (r!=KErrNone)
+	TInt r = NThreadBase::Create(aInfo, aInitial);
+	if (r != KErrNone)
 		return r;
 
 	// the rest has to be all or nothing, we must complete it
@@ -237,7 +401,7 @@
 #ifdef MONITOR_THREAD_CPU_TIME
 		iLastStartTime = NKern::FastCounter();
 #endif
-		iUserStackBase = (((TLinAddr)&r)+0xfff)&~0xfff; // base address of stack
+		iUserStackBase = (((TLinAddr)&r) + 0xfff) & ~0xfff; // base address of stack
 		SchedulerInit(*this);
 		return KErrNone;
 		}
@@ -246,7 +410,6 @@
 	//
 	SCreateThread start;
 	start.iInfo = &aInfo;
-
 	iWinThread = CreateWin32Thread(EThreadNKern, &StartThread, &start, FALSE);
 	if (iWinThread == NULL)
 		{
@@ -256,7 +419,7 @@
 		}
 
 #ifdef BTRACE_THREAD_IDENTIFICATION
-	BTrace4(BTrace::EThreadIdentification,BTrace::ENanoThreadCreate,this);
+	BTrace4(BTrace::EThreadIdentification, BTrace::ENanoThreadCreate, this);
 #endif
 	// switch to the new thread to hand over the parameter block
 	NKern::Lock();
@@ -273,202 +436,33 @@
 	return KErrNone;
 	}
 
-void NThread__HandleException(TWin32ExcInfo aExc)
-//
-// Final stage NKern exception handler.
-//
-// Check for a fatal exception when the kernel is locked
-//
-// Note that the parameter struct is passed by value, this allows for
-// direct access to the exception context created on the call stack by
-// NThread::Exception().
-//
-	{
-	if (TheScheduler.iKernCSLocked)
-		ExcFault(&aExc);
 
-	// Complete the exception data. Note that the call to EnterKernel() in
-	// ExceptionFilter() will have incremented iInKernel after the exception
-	// occurred.
-	NThread* me = static_cast<NThread*>(TheScheduler.iCurrentThread);
-	__NK_ASSERT_DEBUG(me->iInKernel);
-	aExc.iFlags = me->iInKernel == 1 ? 0 : TWin32ExcInfo::EExcInKernel;
-	aExc.iHandler = NULL;
-
-	// run NThread exception handler in 'kernel' mode
-	me->iHandlers->iExceptionHandler(&aExc, me);
-	LeaveKernel();
-
-	// If a 'user' handler is set by the kernel handler, run it
-	if (aExc.iHandler)
-		aExc.iHandler(aExc.iParam[0], aExc.iParam[1]);
-	}
-
-void NKern__Unlock()
-//
-// CW asm ICE workaround
-//
-	{
-	NKern::Unlock();
-	}
-
-__NAKED__ void NThread::Exception()
-//
-// Trampoline to nKern exception handler
-// must preserve all registers in the structure defined by TWin32Exc
-//
-	{
-	// this is the TWin32Exc structure
-	__asm push Win32ExcAddress			// save return address followed by EBP first to help debugger
-	__asm push ebp
-	__asm mov ebp, esp
-	__asm push cs
-	__asm pushfd
-	__asm push gs
-	__asm push fs
-	__asm push es
-	__asm push ds
-	__asm push ss
-	__asm push edi
-	__asm push esi
-	__asm lea esi, [ebp+8]
-	__asm push esi		// original esp
-	__asm push ebx
-	__asm push edx
-	__asm push ecx
-	__asm push eax
-	__asm push Win32ExcDataAddress
-	__asm push Win32ExcCode
-	__asm sub esp, 20	// struct init completed by NThread__HandleException()
-
-	__asm call NKern__Unlock
-
-	__asm call NThread__HandleException
-
-	__asm add esp, 28
-	__asm pop eax
-	__asm pop ecx
-	__asm pop edx
-	__asm pop ebx
-	__asm pop esi		// original ESP - ignore
-	__asm pop esi
-	__asm pop edi
-	__asm pop ebp		// original SS - ignore
-	__asm pop ds
-	__asm pop es
-	__asm pop fs
-	__asm pop gs
-	__asm popfd
-	__asm pop ebp		// original CS - ignore
-	__asm pop ebp
-	__asm ret
-	}
-
-LONG WINAPI NThread::ExceptionFilter(EXCEPTION_POINTERS* aExc)
-//
-// Filter wrapper for main Win32 exception handler
-//
-	{
-	LONG ret = EXCEPTION_CONTINUE_SEARCH;
-
-	switch (ExceptionHandler(aExc->ExceptionRecord, aExc->ContextRecord))
-		{
-		case ExceptionContinueExecution:
-			{
-			ret = EXCEPTION_CONTINUE_EXECUTION;
-			}
-			break;
-		case ExceptionContinueSearch:
-		default:
-			{
-			}
-			break;
-		}
-
-	return ret;
-	}
-
-// From e32/commmon/win32/seh.cpp
-extern DWORD CallFinalSEHHandler(EXCEPTION_RECORD* aException, CONTEXT* aContext);
-
-extern void DivertHook();
-
-DWORD NThread::ExceptionHandler(EXCEPTION_RECORD* aException, CONTEXT* aContext)
-//
-// Win32 exception handler for EPOC threads
-//
-	{
-	if (aException->ExceptionCode == EXCEPTION_BREAKPOINT)
-		{
-		// Hardcoded breakpoint
-		//
-		// Jump directly to NT's default unhandled exception handler which will
-		// either display a dialog, directly invoke the JIT debugger or do nothing
-		// dependent upon the AeDebug and ErrorMode registry settings.
-		//
-		// Note this handler is always installed on the SEH chain and is always
-		// the last handler on this chain, as it is installed by NT in kernel32.dll
-		// before invoking the Win32 thread function.
-		return CallFinalSEHHandler(aException, aContext);
-		}
-
-	// deal with conflict between preemption and diversion
-	// the diversion will have been applied to the pre-exception context, not
-	// the current context, and thus will get 'lost'. Wake-up of a pre-empted
-	// thread with a diversion will not unlock the kernel, so need to deal with
-	// the possibility that the kernel may be locked if a diversion exists
-
-	NThread& me = *static_cast<NThread*>(TheScheduler.iCurrentThread);
-	if (me.iDiverted && me.iDivert)
-		{
-		// The thread is being forced to exit - run the diversion outside of Win32 exception handler
-		__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
-		aContext->Eip = (TUint32)&DivertHook;
-		}
-	else
-		{
-		if (me.iDiverted)
-			{
-			// The thread is being prodded to pick up its callbacks.  This will happen when the
-			// exception handler calls LeaveKernel(), so we can remove the diversion
-			__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
-			if (aException->ExceptionAddress == &DivertHook)
-				aException->ExceptionAddress = me.iDivertReturn;
-			me.iDiverted = EFalse;
-			me.iDivertReturn = NULL;
-			EnterKernel(FALSE);
-			}
-		else
-			{
-			EnterKernel();
-			TheScheduler.iKernCSLocked = 1;	// prevent pre-emption
-			}
-		
-		// If the kernel was already locked, this will be detected in the next stage handler
-		// run 2nd stage handler outside of Win32 exception context
-		Win32ExcAddress = aException->ExceptionAddress;
-		Win32ExcDataAddress = (TAny*)aException->ExceptionInformation[1];
-		Win32ExcCode = aException->ExceptionCode;
-		aContext->Eip = (TUint32)&Exception;
-		}
-	return ExceptionContinueExecution;
-	}
 
 void NThread::Diverted()
 //
-// Forced diversion go through here, in order to 'enter' the kernel
+// This function is called in the context of a thread that is being diverted.
+// This can be for either of two reasons: if iDivertFn has been set, that
+// function will be called and is not expected to return i.e.  it should force
+// the thread to exit. Otherwise, the thread will make a null trip through the
+// kernel, causing it to run pending user-mode callbacks on the way out.
+//
+// On entry, the kernel is locked and interrupts enabled
 //
 	{
 	NThread& me = *static_cast<NThread*>(TheScheduler.iCurrentThread);
 	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
-	__NK_ASSERT_ALWAYS(me.iDiverted);
-	NThread::TDivert divert = me.iDivert;
-	me.iDiverted = EFalse;
-	me.iDivert = NULL;
+	__NK_ASSERT_ALWAYS(me.iInKernel == 0);
+	__NK_ASSERT_ALWAYS(me.iDiverting);
+	NThread::TDivert divertFn = me.iDivertFn;
+	me.iDivertFn = NULL;
 	me.iDivertReturn = NULL;
-	EnterKernel(FALSE);
-	if (divert)
-		divert();	// does not return
+	me.iDiverting = EFalse;
+
+	EnterKernel(TRUE);
+
+	if (divertFn)
+		divertFn();					// does not return
+
 	NKern::Unlock();
 	LeaveKernel();
 	}
@@ -488,10 +482,10 @@
 	//		| saved eax		 |
 	//		| saved ecx		 |
 	//      | saved edx		 |
-	//		
+	//
 	__asm push eax					// reserve word for return address
 	__asm push ebp
-	__asm mov ebp, esp 
+	__asm mov ebp, esp
 	__asm pushfd
 	__asm push eax
 	__asm push ecx
@@ -510,28 +504,43 @@
 
 
 void NThread::ApplyDiversion()
+//
+// Arrange that the thread will be diverted when next it runs.
+// This can be for either of two reasons: if iDivertFn has been set,
+// that function will be called and is not expected to return i.e.
+// it should force the thread to exit. Otherwise, the thread will
+// make a null trip through the kernel, causing it to run pending
+// user-mode callbacks on the way out.
+//
+// This uses the Win32 CONTEXT functions to change the thread's PC
+// so that execution restarts at DivertHook ...
+//
 	{
 	// Called with interrupts disabled and kernel locked
 	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
-	if (iDiverted)
+	__NK_ASSERT_ALWAYS(iDivertReturn == NULL || iDiverting);
+
+	if (iDiverting)
 		return;
+
 	CONTEXT c;
-	c.ContextFlags=CONTEXT_FULL;
-	GetThreadContext(iWinThread, &c);
-	__NK_ASSERT_ALWAYS(iDivertReturn == NULL);
+	c.ContextFlags = CONTEXT_CONTROL;
+	CheckedGetThreadContext(iWinThread, &c);
 	iDivertReturn = (TAny*)c.Eip;
-	c.Eip=(TUint32)&DivertHook;
-	SetThreadContext(iWinThread, &c);
-	iDiverted = ETrue;
+	c.Eip = (TUint32)&DivertHook;
+	c.ContextFlags = CONTEXT_CONTROL;
+	CheckedSetThreadContext(iWinThread, &c);
+	iDiverting = ETrue;
 	}
 
-void NThread::Divert(TDivert aDivert)
+void NThread::Divert(TDivert aDivertFn)
 //
-// Divert the thread from its current path
-// The diversion function is called with the kernel locked and interrupts enabled
+// Arrange that the thread will exit by calling aDivertFn when next
+// it runs.  The diversion function will be called with the kernel
+// locked and interrupts enabled.  It is not expected to return.
 //
 	{
-	iDivert = aDivert;
+	iDivertFn = aDivertFn;
 	if (iWakeup == EResume)
 		iWakeup = EResumeDiverted;
 	else
@@ -544,9 +553,9 @@
 // On entry, kernel is locked, interrupts are enabled and we hold an interlock mutex
 //
 	{
-	NThreadBase& me=*TheScheduler.iCurrentThread;
+	NThreadBase& me = *TheScheduler.iCurrentThread;
 	me.iHeldFastMutex->Signal();	// release the interlock
-	me.iNState=EDead;				// mark ourselves as dead which will take thread out of scheduler
+	me.iNState = EDead;				// mark ourselves as dead which will take thread out of scheduler
 	TheScheduler.Remove(&me);
 	RescheduleNeeded();
 	TScheduler::Reschedule();	// this won't return
@@ -558,7 +567,7 @@
 // Called if the new thread creation was aborted - so it will not be killed in the usual manner
 //
 // This function needs to exit the thread synchronously as on return we will destroy the thread control block
-// Thus wee need to use an interlock that ensure that the target thread runs the exit handler before we continue
+// Thus we need to use an interlock that ensure that the target thread runs the exit handler before we continue
 //
 	{
 	// check if the Win32 thread was created
@@ -570,8 +579,8 @@
 	ForceResume();
 	// create and assign mutex to stillborn thread
 	NFastMutex interlock;
-	interlock.iHoldingThread=this;
-	iHeldFastMutex=&interlock;
+	interlock.iHoldingThread = this;
+	iHeldFastMutex = &interlock;
 	interlock.Wait();			// interlock on thread exit handler
 	interlock.Signal();
 	NKern::Unlock();
@@ -584,23 +593,14 @@
 //
 	{
 	NThreadBase& me = *TheScheduler.iCurrentThread;
+	__NK_ASSERT_ALWAYS(static_cast<NThread&>(me).iInKernel > 0);
 	me.iCsCount = 0;
-	__NK_ASSERT_ALWAYS(static_cast<NThread&>(me).iInKernel>0);
 	me.Exit();
 	}
 
-void NThreadBase::OnKill()
-	{
-	}
-
-void NThreadBase::OnExit()
-	{
-	}
-
 inline void NThread::DoForceExit()
 	{
 	__NK_ASSERT_DEBUG(TheScheduler.iKernCSLocked);
-//
 	Divert(&ExitAsync);
 	}
 
@@ -612,39 +612,11 @@
 	static_cast<NThread*>(this)->DoForceExit();
 	}
 
-//
-// We need a global lock in the emulator to avoid scheduling reentrancy problems with the host
-// in particular, some host API calls acquire host mutexes, preempting such services results
-// in suspension of those threads which can cause deadlock if another thread requires that host
-// mutex.
-//
-// Because thread dreaction and code loading also require the same underlying mutex (used
-// by NT to protect DLL entrypoint calling), this would be rather complex with a fast mutex.
-// For now, keep it simple and use the preemption lock. Note that this means that the
-// MS timer DFC may be significantly delayed when loading large DLL trees, for example.
-//
-
-void SchedulerLock()
-//
-// Acquire the global lock. May be called before scheduler running, so handle that case
-//
+void NThreadBase::OnExit()
 	{
-	if (TheScheduler.iCurrentThread)
-		{
-		EnterKernel();
-		NKern::Lock();
-		}
 	}
 
-void SchedulerUnlock()
-//
-// Release the global lock. May be called before scheduler running, so handle that case
-//
+void NThreadBase::OnKill()
 	{
-	if (TheScheduler.iCurrentThread)
-		{
-		NKern::Unlock();
-		LeaveKernel();
-		}
 	}
 
--- a/kernel/eka/nkern/win32/vectors.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/nkern/win32/vectors.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -1,4 +1,4 @@
-// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 1998-2010 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"
@@ -12,13 +12,15 @@
 //
 // Description:
 // e32\nkern\win32\vectors.cpp
-// 
+//
 //
 
 #include "nk_priv.h"
 
-inline TInt Invoke(TLinAddr aHandler,const TInt* aArgs)
-	{return (TExecHandler(aHandler))(aArgs[0],aArgs[1],aArgs[2],aArgs[3]);}
+inline TInt Invoke(TLinAddr aHandler, const TInt* aArgs)
+	{
+	return (TExecHandler(aHandler))(aArgs[0], aArgs[1], aArgs[2], aArgs[3]);
+	}
 
 /**	Executive dispatcher.
 	This is hooked by EUSER to handle executive dispatch into the kernel.
@@ -29,15 +31,16 @@
 EXPORT_C TInt __fastcall Dispatch(TInt aFunction, TInt* aArgs)
 	{
 	NThread& me = *static_cast<NThread*>(TheScheduler.iCurrentThread);
-	__NK_ASSERT_ALWAYS(!me.iDiverted);
+	__NK_ASSERT_ALWAYS(!me.iDiverting);
 	
 	EnterKernel();
 
 	if (aFunction & 0x800000)
 		{
-		aFunction &= 0x7fffff;
 		// fast exec
 		const SFastExecTable* table = me.iFastExecTable;
+
+		aFunction &= 0x7fffff;
 		if (aFunction == 0)
 			{
 			// special case fast exec call
@@ -45,38 +48,44 @@
 			LeaveKernel();
 			return 0;
 			}
-		if (TUint(aFunction)<TUint(table->iFastExecCount))
+
+		if (TUint(aFunction) < TUint(table->iFastExecCount))
 			{
 			NKern::Lock();
-			TInt r = Invoke(table->iFunction[aFunction-1],aArgs);
+			TInt r = Invoke(table->iFunction[aFunction-1], aArgs);
 			NKern::Unlock();
 			LeaveKernel();
 			return r;
 			}
+
 		// invalid exec number passed, so ensure we invoke the invalid exec
 		// handler by setting an illegal slow exec number
 		aFunction = -1;
 		}
 
 	// slow exec
+	const SSlowExecTable* table = (const SSlowExecTable*)((const TUint8*)me.iSlowExecTable - _FOFF(SSlowExecTable, iEntries));
 
-	
-	const SSlowExecTable* table = (const SSlowExecTable*)((const TUint8*)me.iSlowExecTable - _FOFF(SSlowExecTable,iEntries));
 	if (TUint(aFunction) >= TUint(table->iSlowExecCount))
-		return Invoke(table->iInvalidExecHandler,aArgs);
+		return Invoke(table->iInvalidExecHandler, aArgs);
 
 	const SSlowExecEntry& e = table->iEntries[aFunction];
+
 	if (e.iFlags & KExecFlagClaim)
 		NKern::LockSystem();
+
 	if (e.iFlags & KExecFlagPreprocess)
 		{
 		// replace the first argument with the result of preprocessing
 		TPreprocessHandler preprocesser = (TPreprocessHandler)table->iPreprocessHandler;
 		preprocesser(aArgs, e.iFlags);
 		}
-	TInt r = Invoke(e.iFunction,aArgs);
+
+	TInt r = Invoke(e.iFunction, aArgs);
+
 	if (e.iFlags & KExecFlagRelease)
 		NKern::UnlockSystem();
+
 	LeaveKernel();
 	return r;
 	}
--- a/kernel/eka/release.txt	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/release.txt	Mon Sep 27 10:52:00 2010 +0100
@@ -1,3 +1,29 @@
+Version 2.00.4003
+=================
+(Made by vfebvre 21/09/2010)
+
+1.	jinmowan
+	1.	ou1cimx1#578547 USB e32test code are not smpsafe
+
+2.	y102chen
+	1.	ou1cimx1#563014 MCL NCP build Critical warnings in kerneltest/e32test/device
+
+
+Version 2.00.4002
+=================
+(Made by vfebvre 20/09/2010)
+
+1.	vfebvre
+	1.	ou1cimx1#551193 ENV nandtest_load ROMs cannot be built from outside eka/rombuild
+	2.	ou1cimx1#582734 ENV Extension makefiles cannot be exported and used from the same bld.inf on SBSv1
+
+2.	genwei
+	1.	ou1cimx1#561220 mcl otg2.0 descriptor support, and B HNP not supported
+
+3.	davegord
+	1.	ou1cimx1#532104 Emulator panics with kernel precondition failure
+
+
 Version 2.00.4001
 =================
 (Made by vfebvre 14/09/2010)
--- a/kernel/eka/rombuild/alltests.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/alltests.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -21,7 +21,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt					Test\test_paged.cpp
+data=gentestpaged.txt										Test\test_paged.cpp
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -58,7 +58,7 @@
 data=EPOCROOT##epoc32\Release\##KMAIN##\##BUILD##\minkda.ldd						\sys\bin\minkda.ldd
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt				Test\test_unpaged.cpp	unpaged
+data=gentestnonpaged.txt															Test\test_unpaged.cpp	unpaged
 #endif
 
 #if defined(SMPSOAK)
--- a/kernel/eka/rombuild/autotest.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/autotest.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -21,7 +21,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged.cpp
+data=gentestpaged.txt			Test\test_paged.cpp
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -59,5 +59,5 @@
 data=EPOCROOT##Epoc32\Release\##KMAIN##\##BUILD##\minkda.ldd			\sys\bin\minkda.ldd
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged
 #endif
--- a/kernel/eka/rombuild/autotest_e32tests.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/autotest_e32tests.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -21,7 +21,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged.cpp
+data=gentestpaged.txt			Test\test_paged.cpp
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -43,5 +43,5 @@
 data=EPOCROOT##epoc32\rom\##VARIANT##\autoexec_e32test.bat				\autoexec.bat
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged
 #endif
--- a/kernel/eka/rombuild/autotest_f32tests.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/autotest_f32tests.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -20,7 +20,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged.cpp
+data=gentestpaged.txt			Test\test_paged.cpp
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -56,5 +56,5 @@
 data=EPOCROOT##epoc32\rom\##VARIANT##\autoexec_f32test.bat				\autoexec.bat
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged
 #endif
--- a/kernel/eka/rombuild/f32_perf_tests.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/f32_perf_tests.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -34,7 +34,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt           Test\test_paged.cpp
+data=gentestpaged.txt           Test\test_paged.cpp
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -60,7 +60,7 @@
 #endif
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt            Test\test_unpaged.cpp   unpaged
+data=gentestnonpaged.txt            Test\test_unpaged.cpp   unpaged
 #endif
 
 //-------------------------------------------------------------------------------------------------
--- a/kernel/eka/rombuild/f32_perf_tests_fat_exfat.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/f32_perf_tests_fat_exfat.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -36,7 +36,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt           Test\test_paged.cpp
+data=gentestpaged.txt           Test\test_paged.cpp
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -58,7 +58,7 @@
 #include <rom##E32PATH##\kernelhwsrv\kerneltest\f32test\rofs\##MAIN##test.iby>
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt            Test\test_unpaged.cpp   unpaged
+data=gentestnonpaged.txt            Test\test_unpaged.cpp   unpaged
 #endif
 
 //-------------------------------------------------------------------------------------------------
--- a/kernel/eka/rombuild/f32tests.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/f32tests.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -22,7 +22,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged.cpp
+data=gentestpaged.txt			Test\test_paged.cpp
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -48,7 +48,7 @@
 data=EPOCROOT##Epoc32\Release\##KMAIN##\##BUILD##\minkda.ldd			\sys\bin\minkda.ldd
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged
 #endif
 
 #if defined(SYMBIAN_INCLUDE_USB_OTG_HOST) && defined(WITH_MASS_STORAGE)
--- a/kernel/eka/rombuild/h4usbmmctest_load.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/h4usbmmctest_load.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -57,13 +57,13 @@
 
 #if defined(MULTIPLEROFS)
 // Built by rom.pl with type=nandtest_test
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\tests.rofs								\rofs1.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir.rofs								\rofs2.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\extension.rofs							\rofsextension3.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir1.rofs								\rofs4.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir2.rofs								\rofs5.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir3.rofs								\rofs6.img
+data=tests.rofs								\rofs1.img
+data=dir.rofs								\rofs2.img
+data=extension.rofs							\rofsextension3.img
+data=dir1.rofs								\rofs4.img
+data=dir2.rofs								\rofs5.img
+data=dir3.rofs								\rofs6.img
 data=\epoc32\rom\rofstest\fatimage.bin					\user3.img
 #else
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir.rofs								\rofs1.img
+data=dir.rofs								\rofs1.img
 #endif
--- a/kernel/eka/rombuild/h4usbmmctest_test.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/h4usbmmctest_test.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -29,7 +29,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged.cpp paging_unmovable
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -37,7 +37,7 @@
 #include <rom\hal\hal.iby>
 #include <rom\f32\f32.iby>
 
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
 
 // scripts
 #if !defined(MANUALROM)
@@ -46,7 +46,7 @@
 
 #ifdef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 
 #ifdef MULTIPLEROFS
@@ -71,7 +71,7 @@
 
 #ifndef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 #endif
 
--- a/kernel/eka/rombuild/h4usbstress.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/h4usbstress.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -21,7 +21,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged.cpp
+data=gentestpaged.txt			Test\test_paged.cpp
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -50,5 +50,5 @@
 data=EPOCROOT##epoc32\rom\##VARIANT##\autoexec.bat				\alltests.bat
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged
 #endif
--- a/kernel/eka/rombuild/mmctest_load.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/mmctest_load.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -58,13 +58,13 @@
 
 #if defined(MULTIPLEROFS)
 // Built by rom.pl with type=nandtest_test
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\tests.rofs								\rofs1.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir.rofs								\rofs2.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\extension.rofs							\rofsextension3.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir1.rofs								\rofs4.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir2.rofs								\rofs5.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir3.rofs								\rofs6.img
-data=\epoc32\rom\rofstest\fatimage.bin					\user3.img
+data=tests.rofs								\rofs1.img
+data=dir.rofs								\rofs2.img
+data=extension.rofs							\rofsextension3.img
+data=dir1.rofs								\rofs4.img
+data=dir2.rofs								\rofs5.img
+data=dir3.rofs								\rofs6.img
+data=\epoc32\rom\rofstest\fatimage.bin		\user3.img
 #else
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir.rofs								\rofs1.img
+data=dir.rofs								\rofs1.img
 #endif
--- a/kernel/eka/rombuild/mmctest_test.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/mmctest_test.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -31,7 +31,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged.cpp paging_unmovable
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -62,7 +62,7 @@
 
 #endif // #ifndef EXCLUDE_TESTS
 
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
 
 // scripts
 #if !defined(MANUALROM)
@@ -95,7 +95,7 @@
 
 #ifdef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 
 #ifdef MULTIPLEROFS
@@ -126,7 +126,7 @@
 
 #ifndef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 #endif
 
--- a/kernel/eka/rombuild/mmctest_test_e32tests.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/mmctest_test_e32tests.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -36,7 +36,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged.cpp paging_unmovable
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -56,7 +56,7 @@
 data=EPOCROOT##epoc32\release\##MAIN##\##BUILD##\t_ldrtst.exe			sys\bin\t_ldrtst.exe
 
 
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
 
 // scripts
 #if !defined(MANUALROM)
@@ -73,7 +73,7 @@
 
 #ifdef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 
 rofsname = dir.rofs
@@ -100,7 +100,7 @@
 
 #ifndef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 #endif
 
--- a/kernel/eka/rombuild/mmctest_test_f32tests.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/mmctest_test_f32tests.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -36,7 +36,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged.cpp paging_unmovable
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -59,7 +59,7 @@
 #include <rom##E32PATH##\kernelhwsrv\kerneltest\f32test\shostmassstorage\##MAIN##test.iby>
 #endif
 
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
 
 // scripts
 #if !defined(MANUALROM)
@@ -76,7 +76,7 @@
 
 #ifdef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 
 rofsname = dir.rofs
@@ -106,7 +106,7 @@
 
 #ifndef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 #endif
 
--- a/kernel/eka/rombuild/nandtest_load.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/nandtest_load.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -70,18 +70,17 @@
 
 #if defined(MULTIPLEROFS)
 // Built by rom.pl with type=nandtest_test
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\tests.rofs								\rofs1.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir.rofs								\rofs2.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\extension.rofs							\rofsextension3.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir1.rofs								\rofs4.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir2.rofs								\rofs5.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir3.rofs								\rofs6.img
+data=tests.rofs								\rofs1.img
+data=dir.rofs								\rofs2.img
+data=extension.rofs							\rofsextension3.img
+data=dir1.rofs								\rofs4.img
+data=dir2.rofs								\rofs5.img
+data=dir3.rofs								\rofs6.img
 data=\epoc32\rom\rofstest\fatimage.bin		\user3.img
 #else
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\dir.rofs								\rofs1.img
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\extension.rofs							\rofsextension2.img
+data=dir.rofs								\rofs1.img
+data=extension.rofs							\rofsextension2.img
 #endif
 
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\smr1.img								\smr1.img
+data=smr1.img								\smr1.img
 data=\epoc32\data\smr_part_102400.img		\smr2.img
-
--- a/kernel/eka/rombuild/nandtest_test.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/nandtest_test.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -40,7 +40,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged.cpp paging_unmovable
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -70,7 +70,7 @@
 data=EPOCROOT##epoc32\release\##MAIN##\##BUILD##\t_ldrtst.exe			sys\bin\t_ldrtst.exe
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
 #endif
 
 #endif // #ifndef EXCLUDE_TESTS
@@ -109,7 +109,7 @@
 
 #ifdef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 
 #ifdef MULTIPLEROFS
@@ -149,7 +149,7 @@
 
 #ifndef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 #endif
 
--- a/kernel/eka/rombuild/nandtest_test_e32tests.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/nandtest_test_e32tests.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -35,7 +35,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged.cpp paging_unmovable
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -63,7 +63,7 @@
 data=EPOCROOT##epoc32\release\##MAIN##\##BUILD##\t_ldrtst.exe			sys\bin\t_ldrtst.exe
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
 #endif
 
 // scripts
@@ -87,7 +87,7 @@
 
 #ifdef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 
 #ifdef MULTIPLEROFS
@@ -123,7 +123,7 @@
 
 #ifndef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 #endif
 
--- a/kernel/eka/rombuild/nandtest_test_f32tests.oby	Wed Sep 22 10:53:45 2010 +0100
+++ b/kernel/eka/rombuild/nandtest_test_f32tests.oby	Mon Sep 27 10:52:00 2010 +0100
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* Copyright (c) 2009-2010 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"
@@ -34,7 +34,7 @@
 files=
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged.cpp paging_unmovable
 #endif
 
 #include <rom\##VARIANT##\kernel.iby>
@@ -68,7 +68,7 @@
 #endif
 
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
+data=gentestpaged.txt			Test\test_paged1.cpp paging_unmovable
 #endif
 
 // scripts
@@ -92,7 +92,7 @@
 
 #ifdef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 
 #ifdef MULTIPLEROFS
@@ -129,7 +129,7 @@
 
 #ifndef WITH_COMP
 #ifdef PAGED_ROM
-data=##BASEPATH##kernelhwsrv\kernel\eka\rombuild\gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
+data=gentestnonpaged.txt			Test\test_unpaged.cpp	unpaged paging_unmovable
 #endif
 #endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/active/t_schedrace.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -0,0 +1,381 @@
+// Copyright (c) 2010 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:
+// e32test\active\t_schedrace.cpp
+// Overview:
+// Test for race conditions in emulator scheduler
+// API Information:
+// RMessage2, RMessagePtr2, RSessionBase, CSession2, CServer2, CPeriodic
+// Details:
+// - The client and server shuttle messages back and forth with variable timing
+// - The client also has a periodic timer, which fires at a random phase relative to the IPC
+// - The client should have higher priority than the server
+// - The race may occur when the timer interrupt preempts kernel code and disables interrupts
+// - The "preempted" code nonetheless runs and sees the "impossible" disabled interrupts
+// - The result is a precondition failure at a random point
+// Platforms/Drives/Compatibility:
+// Will run on all platforms, but precondition failure is expected only on the UDEB emulator.
+// Assumptions/Requirement/Pre-requisites:
+// Failures and causes:
+// Base Port information:
+
+#define	__E32TEST_EXTENSION__
+
+#include <e32std.h>
+#include <e32std_private.h>
+#include <e32math.h>
+#include <e32panic.h>
+#include <e32svr.h>
+#include <e32test.h>
+#include <e32ver.h>
+
+_LIT(KServerName, "CTestServer");
+const TVersion version(KE32MajorVersionNumber,
+					   KE32MinorVersionNumber,
+					   KE32BuildVersionNumber);
+
+// Globals for counting number of times each thread/object runs
+TInt nIdleCalls, nTimerCalls, nServerCalls;
+
+
+
+//
+// Server classes and code ...
+//
+class CTestServer : public CServer2
+	{
+public:
+	IMPORT_C CTestServer(RTest* aTest) : CServer2(EPriorityIdle), iTest(aTest) {};
+protected:
+	IMPORT_C CSession2* NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const;
+public:
+	RTest* iTest;
+	};
+
+class CTestSession : public CSession2
+	{
+public:
+	IMPORT_C void ServiceL(const RMessage2& aMessage);
+	enum Action
+		{
+		EStop = 0,
+		EDelay
+		};
+public:
+	RTest* iTest;
+	};
+
+//
+// CTestServer functions
+//
+EXPORT_C CSession2* CTestServer::NewSessionL(const TVersion& aVersion, const RMessage2& /*aMessage*/) const
+	{
+	if (User::QueryVersionSupported(version, aVersion) == EFalse)
+		User::Leave(KErrNotSupported);
+
+	CTestSession* newCTestSession = new CTestSession;
+	if (newCTestSession == NULL)
+		User::Leave(KErrNoMemory);
+	newCTestSession->iTest = iTest;
+
+	return newCTestSession;
+	}
+
+//
+// CTestSession functions
+//
+EXPORT_C void CTestSession::ServiceL(const RMessage2& aMessage)
+	{
+	if ((++nServerCalls & 0x03ff) == 10000)		// never true, to suppress message
+		iTest->Printf(_L("S:calls: I=%-7d  S=%-7d  T=%-7d  D=%-7d\n"),
+				nIdleCalls, nServerCalls, nTimerCalls, aMessage.Int0());
+	TInt r = KErrNone;
+	TInt i = 0;
+
+	switch (aMessage.Function())
+		{
+	case EStop:
+		CActiveScheduler::Stop();
+		break;
+
+	case EDelay:
+		// Spin a bit before replying
+		// The compiler can't optimise this away because 'i' is used below ...
+		for (i = 0; i < aMessage.Int0(); ++i)
+			;
+		break;
+
+	default:
+		r = KErrNotSupported;
+		break;
+		}
+
+	if (i != -1)								// always true :)
+		aMessage.Complete(r);
+	}
+
+//
+// Thread to run the server code
+//
+TInt ServerThread(TAny*)
+	{
+	RTest test(_L("T_SCHEDRACE server"));
+	test.Title();
+
+// UserSvr::FsRegisterThread();
+
+	test.Start(_L("Create and install ActiveScheduler"));
+	CActiveScheduler* pScheduler = new CActiveScheduler;
+	test_NotNull(pScheduler);
+	CActiveScheduler::Install(pScheduler);
+
+	test.Next(_L("Creating and starting Server"));
+	CTestServer* pServer = new CTestServer(&test);
+	test_NotNull(pServer);
+	test_KErrNone(pServer->Start(KServerName));		// Starting a CServer2 also Adds it to the ActiveScheduler
+
+	test.Next(_L("Rendezvous with main thread, then Start ActiveScheduler"));
+	RThread self;
+	self.Rendezvous(KErrNone);
+	test.Printf(_L("        There might be something going on beneath this window\n"));
+	CActiveScheduler::Start();
+
+	// This code is not reached until the active scheduler exits.
+	test.Next(_L("Destroy Server and ActiveScheduler"));
+	delete pServer;
+	delete pScheduler;
+	test.Close();
+	return (KErrNone);
+	}
+
+
+
+//
+// Client classes and code ...
+//
+class RTestSession : public RSessionBase
+	{
+	public:
+		RTestSession(RTest* aTest, TInt aTicks) : iTest(aTest), iMax(aTicks)
+			{
+			iDelay = iMax;
+			iDelta = -1;
+			};
+		TInt Connect(const TDesC& aServer, int aSlots)
+			{
+			return RSessionBase::CreateSession(aServer, version, aSlots);
+			};
+		TInt SendBlind(TInt aFunction, const TIpcArgs& aArgs) const
+			{
+			return RSessionBase::Send(aFunction, aArgs);
+			};
+		TInt SendSync(TInt aFunction, const TIpcArgs& aArgs) const
+			{
+			return RSessionBase::SendReceive(aFunction, aArgs);
+			};
+		void SendAsync(TInt aFunction, const TIpcArgs& aArgs, TRequestStatus& aStatus) const
+			{
+			RSessionBase::SendReceive(aFunction, aArgs, aStatus);
+			};
+	public:
+		RTest* iTest;
+		TInt iMax;
+		TInt iDelay;
+		TInt iDelta;
+	};
+
+RTestSession* TheSession;
+
+class CIdler : public CIdle
+	{
+	public:
+		CIdler() : CIdle(EPriorityIdle)
+			{
+			CActiveScheduler::Add(this);
+			};
+		void Callback();
+	};
+
+void CIdler::Callback()
+	{
+	if ((++nIdleCalls & 0x03ff) == 10000)		// never true, to suppress message
+		TheSession->iTest->Printf(_L("I:calls: I=%-7d  S=%-7d  T=%-7d  D=%-7d\n"),
+						nIdleCalls, nServerCalls, nTimerCalls, TheSession->iDelay);
+	// TInt delay = Math::Random() & 0xffff;					// up to ~64ms
+	TheSession->SendBlind(CTestSession::EDelay, TIpcArgs(TheSession->iDelay));
+	TheSession->SendAsync(CTestSession::EDelay, TIpcArgs(0), iStatus);
+	SetActive();
+	}
+
+//
+// CIdler callback wrapper
+//
+TInt IdleCallback(TAny* aPtr)
+	{
+	((CIdler*)aPtr)->Callback();
+	return EFalse;
+	}
+
+//
+// CPeriodic callback
+//
+TInt TimerCallback(TAny*)
+	{
+	if ((++nTimerCalls & 0x003f) == 1)			// true in one out of 64 cycles
+		TheSession->iTest->Printf(_L("T:calls: I=%-7d  S=%-7d  T=%-7d  D=%-7d\n"),
+						nIdleCalls, nServerCalls, nTimerCalls, TheSession->iDelay);
+	if (TheSession->iDelay >= TheSession->iMax)
+		TheSession->iDelta = -1;
+//	if (TheSession->iDelay < 1)
+//		TheSession->iDelta = 1;
+	TheSession->iDelay += TheSession->iDelta;
+	if (TheSession->iDelay < 0)
+		CActiveScheduler::Stop();
+	return ETrue;
+	}
+
+//
+// Thread to run the client code
+//
+TInt ClientThread(TAny*)
+	{
+	RTest test(_L("T_SCHEDRACE client"));
+	test.Title();
+
+// UserSvr::FsRegisterThread();
+
+	test.Start(_L("Create Session"));
+	TheSession = new RTestSession(&test, 5*60*64);	// will run for 5 minutes
+	test_NotNull(TheSession);
+	test_KErrNone(TheSession->Connect(KServerName, 2));
+
+	test.Start(_L("Create and install ActiveScheduler"));
+	CActiveScheduler* pScheduler = new CActiveScheduler;
+	test_NotNull(pScheduler);
+	CActiveScheduler::Install(pScheduler);
+
+	test.Next(_L("Create timer and idle task"));
+	CPeriodic* pTimer = CPeriodic::New(CActive::EPriorityStandard);
+	test_NotNull(pTimer);
+	CIdler* pIdler = new CIdler();
+	test_NotNull(pIdler);
+
+	test.Next(_L("Rendezvous with main thread"));
+	RThread self;
+	self.Rendezvous(KErrNone);
+
+	test.Next(_L("Start idle task, timer, and active scheduler"));
+	pIdler->Start(TCallBack(IdleCallback, pIdler));
+	pTimer->Start(1000000, 1000, TCallBack(TimerCallback, pTimer));
+	test.Printf(_L("        There might be something going on beneath this window\n"));
+	CActiveScheduler::Start();
+
+	// This code is not reached until the active scheduler exits.
+	TheSession->SendSync(CTestSession::EStop, TIpcArgs());
+	TheSession->Close();
+	test.Next(_L("Destroy Idle task, Timer, and ActiveScheduler"));
+	delete pIdler;
+	delete pTimer;
+	delete pScheduler;
+	test.Close();
+	return (KErrNone);
+	}
+
+
+//
+// Main program ...
+//
+GLDEF_C TInt E32Main()
+	{
+	RTest test(_L("Main T_SCHEDRACE test"));
+	test.Title();
+
+	test.Start(_L("Create server and client threads"));
+	const TInt KHeapMinSize = 0x1000;
+	const TInt KHeapMaxSize = 0x1000;
+	RThread serverThread, clientThread;
+	test_KErrNone(serverThread.Create(_L("Server Thread"), ServerThread, KDefaultStackSize, KHeapMinSize, KHeapMaxSize, NULL));
+	test_KErrNone(clientThread.Create(_L("Client Thread"), ClientThread, KDefaultStackSize, KHeapMinSize, KHeapMaxSize, NULL));
+
+	TRequestStatus serverStat, clientStat;
+	serverThread.Rendezvous(serverStat);
+	clientThread.Rendezvous(clientStat);
+	serverThread.SetPriority(EPriorityMuchLess);
+	clientThread.SetPriority(EPriorityMore);
+
+	test.Next(_L("Start the threads"));
+	serverThread.Resume();
+	User::WaitForRequest(serverStat);
+	test_KErrNone(serverStat.Int());
+	clientThread.Resume();
+	User::WaitForRequest(clientStat);
+	test_KErrNone(clientStat.Int());
+
+	test.Next(_L("Wait for the threads to stop"));
+	serverThread.Logon(serverStat);
+	clientThread.Logon(clientStat);
+	User::WaitForRequest(clientStat);
+	User::WaitForRequest(serverStat);
+
+	switch (clientThread.ExitType())
+		{
+	case EExitKill:
+		test.Printf(_L("  Client thread killed\n"));
+		break;
+
+	case EExitTerminate:
+		test.Printf(_L("!!Client thread terminated:"));
+		test.Panic(clientThread.ExitCategory(), clientThread.ExitReason());
+		break;
+
+	case EExitPanic:
+		test.Panic(_L("!!Client thread panicked:"));
+		test.Panic(clientThread.ExitCategory(), clientThread.ExitReason());
+		break;
+
+	default:
+		test.Panic(_L("!!Client thread did something bizarre"), clientThread.ExitReason());
+		break;
+		}
+
+	switch (serverThread.ExitType())
+		{
+	case EExitKill:
+		test.Printf(_L("  Server thread killed\n"));
+		break;
+
+	case EExitTerminate:
+		test.Printf(_L("!!Server thread terminated:"));
+		test.Panic(serverThread.ExitCategory(), serverThread.ExitReason());
+		break;
+
+	case EExitPanic:
+		//
+		// To catch a panic put a breakpoint in User::Panic() (in UCDT\UC_UNC.CPP).
+		//
+		test.Printf(_L("!!Server thread panicked:"));
+		test.Panic(serverThread.ExitCategory(), serverThread.ExitReason());
+		break;
+
+	default:
+		test.Panic(_L("!!Server thread did something bizarre"), serverThread.ExitReason());
+		break;
+		}
+
+	test.Next(_L("Close the threads"));
+	CLOSE_AND_WAIT(serverThread);
+	CLOSE_AND_WAIT(clientThread);
+	test.End();
+	return (KErrNone);
+	}
+
--- a/kerneltest/e32test/device/t_usbcsc.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/kerneltest/e32test/device/t_usbcsc.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -1312,8 +1312,8 @@
 				if (iTransfer->iFlags&KUsbcScStateChange)
 					{
 					TInt s = *iTransfer->iData.i;
-					test.Printf(_L("STATE CHANGE! %d : %S \n"),s,((s<0) || (s>7))?KStates[8]:KStates[s]);
-					OstTraceExt2(TRACE_NORMAL, TBUFFER_PROCESSDATA_DUP05, "STATE CHANGE! %d : %S \n",s,((s<0) || (s>7))?(*KStates[8]):(*KStates[s]));
+					test.Printf(_L("STATE CHANGE! %d : %S \n"),s,((s<0) || (s>7))?KStates[7]:KStates[s]);
+					OstTraceExt2(TRACE_NORMAL, TBUFFER_PROCESSDATA_DUP05, "STATE CHANGE! %d : %S \n",s,((s<0) || (s>7))?(*KStates[7]):(*KStates[s]));
 					}
 				else
 					{
@@ -1676,7 +1676,10 @@
 	TInt r;
 	TAltSetConfig *altSetConfig = new TAltSetConfig;
 	TInt altSetNo = 0;
-	__KHEAP_MARK;
+/*	because the kernel heap test is still failed in base team, it's caused by the display driver. So we 
+	remove the kernal heap check now. Once the error is fixed by base team, we can add it again.
+*/	
+//	__KHEAP_MARK;  
 	//1 - This test is to see if chunk is populated correctly (Default Setting), - It is 
 	//2 - Test Release Interface
 	//3 - Test Set and Release Interface after Realize Interface 
@@ -1689,13 +1692,15 @@
 	r = SettingOne(++altSetNo);
 	test_KErrNone(r);		
 	
-	test.Printf(_L("Release Interface %d\n"), --altSetNo);
-	OstTrace1(TRACE_NORMAL, TESTSETINTERFACE_TESTSETINTERFACE, "Release Interface %d\n", --altSetNo);
+	--altSetNo;
+	test.Printf(_L("Release Interface %d\n"), altSetNo);
+	OstTrace1(TRACE_NORMAL, TESTSETINTERFACE_TESTSETINTERFACE, "Release Interface %d\n", altSetNo);
 	r = gPort.ReleaseInterface(altSetNo);
 	test_Compare(r, !=, KErrNone);				
 
-	test.Printf(_L("Release Interface %d\n"), ++altSetNo);
-	OstTrace1(TRACE_NORMAL, TESTSETINTERFACE_TESTSETINTERFACE_DUP01, "Release Interface %d\n", ++altSetNo);
+	++altSetNo;
+	test.Printf(_L("Release Interface %d\n"), altSetNo);
+	OstTrace1(TRACE_NORMAL, TESTSETINTERFACE_TESTSETINTERFACE_DUP01, "Release Interface %d\n", altSetNo);
 	r = gPort.ReleaseInterface(altSetNo);					
 	test_KErrNone(r);
 	
@@ -1845,9 +1850,9 @@
 	CloseChannel();
 	UnloadDriver();			
 	UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, (TAny*)5000, 0);
-	__KHEAP_MARKEND;
+//	__KHEAP_MARKEND;
 	test.Next(_L("Test Release Interface, Release all interfaces one by one \n")); 
-	__KHEAP_MARK;
+//	__KHEAP_MARK;
 	LoadDriver();
 	OpenChannel();
 
@@ -1868,7 +1873,7 @@
 	CloseChannel();
 	UnloadDriver();			
 	UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, (TAny*)5000, 0);
-	__KHEAP_MARKEND;
+//	__KHEAP_MARKEND;
 	delete altSetConfig;	
 	test.End();
 	}
@@ -3640,17 +3645,26 @@
 				break;
 
 			case '3':	
-				//case 3: Write maxpacketsize (64 bytes) of data to USBIO demo app, queue remianing data in buffer (full buffer length-maxpacket size), wait for results: Total data written- 1xBuffersize
-				WriteDataToBuffer(buffer,64,aWriteBuf);
+				//case 3: Write maxpacketsize of data to USBIO demo app, queue remianing data in buffer (full buffer length-maxpacket size), wait for results: Total data written- 1xBuffersize
+			    TUint maxPacketSize;
+			    if (gSupportsHighSpeed)
+			        {
+			        maxPacketSize = KUsbEpSize512;
+			        }
+			    else
+			        {
+			        maxPacketSize = KUsbEpSize64;
+			        }
+			    WriteDataToBuffer(buffer,maxPacketSize,aWriteBuf);
 				test.Printf(_L("Data ready to be written out, Start the write mode on USBIO demo application and press a key when ready to proceed\n"));
 				OstTrace0(TRACE_NORMAL, BILWRITE_BILWRITE_DUP09, "Data ready to be written out, Start the write mode on USBIO demo application and press a key when ready to proceed\n");
 				test.Getch();
 
-				ret = epBuf.WriteBuffer(buffer,64,EFalse,status1);
+				ret = epBuf.WriteBuffer(buffer,maxPacketSize,EFalse,status1);
 				test_KErrNone(ret);
 
-				WriteDataToBuffer((TUint8*)buffer+64,length-64,aWriteBuf);
-				ret = epBuf.WriteBuffer((TUint8*)buffer+64,length-64,ETrue,status2);
+				WriteDataToBuffer((TUint8*)buffer+maxPacketSize,length-maxPacketSize,aWriteBuf);  
+				ret = epBuf.WriteBuffer((TUint8*)buffer+maxPacketSize,length-maxPacketSize,ETrue,status2);
 				test_KErrNone(ret);
 
 				User::WaitForRequest(status1);
@@ -3945,8 +3959,8 @@
 			else if (ret==TEndpointBuffer::KStateChange)
 				{
 				TInt state = *((TInt*) readBuf);
-				test.Printf(_L("Status Change:! %d : %S \n"),state,((state<0) || (state>7))?KStates[8]:KStates[state]);
-				OstTraceExt2(TRACE_NORMAL, TESTBILEP0_TESTBILEP0_DUP03, "Status Change:! %d : %S \n",state,((state<0) || (state>7))?*KStates[8]:*KStates[state]);
+				test.Printf(_L("Status Change:! %d : %S \n"),state,((state<0) || (state>7))?KStates[7]:KStates[state]);
+				OstTraceExt2(TRACE_NORMAL, TESTBILEP0_TESTBILEP0_DUP03, "Status Change:! %d : %S \n",state,((state<0) || (state>7))?*KStates[7]:*KStates[state]);
 				test_Equal(aSize, 4);
 				goodStateChange++;
 				}
--- a/kerneltest/e32test/group/bld.inf	Wed Sep 22 10:53:45 2010 +0100
+++ b/kerneltest/e32test/group/bld.inf	Mon Sep 27 10:52:00 2010 +0100
@@ -282,6 +282,7 @@
 t_dtim      
 t_idle      
 t_messge    
+t_schedrace
 
 // /E32TEST/BENCH tests
 #ifdef GENERIC_MARM
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/group/t_schedrace.mmp	Mon Sep 27 10:52:00 2010 +0100
@@ -0,0 +1,30 @@
+// Copyright (c) 2010 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:
+// e32test/group/t_schedrace.mmp
+// 
+//
+
+TARGET         t_schedrace.exe        
+TARGETTYPE     EXE
+SOURCEPATH	../active
+SOURCE         t_schedrace.cpp
+LIBRARY        euser.lib
+OS_LAYER_SYSTEMINCLUDE_SYMBIAN
+
+
+capability		all
+
+VENDORID 0x70000001
+
+SMPSAFE
--- a/kerneltest/e32test/group/t_usb_device.mmp	Wed Sep 22 10:53:45 2010 +0100
+++ b/kerneltest/e32test/group/t_usb_device.mmp	Mon Sep 27 10:52:00 2010 +0100
@@ -51,6 +51,9 @@
 // 0x101fe1db to pretend to be USB Manager (needed for the OTG drivers)
 UID 0x0 0x101fe1db
 
+// stack size 32KB
+EPOCSTACKSIZE 0x8000
+
 // Larger user heap than default: maximum = 16MB
 EPOCHEAPSIZE  0x1000 0x01000000
 
--- a/kerneltest/e32test/group/t_usb_scdevice.mmp	Wed Sep 22 10:53:45 2010 +0100
+++ b/kerneltest/e32test/group/t_usb_scdevice.mmp	Mon Sep 27 10:52:00 2010 +0100
@@ -56,7 +56,8 @@
 
 CAPABILITY    ALL
 
-
+// stack size 32KB
+EPOCSTACKSIZE 0x8000
 // Larger user heap than default: maximum = 16MB
 EPOCHEAPSIZE  0x1000 0x01000000
 
--- a/kerneltest/e32test/traces_t_usbcsc/fixed_id.definitions	Wed Sep 22 10:53:45 2010 +0100
+++ b/kerneltest/e32test/traces_t_usbcsc/fixed_id.definitions	Mon Sep 27 10:52:00 2010 +0100
@@ -207,6 +207,8 @@
 [TRACE]TRACE_NORMAL[0x86]_TESTCANCEL_TESTCANCEL_DUP03=0x54
 [TRACE]TRACE_NORMAL[0x86]_TESTDEVICEQUALIFIERDESCRIPTOR_TESTDEVICEQUALIFIERDESCRIPTOR=0x7c
 [TRACE]TRACE_NORMAL[0x86]_TESTENDPOINTSTALLSTATUS_TESTENDPOINTSTALLSTATUS=0x93
+[TRACE]TRACE_NORMAL[0x86]_TESTENDPOINTSTALLSTATUS_TESTENDPOINTSTALLSTATUS_DUP01=0xf2
+[TRACE]TRACE_NORMAL[0x86]_TESTENDPOINTSTALLSTATUS_TESTENDPOINTSTALLSTATUS_DUP02=0xf3
 [TRACE]TRACE_NORMAL[0x86]_TESTENDPOINTSTATUSNOTIFY_TESTENDPOINTSTATUSNOTIFY=0x94
 [TRACE]TRACE_NORMAL[0x86]_TESTENDPOINTSTATUSNOTIFY_TESTENDPOINTSTATUSNOTIFY_DUP01=0x95
 [TRACE]TRACE_NORMAL[0x86]_TESTEXTENDEDENDPOINTDESCRIPTOR_TESTEXTENDEDENDPOINTDESCRIPTOR=0x7f
--- a/kerneltest/e32test/usb/t_usb_device/src/activecontrol.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/kerneltest/e32test/usb/t_usb_device/src/activecontrol.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -1447,6 +1447,11 @@
 					SetupDescriptors(iLddPtr, &iPort[0],value);
 					StartMassStorage(&iPort[0]);
 
+#ifdef USB_SC
+					r = iPort[0].OpenEndpoint(iEp0Buf,0);
+					test_KErrNone(r);
+#endif
+
 					OpenStackIfOtg();
 					test.Next (_L("Enumeration..."));
 					r = ReEnumerate();
--- a/kerneltest/f32test/plugins/version_1/virus/t_vshook.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/kerneltest/f32test/plugins/version_1/virus/t_vshook.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -150,27 +150,26 @@
 		{
 		ptr.Set(defBuf->Des());
 		ptr.Set(&ptr[bytesParsed], fileSize-bytesParsed, fileSize-bytesParsed);
-		stringBeginPos = ptr.MatchF(_L8("startdef:*:enddef*"));
+		stringBeginPos = ptr.MatchF(_L8(":*;*"));
 
 		if (stringBeginPos < 0)
 			{
 			break;
 			}
 
-		stringBeginPos += 9; //stardef:
+		stringBeginPos += 1; //:
 		stringBeginPos += bytesParsed;
 		ptr.Set(defBuf->Des());
 		ptr.Set(&ptr[stringBeginPos], fileSize-stringBeginPos, fileSize-stringBeginPos);
-		stringEndPos = ptr.MatchF(_L8("*:enddef*"));
+		stringEndPos = ptr.MatchF(_L8("*;*"));
 
 		if (stringEndPos < 0)
 			{
 			break;
 			}
 
-		stringEndPos += 9; //stardef:
 		stringEndPos += bytesParsed;
-		stringLength = stringEndPos - stringBeginPos;
+		stringLength = stringEndPos - stringBeginPos + 1;
 
 		ptr.Set(defBuf->Des());
 		TRAP(r,signatureBuf = HBufC8::NewL(stringLength));
@@ -182,9 +181,9 @@
 		iKnownSignatures[iSignaturesLoaded] = signatureBuf;
 		iSignaturesLoaded++;
 
-		bytesParsed += 9; //startdef:
+		bytesParsed += 1; //:
 		bytesParsed += stringLength;
-		bytesParsed += 9; //:enddef\n
+		bytesParsed += 1; //;
 		}
 
 	//Cleanup
--- a/kerneltest/f32test/plugins/version_1/virus/virusdef.txt	Wed Sep 22 10:53:45 2010 +0100
+++ b/kerneltest/f32test/plugins/version_1/virus/virusdef.txt	Mon Sep 27 10:52:00 2010 +0100
@@ -1,7 +1,1 @@
-startdef:virus:enddef
-startdef:potato:enddef
-startdef:carrot:enddef
-startdef:infected:enddef
-startdef:blahblah:enddef
-startdef:fish:enddef
-
+:virus;:potato;:carrot;:infected;:blahblah;:fish;
\ No newline at end of file
--- a/kerneltest/f32test/server/t_fsrv.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/kerneltest/f32test/server/t_fsrv.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -210,6 +210,9 @@
  	test.Printf(_L("Dismounting the Remote Drive returned %d\n"),r);
  	
  	test_Value(r, r == KErrNone );
+	
+	r=TheFs.RemoveFileSystem(_L("DELAYFS"));
+   	test_KErrNone(r);
 	}
 
 
--- a/package_definition.xml	Wed Sep 22 10:53:45 2010 +0100
+++ b/package_definition.xml	Mon Sep 27 10:52:00 2010 +0100
@@ -15,6 +15,9 @@
       <component id="eka" name="Kernel Architecture" introduced="8.0" purpose="mandatory">
         <unit bldFile="kernel/eka" mrp="kernel/eka/base_e32.mrp"/>
       </component>
+      <component id="extension" name="Kernel Extension Makefiles" purpose="mandatory">
+        <unit bldFile="kernel/eka/extension"/>
+      </component>
     </collection>
     <collection id="kerneltest" name="Kernel Test" level="hw-if">
       <component id="e32utils" name="E32 Utilities" purpose="development">
--- a/userlibandfileserver/fileserver/group/release.txt	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/group/release.txt	Mon Sep 27 10:52:00 2010 +0100
@@ -1,3 +1,19 @@
+Version 2.00.4003
+=================
+(Made by vfebvre 21/09/2010)
+
+1.	paconway
+	1.	ou1cimx1#581599 [MCL][BRIDGE] F32tests T_VIRUS fails
+
+
+Version 2.00.4002
+=================
+(Made by vfebvre 20/09/2010)
+
+1.	migubarr
+	1.	ou1cimx1#558675 Inefficiencies in File Server session disconnection
+
+
 Version 2.00.4001
 =================
 (Made by vfebvre 14/09/2010)
--- a/userlibandfileserver/fileserver/inc/f32fsys.h	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/inc/f32fsys.h	Mon Sep 27 10:52:00 2010 +0100
@@ -251,6 +251,7 @@
 	IMPORT_C TName Name() const;
 	IMPORT_C virtual TBool IsCorrectThread();
 	inline CFsObjectCon* Container() const;
+	inline TInt AccessCount() const;
 protected:
 	void DoClose();
 	TInt UniqueID() const;
@@ -2038,7 +2039,10 @@
 	void InitL();
 	inline CFileCB& File();
 
-	// For serialising async requests 
+	// override CFsDispatchObject::Close() so that we can flush dirty data
+	void Close();
+
+	// For serialising aync requests 
 	TBool RequestStart(CFsMessageRequest* aRequest);
 	void RequestEnd(CFsMessageRequest* aRequest);
 	TBool RequestInProgress() const;
--- a/userlibandfileserver/fileserver/inc/f32fsys.inl	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/inc/f32fsys.inl	Mon Sep 27 10:52:00 2010 +0100
@@ -1347,4 +1347,6 @@
 inline TInt CFsObject::Dec()
 	{ return __e32_atomic_tas_ord32(&iAccessCount, 1, -1, 0); }
 
+inline TInt CFsObject::AccessCount() const
+	{return iAccessCount;}
 
--- a/userlibandfileserver/fileserver/inc/f32ver.h	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/inc/f32ver.h	Mon Sep 27 10:52:00 2010 +0100
@@ -58,6 +58,6 @@
 
 @see TVersion
 */
-const TInt KF32BuildVersionNumber=4001;
+const TInt KF32BuildVersionNumber=4003;
 //
 #endif
--- a/userlibandfileserver/fileserver/sfile/sf_file.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_file.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -2772,6 +2772,24 @@
 	iFile->Close();
 	}
 
+void CFileShare::Close()
+	{
+	
+	// Flush the write cache before closing the file share
+	// NB If there is any dirty data, then a new request will be allocated which will increase
+	// the reference count on this file share, thus preventing it from being deleted untill all 
+	// data has been flushed
+	if (AccessCount() == 1)
+		{
+		CFileCache* fileCache = File().FileCache();
+		if (fileCache)
+			fileCache->FlushDirty();
+		}
+
+	CFsDispatchObject::Close();
+	}
+
+
 /**
 Check that the media is still mounted.
 
--- a/userlibandfileserver/fileserver/sfile/sf_func.h	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_func.h	Mon Sep 27 10:52:00 2010 +0100
@@ -729,13 +729,6 @@
 	static TInt Complete(CFsRequest* aRequest);
 	};
 
-class TFsCancelSession
-	{
-public:
-	static TInt Initialise(CFsRequest* aRequest);
-	static TInt DoRequestL(CFsRequest* aRequest);
-	};
-
 class TFsFlushDirtyData
 	{
 public:
--- a/userlibandfileserver/fileserver/sfile/sf_main.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_main.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -78,8 +78,7 @@
 	TInt fn = Message().Function();
 
 	// CServer2::DoConnectL() manipulates iSessionQ & so does CSession2::~CSession2().
-	// Unfortunately the session is deleted from a seperate thread (the disconnect 
-	// thread) so we need a lock to protect it.
+	// Unfortunately the session may be deleted from a drive thread so we need a lock to protect it.
 	if (fn == RMessage2::EConnect)
 		{
 		SessionQueueLockWait();		// lock
@@ -459,8 +458,6 @@
 	DisabledCapabilities=*(SCapabilitySet*)&caps;
 
 	FsThreadManager::SetMainThreadId();
-	r=FsThreadManager::CreateDisconnectThread();
-	__ASSERT_ALWAYS(r==KErrNone,Fault(EMainDisconnectThread));
 
 
 	//
--- a/userlibandfileserver/fileserver/sfile/sf_notify.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_notify.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -49,7 +49,7 @@
 //
 	{
 	__PRINT2(_L("CNotifyInfo::Complete 0x%x error=%d"),this,aError);
-	if (iType != EDismount || !iMessage.IsNull())	// Dismount notifiers may be completed but remain in the list
+	if (!iMessage.IsNull())				// Dismount notifiers may be completed but remain in the list
 		{											// until handled by the client or the session is closed.
 		iMessage.Complete(aError);
 		}
--- a/userlibandfileserver/fileserver/sfile/sf_ops.h	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_ops.h	Mon Sep 27 10:52:00 2010 +0100
@@ -25,150 +25,150 @@
 #define MSG3(aType) ((TUint32)(TFsPluginRequest::aType) << 24)  
 
 static const TOperation OperationArray[EMaxClientOperations]=
-	{/*		function					Flags					iInitialise									iPostInitialise						iDoRequestL									iMessageArguments*/
-		{	EFsAddFileSystem,			ESync,					&TFsAddFileSystem::Initialise,				NULL,								&TFsAddFileSystem::DoRequestL				},
-		{	EFsRemoveFileSystem,		ESync,					&TFsRemoveFileSystem::Initialise,			NULL,								&TFsRemoveFileSystem::DoRequestL			},
-		{	EFsMountFileSystem,			0,						&TFsMountFileSystem::Initialise,			NULL,								&TFsMountFileSystem::DoRequestL				},
-		{	EFsNotifyChange,			ESync,					&TFsNotifyChange::Initialise,				NULL,								&TFsNotifyChange::DoRequestL				},
-		{	EFsNotifyChangeCancel,		ESync,					&TFsNotifyChangeCancel::Initialise,			NULL,								&TFsNotifyChangeCancel::DoRequestL			},
-		{	EFsDriveList,				ESync,					&TFsDriveList::Initialise,					NULL,								&TFsDriveList::DoRequestL					},
-		{	EFsDrive,					ESync,					&TFsDrive::Initialise,						NULL,								&TFsDrive::DoRequestL						},
-		{	EFsVolume,					0,						&TFsVolume::Initialise,						NULL,								&TFsVolume::DoRequestL						, MSG0(EVolumeInfo)},
-		{	EFsSetVolume,				0,						&TFsSetVolume::Initialise,					NULL,								&TFsSetVolume::DoRequestL					},
-		{	EFsSubst,					ESync,					&TFsSubst::Initialise,						NULL,								&TFsSubst::DoRequestL						},
-		{	EFsSetSubst,				ESync | EParseSrc,		&TFsSetSubst::Initialise,					NULL,								&TFsSetSubst::DoRequestL					},
-		{	EFsRealName,				ESync | EParseSrc,		&TFsRealName::Initialise,					NULL,								&TFsRealName::DoRequestL					},
-		{	EFsDefaultPath,				ESync,					&TFsDefaultPath::Initialise,				NULL,								&TFsDefaultPath::DoRequestL					},
-		{	EFsSetDefaultPath,			ESync,					&TFsSetDefaultPath::Initialise,				NULL,								&TFsSetDefaultPath::DoRequestL				},
-		{	EFsSessionPath,				ESync,					&TFsSessionPath::Initialise,				NULL,								&TFsSessionPath::DoRequestL					},
-		{	EFsSetSessionPath,			ESync,					&TFsSetSessionPath::Initialise,				NULL,								&TFsSetSessionPath::DoRequestL				},
-		{	EFsMkDir,					EParseSrc,				&TFsMkDir::Initialise,						NULL,								&TFsMkDir::DoRequestL						, MSG0(EName) | MSG1(EMode)},
-		{	EFsRmDir,					EParseSrc,				&TFsRmDir::Initialise,						NULL,								&TFsRmDir::DoRequestL						, MSG0(EName)},
-		{	EFsParse,					ESync,					&TFsParse::Initialise,						NULL,								&TFsParse::DoRequestL						},
-		{	EFsDelete,					EParseSrc,				&TFsDelete::Initialise,						NULL,								&TFsDelete::DoRequestL						, MSG0(EName)},
-		{	EFsRename,					EParseDst | EParseSrc,	&TFsRename::Initialise,						NULL,								&TFsRename::DoRequestL						, MSG0(EName) | MSG1(ENewName)},
-		{	EFsReplace,					EParseDst | EParseSrc,	&TFsReplace::Initialise,					NULL,								&TFsReplace::DoRequestL						, MSG0(EName) | MSG1(ENewName)},
-		{	EFsEntry,					EParseSrc,				&TFsEntry::Initialise,						NULL,								&TFsEntry::DoRequestL						, MSG0(EName) | MSG1(EEntry)},
-		{	EFsSetEntry,				EParseSrc,				&TFsSetEntry::Initialise,					NULL,								&TFsSetEntry::DoRequestL					, MSG0(EName) | MSG1(ETime) | MSG2(ESetAtt) | MSG3(EClearAtt)},
-		{	EFsGetDriveName,			ESync,					&TFsGetDriveName::Initialise,				NULL,								&TFsGetDriveName::DoRequestL				},
-		{	EFsSetDriveName,			ESync,					&TFsSetDriveName::Initialise,				NULL,								&TFsSetDriveName::DoRequestL				},
-		{	EFsFormatSubClose,			ESync,					&TFsSubClose::Initialise,					NULL,								&TFsSubClose::DoRequestL					},
-		{	EFsDirSubClose,				ESync,					&TFsSubClose::Initialise,					NULL,								&TFsSubClose::DoRequestL					},
-		{	EFsFileSubClose,			EFileShare,				&TFsSubClose::Initialise,					NULL,								&TFsSubClose::DoRequestL					},
-		{	EFsRawSubClose,				ESync,					&TFsSubClose::Initialise,					NULL,								&TFsSubClose::DoRequestL					},
-		{	EFsFileOpen,				EParseSrc,				&TFsFileOpen::Initialise,					NULL,								&TFsFileOpen::DoRequestL					, MSG0(EName)     | MSG1(EMode)},
-		{	EFsFileCreate,				EParseSrc,				&TFsFileCreate::Initialise,					NULL,								&TFsFileCreate::DoRequestL					, MSG0(EName)     | MSG1(EMode)},
-		{	EFsFileReplace,				EParseSrc,				&TFsFileReplace::Initialise,				NULL,								&TFsFileReplace::DoRequestL					, MSG0(EName)     | MSG1(EMode)},
-		{	EFsFileTemp,				EParseSrc,				&TFsFileTemp::Initialise,					NULL,								&TFsFileTemp::DoRequestL					, MSG0(EName)     | MSG1(EMode)   | MSG2(ENewName)},
-		{	EFsFileRead,				EParseSrc | EFileShare,	&TFsFileRead::Initialise,					&TFsFileRead::PostInitialise,		&TFsFileRead::DoRequestL					, MSG0(EData)     | MSG1(ELength) | MSG2(EPosition) },
-		{	EFsFileWrite,				EParseSrc | EFileShare,	&TFsFileWrite::Initialise,					&TFsFileWrite::PostInitialise,		&TFsFileWrite::DoRequestL					, MSG0(EData)     | MSG1(ELength) | MSG2(EPosition) },
-		{	EFsFileLock,				EParseSrc | EFileShare,	&TFsFileLock::Initialise,					NULL,								&TFsFileLock::DoRequestL					, MSG0(EPosition) | MSG1(ELength)},
-		{	EFsFileUnLock,				EParseSrc | EFileShare,	&TFsFileUnlock::Initialise,					NULL,								&TFsFileUnlock::DoRequestL					, MSG0(EPosition) | MSG1(ELength)},
-		{	EFsFileSeek,				EParseSrc | EFileShare,	&TFsFileSeek::Initialise,					NULL,								&TFsFileSeek::DoRequestL					, MSG0(EPosition) | MSG1(EMode)   | MSG2(ENewPosition)},
-		{	EFsFileFlush,				EParseSrc | EFileShare,	&TFsFileFlush::Initialise,					NULL,								&TFsFileFlush::DoRequestL					},
-		{	EFsFileSize,				EParseSrc | EFileShare,	&TFsFileSize::Initialise,					NULL,								&TFsFileSize::DoRequestL					, MSG0(ESize)},
-		{	EFsFileSetSize,				EParseSrc | EFileShare,	&TFsFileSetSize::Initialise,				NULL,								&TFsFileSetSize::DoRequestL					, MSG0(ESize)},
-		{	EFsFileAtt,					EParseSrc | EFileShare,	&TFsFileAtt::Initialise,					NULL,								&TFsFileAtt::DoRequestL						, MSG0(EAtt)},
-		{	EFsFileSetAtt,				EParseSrc | EFileShare,	&TFsFileSetAtt::Initialise,					NULL,								&TFsFileSetAtt::DoRequestL					, MSG0(ESetAtt) | MSG1(EClearAtt)},
-		{	EFsFileModified,			EParseSrc | EFileShare,	&TFsFileModified::Initialise,				NULL,								&TFsFileModified::DoRequestL				, MSG0(ETime)},
-		{	EFsFileSetModified,			EParseSrc | EFileShare,	&TFsFileSetModified::Initialise,			NULL,								&TFsFileSetModified::DoRequestL				, MSG0(ETime)},
-		{	EFsFileSet,					EParseSrc | EFileShare,	&TFsFileSet::Initialise,					NULL,								&TFsFileSet::DoRequestL						, MSG0(ETime) | MSG1(ESetAtt) | MSG2(EClearAtt)},
-		{	EFsFileChangeMode,			EParseSrc | EFileShare,	&TFsFileChangeMode::Initialise,				NULL,								&TFsFileChangeMode::DoRequestL				, MSG0(EMode)},
-		{	EFsFileRename,				EParseDst | EParseSrc,	&TFsFileRename::Initialise,					NULL,								&TFsFileRename::DoRequestL					, MSG0(ENewName)},
-		{	EFsDirOpen,					EParseSrc,				&TFsDirOpen::Initialise,					NULL,								&TFsDirOpen::DoRequestL						, MSG0(EName) | MSG1(EAttMask) | MSG2(EUid)},
-		{	EFsDirReadOne,				0,						&TFsDirReadOne::Initialise,					NULL,								&TFsDirReadOne::DoRequestL					, MSG0(EEntry)},
-		{	EFsDirReadPacked,			0,						&TFsDirReadPacked::Initialise,				NULL,								&TFsDirReadPacked::DoRequestL				, MSG0(EEntryArray)},
-		{	EFsFormatOpen,				EParseSrc,				&TFsFormatOpen::Initialise,					NULL,								&TFsFormatOpen::DoRequestL					},
-		{	EFsFormatNext,				EParseSrc,				&TFsFormatNext::Initialise,					NULL,								&TFsFormatNext::DoRequestL					},
-		{	EFsRawDiskOpen,				0,						&TFsRawDiskOpen::Initialise,				NULL,								&TFsRawDiskOpen::DoRequestL					},
-		{	EFsRawDiskRead,				EParseSrc,				&TFsRawDiskRead::Initialise,				NULL,								&TFsRawDiskRead::DoRequestL					},
-		{	EFsRawDiskWrite,			EParseSrc,				&TFsRawDiskWrite::Initialise,				NULL,								&TFsRawDiskWrite::DoRequestL				},
-		{	EFsResourceCountMarkStart,	ESync,					&TFsResourceCountMarkStart::Initialise,		NULL,								&TFsResourceCountMarkStart::DoRequestL		},
-		{	EFsResourceCountMarkEnd,	ESync,					&TFsResourceCountMarkEnd::Initialise,		NULL,								&TFsResourceCountMarkEnd::DoRequestL		},
-		{	EFsResourceCount,			ESync,					&TFsResourceCount::Initialise,				NULL,								&TFsResourceCount::DoRequestL				},
-		{	EFsCheckDisk,				EParseSrc,				&TFsCheckDisk::Initialise,					NULL,								&TFsCheckDisk::DoRequestL					},
-		{	EFsGetShortName,			EParseSrc,				&TFsGetShortName::Initialise,				NULL,								&TFsGetShortName::DoRequestL				},
-		{	EFsGetLongName,				EParseSrc,				&TFsGetLongName::Initialise,				NULL,								&TFsGetLongName::DoRequestL					},
-		{	EFsIsFileOpen,				EParseSrc,				&TFsIsFileOpen::Initialise,					NULL,								&TFsIsFileOpen::DoRequestL					},
-		{	EFsListOpenFiles,			ESync,					&TFsListOpenFiles::Initialise,				NULL,								&TFsListOpenFiles::DoRequestL				},
-		{	EFsGetNotifyUser,			ESync,					&TFsGetNotifyUser::Initialise,				NULL,								&TFsGetNotifyUser::DoRequestL				},
-		{	EFsSetNotifyUser,			ESync,					&TFsSetNotifyUser::Initialise,				NULL,								&TFsSetNotifyUser::DoRequestL				},
-		{	EFsIsFileInRom,				EParseSrc,				&TFsIsFileInRom::Initialise,				NULL,								&TFsIsFileInRom::DoRequestL					},
-		{	EFsIsValidName,				ESync,					&TFsIsValidName::Initialise,				NULL,								&TFsIsValidName::DoRequestL					},
-		{	EFsDebugFunction,			ESync,					&TFsDebugFunc::Initialise,					NULL,								&TFsDebugFunc::DoRequestL					},
-		{	EFsReadFileSection,			EParseSrc,				&TFsReadFileSection::Initialise,			NULL,								&TFsReadFileSection::DoRequestL				, MSG0(EData) | MSG1(EName) | MSG2(EPosition) | MSG3(ELength)},
-		{	EFsNotifyChangeEx,			ESync | EParseSrc,		&TFsNotifyChangeEx::Initialise,				NULL,								&TFsNotifyChangeEx::DoRequestL				},
-		{	EFsNotifyChangeCancelEx,	ESync,					&TFsNotifyChangeCancelEx::Initialise,		NULL,								&TFsNotifyChangeCancelEx::DoRequestL		},
-		{	EFsDismountFileSystem,		0,						&TFsDismountFileSystem::Initialise,			NULL,								&TFsDismountFileSystem::DoRequestL			},
-		{	EFsFileSystemName,			ESync,					&TFsFileSystemName::Initialise,				NULL,								&TFsFileSystemName::DoRequestL				},
-		{	EFsScanDrive,				EParseSrc,				&TFsScanDrive::Initialise,					NULL,								&TFsScanDrive::DoRequestL					},
-		{	EFsControlIo,				0,						&TFsControlIo::Initialise,					NULL,								&TFsControlIo::DoRequestL					},
-		{	EFsLockDrive,				0,						&TFsLockDrive::Initialise,					NULL,								&TFsLockDrive::DoRequestL					},
-		{	EFsUnlockDrive,				0,						&TFsUnlockDrive::Initialise,				NULL,								&TFsUnlockDrive::DoRequestL					},
-		{	EFsClearPassword,			0,						&TFsClearPassword::Initialise,				NULL,								&TFsClearPassword::DoRequestL				},
-		{	EFsNotifyDiskSpace,			0,						&TFsNotifyDiskSpace::Initialise,			NULL,								&TFsNotifyDiskSpace::DoRequestL				},
-		{	EFsNotifyDiskSpaceCancel,	ESync,					&TFsNotifyDiskSpaceCancel::Initialise,		NULL,								&TFsNotifyDiskSpaceCancel::DoRequestL		},
-		{	EFsFileDrive,				EParseSrc | EFileShare,	&TFsFileDrive::Initialise,					NULL,								&TFsFileDrive::DoRequestL					},
-		{	EFsRemountDrive,			0,						&TFsRemountDrive::Initialise,				NULL,								&TFsRemountDrive::DoRequestL				},
-		{	EFsMountFileSystemScan,		0,						&TFsMountFileSystemScan::Initialise,		NULL,								&TFsMountFileSystemScan::DoRequestL			},
-		{	EFsSessionToPrivate,		ESync,					&TFsSessionToPrivate::Initialise,			NULL,								&TFsSessionToPrivate::DoRequestL			},
-		{	EFsPrivatePath,				ESync,					&TFsPrivatePath::Initialise,				NULL,								&TFsPrivatePath::DoRequestL					},
-		{	EFsCreatePrivatePath,		0,						&TFsCreatePrivatePath::Initialise,			NULL,								&TFsCreatePrivatePath::DoRequestL			},
-		{	EFsAddExtension,			ESync,					&TFsAddExtension::Initialise,				NULL,								&TFsAddExtension::DoRequestL				},
-		{	EFsMountExtension,			0,						&TFsMountExtension::Initialise,				NULL,								&TFsMountExtension::DoRequestL				},
-		{	EFsDismountExtension,		0,						&TFsDismountExtension::Initialise,			NULL,								&TFsDismountExtension::DoRequestL			},
-		{	EFsRemoveExtension,			ESync,					&TFsRemoveExtension::Initialise,			NULL,								&TFsRemoveExtension::DoRequestL				},
-		{	EFsExtensionName,			0,						&TFsExtensionName::Initialise,				NULL,								&TFsExtensionName::DoRequestL				},
-		{	EFsStartupInitComplete,		ESync,					&TFsStartupInitComplete::Initialise,		NULL,								&TFsStartupInitComplete::DoRequestL			},
-		{	EFsSetLocalDriveMapping,	ESync,					&TFsSetLocalDriveMapping::Initialise,		NULL,								&TFsSetLocalDriveMapping::DoRequestL		},
-		{	EFsFinaliseDrive,			0,						&TFsFinaliseDrive::Initialise,				NULL,								&TFsFinaliseDrive::DoRequestL				},
-		{	EFsFileDuplicate,			0 | EFileShare,			&TFsFileDuplicate::Initialise,				NULL,								&TFsFileDuplicate::DoRequestL				},	// Not done
-		{	EFsFileAdopt,				ESync,					&TFsFileAdopt::Initialise,					NULL,								&TFsFileAdopt::DoRequestL					},	// Not done
-		{	EFsSwapFileSystem,			ESync,					&TFsSwapFileSystem::Initialise,				NULL,								&TFsSwapFileSystem::DoRequestL				},
-		{	EFsErasePassword,			0,						&TFsErasePassword::Initialise,				NULL,								&TFsErasePassword::DoRequestL				},
-		{	EFsReserveDriveSpace,		0,						&TFsReserveDriveSpace::Initialise,			NULL,								&TFsReserveDriveSpace::DoRequestL			},
-		{	EFsGetReserveAccess,		ESync,  				&TFsGetReserveAccess::Initialise,			NULL,								&TFsGetReserveAccess::DoRequestL			},
-		{	EFsReleaseReserveAccess,	ESync,					&TFsReleaseReserveAccess::Initialise,		NULL,								&TFsReleaseReserveAccess::DoRequestL		},
-		{	EFsFileName,				ESync,					&TFsFileName::Initialise,					NULL,								&TFsFileName::DoRequestL					, MSG0(EName)},
-		{	EFsGetMediaSerialNumber,	0,					    &TFsGetMediaSerialNumber::Initialise,		NULL,								&TFsGetMediaSerialNumber::DoRequestL		},
-		{	EFsFileFullName,			ESync,					&TFsFileFullName::Initialise,				NULL,								&TFsFileFullName::DoRequestL				, MSG0(EName)},	// Wasn't in original list?
-		{	EFsAddPlugin,				ESync,					&TFsAddPlugin::Initialise,					NULL,								&TFsAddPlugin::DoRequestL					},
-		{	EFsRemovePlugin,			ESync,					&TFsRemovePlugin::Initialise,				NULL,								&TFsRemovePlugin::DoRequestL				},
-		{	EFsMountPlugin,				ESync,					&TFsMountPlugin::Initialise,				NULL,								&TFsMountPlugin::DoRequestL					},
-		{	EFsDismountPlugin,			0, /*PluginThrdContxt*/	&TFsDismountPlugin::Initialise,				NULL,								&TFsDismountPlugin::DoRequestL				},
-		{	EFsPluginName,				ESync,					&TFsPluginName::Initialise,					NULL,								&TFsPluginName::DoRequestL					},
-		{	EFsPluginOpen,				ESync | EParseSrc,		&TFsPluginOpen::Initialise,					NULL,								&TFsPluginOpen::DoRequestL					},
-		{	EFsPluginSubClose,			ESync,					&TFsSubClose::Initialise,					NULL,								&TFsSubClose::DoRequestL					},
-		{	EFsPluginDoRequest,			0,						&TFsPluginDoRequest::Initialise,			NULL,								&TFsPluginDoRequest::DoRequestL				},
-		{	EFsPluginDoControl,			0,						&TFsPluginDoControl::Initialise,			NULL,								&TFsPluginDoControl::DoRequestL				},
-		{	EFsPluginDoCancel,			0,						&TFsPluginDoCancel::Initialise,				NULL,								&TFsPluginDoCancel::DoRequestL				},
-		{	EFsNotifyDismount,			0,						&TFsNotifyDismount::Initialise,				NULL,								&TFsNotifyDismount::DoRequestL				},
-		{	EFsNotifyDismountCancel,	ESync,					&TFsNotifyDismountCancel::Initialise,		NULL,								&TFsNotifyDismountCancel::DoRequestL		},
-		{	EFsAllowDismount,			0,						&TFsAllowDismount::Initialise,				NULL,								&TFsAllowDismount::DoRequestL				},
-		{	EFsSetStartupConfiguration,	ESync,					&TFsSetStartupConfiguration::Initialise,	NULL,								&TFsSetStartupConfiguration::DoRequestL		},
-		{	EFsFileReadCancel,			ESync,					&TFsFileReadCancel::Initialise,				NULL,								&TFsFileReadCancel::DoRequestL				},
-		{	EFsAddCompositeMount,		ESync,					&TFsAddCompositeMount::Initialise,			NULL,								&TFsAddCompositeMount::DoRequestL			},
-		{	EFsSetSessionFlags,			ESync,					&TFsSetSessionFlags::Initialise,			NULL,								&TFsSetSessionFlags::DoRequestL				},
-		{	EFsSetSystemDrive,			ESync,					&TFsSetSystemDrive::Initialise,				NULL,								&TFsSetSystemDrive::DoRequestL				},
-		{	EFsBlockMap,				EParseSrc,				&TFsBlockMap::Initialise,					NULL,								&TFsBlockMap::DoRequestL					},
-		{	EFsUnclamp,					0,						&TFsUnclamp::Initialise,					NULL,								&TFsUnclamp::DoRequestL						},
-		{	EFsFileClamp,				EParseSrc,				&TFsFileClamp::Initialise,					NULL,								&TFsFileClamp::DoRequestL					},
-		{	EFsQueryVolumeInfoExt,		0,						&TFsQueryVolumeInfoExt::Initialise,			NULL,								&TFsQueryVolumeInfoExt::DoRequestL			},
-		{	EFsInitialisePropertiesFile,0,						&TFsInitialisePropertiesFile::Initialise,	NULL,								&TFsInitialisePropertiesFile::DoRequestL	},
-		{	EFsFileWriteDirty,			EFileShare,				NULL,										&TFsFileWriteDirty::PostInitialise,	&TFsFileWrite::DoRequestL					},
-		{	EFsSynchroniseDriveThread,	0,						&TFsSynchroniseDriveThread::Initialise,		NULL,								&TFsSynchroniseDriveThread::DoRequestL		},
-		{	EFsAddProxyDrive,			ESync,					&TFsAddProxyDrive::Initialise,				NULL,								&TFsAddProxyDrive::DoRequestL				},
-		{	EFsRemoveProxyDrive,		ESync,					&TFsRemoveProxyDrive::Initialise,			NULL,								&TFsRemoveProxyDrive::DoRequestL			},
-		{	EFsMountProxyDrive,			0,						&TFsMountProxyDrive::Initialise,			NULL,								&TFsMountProxyDrive::DoRequestL				},
-		{	EFsDismountProxyDrive,		0,						&TFsDismountProxyDrive::Initialise,			NULL,								&TFsDismountProxyDrive::DoRequestL			},
-		{	EFsNotificationOpen,		ESync,					&TFsNotificationOpen::Initialise,			NULL,								&TFsNotificationOpen::DoRequestL			},
-		{	EFsNotificationBuffer,		ESync,					&TFsNotificationBuffer::Initialise,			NULL,								&TFsNotificationBuffer::DoRequestL			},		
-		{	EFsNotificationRequest,		ESync,					&TFsNotificationRequest::Initialise,		NULL,								&TFsNotificationRequest::DoRequestL			},
-		{	EFsNotificationCancel,		ESync,					&TFsNotificationCancel::Initialise,			NULL,								&TFsNotificationCancel::DoRequestL			},
-		{	EFsNotificationSubClose,	ESync,					&TFsNotificationSubClose::Initialise,		NULL,								&TFsNotificationSubClose::DoRequestL		},
-		{	EFsNotificationAdd,			ESync,					&TFsNotificationAdd::Initialise,			NULL,								&TFsNotificationAdd::DoRequestL				},
-		{	EFsNotificationRemove,		ESync,					&TFsNotificationRemove::Initialise,			NULL,								&TFsNotificationRemove::DoRequestL			},
-		{	EFsLoadCodePage,			0,						&TFsLoadCodePage::Initialise,				NULL,								&TFsLoadCodePage::DoRequestL				},
+	{/*		function					Flags								iInitialise									iPostInitialise						iDoRequestL									iMessageArguments*/
+		{	EFsAddFileSystem,			ESync,								&TFsAddFileSystem::Initialise,				NULL,								&TFsAddFileSystem::DoRequestL				},
+		{	EFsRemoveFileSystem,		ESync,								&TFsRemoveFileSystem::Initialise,			NULL,								&TFsRemoveFileSystem::DoRequestL			},
+		{	EFsMountFileSystem,			0,									&TFsMountFileSystem::Initialise,			NULL,								&TFsMountFileSystem::DoRequestL				},
+		{	EFsNotifyChange,			ESync,								&TFsNotifyChange::Initialise,				NULL,								&TFsNotifyChange::DoRequestL				},
+		{	EFsNotifyChangeCancel,		ESync,								&TFsNotifyChangeCancel::Initialise,			NULL,								&TFsNotifyChangeCancel::DoRequestL			},
+		{	EFsDriveList,				ESync,								&TFsDriveList::Initialise,					NULL,								&TFsDriveList::DoRequestL					},
+		{	EFsDrive,					ESync,								&TFsDrive::Initialise,						NULL,								&TFsDrive::DoRequestL						},
+		{	EFsVolume,					0,									&TFsVolume::Initialise,						NULL,								&TFsVolume::DoRequestL						, MSG0(EVolumeInfo)},
+		{	EFsSetVolume,				0,									&TFsSetVolume::Initialise,					NULL,								&TFsSetVolume::DoRequestL					},
+		{	EFsSubst,					ESync,								&TFsSubst::Initialise,						NULL,								&TFsSubst::DoRequestL						},
+		{	EFsSetSubst,				ESync | EParseSrc,					&TFsSetSubst::Initialise,					NULL,								&TFsSetSubst::DoRequestL					},
+		{	EFsRealName,				ESync | EParseSrc,					&TFsRealName::Initialise,					NULL,								&TFsRealName::DoRequestL					},
+		{	EFsDefaultPath,				ESync,								&TFsDefaultPath::Initialise,				NULL,								&TFsDefaultPath::DoRequestL					},
+		{	EFsSetDefaultPath,			ESync,								&TFsSetDefaultPath::Initialise,				NULL,								&TFsSetDefaultPath::DoRequestL				},
+		{	EFsSessionPath,				ESync,								&TFsSessionPath::Initialise,				NULL,								&TFsSessionPath::DoRequestL					},
+		{	EFsSetSessionPath,			ESync,								&TFsSetSessionPath::Initialise,				NULL,								&TFsSetSessionPath::DoRequestL				},
+		{	EFsMkDir,					EParseSrc,							&TFsMkDir::Initialise,						NULL,								&TFsMkDir::DoRequestL						, MSG0(EName) | MSG1(EMode)},
+		{	EFsRmDir,					EParseSrc,							&TFsRmDir::Initialise,						NULL,								&TFsRmDir::DoRequestL						, MSG0(EName)},
+		{	EFsParse,					ESync,								&TFsParse::Initialise,						NULL,								&TFsParse::DoRequestL						},
+		{	EFsDelete,					EParseSrc,							&TFsDelete::Initialise,						NULL,								&TFsDelete::DoRequestL						, MSG0(EName)},
+		{	EFsRename,					EParseDst | EParseSrc,				&TFsRename::Initialise,						NULL,								&TFsRename::DoRequestL						, MSG0(EName) | MSG1(ENewName)},
+		{	EFsReplace,					EParseDst | EParseSrc,				&TFsReplace::Initialise,					NULL,								&TFsReplace::DoRequestL						, MSG0(EName) | MSG1(ENewName)},
+		{	EFsEntry,					EParseSrc,							&TFsEntry::Initialise,						NULL,								&TFsEntry::DoRequestL						, MSG0(EName) | MSG1(EEntry)},
+		{	EFsSetEntry,				EParseSrc,							&TFsSetEntry::Initialise,					NULL,								&TFsSetEntry::DoRequestL					, MSG0(EName) | MSG1(ETime) | MSG2(ESetAtt) | MSG3(EClearAtt)},
+		{	EFsGetDriveName,			ESync,								&TFsGetDriveName::Initialise,				NULL,								&TFsGetDriveName::DoRequestL				},
+		{	EFsSetDriveName,			ESync,								&TFsSetDriveName::Initialise,				NULL,								&TFsSetDriveName::DoRequestL				},
+		{	EFsFormatSubClose,			ESync,								&TFsSubClose::Initialise,					NULL,								&TFsSubClose::DoRequestL					},
+		{	EFsDirSubClose,				ESync,								&TFsSubClose::Initialise,					NULL,								&TFsSubClose::DoRequestL					},
+		{	EFsFileSubClose,			EFileShare | EFsDspObj,				&TFsSubClose::Initialise,					NULL,								&TFsSubClose::DoRequestL					},
+		{	EFsRawSubClose,				ESync,								&TFsSubClose::Initialise,					NULL,								&TFsSubClose::DoRequestL					},
+		{	EFsFileOpen,				EParseSrc,							&TFsFileOpen::Initialise,					NULL,								&TFsFileOpen::DoRequestL					, MSG0(EName)     | MSG1(EMode)},
+		{	EFsFileCreate,				EParseSrc,							&TFsFileCreate::Initialise,					NULL,								&TFsFileCreate::DoRequestL					, MSG0(EName)     | MSG1(EMode)},
+		{	EFsFileReplace,				EParseSrc,							&TFsFileReplace::Initialise,				NULL,								&TFsFileReplace::DoRequestL					, MSG0(EName)     | MSG1(EMode)},
+		{	EFsFileTemp,				EParseSrc,							&TFsFileTemp::Initialise,					NULL,								&TFsFileTemp::DoRequestL					, MSG0(EName)     | MSG1(EMode)   | MSG2(ENewName)},
+		{	EFsFileRead,				EParseSrc | EFileShare | EFsDspObj,	&TFsFileRead::Initialise,					&TFsFileRead::PostInitialise,		&TFsFileRead::DoRequestL					, MSG0(EData)     | MSG1(ELength) | MSG2(EPosition) },
+		{	EFsFileWrite,				EParseSrc | EFileShare | EFsDspObj,	&TFsFileWrite::Initialise,					&TFsFileWrite::PostInitialise,		&TFsFileWrite::DoRequestL					, MSG0(EData)     | MSG1(ELength) | MSG2(EPosition) },
+		{	EFsFileLock,				EParseSrc | EFileShare | EFsDspObj,	&TFsFileLock::Initialise,					NULL,								&TFsFileLock::DoRequestL					, MSG0(EPosition) | MSG1(ELength)},
+		{	EFsFileUnLock,				EParseSrc | EFileShare | EFsDspObj,	&TFsFileUnlock::Initialise,					NULL,								&TFsFileUnlock::DoRequestL					, MSG0(EPosition) | MSG1(ELength)},
+		{	EFsFileSeek,				EParseSrc | EFileShare | EFsDspObj,	&TFsFileSeek::Initialise,					NULL,								&TFsFileSeek::DoRequestL					, MSG0(EPosition) | MSG1(EMode)   | MSG2(ENewPosition)},
+		{	EFsFileFlush,				EParseSrc | EFileShare | EFsDspObj,	&TFsFileFlush::Initialise,					NULL,								&TFsFileFlush::DoRequestL					},
+		{	EFsFileSize,				EParseSrc | EFileShare | EFsDspObj,	&TFsFileSize::Initialise,					NULL,								&TFsFileSize::DoRequestL					, MSG0(ESize)},
+		{	EFsFileSetSize,				EParseSrc | EFileShare | EFsDspObj,	&TFsFileSetSize::Initialise,				NULL,								&TFsFileSetSize::DoRequestL					, MSG0(ESize)},
+		{	EFsFileAtt,					EParseSrc | EFileShare | EFsDspObj,	&TFsFileAtt::Initialise,					NULL,								&TFsFileAtt::DoRequestL						, MSG0(EAtt)},
+		{	EFsFileSetAtt,				EParseSrc | EFileShare | EFsDspObj,	&TFsFileSetAtt::Initialise,					NULL,								&TFsFileSetAtt::DoRequestL					, MSG0(ESetAtt) | MSG1(EClearAtt)},
+		{	EFsFileModified,			EParseSrc | EFileShare | EFsDspObj,	&TFsFileModified::Initialise,				NULL,								&TFsFileModified::DoRequestL				, MSG0(ETime)},
+		{	EFsFileSetModified,			EParseSrc | EFileShare | EFsDspObj,	&TFsFileSetModified::Initialise,			NULL,								&TFsFileSetModified::DoRequestL				, MSG0(ETime)},
+		{	EFsFileSet,					EParseSrc | EFileShare | EFsDspObj,	&TFsFileSet::Initialise,					NULL,								&TFsFileSet::DoRequestL						, MSG0(ETime) | MSG1(ESetAtt) | MSG2(EClearAtt)},
+		{	EFsFileChangeMode,			EParseSrc | EFileShare | EFsDspObj,	&TFsFileChangeMode::Initialise,				NULL,								&TFsFileChangeMode::DoRequestL				, MSG0(EMode)},
+		{	EFsFileRename,				EParseDst | EParseSrc,				&TFsFileRename::Initialise,					NULL,								&TFsFileRename::DoRequestL					, MSG0(ENewName)},
+		{	EFsDirOpen,					EParseSrc,							&TFsDirOpen::Initialise,					NULL,								&TFsDirOpen::DoRequestL						, MSG0(EName) | MSG1(EAttMask) | MSG2(EUid)},
+		{	EFsDirReadOne,				EFsDspObj,							&TFsDirReadOne::Initialise,					NULL,								&TFsDirReadOne::DoRequestL					, MSG0(EEntry)},
+		{	EFsDirReadPacked,			EFsDspObj,							&TFsDirReadPacked::Initialise,				NULL,								&TFsDirReadPacked::DoRequestL				, MSG0(EEntryArray)},
+		{	EFsFormatOpen,				EParseSrc,							&TFsFormatOpen::Initialise,					NULL,								&TFsFormatOpen::DoRequestL					},
+		{	EFsFormatNext,				EFsDspObj,							&TFsFormatNext::Initialise,					NULL,								&TFsFormatNext::DoRequestL					},
+		{	EFsRawDiskOpen,				0,									&TFsRawDiskOpen::Initialise,				NULL,								&TFsRawDiskOpen::DoRequestL					},
+		{	EFsRawDiskRead,				EFsDspObj,							&TFsRawDiskRead::Initialise,				NULL,								&TFsRawDiskRead::DoRequestL					},
+		{	EFsRawDiskWrite,			EFsDspObj,							&TFsRawDiskWrite::Initialise,				NULL,								&TFsRawDiskWrite::DoRequestL				},
+		{	EFsResourceCountMarkStart,	ESync,								&TFsResourceCountMarkStart::Initialise,		NULL,								&TFsResourceCountMarkStart::DoRequestL		},
+		{	EFsResourceCountMarkEnd,	ESync,								&TFsResourceCountMarkEnd::Initialise,		NULL,								&TFsResourceCountMarkEnd::DoRequestL		},
+		{	EFsResourceCount,			ESync,								&TFsResourceCount::Initialise,				NULL,								&TFsResourceCount::DoRequestL				},
+		{	EFsCheckDisk,				EParseSrc,							&TFsCheckDisk::Initialise,					NULL,								&TFsCheckDisk::DoRequestL					},
+		{	EFsGetShortName,			EParseSrc,							&TFsGetShortName::Initialise,				NULL,								&TFsGetShortName::DoRequestL				},
+		{	EFsGetLongName,				EParseSrc,							&TFsGetLongName::Initialise,				NULL,								&TFsGetLongName::DoRequestL					},
+		{	EFsIsFileOpen,				EParseSrc,							&TFsIsFileOpen::Initialise,					NULL,								&TFsIsFileOpen::DoRequestL					},
+		{	EFsListOpenFiles,			ESync,								&TFsListOpenFiles::Initialise,				NULL,								&TFsListOpenFiles::DoRequestL				},
+		{	EFsGetNotifyUser,			ESync,								&TFsGetNotifyUser::Initialise,				NULL,								&TFsGetNotifyUser::DoRequestL				},
+		{	EFsSetNotifyUser,			ESync,								&TFsSetNotifyUser::Initialise,				NULL,								&TFsSetNotifyUser::DoRequestL				},
+		{	EFsIsFileInRom,				EParseSrc,							&TFsIsFileInRom::Initialise,				NULL,								&TFsIsFileInRom::DoRequestL					},
+		{	EFsIsValidName,				ESync,								&TFsIsValidName::Initialise,				NULL,								&TFsIsValidName::DoRequestL					},
+		{	EFsDebugFunction,			ESync,								&TFsDebugFunc::Initialise,					NULL,								&TFsDebugFunc::DoRequestL					},
+		{	EFsReadFileSection,			EParseSrc,							&TFsReadFileSection::Initialise,			NULL,								&TFsReadFileSection::DoRequestL				, MSG0(EData) | MSG1(EName) | MSG2(EPosition) | MSG3(ELength)},
+		{	EFsNotifyChangeEx,			ESync | EParseSrc,					&TFsNotifyChangeEx::Initialise,				NULL,								&TFsNotifyChangeEx::DoRequestL				},
+		{	EFsNotifyChangeCancelEx,	ESync,								&TFsNotifyChangeCancelEx::Initialise,		NULL,								&TFsNotifyChangeCancelEx::DoRequestL		},
+		{	EFsDismountFileSystem,		0,									&TFsDismountFileSystem::Initialise,			NULL,								&TFsDismountFileSystem::DoRequestL			},
+		{	EFsFileSystemName,			ESync,								&TFsFileSystemName::Initialise,				NULL,								&TFsFileSystemName::DoRequestL				},
+		{	EFsScanDrive,				EParseSrc,							&TFsScanDrive::Initialise,					NULL,								&TFsScanDrive::DoRequestL					},
+		{	EFsControlIo,				0,									&TFsControlIo::Initialise,					NULL,								&TFsControlIo::DoRequestL					},
+		{	EFsLockDrive,				0,									&TFsLockDrive::Initialise,					NULL,								&TFsLockDrive::DoRequestL					},
+		{	EFsUnlockDrive,				0,									&TFsUnlockDrive::Initialise,				NULL,								&TFsUnlockDrive::DoRequestL					},
+		{	EFsClearPassword,			0,									&TFsClearPassword::Initialise,				NULL,								&TFsClearPassword::DoRequestL				},
+		{	EFsNotifyDiskSpace,			0,									&TFsNotifyDiskSpace::Initialise,			NULL,								&TFsNotifyDiskSpace::DoRequestL				},
+		{	EFsNotifyDiskSpaceCancel,	ESync,								&TFsNotifyDiskSpaceCancel::Initialise,		NULL,								&TFsNotifyDiskSpaceCancel::DoRequestL		},
+		{	EFsFileDrive,				EParseSrc | EFileShare | EFsDspObj,	&TFsFileDrive::Initialise,					NULL,								&TFsFileDrive::DoRequestL					},
+		{	EFsRemountDrive,			0,									&TFsRemountDrive::Initialise,				NULL,								&TFsRemountDrive::DoRequestL				},
+		{	EFsMountFileSystemScan,		0,									&TFsMountFileSystemScan::Initialise,		NULL,								&TFsMountFileSystemScan::DoRequestL			},
+		{	EFsSessionToPrivate,		ESync,								&TFsSessionToPrivate::Initialise,			NULL,								&TFsSessionToPrivate::DoRequestL			},
+		{	EFsPrivatePath,				ESync,								&TFsPrivatePath::Initialise,				NULL,								&TFsPrivatePath::DoRequestL					},
+		{	EFsCreatePrivatePath,		0,									&TFsCreatePrivatePath::Initialise,			NULL,								&TFsCreatePrivatePath::DoRequestL			},
+		{	EFsAddExtension,			ESync,								&TFsAddExtension::Initialise,				NULL,								&TFsAddExtension::DoRequestL				},
+		{	EFsMountExtension,			0,									&TFsMountExtension::Initialise,				NULL,								&TFsMountExtension::DoRequestL				},
+		{	EFsDismountExtension,		0,									&TFsDismountExtension::Initialise,			NULL,								&TFsDismountExtension::DoRequestL			},
+		{	EFsRemoveExtension,			ESync,								&TFsRemoveExtension::Initialise,			NULL,								&TFsRemoveExtension::DoRequestL				},
+		{	EFsExtensionName,			0,									&TFsExtensionName::Initialise,				NULL,								&TFsExtensionName::DoRequestL				},
+		{	EFsStartupInitComplete,		ESync,								&TFsStartupInitComplete::Initialise,		NULL,								&TFsStartupInitComplete::DoRequestL			},
+		{	EFsSetLocalDriveMapping,	ESync,								&TFsSetLocalDriveMapping::Initialise,		NULL,								&TFsSetLocalDriveMapping::DoRequestL		},
+		{	EFsFinaliseDrive,			0,									&TFsFinaliseDrive::Initialise,				NULL,								&TFsFinaliseDrive::DoRequestL				},
+		{	EFsFileDuplicate,			EFileShare | EFsDspObj,				&TFsFileDuplicate::Initialise,				NULL,								&TFsFileDuplicate::DoRequestL				},
+		{	EFsFileAdopt,				ESync,								&TFsFileAdopt::Initialise,					NULL,								&TFsFileAdopt::DoRequestL					},
+		{	EFsSwapFileSystem,			ESync,								&TFsSwapFileSystem::Initialise,				NULL,								&TFsSwapFileSystem::DoRequestL				},
+		{	EFsErasePassword,			0,									&TFsErasePassword::Initialise,				NULL,								&TFsErasePassword::DoRequestL				},
+		{	EFsReserveDriveSpace,		0,									&TFsReserveDriveSpace::Initialise,			NULL,								&TFsReserveDriveSpace::DoRequestL			},
+		{	EFsGetReserveAccess,		ESync,  							&TFsGetReserveAccess::Initialise,			NULL,								&TFsGetReserveAccess::DoRequestL			},
+		{	EFsReleaseReserveAccess,	ESync,								&TFsReleaseReserveAccess::Initialise,		NULL,								&TFsReleaseReserveAccess::DoRequestL		},
+		{	EFsFileName,				ESync,								&TFsFileName::Initialise,					NULL,								&TFsFileName::DoRequestL					, MSG0(EName)},
+		{	EFsGetMediaSerialNumber,	0,									&TFsGetMediaSerialNumber::Initialise,		NULL,								&TFsGetMediaSerialNumber::DoRequestL		},
+		{	EFsFileFullName,			ESync,								&TFsFileFullName::Initialise,				NULL,								&TFsFileFullName::DoRequestL				, MSG0(EName)},
+		{	EFsAddPlugin,				ESync,								&TFsAddPlugin::Initialise,					NULL,								&TFsAddPlugin::DoRequestL					},
+		{	EFsRemovePlugin,			ESync,								&TFsRemovePlugin::Initialise,				NULL,								&TFsRemovePlugin::DoRequestL				},
+		{	EFsMountPlugin,				ESync,								&TFsMountPlugin::Initialise,				NULL,								&TFsMountPlugin::DoRequestL					},
+		{	EFsDismountPlugin,			0,									&TFsDismountPlugin::Initialise,				NULL,								&TFsDismountPlugin::DoRequestL				},
+		{	EFsPluginName,				ESync,								&TFsPluginName::Initialise,					NULL,								&TFsPluginName::DoRequestL					},
+		{	EFsPluginOpen,				ESync | EParseSrc,					&TFsPluginOpen::Initialise,					NULL,								&TFsPluginOpen::DoRequestL					},
+		{	EFsPluginSubClose,			ESync,								&TFsSubClose::Initialise,					NULL,								&TFsSubClose::DoRequestL					},
+		{	EFsPluginDoRequest,			0,									&TFsPluginDoRequest::Initialise,			NULL,								&TFsPluginDoRequest::DoRequestL				},
+		{	EFsPluginDoControl,			0,									&TFsPluginDoControl::Initialise,			NULL,								&TFsPluginDoControl::DoRequestL				},
+		{	EFsPluginDoCancel,			0,									&TFsPluginDoCancel::Initialise,				NULL,								&TFsPluginDoCancel::DoRequestL				},
+		{	EFsNotifyDismount,			0,									&TFsNotifyDismount::Initialise,				NULL,								&TFsNotifyDismount::DoRequestL				},
+		{	EFsNotifyDismountCancel,	ESync,								&TFsNotifyDismountCancel::Initialise,		NULL,								&TFsNotifyDismountCancel::DoRequestL		},
+		{	EFsAllowDismount,			0,									&TFsAllowDismount::Initialise,				NULL,								&TFsAllowDismount::DoRequestL				},
+		{	EFsSetStartupConfiguration,	ESync,								&TFsSetStartupConfiguration::Initialise,	NULL,								&TFsSetStartupConfiguration::DoRequestL		},
+		{	EFsFileReadCancel,			ESync,								&TFsFileReadCancel::Initialise,				NULL,								&TFsFileReadCancel::DoRequestL				},
+		{	EFsAddCompositeMount,		ESync,								&TFsAddCompositeMount::Initialise,			NULL,								&TFsAddCompositeMount::DoRequestL			},
+		{	EFsSetSessionFlags,			ESync,								&TFsSetSessionFlags::Initialise,			NULL,								&TFsSetSessionFlags::DoRequestL				},
+		{	EFsSetSystemDrive,			ESync,								&TFsSetSystemDrive::Initialise,				NULL,								&TFsSetSystemDrive::DoRequestL				},
+		{	EFsBlockMap,				EParseSrc,							&TFsBlockMap::Initialise,					NULL,								&TFsBlockMap::DoRequestL					},
+		{	EFsUnclamp,					0,									&TFsUnclamp::Initialise,					NULL,								&TFsUnclamp::DoRequestL						},
+		{	EFsFileClamp,				EParseSrc,							&TFsFileClamp::Initialise,					NULL,								&TFsFileClamp::DoRequestL					},
+		{	EFsQueryVolumeInfoExt,		0,									&TFsQueryVolumeInfoExt::Initialise,			NULL,								&TFsQueryVolumeInfoExt::DoRequestL			},
+		{	EFsInitialisePropertiesFile,0,									&TFsInitialisePropertiesFile::Initialise,	NULL,								&TFsInitialisePropertiesFile::DoRequestL	},
+		{	EFsFileWriteDirty,			EFileShare | EFsDspObj,				NULL,										&TFsFileWriteDirty::PostInitialise,	&TFsFileWrite::DoRequestL					},
+		{	EFsSynchroniseDriveThread,	0,									&TFsSynchroniseDriveThread::Initialise,		NULL,								&TFsSynchroniseDriveThread::DoRequestL		},
+		{	EFsAddProxyDrive,			ESync,								&TFsAddProxyDrive::Initialise,				NULL,								&TFsAddProxyDrive::DoRequestL				},
+		{	EFsRemoveProxyDrive,		ESync,								&TFsRemoveProxyDrive::Initialise,			NULL,								&TFsRemoveProxyDrive::DoRequestL			},
+		{	EFsMountProxyDrive,			0,									&TFsMountProxyDrive::Initialise,			NULL,								&TFsMountProxyDrive::DoRequestL				},
+		{	EFsDismountProxyDrive,		0,									&TFsDismountProxyDrive::Initialise,			NULL,								&TFsDismountProxyDrive::DoRequestL			},
+		{	EFsNotificationOpen,		ESync,								&TFsNotificationOpen::Initialise,			NULL,								&TFsNotificationOpen::DoRequestL			},
+		{	EFsNotificationBuffer,		ESync,								&TFsNotificationBuffer::Initialise,			NULL,								&TFsNotificationBuffer::DoRequestL			},		
+		{	EFsNotificationRequest,		ESync,								&TFsNotificationRequest::Initialise,		NULL,								&TFsNotificationRequest::DoRequestL			},
+		{	EFsNotificationCancel,		ESync,								&TFsNotificationCancel::Initialise,			NULL,								&TFsNotificationCancel::DoRequestL			},
+		{	EFsNotificationSubClose,	ESync,								&TFsNotificationSubClose::Initialise,		NULL,								&TFsNotificationSubClose::DoRequestL		},
+		{	EFsNotificationAdd,			ESync,								&TFsNotificationAdd::Initialise,			NULL,								&TFsNotificationAdd::DoRequestL				},
+		{	EFsNotificationRemove,		ESync,								&TFsNotificationRemove::Initialise,			NULL,								&TFsNotificationRemove::DoRequestL			},
+		{	EFsLoadCodePage,			0,									&TFsLoadCodePage::Initialise,				NULL,								&TFsLoadCodePage::DoRequestL				},
 	};
 
 #endif //SF_OPS_H
--- a/userlibandfileserver/fileserver/sfile/sf_plugin.h	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_plugin.h	Mon Sep 27 10:52:00 2010 +0100
@@ -68,7 +68,6 @@
 
 	static TInt InitPlugin(CFsPlugin& aPlugin, RLibrary aLibrary);
 	static void TransferRequests(CPluginThread* aPluginThread);
-	static void CancelPlugin(CFsPlugin* aPlugin,CSessionFs* aSession);
 	static TInt ChainCount();
 	static TInt Plugin(CFsPlugin*& aPlugin, TInt aPos);
 
@@ -82,11 +81,11 @@
 	static TBool IsPluginConnThread(TThreadId tid, CFsPlugin* aPlugin);
 
 	static void DispatchSync(CFsRequest* aRequest);
-	static void CompleteSessionRequests(CSessionFs* aSession, TInt aValue, CFsInternalRequest* aRequest);
 
 private:
 	static TInt UpdateMountedDrive(CFsPlugin* aPlugin, CFsPluginFactory* aFactory,TInt aDrive);
-	static void GetNextCancelPluginOpRequest(CPluginThread* aPluginThread, CFsRequest*& aCancelPluginRequest);
+
+
 private:
 	static CFsObjectCon* iPluginFactories;
 	static CFsObjectCon* iPluginConns;
--- a/userlibandfileserver/fileserver/sfile/sf_plugin_man.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_plugin_man.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -205,28 +205,6 @@
 	aPluginFactory.DecrementMounted();
 	}
 
-/*
- * This will iterate through a plugins request queue and 
- * search for the first occurance it finds of a CancelPluginOp
- * request.
- */
-void FsPluginManager::GetNextCancelPluginOpRequest(CPluginThread* aPluginThread, CFsRequest*& aCancelPluginRequest)
-    {
-    __THRD_PRINT(_L("FsPluginManager::GetNextCancelPluginOpRequest"));
-    
-    TDblQueIter<CFsRequest> iter(aPluginThread->iList);
-    CFsRequest* request = NULL;
-
-    while((request=iter++)!=NULL)
-        {
-        if(request->Operation()->iFunction == KCancelPlugin)
-            {
-            aCancelPluginRequest = request;
-            break;
-            }
-        }
-    }
- 
 
 
 
@@ -248,100 +226,51 @@
 	 * We are transferring requests up and down the chain
 	 * because this plugin is being removed.
 	 * 
-	 * There is a potential problem when one of the outstanding requests
-	 * is CancelPluginOp which is called when the Session is being closed.
-	 * The CancelPluginOp will try to cancel all of the requests on a plugin's
-	 * queue which is associated with that session.
-	 * DismountPlugin(and thus TransferRequests) is trying to preserve the requests
-	 * by passing them along to the Next/Previous plugins. 
-	 * 
-	 * If there is a cancel in the chain we must NOT pass any requests to Previous Plugins 
-	 * as these have already had their chains emptied.
-	 * We should also be wary of passing requests up the chain as they will simply be cancelled 
-	 * somewhere closer to the drive [thread].
-	 * 
-	 * Therefore, we shall check whether there is a KCancelPlugin op in the 
-	 * chain first. 
-     * If there is a cancelPluginOp in the chain, we will cancel of the requests 
-     * that are associated with that session.
-     * 
-     * After that is out of the way we preserve the remaining requests for different sessions by
-     * passing them on.
+	 * ToDo: This next 'while' might be able to be replaced with a call to
+	 * DispatchToPlugin/DispatchToDrive instead.
 	 */
-	if(!aPluginThread->iList.IsEmpty())
+	while(!aPluginThread->iList.IsEmpty())
 	    {
-	    CFsRequest* cancelRequest = NULL;
-	    //For every CancelPluginOp 
-	    while(FsPluginManager::GetNextCancelPluginOpRequest(aPluginThread, cancelRequest), cancelRequest!=NULL)
+	    CFsRequest* pR=aPluginThread->iList.First();
+	    CFsMessageRequest& mR = *(CFsMessageRequest*) pR;
+	    pR->iLink.Deque();
+	    pR->iCurrentPlugin=NULL;
+
+	    if(pR->IsPluginSpecific())
 	        {
-	        RDebug::Print(_L("Transferring Plugin Requests - CancelPluginOp"));
-	        TDblQueIter<CFsRequest> iter(aPluginThread->iList);
-	        CFsRequest* request = NULL;
-	        //For every request
-	        while((request=iter++)!=NULL)
-	            {
-	            if(request->Session() == cancelRequest->Session() && request != cancelRequest)
-	                {
-	                request->iLink.Deque();
-	                request->Complete(KErrCancel);
-	                }
-	            }
-	        cancelRequest->iLink.Deque();
-	        cancelRequest->Complete(KErrNone);
-	        cancelRequest = NULL;
+	        pR->Complete(KErrCancel);
+	        continue;
 	        }
 
-	    /*
-	     * Now that all requests that were to be cancelled have been cancelled,
-	     * we can now go about moving the remaining ones on to , or back to, 
-	     * the appropriate next or previous plugins.
-	     * 
-	     * ToDo: This next 'while' might be able to be replaced with a call to
-	     * DispatchToPlugin/DispatchToDrive instead.
-	     */
-	    while(!aPluginThread->iList.IsEmpty())
+	    if(pR->IsPostOperation())
+	        {
+	        //[set the plugin to] pass the request backwards in the chain
+	        PrevPlugin(pR->iCurrentPlugin, &mR);
+	        }
+	    else //IsPreOperations
 	        {
-	        CFsRequest* pR=aPluginThread->iList.First();
-	        CFsMessageRequest& mR = *(CFsMessageRequest*) pR;
-	        pR->iLink.Deque();
-	        pR->iCurrentPlugin=NULL;
+	        //[set the plugin to] pass the request forwards in the chain
+	        NextPlugin(pR->iCurrentPlugin, &mR);
+	        }
 
-	        if(pR->IsPluginSpecific())
+	    if(pR->iCurrentPlugin)
+	        {
+	        pR->iCurrentPlugin->iThreadP->DeliverBack(pR);
+	        }
+	    else
+	        {
+	        if(!pR->IsPostOperation() && (pR->DriveNumber()>=EDriveA && pR->DriveNumber()<=EDriveZ))
 	            {
-	            pR->Complete(KErrCancel);
-	            continue;
-	            }
-
-	        if(pR->IsPostOperation())
-	            {
-	            //[set the plugin to] pass the request backwards in the chain
-	            PrevPlugin(pR->iCurrentPlugin, &mR);
-	            }
-	        else //IsPreOperations
-	            {
-	            //[set the plugin to] pass the request forwards in the chain
-	            NextPlugin(pR->iCurrentPlugin, &mR);
-	            }
-
-	        if(pR->iCurrentPlugin)
-	            {
-	            pR->iCurrentPlugin->iThreadP->DeliverBack(pR);
+	            //Deliver to drive thread
+	            CDriveThread* dT=NULL;
+	            TInt r=FsThreadManager::GetDriveThread(pR->DriveNumber(),&dT);
+	            __ASSERT_ALWAYS(r==KErrNone && dT,Fault(EFsDriveThreadError));
+	            CRequestThread* pT = (CRequestThread*)dT;
+	            pT->DeliverBack(pR);
 	            }
 	        else
 	            {
-	            if(!pR->IsPostOperation() && (pR->DriveNumber()>=EDriveA && pR->DriveNumber()<=EDriveZ))
-	                {
-	                //Deliver to drive thread
-	                CDriveThread* dT=NULL;
-	                TInt r=FsThreadManager::GetDriveThread(pR->DriveNumber(),&dT);
-	                __ASSERT_ALWAYS(r==KErrNone && dT,Fault(EFsDriveThreadError));
-	                CRequestThread* pT = (CRequestThread*)dT;
-	                pT->DeliverBack(pR);
-	                }
-	            else
-	                {
-	                pR->Complete(KErrCancel);
-	                }
+	            pR->Complete(KErrCancel);
 	            }
 	        }
 	    }
@@ -624,13 +553,6 @@
 	aPlugin.iThreadId = aPlugin.iThreadP->StartL();
 	return err;
 	}
-/**
-Cancels plugin requests
-*/
-void FsPluginManager::CancelPlugin(CFsPlugin* aPlugin,CSessionFs* aSession)
-	{
-	aPlugin->iThreadP->CompleteSessionRequests(aSession,KErrCancel);
-	}
 
 /**
 Gets number of plugins in the plugin stack
@@ -727,46 +649,4 @@
 		}
 	}
 
-void FsPluginManager::CompleteSessionRequests(CSessionFs* aSession, TInt aValue, CFsInternalRequest* aRequest)
-/**
- * Complete outstanding requests for the specified session
- */
-	{
-	__PRINT2(_L("FsPluginManager::CompleteSessionRequests(%08x, %d)"), aSession, aValue);
 
-	// Iterate through all plugins, cancelling outstanding session requests
-	aRequest->Set(CancelPluginOp, aSession);
-
-	FsPluginManager::ReadLockChain();
-	TInt count = FsPluginManager::ChainCount();
-	TInt oldCount = count;
-	TInt i;
-	for(i=0; i<count; i++)
-	    {
-	    CFsPlugin* plugin = NULL;
-	    (void) FsPluginManager::Plugin(plugin, i); // (void) as chain is locked.
-	    __ASSERT_DEBUG(plugin, User::Leave(KErrNotFound));
-	    aRequest->iCurrentPlugin = plugin;
-	    aRequest->Status() = KRequestPending;
-	    aRequest->Dispatch();
-	    //Cancel is delivered to the front of the request queue
-	    //so hopefully this wont take too long.
-	    FsPluginManager::UnlockChain();
-	    User::WaitForRequest(aRequest->Status());
-	    FsPluginManager::ReadLockChain();
-	    __ASSERT_ALWAYS(aRequest->Status().Int()==KErrNone||aRequest->Status().Int()==KErrCancel,Fault(ESessionDisconnectThread2));
-	    count = FsPluginManager::ChainCount();
-	    //If a plugin was removed whilst the chain was unlocked we need to make sure we don't skip any plugins
-	    if(count != oldCount)
-	        {
-	        i=0;
-	        oldCount = count;
-	        }
-	    }
-	FsPluginManager::UnlockChain();
-	
-//	RDebug::Print(_L("FsPluginManager::CompleteSessionRequests - CSRs"));
-	iScheduler->CompleteSessionRequests(aSession, aValue);
-	}
-
-
--- a/userlibandfileserver/fileserver/sfile/sf_request.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_request.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -369,7 +369,9 @@
 //
 //
 //
-	{}
+	{
+	Close();
+	}
 
 void CFsRequest::Set(const TOperation& aOperation,CSessionFs* aSession)
 //
@@ -380,16 +382,7 @@
 	SetState(EReqStateInitialise);
 
 	iOperation     = const_cast<TOperation*>(&aOperation);
-	iSession       = aSession;
-	iIsCompleted   = aOperation.IsCompleted();
-	iError         = KErrNone;
-	iDriveNumber   = KDriveInvalid;
-	iCurrentPlugin = NULL;
-	iOwnerPlugin   = NULL;
-	iDirectToDrive = EFalse;
-	iClientThreadId= 0;
-	iFlags &= ~(EFreeChanged | EPostInterceptEnabled | EPostOperation | EFsObjectOpen);
-	iScratchValue = 0;
+	Set(aSession);
 	}
 
 void CFsRequest::Set(CSessionFs* aSession)
@@ -401,7 +394,6 @@
 
 	SetState(EReqStateInitialise);
 
-	iSession       = aSession;
 	iIsCompleted   = iOperation->IsCompleted();
 	iError         = KErrNone;
 	iDriveNumber   = KDriveInvalid;
@@ -409,8 +401,11 @@
 	iOwnerPlugin   = NULL;
 	iDirectToDrive = EFalse;
 	iClientThreadId= 0;
-	iFlags &= ~(EFreeChanged | EPostInterceptEnabled | EPostOperation | EFsObjectOpen);
+	iFlags &= ~(EFreeChanged | EPostInterceptEnabled | EPostOperation | EFsDspObjOpen);
+
 	iScratchValue = 0;
+
+	OpenSession(aSession);
 	}
 
 
@@ -643,21 +638,50 @@
 	return KErrNotSupported;
 	}
 
-void CFsRequest::SetAndOpenScratchValue(const TInt64& aValue)
+void CFsRequest::OpenDispatchObject(const TInt64& aValue)
 	{
-	if (IsFsObjectOpen())
+	CloseDispatchObject();
+
+	iScratchValue = aValue;
+
+	if (I64LOW(iScratchValue) && iOperation && (iOperation->iFlags & EFsDspObj))
+		{
+		((CFsDispatchObject*) I64LOW(iScratchValue))->Open();
+		iFlags |= EFsDspObjOpen;
+		}
+	}
+
+void CFsRequest::CloseDispatchObject()
+	{
+	if (iFlags & EFsDspObjOpen)
 		{
 		((CFsDispatchObject*) I64LOW(iScratchValue))->Close();
-		SetFsObjectOpen(EFalse);
+		iFlags &= ~EFsDspObjOpen;
 		}
-	if (I64LOW(aValue) && iOperation && (iOperation->iFlags & EFileShare))
-		{
-		((CFsDispatchObject*) I64LOW(aValue))->Open();
-		SetFsObjectOpen(ETrue);
-		}
-	iScratchValue = aValue;
+	}
+
+void CFsRequest::OpenSession(CSessionFs* aSession)
+	{
+	CloseSession();
+	iSession = aSession;
+	if (iSession)
+		iSession->Open();
 	}
 
+void CFsRequest::CloseSession()
+	{
+	if (iSession)
+		{
+		iSession->Close();
+		iSession = NULL;
+		}
+	}
+
+void CFsRequest::Close()
+	{
+	SetScratchValue(0);	// this should close the CFsObject
+	CloseSession();
+	}
 
 TInt CFsRequest::Read(TFsPluginRequest::TF32ArgType aType, TDes8& aDes, TInt aOffset)
 	{
@@ -1358,7 +1382,7 @@
 	{
 	__THRD_PRINT1(_L("CFsMessageRequest::Free() isAllocated=%d"), IsAllocated());
 
-	SetScratchValue(0);	// this should close the CFsObject
+	Close();
 
 	if(!IsAllocated())
 		delete(this);
@@ -1962,7 +1986,8 @@
 		iPoolDest = 0;
 		}
 
-	SetScratchValue(0);	// this should close the CFsObject
+	Close();
+
 	iOperation = NULL;
 	RequestAllocator::FreeRequest(this);
 	}
@@ -2170,16 +2195,7 @@
 	{
 	__PRINT1(_L("CFsInternalRequest::Complete() with %d"),aError);
 	TInt func = Operation()->Function();
-	if(func==KCancelSession || func==KCancelPlugin || func==KFlushDirtyData)
-		{
-		__ASSERT_DEBUG(ThreadHandle()!=0 && !FsThreadManager::IsDisconnectThread(),Fault(EInternalRequestComplete1));
-		RThread t;
-		t.SetHandle(ThreadHandle());
-		TRequestStatus* s=&Status();
-		t.RequestComplete(s,aError);
-		Free();
-		}
-	else if(func == KDispatchObjectClose)
+	if(func == KDispatchObjectClose)
 		{
 		TFsCloseObject::Complete(this);
 		Free();
@@ -2208,30 +2224,21 @@
 	__THRD_PRINT(_L("CFsInternalRequest::Dispatch()"));
 	__ASSERT_ALWAYS(Initialise()==KErrNone,Fault(EInternalRequestDispatch1));
 
-	if(iCurrentPlugin && Operation()->Function() == KCancelPlugin)
-		{
-		TFsPluginRequest request(this);
-		TInt r = iCurrentPlugin->Deliver(request);
-		__ASSERT_ALWAYS(r == KErrNone, Fault(EInternalRequestDispatchCancelPlugin));
-		}
+	TInt drivenumber = DriveNumber();
+	FsThreadManager::LockDrive(drivenumber);
+	// shouldn't dispath if no drive available
+	__ASSERT_ALWAYS(FsThreadManager::IsDriveAvailable(drivenumber,EFalse) && !FsThreadManager::IsDriveSync(drivenumber,EFalse),Fault(EInternalRequestDispatch2));
+	CDriveThread* dT=NULL;
+	TInt r=FsThreadManager::GetDriveThread(drivenumber,&dT);
+	__THRD_PRINT2(_L("deliver to thread 0x%x, drive number %d"),dT,drivenumber);
+	__ASSERT_ALWAYS(r==KErrNone && dT,Fault(EInternalRequestDispatch3));
+	CRequestThread* pT = (CRequestThread*)dT;
+	TInt func = Operation()->Function();
+	if(func == KDispatchObjectClose || func == KFileShareClose || func == KFlushDirtyData)
+		pT->DeliverBack(this);
 	else
-		{
-		TInt drivenumber = DriveNumber();
-		FsThreadManager::LockDrive(drivenumber);
-		// shouldn't dispath if no drive available
-		__ASSERT_ALWAYS(FsThreadManager::IsDriveAvailable(drivenumber,EFalse) && !FsThreadManager::IsDriveSync(drivenumber,EFalse),Fault(EInternalRequestDispatch2));
-		CDriveThread* dT=NULL;
-		TInt r=FsThreadManager::GetDriveThread(drivenumber,&dT);
-		__THRD_PRINT2(_L("deliver to thread 0x%x, drive number %d"),dT,drivenumber);
-		__ASSERT_ALWAYS(r==KErrNone && dT,Fault(EInternalRequestDispatch3));
-		CRequestThread* pT = (CRequestThread*)dT;
-		TInt func = Operation()->Function();
-		if(func == KDispatchObjectClose || func == KFileShareClose || func == KFlushDirtyData)
-			pT->DeliverBack(this);
-		else
-			pT->DeliverFront(this);
-		FsThreadManager::UnlockDrive(drivenumber);
-		}
+		pT->DeliverFront(this);
+	FsThreadManager::UnlockDrive(drivenumber);
 	}
 
 void CFsInternalRequest::Free()
@@ -2241,58 +2248,12 @@
 	{
 	__THRD_PRINT1(_L("CFsInternalRequest::Free() isAllocated=%d"),IsAllocated());
 
-	SetScratchValue(0);	// this should close the CFsObject
+	Close();
 
 	if(!IsAllocated())
 		delete(this);
 	}
 
-void CFsDisconnectRequest::Dispatch()
-//
-//
-//
-	{
-	__THRD_PRINT(_L("CFsDisconnectRequest::Dispatch()"));
-	// no need to lock
-	TInt r=Initialise();
-	__ASSERT_ALWAYS(r==KErrNone,Fault(EDisconnectRequestDispatch1));
-	CRequestThread* pT=FsThreadManager::GetDisconnectThread();
-	__ASSERT_ALWAYS(pT,Fault(EDisconnectRequestDispatch2));
-	pT->DeliverBack(this);
-	}
-
-void CFsDisconnectRequest::Process()
-//
-//
-//
-	{
-	__THRD_PRINT(_L("CFsDisconnectRequest::Process()"));
-	TInt r=KErrNone;
-	TRAPD(leaveValue,r=iOperation->DoRequestL(this));
-	leaveValue=leaveValue; // just to make compiler happy
-	__ASSERT_DEBUG(leaveValue==KErrNone && r==KErrNone,Fault(EDisonncectRequestProcess));
-	Complete(r);
-	}
-
-void CFsDisconnectRequest::Complete(TInt aError)
-//
-//
-//
-	{
-	__PRINT1(_L("CFsDisconnectRequest::Complete() with %d"),aError);
-	__ASSERT_ALWAYS(aError==KErrNone,Fault(EDisconnectRequestComplete));
-	// set session disconnect reqeust to NULL
-	// will be freed in CFsMessageRequest::Free()
-	Session()->iDisconnectRequest=NULL;
-	// now delete session
-	TheFileServer->SessionQueueLockWait();
-	delete(Session());
-	TheFileServer->SessionQueueLockSignal();
-	// NB Must complete the message AFTER the session has been deleted...
-	Message().Complete(aError);
-	delete(this);	
-	}
-
 
 /**
 Create a new synchronous message scheduler
@@ -2410,24 +2371,3 @@
 	}
 
 
-/**
-Complete outstanding requests for the specified session
-*/
-void CFsSyncMessageScheduler::CompleteSessionRequests(CSessionFs* aSession, TInt aValue)
-	{
-	__PRINT2(_L("FsPluginManager::CompleteSessionRequests(%08x, %d)"), aSession, aValue);
-	
-	iLock.Wait();
-	TDblQueIter<CFsRequest> q(iList);
-	CFsRequest* pR;
-	while((pR=q++)!=NULL)
-		{
-		if(pR->Session()==aSession)
-			{
-			pR->iLink.Deque();
-			pR->Complete(aValue);
-			}
-		}
-	iLock.Signal();
-	}
-
--- a/userlibandfileserver/fileserver/sfile/sf_ses.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_ses.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -22,10 +22,13 @@
 #include "sf_notifier.h"
 #endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION	
 
+TInt CancelAsyncRequests(CSessionFs* aSession);
+
+
 CSessionFs::CSessionFs()
 	       :iSessionFlags((TInt)EFsSessionFlagsAll), 
           iReservedDriveAccess(KReservedDriveAccessArrayGranularity, _FOFF(TReservedDriveAccess, iDriveNumber)),
-	       iId(0)
+	       iId(0), iAccessCount(1)
 	{
 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
     __e32_atomic_add_ord32(&SessionCount, 1);
@@ -41,6 +44,13 @@
 	{
 	__PRINT1(_L("CSessionFs::~CSessionFs() deleting... = 0x%x"),this);
 		
+	FsNotify::CancelSession(this);
+
+#ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
+	FsNotificationManager::RemoveNotificationRequest(this);
+#endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
+
+
 	//take out all the reserved space set by this session
 	while(iReservedDriveAccess.Count())
 		{
@@ -65,14 +75,42 @@
 	
 	delete iPath;
 	iSessionFlagsLock.Close();
-	if(iDisconnectRequest)
-		delete(iDisconnectRequest);
 
 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
     __e32_atomic_add_ord32(&SessionCount, (TUint32) -1);
 #endif
 	}
 
+void CSessionFs::Close()
+	{
+	TheFileServer->SessionQueueLockWait();
+
+	if (iAccessCount == 1)
+		{
+		// close the objects owned by this session 
+		// NB closing a CFileShare may allocate a request to flush dirty data which will
+		// in turn increment iAccessCount on this session
+		if (iHandles)
+			{
+			// Cancel any ASYNC requests belonging to this session BEFORE 
+			// CSessionFs is deleted to avoid a KERN-EXEC 44 (EBadMessageHandle)
+			CancelAsyncRequests(this);
+			delete iHandles;
+			iHandles = NULL;
+			}
+		}
+
+	if (__e32_atomic_tas_ord32(&iAccessCount, 1, -1, 0) == 1)
+		{
+		RMessage2 message = iMessage;
+		delete this;
+		// NB Must complete the message AFTER the session has been deleted...
+		message.Complete(KErrNone);
+		}
+
+	TheFileServer->SessionQueueLockSignal();
+	}
+
 void CSessionFs::CreateL()
 //
 // Create any additional resources.
@@ -83,12 +121,6 @@
 	iHandles=CFsObjectIx::NewL();
 	TInt r = iSessionFlagsLock.CreateLocal();
 	User::LeaveIfError(r);
-	RMessage2 m;
-
-	iDisconnectRequest=new(ELeave) CFsDisconnectRequest;
-	iDisconnectRequest->Set(m,SessionDisconnectOp,this);
-
-
 	}
 
 TInt CSessionFs::CurrentDrive()
@@ -144,9 +176,10 @@
 	__THRD_PRINT1(_L("CSessionFs::Disconnect() 0x%x"),this);
 
 	iHandles->CloseMainThreadObjects();
-	iDisconnectRequest->SetMessage((RMessage2&)aMessage);
+	iMessage = aMessage;
 
-	iDisconnectRequest->Dispatch();
+	// close the session - if there are no requests using this session then the session will be freed
+	Close();
 	}
 
 
@@ -478,107 +511,6 @@
 
 
 
-TInt TFsCancelSession::DoRequestL(CFsRequest* aRequest)
-	{
-	__CHECK_DRIVETHREAD(aRequest->DriveNumber());
-
-	// Cancel any outstanding requests
-	CDriveThread* pT=NULL;
-	TInt r=FsThreadManager::GetDriveThread(aRequest->DriveNumber(), &pT);
-	if(r==KErrNone)
-		pT->CompleteSessionRequests(aRequest->Session(),KErrCancel);
-	// We must also cancel any ASYNC requests belonging to this session BEFORE 
-	// ~CSessionFs() is called to avoid a KERN-EXEC 44 (EBadMessageHandle)
-	CancelAsyncRequests(aRequest->Session());
-	return(r);
-	}
-
-TInt TFsCancelSession::Initialise(CFsRequest* /*aRequest*/)
-	{
-	return(KErrNone);
-	}
-
-TInt TFsSessionDisconnect::DoRequestL(CFsRequest* aRequest)
-	{
-	__PRINT(_L("TFsSessionDisconnect::DoRequestL()"));
-	__ASSERT_DEBUG(FsThreadManager::IsDisconnectThread(),Fault(ESessionDisconnectThread1));
-	CDisconnectThread* pT=FsThreadManager::GetDisconnectThread();
-	
-	// Complete requests on all plugins
-	CFsInternalRequest* pR=pT->GetRequest();
-	FsPluginManager::CompleteSessionRequests(aRequest->Session(), KErrCancel, pR);
-
-	// ...and on all drives
-	for(TInt i=0;i<KMaxDrives;++i)
-		{
-		FsThreadManager::LockDrive(i);
-		if(!FsThreadManager::IsDriveAvailable(i,EFalse)||FsThreadManager::IsDriveSync(i,EFalse))
-			{
-			FsThreadManager::UnlockDrive(i);
-			continue;
-			}
-		pR->Set(CancelSessionOp,aRequest->Session());
-		pR->SetDriveNumber(i);
-		pR->Status()=KRequestPending;
-		pR->Dispatch();
-		FsThreadManager::UnlockDrive(i);
-		User::WaitForRequest(pR->Status());
-		// check request completed or cancelled (by file system dismount which completes requests with KErrNotReady)
-		__ASSERT_ALWAYS(pR->Status().Int()==KErrNone||pR->Status().Int()==KErrNotReady,Fault(ESessionDisconnectThread2));
-		__THRD_PRINT2(_L("cancel session requests on drive %d r=%d"),i,pR->Status().Int());
-
-		if (TFileCacheSettings::Flags(i) & (EFileCacheWriteEnabled | EFileCacheWriteOn))
-			{
-			FsThreadManager::LockDrive(i);
-			if(!FsThreadManager::IsDriveAvailable(i,EFalse)||FsThreadManager::IsDriveSync(i,EFalse))
-				{
-				FsThreadManager::UnlockDrive(i);
-				continue;
-				}
-
-			// Flush dirty data
-			pR->Set(FlushDirtyDataOp,aRequest->Session());
-			pR->SetDriveNumber(i);
-			pR->Status()=KRequestPending;
-			pR->Dispatch();
-			FsThreadManager::UnlockDrive(i);
-			User::WaitForRequest(pR->Status());
-			// check request completed or cancelled (by file system dismount which completes requests with KErrNotReady)
-			__ASSERT_ALWAYS(pR->Status().Int()==KErrNone||pR->Status().Int()==KErrNotReady,Fault(ESessionDisconnectThread2));
-			__THRD_PRINT2(_L("Flush dirty data on drive %d r=%d"),i,pR->Status().Int());
-			}
-
-		}
-	FsNotify::CancelSession(aRequest->Session());
-	
-#ifdef SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
-	FsNotificationManager::RemoveNotificationRequest(aRequest->Session());
-#endif //SYMBIAN_F32_ENHANCED_CHANGE_NOTIFICATION
-
-
-	// don't delete session here, will be done in CFsDisconnectRequest::Complete()
-	return(KErrNone);
-	}
-
-TInt TFsSessionDisconnect::Initialise(CFsRequest* /*aRequest*/)
-	{
-	return(KErrNone);
-	}
-
-TInt TFsCancelPlugin::DoRequestL(CFsRequest* aRequest)
-	{
-	//__ASSERT_DEBUG(FsPluginManager::IsPluginThread(),Fault(EFsPluginThreadError));
-	FsPluginManager::CancelPlugin(aRequest->iCurrentPlugin,aRequest->Session());
-	TInt err = aRequest->iCurrentPlugin->SessionDisconnect(aRequest->Session());
-	return(err);
-	}
-
-TInt TFsCancelPlugin::Initialise(CFsRequest* /*aRequest*/)
-	{
-	// Notify plugin of session disconnect
-	return(KErrNone);
-	}
-
 TInt TFsSetSessionFlags::DoRequestL(CFsRequest* aRequest)
 	{
 	aRequest->Session()->SetSessionFlags(aRequest->Message().Int0(), aRequest->Message().Int1());
--- a/userlibandfileserver/fileserver/sfile/sf_std.h	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_std.h	Mon Sep 27 10:52:00 2010 +0100
@@ -35,6 +35,7 @@
 #include <f32plugin.h>
 #include "f32trace.h"
 
+
 #define __PRINT1TEMP_ALWAYS(t,a) {{TBuf<KMaxFileName>temp(a);RDebug::Print(t,&temp);}}
 #define __PRINT2TEMP_ALWAYS(t,a,b) {{TBuf<KMaxFileName>temp(b);RDebug::Print(t,a,&temp);}}
 #define __PRINT3TEMP_ALWAYS(t,a,b,c) {{TBuf<KMaxFileName>temp(c);RDebug::Print(t,a,b,&temp);}}
@@ -452,7 +453,8 @@
 	ETooManyDrivesPerSocket,
 	ENotificationFault,
 	EFsObjectOpen,
-	EContainerHeapCorruptionOnRemove
+	EContainerHeapCorruptionOnRemove,
+	ESessionOpenError,
 	};
 
 
@@ -546,7 +548,6 @@
 	void DoCancel();
 	void RunL();
 	void Dispatch(CFsRequest* aRequest);
-	void CompleteSessionRequests(CSessionFs* aSession, TInt aValue);
 private:
 	CFsSyncMessageScheduler();
 	void ConstructL();
@@ -769,7 +770,6 @@
 	{
 public:
 	void CompleteReadWriteRequests();
-	void CompleteSessionRequests(CSessionFs* aSession, TInt aValue);
 	void CompleteClientRequests(TInt aValue);
 	TBool IsRequestWriteable();
 	TBool IsSessionNotifyUser();
@@ -792,19 +792,6 @@
 
 class CFsInternalRequest;
 
-NONSHARABLE_CLASS(CDisconnectThread) : public CRequestThread
-	{
-public:
-	inline CFsInternalRequest* GetRequest();
-private:
-	static CDisconnectThread* NewL();
-	TUint StartL();
-	~CDisconnectThread();	
-private:
-	CFsInternalRequest* iRequest;
-friend class FsThreadManager;
-	};
-
 class CFsPlugin;
 NONSHARABLE_CLASS(CPluginThread) : public CRequestThread
 	{
@@ -812,8 +799,6 @@
 	CPluginThread(CFsPlugin& aPlugin, RLibrary aLibrary);
 	~CPluginThread();
 	
-	void CompleteSessionRequests(CSessionFs* aSession, TInt aValue);
-
 	/** @prototype */
 	void OperationLockWait();
 
@@ -852,9 +837,6 @@
 class FsThreadManager
 	{
 public:
-	static TInt CreateDisconnectThread();
-	static inline CDisconnectThread* GetDisconnectThread() {return(iDisconnectThread);}
-	static TBool IsDisconnectThread();
 //
 	static void SetMainThreadId();
 	static TBool IsMainThread();
@@ -879,7 +861,6 @@
 private:
 	static TFsDriveThread iFsThreads[KMaxDrives];
 	static TUint iMainId;
-	static CDisconnectThread* iDisconnectThread;
 	static TUint iDisconnectThreadId;
 	};
 
@@ -905,8 +886,11 @@
 	{
 public:
 	static CSessionFs* NewL();
-	~CSessionFs();
 	virtual void CreateL();
+
+	inline void Open();
+	void Close();
+
 	TInt CurrentDrive();
 	void ServiceL(const RMessage2& aMessage);
 	TInt CountResources();
@@ -937,6 +921,7 @@
 	void SetReservedAccess(const TInt aDriveNumber, const TBool aReservedAccess);
 private:
 	CSessionFs();
+	~CSessionFs();
 
 private:
 	TInt iResourceCountMark;
@@ -945,11 +930,11 @@
 	RFastLock iSessionFlagsLock;
 	CFsObjectIx* iHandles;
 	HBufC* iPath;
-	CFsMessageRequest* iDisconnectRequest;
 	RArray<TReservedDriveAccess> iReservedDriveAccess;
 	TThreadId iId;
 	TInt iCloseRequestCount;	// number of close requests owned by this sessions on the RequestAllocator close queue
-friend class CFsDisconnectRequest;
+	TInt iAccessCount;
+	RMessage2 iMessage;		// message passed to CSessionFs::Disconnect()
 	};
 
 NONSHARABLE_CLASS(CServerFs) : public CServer2
@@ -1011,7 +996,8 @@
 		EInternalRequest = 0x02,	// NB Not really used!
 		EParseSrc = 0x04, 
 		EParseDst = 0x08,
-		EFileShare = 0x10,			// Operates on an open file share
+		EFileShare = 0x10,			// Operates on an open file share. NB not currently used
+		EFsDspObj = 0x20,			// Bottom 32 bits of scratch value is a CFsDispatchObject
 		};
 
 class TOperation
@@ -1221,6 +1207,7 @@
 	inline TBool DirectToDrive();
 	inline TBool IsDescData(TInt aMsgNum);
 	inline TInt FsFunction();
+	void Close();	// close the session & dispatch object this request is using
 
 public:
 	CFsRequest();
@@ -1231,9 +1218,11 @@
 	inline TInt GetError() const;
 	inline void SetPostOperation(TBool aSet);
 
-	inline TBool IsFsObjectOpen();
-	inline void SetFsObjectOpen(TBool aSet);
-	void SetAndOpenScratchValue(const TInt64& aValue);
+
+	void OpenDispatchObject(const TInt64& aValue);	// open the dispatch object this request is using
+	void CloseDispatchObject();
+	void OpenSession(CSessionFs* aSession);			// open the session this request is using
+	void CloseSession();
 
 private:
 	TInt GetSlot(TFsPluginRequest::TF32ArgType aType);
@@ -1260,7 +1249,7 @@
 		EFreeChanged			= 0x02,		// valid only for EFsFileWrite
 		EPostInterceptEnabled	= 0x04,
 		EPostOperation			= 0x08,
-		EFsObjectOpen			= 0x10,
+		EFsDspObjOpen			= 0x10,		// scratch value (a CFsDispatchObject) has been opened
 		};
 	TUint iFlags;
 
@@ -1381,14 +1370,6 @@
 	TParsePool* iPoolDest;
 	};
 
-NONSHARABLE_CLASS(CFsDisconnectRequest) : public CFsMessageRequest
-	{
-public:
-	virtual void Process();
-	virtual void Dispatch();
-	virtual void Complete(TInt aError);
-	};
-
 NONSHARABLE_CLASS(CFsInternalRequest) : public CFsRequest
 	{
 public:
@@ -1721,18 +1702,14 @@
 extern SCapabilitySet DisabledCapabilities;
 
 const TInt KDispatchObjectClose=KMaxTInt-1;
-const TInt KSessionDisconnect=KMaxTInt-2;
-const TInt KCancelSession=KMaxTInt-3;
-const TInt KCancelPlugin=KMaxTInt-4;
+const TInt KSessionInternalReserved2=KMaxTInt-2;	// not used any more - placeholder
+const TInt KSessionInternalReserved3=KMaxTInt-3;	// not used any more - placeholder
+const TInt KSessionInternalReserved4=KMaxTInt-4;	// not used any more - placeholder
 const TInt KFileShareClose=KMaxTInt-5;
 const TInt KFlushDirtyData=KMaxTInt-6;
 
 const TOperation DispatchObjectCloseOp=	{KDispatchObjectClose,	EInternalRequest,	&TFsCloseObject::Initialise,		NULL,	&TFsCloseObject::DoRequestL			};
-const TOperation SessionDisconnectOp=	{KSessionDisconnect,	EInternalRequest,	&TFsSessionDisconnect::Initialise,	NULL,	&TFsSessionDisconnect::DoRequestL	};
-const TOperation CancelSessionOp=		{KCancelSession,		EInternalRequest,	&TFsCancelSession::Initialise,		NULL,	&TFsCancelSession::DoRequestL		};
-const TOperation CancelPluginOp=		{KCancelPlugin,			EInternalRequest,	&TFsCancelPlugin::Initialise,		NULL,	&TFsCancelPlugin::DoRequestL		};
 const TOperation FileShareCloseOp=		{KFileShareClose,		EInternalRequest,	&TFsCloseFileShare::Initialise,		NULL,	&TFsCloseFileShare::DoRequestL		};
-const TOperation FlushDirtyDataOp=		{KFlushDirtyData,		EInternalRequest,	&TFsFlushDirtyData::Initialise,		NULL,	&TFsFlushDirtyData::DoRequestL		};
 
 extern TBool OpenOnDriveZOnly;
 extern TBool LocalFileSystemInitialized;
--- a/userlibandfileserver/fileserver/sfile/sf_std.inl	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_std.inl	Mon Sep 27 10:52:00 2010 +0100
@@ -73,15 +73,6 @@
 TInt CFsObjectCon::Count() const 
 	{return(iCount);}
 
-// class CDisconnectThread
-CFsInternalRequest* CDisconnectThread::GetRequest() 
-	{return(iRequest);}
-
-
-
-
-
-
 
 
 // class CServerFs
@@ -112,6 +103,11 @@
 	iId = aId; 
 	}
 
+inline void CSessionFs::Open()
+	{
+	TInt oldCount = __e32_atomic_tas_ord32(&iAccessCount, 1, 1, 0);
+	__ASSERT_ALWAYS(oldCount, Fault(ESessionOpenError));
+	}
 
 // class TReservedDriveAccess
 TReservedDriveAccess::TReservedDriveAccess(TInt aDriveNumber)
@@ -181,11 +177,11 @@
 TUint CFsRequest::ScratchValue() 
 	{return I64LOW(iScratchValue);}
 void CFsRequest::SetScratchValue(const TUint aValue) 
-	{SetAndOpenScratchValue(aValue);}
+	{OpenDispatchObject(aValue);}
 TInt64 CFsRequest::ScratchValue64() 
 	{return(iScratchValue);}
 void CFsRequest::SetScratchValue64(const TInt64& aValue) 
-	{SetAndOpenScratchValue(aValue);}
+	{OpenDispatchObject(aValue);}
 TBool CFsRequest::IsSeparateThread() 
 	{return(!iOperation->IsSync());}
 TBool CFsRequest::IsPostOperation() const
@@ -217,10 +213,6 @@
 TBool CFsRequest::DirectToDrive() 
 	{ return(iDirectToDrive); }
 
-TBool CFsRequest::IsFsObjectOpen()
-	{ return iFlags & EFsObjectOpen;}
-void CFsRequest::SetFsObjectOpen(TBool aSet)
-	{aSet? iFlags |= EFsObjectOpen : iFlags &= ~EFsObjectOpen;}
 
 /**
 Returns ETrue if the IPC Message Argument slot is packed with descriptor data for
--- a/userlibandfileserver/fileserver/sfile/sf_thread.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_thread.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -31,8 +31,6 @@
 
 TFsDriveThread FsThreadManager::iFsThreads[KMaxDrives];
 TUint FsThreadManager::iMainId=0;
-CDisconnectThread* FsThreadManager::iDisconnectThread=NULL;
-TUint FsThreadManager::iDisconnectThreadId=0;
 
 TFsDriveThread::TFsDriveThread()
 //
@@ -55,34 +53,6 @@
 	__ASSERT_ALWAYS(r==KErrNone,Fault(EFsThreadConstructor));
 	}
 
-TInt FsThreadManager::CreateDisconnectThread()
-//
-// Called just once at startup
-//
-	{
-	__PRINT(_L("Create disconnect thread"));
-	TRAPD(r,iDisconnectThread=CDisconnectThread::NewL());
-	if(r!=KErrNone)
-		return(r);
-	TRAP(r,iDisconnectThreadId=iDisconnectThread->StartL());
-	if(r!=KErrNone)
-		{
-		delete(iDisconnectThread);
-		iDisconnectThread=NULL;
-		iDisconnectThreadId=0;
-		}
-	__THRD_PRINT2(_L("iDisconnectThread=0x%x id=0x%x"),iDisconnectThread,iDisconnectThreadId);
-	return(r);
-	}
-
-TBool FsThreadManager::IsDisconnectThread()
-//
-// Return ETrue if the calling thread is the disconnect thread
-//
-	{
-	return(iDisconnectThreadId==RThread().Id());
-	}
-
 
 TInt FsThreadManager::InitDrive(TInt aDrvNumber,TBool aIsSync)
 //
@@ -726,31 +696,6 @@
 	return(RThread::RenameMe(name));
 	}
 
-void CDriveThread::CompleteSessionRequests(CSessionFs* aSession, TInt aValue)
-//
-//
-//
-	{
-	__THRD_PRINT1(_L("CDriveThread::CompleteSessionReqeusts() drive=%d"),iDriveNumber);
-	iListLock.Wait();
-	TDblQueIter<CFsRequest> q(iList);
-	CFsRequest* pR;
-	while((pR=q++)!=NULL)
-		{
-		if(pR->Session()==aSession)
-			{
-			pR->iLink.Deque();
-			iListLock.Signal();
-			pR->Complete(aValue);
-			iListLock.Wait();
-			// set iterator back to head of queue in case Complete() has itself removed requests from the queue
-			q.SetToFirst();
-			}
-		}
-	iListLock.Signal();
-	__THRD_PRINT(_L("session requests completed"));
-	}
-
 
 void CDriveThread::CompleteReadWriteRequests()
 	{
@@ -865,57 +810,6 @@
 	}
 
 
-CDisconnectThread::~CDisconnectThread()
-//
-//
-//
-	{
-	if(iRequest)
-		delete(iRequest);
-	}
-
-
-CDisconnectThread* CDisconnectThread::NewL()
-//
-//
-//
-	{
-	__THRD_PRINT(_L("CDisconnectThread::NewL()"));
-	CDisconnectThread* pT=new(ELeave) CDisconnectThread;
-	TInt r=pT->Initialise();
-	if(r!=KErrNone)
-		{
-		delete(pT);
-		User::Leave(r);
-		}
-	return(pT);
-	}
-
-TUint CDisconnectThread::StartL()
-//
-//
-//
-	{
-	__PRINT(_L("CDisconnectThread::StartL()"));
-	iRequest = new(ELeave) CFsInternalRequest;
-	__THRD_PRINT1(_L("internal request = 0x%x"),iRequest);
-	iRequest->Set(CancelSessionOp,NULL);	
-	
-	RThread t;
-	TInt r=DoStart(t);
-	if(r!=KErrNone)
-		{
-		delete(iRequest);
-		iRequest=NULL;
-		User::Leave(r);
-		}
-	iRequest->SetThreadHandle(t.Handle());
-	__THRD_PRINT1(_L("CDisconnect::StartL() handle=%d"),t.Handle());
-	iRequest->SetAllocated();
-	TUint id=t.Id();
-	return(id);
-	}
-
 
 CPluginThread::CPluginThread(CFsPlugin& aPlugin, RLibrary aLibrary)
   : iPlugin(aPlugin), iLib(aLibrary)
@@ -966,23 +860,6 @@
 	return(id);
 	}
 
-void CPluginThread::CompleteSessionRequests(CSessionFs* aSession, TInt aValue)
-	{
-	__THRD_PRINT(_L("CPluginThread::CompleteSessionRequests()"));
-	iListLock.Wait();
-	TDblQueIter<CFsRequest> q(iList);
-	CFsRequest* pR;
-	while((pR=q++)!=NULL)
-		{
-		if(pR->Session()==aSession)
-			{
-			pR->iLink.Deque();
-			pR->Complete(aValue);
-			}
-		}
-	iListLock.Signal();
-	__THRD_PRINT(_L("session requests completed"));
-	}
 
 TInt CPluginThread::DoThreadInitialise()
 	{
--- a/userlibandfileserver/fileserver/sfsrv/cl_file.cpp	Wed Sep 22 10:53:45 2010 +0100
+++ b/userlibandfileserver/fileserver/sfsrv/cl_file.cpp	Mon Sep 27 10:52:00 2010 +0100
@@ -246,6 +246,7 @@
 	r = aFile.DuplicateHandle(dupSubSessionHandle);
 	if (r != KErrNone)
 		{
+		fs.Close();
 		OstTrace1(TRACE_BORDER, EFSRV_EFILEDUPLICATERETURN2, "r %d", r);
 		return r;
 		}