# HG changeset patch # User hgs # Date 1273488053 -3600 # Node ID e4a7b1cbe40c557f146f9c5bc8823ff2d423a0f3 # Parent e880629062ddfa15824ccba3e4763d822203ed45 201019_01 diff -r e880629062dd -r e4a7b1cbe40c bsptemplate/asspandvariant/template_variant/hal/config.hcf --- a/bsptemplate/asspandvariant/template_variant/hal/config.hcf Wed May 05 05:11:16 2010 +0100 +++ b/bsptemplate/asspandvariant/template_variant/hal/config.hcf Mon May 10 11:40:53 2010 +0100 @@ -99,3 +99,4 @@ ECustomResourceDrive : set = 0 EDisplayNumberOfScreens=0 ENumCpus=GetNumCpus +EDigitiserOrientation : set = DigitiserOrientation diff -r e880629062dd -r e4a7b1cbe40c halservices/hal/inc/hal_data.h --- a/halservices/hal/inc/hal_data.h Wed May 05 05:11:16 2010 +0100 +++ b/halservices/hal/inc/hal_data.h Mon May 10 11:40:53 2010 +0100 @@ -1110,6 +1110,13 @@ */ ENumCpus, + /** + The orientation of the Digitiser. Usually mirrors device orientation. + + @see TDigitiserOrientation for allowed values + @capability WriteDeviceData needed to Set this attribute + */ + EDigitiserOrientation, /* * NOTE: @@ -1328,6 +1335,29 @@ EPowerBackupStatus_Good, }; + + /** + Describes the orientation of the screen digitiser, usually mirrors the + device orientation not necessarily the display rotation as this might be + limited to upright and left 90 only. The values in degrees measures + the anti-clockwise angle from the left edge of the digitiser from the + normal default position of the device. + + User-side clients can use attribute to inform the digitiser driver of the + digitiser orientation. The driver may then use this information to adjust + X.Y sampling depending on input pointer type. + + @see HALData::TAttribute + */ + enum TDigitiserOrientation + { + EDigitiserOrientation_default, ///< Driver using build-in default + EDigitiserOrientation_000, ///< Device normal 'make-call' position + EDigitiserOrientation_090, ///< Device rotated left 90 degrees + EDigitiserOrientation_180, ///< Device rotated 180 degrees + EDigitiserOrientation_270 ///< Device rotated right 90 degrees + }; + }; #endif diff -r e880629062dd -r e4a7b1cbe40c halservices/hal/rom/hal.hby --- a/halservices/hal/rom/hal.hby Wed May 05 05:11:16 2010 +0100 +++ b/halservices/hal/rom/hal.hby Mon May 10 11:40:53 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" @@ -139,3 +139,5 @@ #define ESerialNumber 117 #define ECpuProfilingDefaultInterruptBase 118 #define ENumCpus 119 +#define EDigitiserOrientation 120 + diff -r e880629062dd -r e4a7b1cbe40c halservices/hal/src/userhal.cpp --- a/halservices/hal/src/userhal.cpp Wed May 05 05:11:16 2010 +0100 +++ b/halservices/hal/src/userhal.cpp Mon May 10 11:40:53 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 1999-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" @@ -41,7 +41,8 @@ EInvalidAttribKeybd=13, EInvalidAttribPen=14, EInvalidAttribMouse=15, - EInvalidAttrib3DPointer=16 + EInvalidAttrib3DPointer=16, + EInvalidAttribDigitiserOrientation=17 }; void Panic(THalUserHalPanic aPanic) @@ -929,3 +930,27 @@ return KErrNone; } +// EDigitiserOrientation +#if defined(_DEBUG) +TInt DigitiserOrientation(TInt aDeviceNumber, TInt aAttrib, TBool aSet, TAny* aInOut) +#else +TInt DigitiserOrientation(TInt aDeviceNumber, TInt /*aAttrib*/, TBool aSet, TAny* aInOut) +#endif + { + __ASSERT_DEBUG(aAttrib == HALData::EDigitiserOrientation, Panic(EInvalidAttribDigitiserOrientation)); + __ASSERT_DEBUG(aDeviceNumber >= 0, Panic(EInvalidAttribDigitiserOrientation)); + + if (aSet) + { + //Set + if ( ((TInt)aInOut) < 0 || ((TInt)aInOut) > HALData::EDigitiserOrientation_270) + return KErrArgument; + return UserSvr::HalFunction(EHalGroupDigitiser, EDigitiserOrientation, aInOut, (TAny*)ETrue, aDeviceNumber); + } + + //Get + __ASSERT_DEBUG(aInOut != 0, Panic(EInvalidAttribDigitiserOrientation)); + return UserSvr::HalFunction(EHalGroupDigitiser, EDigitiserOrientation, aInOut, (TAny*)EFalse, aDeviceNumber); + } + + diff -r e880629062dd -r e4a7b1cbe40c halservices/hal/tsrc/t_newhal.cpp --- a/halservices/hal/tsrc/t_newhal.cpp Wed May 05 05:11:16 2010 +0100 +++ b/halservices/hal/tsrc/t_newhal.cpp Mon May 10 11:40:53 2010 +0100 @@ -144,7 +144,7 @@ _S("ESerialNumber"), _S("ECpuProfilingDefaultInterruptBase"), _S("ENumCpus"), - + _S("EDigitiserOrientation") }; TInt MatchAbbrev(const TDesC& anInput, const TText** aList, TInt aListLen) @@ -159,7 +159,7 @@ if (r>=0) { // substring matches - if (r==0 && list_entry.Length()==anInput.Length()) + if (r==0 && list_entry.Length()==anInput.Length()) { // exact match return i; diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/bmarm/ekernsmp.def --- a/kernel/eka/bmarm/ekernsmp.def Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/bmarm/ekernsmp.def Mon May 10 11:40:53 2010 +0100 @@ -1053,4 +1053,6 @@ Stats__13KernCoreStatsPv @ 1052 NONAME R3UNUSED ; KernCoreStats::Stats(void *) SetNumberOfActiveCpus__5NKerni @ 1053 NONAME SetIdleHandler__3ArmPFPvUlPVv_vPv @ 1054 NONAME R3UNUSED ; Arm::SetIdleHandler(void (*)(void *, unsigned long, void volatile *), void *) + FreeRamZone__4EpocUi @ 1055 NONAME R3UNUSED ; Epoc::FreeRamZone(unsigned int) + SelectiveAlloc__16TBitMapAllocatorii @ 1056 NONAME R3UNUSED ; TBitMapAllocator::SelectiveAlloc(int, int) diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/bmarm/ekernu.def --- a/kernel/eka/bmarm/ekernu.def Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/bmarm/ekernu.def Mon May 10 11:40:53 2010 +0100 @@ -1050,3 +1050,5 @@ Retire__13KernCoreStatsii @ 1049 NONAME R3UNUSED ; KernCoreStats::Retire(int, int) Stats__13KernCoreStatsPv @ 1050 NONAME R3UNUSED ; KernCoreStats::Stats(void *) SetIdleHandler__3ArmPFPvUl_vPv @ 1051 NONAME R3UNUSED ; Arm::SetIdleHandler(void (*)(void *, unsigned long), void *) + FreeRamZone__4EpocUi @ 1052 NONAME R3UNUSED ; Epoc::FreeRamZone(unsigned int) + SelectiveAlloc__16TBitMapAllocatorii @ 1053 NONAME R3UNUSED ; TBitMapAllocator::SelectiveAlloc(int, int) diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/bwins/ekernu.def --- a/kernel/eka/bwins/ekernu.def Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/bwins/ekernu.def Mon May 10 11:40:53 2010 +0100 @@ -934,4 +934,5 @@ ?Engage@KernCoreStats@@SAHH@Z @ 933 NONAME ; public: static int KernCoreStats::Engage(int) ?Retire@KernCoreStats@@SAHHH@Z @ 934 NONAME ; public: static int KernCoreStats::Retire(int, int) ?Stats@KernCoreStats@@SAHPAX@Z @ 935 NONAME ; public: static int KernCoreStats::Stats(void *) + ?SelectiveAlloc@TBitMapAllocator@@QAEIHH@Z @ 936 NONAME ; public: unsigned int __thiscall TBitMapAllocator::SelectiveAlloc(int,int) diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/bx86/ekernsmp.def --- a/kernel/eka/bx86/ekernsmp.def Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/bx86/ekernsmp.def Mon May 10 11:40:53 2010 +0100 @@ -1010,4 +1010,6 @@ ?Retire@KernCoreStats@@SAHHH@Z @ 1009 NONAME ; public: static int KernCoreStats::Retire(int, int) ?Stats@KernCoreStats@@SAHPAX@Z @ 1010 NONAME ; public: static int KernCoreStats::Stats(void *) ?SetNumberOfActiveCpus@NKern@@SAXH@Z @ 1011 NONAME ; public: static void __cdecl NKern::SetNumberOfActiveCpus(int) + ?FreeRamZone@Epoc@@SAHI@Z @ 1012 NONAME ; public: static int Epoc::FreeRamZone(unsigned int) + ?SelectiveAlloc@TBitMapAllocator@@QAEIHH@Z @ 1013 NONAME ; public: unsigned int __thiscall TBitMapAllocator::SelectiveAlloc(int,int) diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/bx86/ekernu.def --- a/kernel/eka/bx86/ekernu.def Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/bx86/ekernu.def Mon May 10 11:40:53 2010 +0100 @@ -955,4 +955,6 @@ ?LeaveIdle@KernCoreStats@@SAXI@Z @ 954 NONAME ; public: static void KernCoreStats::LeaveIdle(unsigned int) ?Retire@KernCoreStats@@SAHHH@Z @ 955 NONAME ; public: static int KernCoreStats::Retire(int, int) ?Stats@KernCoreStats@@SAHPAX@Z @ 956 NONAME ; public: static int KernCoreStats::Stats(void *) + ?FreeRamZone@Epoc@@SAHI@Z @ 957 NONAME ; public: static int Epoc::FreeRamZone(unsigned int) + ?SelectiveAlloc@TBitMapAllocator@@QAEIHH@Z @ 958 NONAME ; public: unsigned int __thiscall TBitMapAllocator::SelectiveAlloc(int,int) diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/bx86gcc/ekernsmp.def --- a/kernel/eka/bx86gcc/ekernsmp.def Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/bx86gcc/ekernsmp.def Mon May 10 11:40:53 2010 +0100 @@ -1098,4 +1098,6 @@ _ZN13KernCoreStats6RetireEii @ 1097 NONAME _ZN13KernCoreStats9ConfigureEj @ 1098 NONAME _ZN5NKern21SetNumberOfActiveCpusEi @ 1099 NONAME + _ZN4Epoc11FreeRamZoneEj @ 1100 NONAME + _ZN16TBitMapAllocator14SelectiveAllocEii @ 1101 NONAME diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/bx86gcc/ekernu.def --- a/kernel/eka/bx86gcc/ekernu.def Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/bx86gcc/ekernu.def Mon May 10 11:40:53 2010 +0100 @@ -1038,4 +1038,6 @@ _ZN13KernCoreStats9ConfigureEj @ 1037 NONAME _ZN13KernCoreStats9EnterIdleEv @ 1038 NONAME _ZN13KernCoreStats9LeaveIdleEj @ 1039 NONAME + _ZN4Epoc11FreeRamZoneEj @ 1040 NONAME + _ZN16TBitMapAllocator14SelectiveAllocEii @ 1041 NONAME diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/drivers/power/smppower/idlehelper.cia --- a/kernel/eka/drivers/power/smppower/idlehelper.cia Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/drivers/power/smppower/idlehelper.cia Mon May 10 11:40:53 2010 +0100 @@ -85,12 +85,12 @@ LDREX(3,1); // r3 = iIdlingCpus asm("orr r3,r0,r3"); // orr in mask for this CPU asm("cmp r3,r2"); // compare to iAllEngagedCpusMask - asm("orreq r3,r3,#%a0" : : "i" (TIdleSupport::KGlobalIdleFlag)); // if equal orr in KGlobalIdleFlag + asm("orreq r3,r3,#%a0" : : "i" ((TUint32)TIdleSupport::KGlobalIdleFlag)); // if equal orr in KGlobalIdleFlag STREX(12,3,1); asm("cmp r12, #0 "); // asm("bne 1b "); // write didn't succeed try again __DATA_MEMORY_BARRIER__(r12); - asm("and r0,r3,#%a0" : : "i" (TIdleSupport::KGlobalIdleFlag)); + asm("and r0,r3,#%a0" : : "i" ((TUint32)TIdleSupport::KGlobalIdleFlag)); __JUMP(,lr); asm("__iAllEngagedCpusMask:"); asm(".word %a0" : : "i" ((TInt)&TIdleSupport::iAllEngagedCpusMask));// @@ -125,7 +125,7 @@ asm("stmfd sp!, {r4-r5,lr} "); asm("add r0,r0,#%a0" : : "i" _FOFF(TSyncPointBase, iStageAndCPUWaitingMask)); // skip vt asm("ldr r4,[r0,#4]"); - asm("ldr r4,[r4]") + asm("ldr r4,[r4]"); __DATA_MEMORY_BARRIER_Z__(r12); // asm("1: "); LDREX(2,0); // r2 = iStageAndCPUWaitingMask, r4 = iAllEnagedCpusMask @@ -149,7 +149,7 @@ #endif asm("2: "); asm("cmp r3,r5"); // all (old stage does not equal new stage) - asm("ldmfdne sp!, {r4-r5,pc}"); // yup return + asm("bne 3f"); // yup return #ifdef SYNCPOINT_WFE __DATA_MEMORY_BARRIER__(r12); ARM_WFE; @@ -158,6 +158,8 @@ __DATA_MEMORY_BARRIER__(r12); // ensure read is observed asm("mov r3,r2,lsr #16"); // re-read new stage asm("b 2b"); // loop back + asm("3: "); + asm("ldmfd sp!, {r4-r5,pc}"); // return } /** @@ -188,7 +190,7 @@ asm("stmfd sp!, {r4,lr} "); asm("add r0,r0,#%a0" : : "i" _FOFF(TSyncPointBase, iStageAndCPUWaitingMask)); // skip vt asm("ldr r4,[r0,#4]"); - asm("ldr r4,[r4]") + asm("ldr r4,[r4]"); __DATA_MEMORY_BARRIER_Z__(r12); // asm("1: "); LDREX(2,0); // r2 = iStageAndCPUWaitingMask, r4 = iAllEnagedCpusMask @@ -208,7 +210,7 @@ #endif asm("2: "); asm("ands r3,r2,#0x80000000"); // MSB set? - asm("ldmfdne sp!, {r4,pc}"); // yup return + asm("bne 4f"); // yup return #ifdef SYNCPOINT_WFE __DATA_MEMORY_BARRIER__(r12); ARM_WFE; @@ -222,7 +224,8 @@ __DATA_MEMORY_BARRIER__(r12); // ensure that's written ARM_SEV; #endif - asm("ldmfd sp!, {r4,pc}"); // yup return + asm("4:"); + asm("ldmfd sp!, {r4,pc}"); // return } @@ -292,7 +295,7 @@ } #endif -__NAKED__ TInt TIdleSupport::IntPending() +__NAKED__ TUint32 TIdleSupport::IntPending() { asm("ldr r1,__KCPUIFAddr");//r1 = address of iBaseIntIfAddress asm("ldr r1, [r1]");//r1 = address of Hw GIC CPU interrupt interface base address diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/drivers/power/smppower/sample_idlehandler/smpidlehandler.cpp --- a/kernel/eka/drivers/power/smppower/sample_idlehandler/smpidlehandler.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/drivers/power/smppower/sample_idlehandler/smpidlehandler.cpp Mon May 10 11:40:53 2010 +0100 @@ -41,6 +41,11 @@ } +DSMPIdleHandler::~DSMPIdleHandler() + { + } + + /** To be called after construction in a thread context with interrupts enabled. Power extension entry point ideal @pre thread context ints enable no kernel locks or fast mutexes diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/drivers/xyin/d_xyin.cpp --- a/kernel/eka/drivers/xyin/d_xyin.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/drivers/xyin/d_xyin.cpp Mon May 10 11:40:53 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" @@ -19,6 +19,7 @@ #include #include +#include _LIT(KLitDigitiser,"Digitiser"); @@ -50,7 +51,8 @@ : DPowerHandler(KLitDigitiser), iMsgQ(rxMsg,this,NULL,1), iSampleDfc(sampleDfc,this,5), - iPenUpDfc(penUpDfc,this,5) + iPenUpDfc(penUpDfc,this,5), + iOrientation(HALData::EDigitiserOrientation_default) { // iBufferIndex=0; // iLastPos=TPoint(0,0); @@ -358,6 +360,26 @@ case EDigitiserHalXYState: kumemput32(a1, (TBool*)&iPointerOn, sizeof(TBool)); break; + + // a2 = TBool aSet (ETrue for setting, EFalse for retrieval) + // a1 = TDigitizerOrientation (set) + // a1 = &TDigitizerOrientation (get) + case EDigitiserOrientation: + if ((TBool)a2) + { + // Set the orientation attribute + // In case user thread, check it has WDD capability + if(!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDigitiserOrientation"))) + return KErrPermissionDenied; + iOrientation = (TInt)a1; + } + else + { + // Get the orientation attribute, safe copy it into user memory + kumemput32(a1, &iOrientation, sizeof(TInt)); + } + break; + default: r=KErrNotSupported; break; diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/eabi/ekernsmp.def --- a/kernel/eka/eabi/ekernsmp.def Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/eabi/ekernsmp.def Mon May 10 11:40:53 2010 +0100 @@ -1187,4 +1187,6 @@ _ZN13KernCoreStats9ConfigureEj @ 1186 NONAME _ZN5NKern21SetNumberOfActiveCpusEi @ 1187 NONAME _ZN3Arm14SetIdleHandlerEPFvPvmPVvES0_ @ 1188 NONAME + _ZN4Epoc11FreeRamZoneEj @ 1189 NONAME + _ZN16TBitMapAllocator14SelectiveAllocEii @ 1190 NONAME diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/eabi/ekernu.def --- a/kernel/eka/eabi/ekernu.def Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/eabi/ekernu.def Mon May 10 11:40:53 2010 +0100 @@ -1179,4 +1179,6 @@ _ZN13KernCoreStats9EnterIdleEv @ 1178 NONAME _ZN13KernCoreStats9LeaveIdleEj @ 1179 NONAME _ZN3Arm14SetIdleHandlerEPFvPvmES0_ @ 1180 NONAME + _ZN4Epoc11FreeRamZoneEj @ 1181 NONAME + _ZN16TBitMapAllocator14SelectiveAllocEii @ 1182 NONAME diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/include/d32usbdi_errors.h --- a/kernel/eka/include/d32usbdi_errors.h Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/include/d32usbdi_errors.h Mon May 10 11:40:53 2010 +0100 @@ -201,6 +201,7 @@ EUsbDevMonDeviceAttachDenied = 41, EUsbHubDriverZeroInterfaceTokenProduced = 42, EUsbInterfaceSuccessfulPipeOpenWithNoPipe = 43, + EFailedToLockHostStackInWaitDeviceStateMutex = 44, }; _LIT(KUsbDescFaultCat, "USBDesc-Fault"); diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/include/drivers/dma_v1.h --- a/kernel/eka/include/drivers/dma_v1.h Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/include/drivers/dma_v1.h Mon May 10 11:40:53 2010 +0100 @@ -349,27 +349,66 @@ virtual void DoUnlink(SDmaDesHdr& aHdr); virtual void DoDfc(DDmaRequest& aCurReq, SDmaDesHdr*& aCompletedHdr) = 0; /** - This function allows the Platform Specific Layer (PSL) to control the - power management of the channel or its controller by overriding the - PIL's default implementation (which does nothing) and making appropriate - use of the Power Resource Manager (PRM). + This function allows the Platform Specific Layer (PSL) to control the + power management of the channel or its controller by overriding the + PIL's default implementation (which does nothing) and making + appropriate use of the Power Resource Manager (PRM). + + The function gets called by the PIL whenever the channel's queued + requests count has changed in a significant way, either before the + channel's Transfer() method is invoked for a request on a previously + empty request queue, or immediately after the request count has become + zero because of request cancellation or completion. + + Depending on the current and previous observed values of + iQueuedRequests, the PSL may power down or power up the channel. - The function gets called by the PIL whenever the channel's queued - requests count has changed in a significant way, either before the - channel's Transfer() method is invoked for a request on a previously - empty request queue, or immediately after the request count has become - zero because of request cancellation or completion. + Note that iQueuedRequests gets accessed and changed by different + threads, so the PSL needs to take the usual precautions when evaluating + the variable's value. Also, due to the multithreaded framework + architecture, there is no guarantee that the function calls always + arrive at the PSL level in the strict chronological order of + iQueuedRequests being incremented/decremented in the PIL, i.e. it might + happen that the PSL finds iQueuedRequests to have the same value in two + or more consecutive calls (that's why the previous observed value needs + to be locally available and taken into account). It is however promised + that before any actual transfer commences the PSL will find the request + count to be greater than zero and that after the last request has + finished it will be found to be zero. + + None of the internal DMA framework mutexes is being held by the PIL + when calling this function. - Depending on the current value of iQueuedRequests, the PSL may power - down or power up the channel. Note that iQueuedRequests gets accessed - and changed by different threads, so the PSL needs to take the usual - precautions when evaluating the variable's value. + Here is an example implementation for a derived channel class: + + @code + + class TFooDmaChannel : public TDmaSgChannel + { + DMutex* iDmaMutex; + TInt iPrevQueuedRequests; + virtual void QueuedRequestCountChanged(); + }; - None of the internal DMA framework mutexes is being held by the PIL when - calling this function. + void TFooDmaChannel::QueuedRequestCountChanged() + { + Kern::MutexWait(*iDmaMutex); + if ((iQueuedRequests > 0) && (iPrevQueuedRequests == 0)) + { + IncreasePowerCount(); // Base port specific + } + else if ((iQueuedRequests == 0) && (iPrevQueuedRequests > 0)) + { + DecreasePowerCount(); // Base port specific + } + iPrevQueuedRequests = iQueuedRequests; + Kern::MutexSignal(*iDmaMutex); + } - @see iQueuedRequests - */ + @endcode + + @see iQueuedRequests + */ virtual void QueuedRequestCountChanged(); #if defined(__CPU_ARM) && !defined(__EABI__) inline virtual ~TDmaChannel() {} // kill really annoying warning diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/include/drivers/dma_v2.h --- a/kernel/eka/include/drivers/dma_v2.h Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/include/drivers/dma_v2.h Mon May 10 11:40:53 2010 +0100 @@ -1197,14 +1197,53 @@ empty request queue, or immediately after the request count has become zero because of request cancellation or completion. - Depending on the current value of iQueuedRequests, the PSL may power - down or power up the channel. Note that iQueuedRequests gets accessed - and changed by different threads, so the PSL needs to take the usual - precautions when evaluating the variable's value. + Depending on the current and previous observed values of + iQueuedRequests, the PSL may power down or power up the channel. + + Note that iQueuedRequests gets accessed and changed by different + threads, so the PSL needs to take the usual precautions when evaluating + the variable's value. Also, due to the multithreaded framework + architecture, there is no guarantee that the function calls always + arrive at the PSL level in the strict chronological order of + iQueuedRequests being incremented/decremented in the PIL, i.e. it might + happen that the PSL finds iQueuedRequests to have the same value in two + or more consecutive calls (that's why the previous observed value needs + to be locally available and taken into account). It is however promised + that before any actual transfer commences the PSL will find the request + count to be greater than zero and that after the last request has + finished it will be found to be zero. None of the internal DMA framework mutexes is being held by the PIL when calling this function. + Here is an example implementation for a derived channel class: + + @code + + class TFooDmaChannel : public TDmaSgChannel + { + DMutex* iDmaMutex; + TInt iPrevQueuedRequests; + virtual void QueuedRequestCountChanged(); + }; + + void TFooDmaChannel::QueuedRequestCountChanged() + { + Kern::MutexWait(*iDmaMutex); + if ((iQueuedRequests > 0) && (iPrevQueuedRequests == 0)) + { + IncreasePowerCount(); // Base port specific + } + else if ((iQueuedRequests == 0) && (iPrevQueuedRequests > 0)) + { + DecreasePowerCount(); // Base port specific + } + iPrevQueuedRequests = iQueuedRequests; + Kern::MutexSignal(*iDmaMutex); + } + + @endcode + @see iQueuedRequests */ virtual void QueuedRequestCountChanged(); diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/include/drivers/smppower/idlehelper.h --- a/kernel/eka/include/drivers/smppower/idlehelper.h Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/include/drivers/smppower/idlehelper.h Mon May 10 11:40:53 2010 +0100 @@ -1,24 +1,26 @@ /* * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. -* This component and the accompanying materials are made available -* under the terms of "Eclipse Public License v1.0" -* which accompanies this distribution, and is available -* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* This material, including documentation and any related computer +* programs, is protected by copyright controlled by Nokia. All +* rights are reserved. Copying, including reproducing, storing +* adapting or translating, any or all of this material requires the +* prior written consent of Nokia. This material also contains +* confidential information which may not be disclosed to others +* without the prior written consent of Nokia. * * Initial Contributors: * Nokia Corporation - initial contribution. * * Contributors: * -* Description: +* Description: * os\kernelhwsrv\kernel\eka\include\drivers\smpidlehelper.h * Helper classes required to implement CPU idle * functionality in a SMP BSP. * */ - /** @file @prototype @@ -174,7 +176,7 @@ static void ClearIdleIPI(); static void DoWFI();//puts current CPU in wait for interrupt state static TBool IsIntPending(); - static TInt IntPending(); + static TUint32 IntPending(); static TUint32 GetTimerCount();//HW timer can be used for tracing //Atomic checks used to synchronise cores going idle static TBool ClearLocalAndCheckGlobalIdle(TUint32); diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/include/drivers/smppower/sample_idlehandler/smpidlehandler.h --- a/kernel/eka/include/drivers/smppower/sample_idlehandler/smpidlehandler.h Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/include/drivers/smppower/sample_idlehandler/smpidlehandler.h Mon May 10 11:40:53 2010 +0100 @@ -1,24 +1,26 @@ /* * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. -* This component and the accompanying materials are made available -* under the terms of "Eclipse Public License v1.0" -* which accompanies this distribution, and is available -* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* This material, including documentation and any related computer +* programs, is protected by copyright controlled by Nokia. All +* rights are reserved. Copying, including reproducing, storing +* adapting or translating, any or all of this material requires the +* prior written consent of Nokia. This material also contains +* confidential information which may not be disclosed to others +* without the prior written consent of Nokia. * * Initial Contributors: * Nokia Corporation - initial contribution. * * Contributors: * -* Description: +* Description: * os/kernelhwsrv/kernel/eka/include/drivers/smppower/sample_idlehandler/smpidlehandler.h * Example of a generic idle handler layer * */ - #ifndef __SMPIDLEHANDLER_H__ #define __SMPIDLEHANDLER_H__ @@ -41,6 +43,8 @@ DSMPIdleHandler(); + virtual ~DSMPIdleHandler(); + /* called to init and bind the idle handler. After this call idle will be directed to idle handler @pre thread context, no locks no fast mutexes, interrupt on diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/include/drivers/xyin.h --- a/kernel/eka/include/drivers/xyin.h Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/include/drivers/xyin.h Mon May 10 11:40:53 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" @@ -27,6 +27,7 @@ #include #include + #ifdef _DEBUG //#define __DIGITISER_DEBUG1__ //#define __DIGITISER_DEBUG2__ @@ -180,6 +181,7 @@ TState iState; TInt iCount; TUint8 iPointerOn; + TInt iOrientation; // HALData::TDigitizerOrientation }; diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/include/e32ver.h --- a/kernel/eka/include/e32ver.h Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/include/e32ver.h Mon May 10 11:40:53 2010 +0100 @@ -28,7 +28,7 @@ const TInt KE32MajorVersionNumber=2; const TInt KE32MinorVersionNumber=0; -const TInt KE32BuildVersionNumber=3076; +const TInt KE32BuildVersionNumber=3079; const TInt KMachineConfigurationMajorVersionNumber=1; const TInt KMachineConfigurationMinorVersionNumber=0; diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/include/kernel/kbma.h --- a/kernel/eka/include/kernel/kbma.h Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/include/kernel/kbma.h Mon May 10 11:40:53 2010 +0100 @@ -39,6 +39,7 @@ IMPORT_C void Free(TInt aPos); IMPORT_C void Alloc(TInt aStart, TInt aLength); IMPORT_C void Free(TInt aStart, TInt aLength); + IMPORT_C TUint SelectiveAlloc(TInt aStart, TInt aLength); IMPORT_C void SelectiveFree(TInt aStart, TInt aLength); IMPORT_C TBool NotFree(TInt aStart, TInt aLength) const; IMPORT_C TBool NotAllocated(TInt aStart, TInt aLength) const; diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/include/kernel/kern_priv.h --- a/kernel/eka/include/kernel/kern_priv.h Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/include/kernel/kern_priv.h Mon May 10 11:40:53 2010 +0100 @@ -2787,6 +2787,7 @@ static TUint NumberOfFreeDpPages(); static TUint NumberOfDirtyDpPages(); static TInt MovePage(TPhysAddr aOld, TPhysAddr& aNew, TUint aBlockZoneId, TBool aBlockRest); + static TInt MoveAndAllocPage(TPhysAddr aAddr, TZonePageType aPageType); static TInt DiscardPage(TPhysAddr aAddr, TUint aBlockZoneId, TBool aBlockRest); static void RamZoneClaimed(SZone* aZone); static TInt RamDefragFault(TAny* aExceptionInfo); diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/include/memmodel/epoc/mmubase/mmubase.h --- a/kernel/eka/include/memmodel/epoc/mmubase/mmubase.h Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/include/memmodel/epoc/mmubase/mmubase.h Mon May 10 11:40:53 2010 +0100 @@ -410,6 +410,7 @@ TInt ZoneAllocPhysicalRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aNumPages, TPhysAddr* aPageList); TInt FreePhysicalRam(TPhysAddr aPhysAddr, TInt aSize); TInt FreePhysicalRam(TInt aNumPages, TPhysAddr* aPageList); + TInt FreeRamZone(TUint aZoneId, TPhysAddr& aZoneBase, TUint& aZoneBytes); TInt ClaimPhysicalRam(TPhysAddr aPhysAddr, TInt aSize); TInt GetPageTableId(TPhysAddr aPtPhys); void MapRamPage(TLinAddr aAddr, TPhysAddr aPage, TPte aPtePerm); @@ -525,8 +526,8 @@ public: TInt AllocRamPages(TPhysAddr* aPageList, TInt aNumPages, TZonePageType aPageType, TUint aBlockedZoneId=KRamZoneInvalidId, TBool aBlockRest=EFalse); TInt ZoneAllocRamPages(TUint* aZoneIdList, TUint aZoneIdCount, TPhysAddr* aPageList, TInt aNumPages, TZonePageType aPageType); - TInt AllocContiguousRam(TInt aSize, TPhysAddr& aPhysAddr, TZonePageType aPageType, TInt aAlign, TUint aBlockedZoneId=KRamZoneInvalidId, TBool aBlockRest=EFalse); - TInt ZoneAllocContiguousRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aSize, TPhysAddr& aPhysAddr, TZonePageType aPageType, TInt aAlign); + TInt AllocContiguousRam(TInt aSize, TPhysAddr& aPhysAddr, TInt aAlign); + TInt ZoneAllocContiguousRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aSize, TPhysAddr& aPhysAddr, TInt aAlign); public: TInt iPageSize; // page size in bytes diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/include/memmodel/epoc/mmubase/ramalloc.h --- a/kernel/eka/include/memmodel/epoc/mmubase/ramalloc.h Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/include/memmodel/epoc/mmubase/ramalloc.h Mon May 10 11:40:53 2010 +0100 @@ -142,8 +142,14 @@ void FreeRamPages(TPhysAddr* aPageList, TInt aNumPages, TZonePageType aType); TInt AllocRamPages(TPhysAddr* aPageList, TInt aNumPages, TZonePageType aType, TUint aBlockedZoneId=KRamZoneInvalidId, TBool aBlockRest=EFalse); TInt ZoneAllocRamPages(TUint* aZoneIdList, TUint aZoneIdCount, TPhysAddr* aPageList, TInt aNumPages, TZonePageType aType); - TInt AllocContiguousRam(TUint aNumPages, TPhysAddr& aPhysAddr, TZonePageType aType, TInt aAlign=0, TUint aBlockZoneId=KRamZoneInvalidId, TBool aBlockRest=EFalse); - TInt ZoneAllocContiguousRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aSize, TPhysAddr& aPhysAddr, TZonePageType aType, TInt aAlign); + TInt AllocContiguousRam(TUint aNumPages, TPhysAddr& aPhysAddr, TInt aAlign=0); +#if !defined(__MEMMODEL_MULTIPLE__) && !defined(__MEMMODEL_MOVING__) + void BlockContiguousRegion(TPhysAddr aAddrBase, TUint aNumPages); + void UnblockSetAllocRuns(TUint& aOffset1, TUint& aOffset2, TUint aRunLength1, TUint aRunLength2, TUint& aAllocLength, TUint& aAllocStart); + void UnblockContiguousRegion(TPhysAddr aAddrBase, TUint aNumPages); + TBool ClearContiguousRegion(TPhysAddr aAddrBase, TPhysAddr aZoneBase, TUint aNumPages, TInt& aOffset); +#endif + TInt ZoneAllocContiguousRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aSize, TPhysAddr& aPhysAddr, TInt aAlign); #ifdef _DEBUG void DebugDump(); #endif @@ -153,11 +159,12 @@ TInt GetZonePageCount(TUint aId, SRamZonePageCount& aPageData); void ChangePageType(SPageInfo* aPageInfo, TZonePageType aOldType, TZonePageType aNewType); #ifdef BTRACE_RAM_ALLOCATOR - void SendInitialBtraceLogs(void); + void DoBTracePrime(void); #endif TInt GetZoneAddress(TUint aZoneId, TPhysAddr& aPhysBase, TUint& aNumPages); TInt HalFunction(TInt aFunction, TAny* a1, TAny* a2); TInt NextAllocatedPage(SZone* aZone, TUint& aOffset, TZonePageType aType) const; + TInt NextAllocatedRun(SZone* aZone, TUint& aOffset, TUint aEndOffset, TZonePageType aType) const; TUint GenDefragFreePages(TZonePageType aType) const; SZone* GeneralDefragStart0(TGenDefragStage& aStage, TUint& aRequiredToBeDiscarded); SZone* GeneralDefragNextZone0(); @@ -205,9 +212,7 @@ SDblQueLink* iZoneGeneralPrefLink; /**< Link to the current RAM zone being defragged*/ SDblQueLink* iZoneGeneralTmpLink; /**< Link to the current RAM zone being defragged*/ TUint iZoneGeneralStage; /**< The current stage of any general defrag operation*/ -#ifdef _DEBUG - TBool iAllowBmaVerify; -#endif + TUint iContiguousReserved; /**< The count of the number of separate contiguous allocations that have reserved pages*/ }; #endif diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/include/u32hal.h --- a/kernel/eka/include/u32hal.h Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/include/u32hal.h Mon May 10 11:40:53 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 1995-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" @@ -2015,7 +2015,23 @@ @see TPckgBuf @see TDigitiserInfoV02 */ - EDigitiserHal3DInfo + EDigitiserHal3DInfo, + + /** + Get or sets the digitiser driver's current orientation property. + Requirements of the HAL function handler's 2nd, 3rd and 4th parameters: + + - TInt aFunction : This enum value. + - TAny* a1 : if Set, a TDigitiserOrientation value the driver should now use + : If Get, a pointer to a TDigitiserOrientation. The HAL function + : needs to set its value to the current value used in the driver. + - TAny* a2 : Cast to a TInt. Should be assigned the value + : EFalse - Get property; ETrue - Set property + + @see HALData::TDigitiserOrientation + @capability WriteDeviceData To set the property, None to read + */ + EDigitiserOrientation }; diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/klib/bma.cpp --- a/kernel/eka/klib/bma.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/klib/bma.cpp Mon May 10 11:40:53 2010 +0100 @@ -762,6 +762,49 @@ } +/** Allocates a specific range of bit positions. + + The specified range must lie within the total range for this allocator but it is + not necessary that all the positions are currently free. + + @param aStart First position to allocate. + @param aLength Number of consecutive positions to allocate, must be >0. + @return The number of previously free positions that were allocated. + */ +EXPORT_C TUint TBitMapAllocator::SelectiveAlloc(TInt aStart, TInt aLength) + { + __ASSERT_ALWAYS(TUint(aStart) < TUint(iSize), TBMA_FAULT()); + __ASSERT_ALWAYS(TUint(aStart + aLength) >= TUint(aStart), TBMA_FAULT()); + __ASSERT_ALWAYS(TUint(aStart + aLength) <= TUint(iSize), TBMA_FAULT()); + TInt wix = aStart >> 5; + TInt sbit = aStart & 31; + TUint32* pW = iMap + wix; + iAvail -= aLength; // update free count assuming no positions already allocated + TInt ebit = sbit + aLength; + if (ebit < 32) + { + TUint32 b = ((0xffffffffu >> aLength) >> sbit) | ~(0xffffffffu >> sbit); + TUint32 w = *pW; + *pW = w & b; // mark all positions allocated + TUint allocated = __e32_bit_count_32(~w & ~b); + iAvail += allocated; // increase free count by number of positions already allocated + return aLength - allocated; + } + TUint32 b = ~(0xffffffffu >> sbit); + while (ebit > 0) + { + TUint32 w = *pW; + *pW++ = w & b; // mark all positions allocated + TUint allocated = __e32_bit_count_32(~w & ~b); + iAvail += allocated; // increase free count by number of positions already allocated + aLength -= allocated; + ebit -= 32; + b = (ebit >= 32)? 0 : 0xffffffff >> ebit; + } + return aLength; + } + + /** Copies a range from another allocator, mark remainder as occupied. Values of bit positions from aFirst to aFirst+aLen-1 inclusive in allocator diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/memmodel/epoc/flexible/mmu/mdefrag.cpp --- a/kernel/eka/memmodel/epoc/flexible/mmu/mdefrag.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mdefrag.cpp Mon May 10 11:40:53 2010 +0100 @@ -124,7 +124,8 @@ TInt M::MovePage(TPhysAddr aOld, TPhysAddr& aNew, TUint aBlockZoneId, TBool aBlockRest) { - TInt r; + // Returns this when page is not paged or managed or free but is a real RAM page. + TInt r = KErrNotSupported; // get memory object corresponding to the page... DMemoryObject* memory = 0; @@ -136,30 +137,76 @@ {// The page is paged so let the pager handle it. return ThePager.DiscardPage(pi, aBlockZoneId, aBlockRest); } - if (pi->Type()==SPageInfo::EManaged) - memory = pi->Owner(); - } - MmuLock::Unlock(); - - // Note, whilst we hold the RamAllocLock the page can't change it's use - // and we can safely assume that it still belongs to the memory object - // at a fixed page index. - // Also, as memory objects can't be destroyed whilst they still own pages - // we can safely access this object without taking an explicit referernce, - // i.e. we don't need to Open() the memory object. - if (!pi) - {// page info for aOld not found so aOld is not a RAM page... - r = KErrArgument; - } - else if(!memory) - { - // page does not have a memory manager, so we can't move it... - r = KErrNotSupported; + switch (pi->Type()) + { + case SPageInfo::EManaged: + memory = pi->Owner(); + // Note, whilst we hold the RamAllocLock the page can't change it's use + // and we can safely assume that it still belongs to the memory object + // at a fixed page index. + // Also, as memory objects can't be destroyed whilst they still own pages + // we can safely access this object without taking an explicit reference, + // i.e. we don't need to Open() the memory object. + MmuLock::Unlock(); + // move page... + r = memory->iManager->MovePage(memory, pi, aNew, aBlockZoneId, aBlockRest); + break; + case SPageInfo::EUnused: + r = KErrNotFound; // This page is free so nothing to do. + // Fall through.. + default: + MmuLock::Unlock(); + } } else - { - // move page... - r = memory->iManager->MovePage(memory, pi, aNew, aBlockZoneId, aBlockRest); + {// page info for aOld not found so aOld is not a RAM page... + MmuLock::Unlock(); + r = KErrArgument; } return r; } + + +TInt M::MoveAndAllocPage(TPhysAddr aAddr, TZonePageType aPageType) + { + // Returns this when page is not paged or managed or free but is a real RAM page. + TInt r = KErrNotSupported; + + // get memory object corresponding to the page... + DMemoryObject* memory = 0; + MmuLock::Lock(); + SPageInfo* pi = SPageInfo::SafeFromPhysAddr(aAddr & ~KPageMask); + if(pi) + { + if (pi->PagedState() != SPageInfo::EUnpaged) + {// The page is paged so let the pager handle it. + return ThePager.DiscardAndAllocPage(pi, aPageType); + } + switch (pi->Type()) + { + case SPageInfo::EManaged: + memory = pi->Owner(); + // Note, whilst we hold the RamAllocLock the page can't change it's use + // and we can safely assume that it still belongs to the memory object + // at a fixed page index. + // Also, as memory objects can't be destroyed whilst they still own pages + // we can safely access this object without taking an explicit referernce, + // i.e. we don't need to Open() the memory object. + MmuLock::Unlock(); + // move page... + r = memory->iManager->MoveAndAllocPage(memory, pi, aPageType); + break; + case SPageInfo::EUnused: + r = KErrNone; // This page is free so nothing to do. + // Fall through.. + default: + MmuLock::Unlock(); + } + } + else + {// page info for aAddr not found so aAddr is not a RAM page... + MmuLock::Unlock(); + r = KErrArgument; + } + return r; + } diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/memmodel/epoc/flexible/mmu/mmanager.cpp --- a/kernel/eka/memmodel/epoc/flexible/mmu/mmanager.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mmanager.cpp Mon May 10 11:40:53 2010 +0100 @@ -66,7 +66,7 @@ } -TInt DMemoryManager::AddPages(DMemoryObject* /*aMemory*/, TUint /*aIndex*/, TUint /*aCount*/, TPhysAddr* /*aPages*/) +TInt DMemoryManager::AddPages(DMemoryObject* /*aMemory*/, TUint /*aIndex*/, TUint /*aCount*/, const TPhysAddr* /*aPages*/) { return KErrNotSupported; } @@ -134,6 +134,13 @@ return KErrNotSupported; } + +TInt DMemoryManager::MoveAndAllocPage(DMemoryObject*, SPageInfo*, TZonePageType) + { + return KErrNotSupported; + } + + TZonePageType DMemoryManager::PageType() {// This should not be invoked on memory managers that do not use the methods // AllocPages() and FreePages(). @@ -721,6 +728,7 @@ public: // from DMemoryManager... virtual TInt MovePage(DMemoryObject* aMemory, SPageInfo* aOldPageInfo, TPhysAddr& aNewPage, TUint aBlockZoneId, TBool aBlockRest); + virtual TInt MoveAndAllocPage(DMemoryObject* aMemory, SPageInfo* aPageInfo, TZonePageType aPageType); virtual TInt HandleFault( DMemoryObject* aMemory, TUint aIndex, DMemoryMapping* aMapping, TUint aMapInstanceCount, TUint aAccessPermissions); virtual TZonePageType PageType(); @@ -887,6 +895,18 @@ } +TInt DMovableMemoryManager::MoveAndAllocPage(DMemoryObject* aMemory, SPageInfo* aPageInfo, TZonePageType aPageType) + { + TPhysAddr newPage; + TInt r = MovePage(aMemory, aPageInfo, newPage, KRamZoneInvalidId, EFalse); + if (r == KErrNone) + { + TheMmu.MarkPageAllocated(aPageInfo->PhysAddr(), aPageType); + } + return r; + } + + TInt DMovableMemoryManager::HandleFault(DMemoryObject* aMemory, TUint aIndex, DMemoryMapping* aMapping, TUint aMapInstanceCount, TUint aAccessPermissions) { @@ -1161,7 +1181,7 @@ public: // from DMemoryManager... virtual void Destruct(DMemoryObject* aMemory); - virtual TInt AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages); + virtual TInt AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, const TPhysAddr* aPages); virtual TInt AddContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr aPhysAddr); virtual TInt RemovePages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages); virtual TInt Pin(DMemoryObject* aMemory, DMemoryMappingBase* aMapping, TPinArgs& aPinArgs); @@ -1226,14 +1246,14 @@ } -TInt DHardwareMemoryManager::AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages) +TInt DHardwareMemoryManager::AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, const TPhysAddr* aPages) { TRACE2(("DHardwareMemoryManager::AddPages(0x%08x,0x%x,0x%x,?)",aMemory, aIndex, aCount)); __NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory)); // validate arguments... - TPhysAddr* pages = aPages; - TPhysAddr* pagesEnd = aPages+aCount; + const TPhysAddr* pages = aPages; + const TPhysAddr* pagesEnd = aPages+aCount; TPhysAddr checkMask = 0; do checkMask |= *pages++; while(pagesType()==SPageInfo::EUnused) pi->SetFixed(); +#ifdef BTRACE_KERNEL_MEMORY + if(r == KErrNone) + ++Epoc::KernelMiscPages; +#endif } } } @@ -500,21 +505,24 @@ r = K::MutexCreate(iPhysMemSyncMutex, KLitPhysMemSync, NULL, EFalse, KMutexOrdSyncPhysMem); if(r!=KErrNone) Panic(EPhysMemSyncMutexCreateFailed); -// VerifyRam(); + +#ifdef FMM_VERIFY_RAM + VerifyRam(); +#endif } void Mmu::Init2FinalCommon() { __KTRACE_OPT2(KBOOT,KMMU,Kern::Printf("Mmu::Init2FinalCommon")); - // hack, reduce free memory to <2GB... + // Reduce free memory to <2GB... while(FreeRamInPages()>=0x80000000/KPageSize) { TPhysAddr dummyPage; TInt r = iRamPageAllocator->AllocRamPages(&dummyPage,1, EPageFixed); __NK_ASSERT_ALWAYS(r==KErrNone); } - // hack, reduce total RAM to <2GB... + // Reduce total RAM to <2GB... if(TheSuperPage().iTotalRamSize<0) TheSuperPage().iTotalRamSize = 0x80000000-KPageSize; @@ -540,6 +548,27 @@ iDefrag->Init3(TheMmu.iRamPageAllocator); } + +void Mmu::BTracePrime(TUint aCategory) + { + (void)aCategory; + +#ifdef BTRACE_RAM_ALLOCATOR + // Must check for -1 as that is the default value of aCategory for + // BTrace::Prime() which is intended to prime all categories that are + // currently enabled via a single invocation of BTrace::Prime(). + if(aCategory==BTrace::ERamAllocator || (TInt)aCategory == -1) + { + NKern::ThreadEnterCS(); + RamAllocLock::Lock(); + iRamPageAllocator->DoBTracePrime(); + RamAllocLock::Unlock(); + NKern::ThreadLeaveCS(); + } +#endif + } + + // // Utils // @@ -593,7 +622,7 @@ __KTRACE_OPT(KMMU,Kern::Printf("Mmu::ZoneAllocPhysicalRam(?,%d,%d,?,%d)", aZoneIdCount, aBytes, aPhysAddr, aAlign)); __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); - TInt r = iRamPageAllocator->ZoneAllocContiguousRam(aZoneIdList, aZoneIdCount, aBytes, aPhysAddr, EPageFixed, aAlign); + TInt r = iRamPageAllocator->ZoneAllocContiguousRam(aZoneIdList, aZoneIdCount, aBytes, aPhysAddr, aAlign); if(r!=KErrNone) iRamAllocFailed = ETrue; else @@ -619,18 +648,7 @@ PagesAllocated(aPageList, aNumPages, (Mmu::TRamAllocFlags)EMemAttStronglyOrdered); // update page infos... - TUint flash = 0; - TPhysAddr* pageEnd = aPageList + aNumPages; - MmuLock::Lock(); - TPhysAddr* page = aPageList; - while (page < pageEnd) - { - MmuLock::Flash(flash,KMaxPageInfoUpdatesInOneGo/2); - TPhysAddr pagePhys = *page++; - __NK_ASSERT_DEBUG(pagePhys != KPhysAddrInvalid); - SPageInfo::FromPhysAddr(pagePhys)->SetPhysAlloc(); - } - MmuLock::Unlock(); + SetAllocPhysRam(aPageList, aNumPages); } __KTRACE_OPT(KMMU,Kern::Printf("Mmu::ZoneAllocPhysicalRam returns %d",r)); return r; @@ -853,6 +871,22 @@ } +/** +Mark a page as being allocated to a particular page type. + +NOTE - This page should not be used until PagesAllocated() has been invoked on it. + +@param aPhysAddr The physical address of the page to mark as allocated. +@param aZonePageType The type of the page to mark as allocated. +*/ +void Mmu::MarkPageAllocated(TPhysAddr aPhysAddr, TZonePageType aZonePageType) + { + __KTRACE_OPT(KMMU,Kern::Printf("Mmu::MarkPageAllocated(0x%x, %d)", aPhysAddr, aZonePageType)); + __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); + iRamPageAllocator->MarkPageAllocated(aPhysAddr, aZonePageType); + } + + void Mmu::FreeRam(TPhysAddr* aPages, TUint aCount, TZonePageType aZonePageType) { __KTRACE_OPT(KMMU,Kern::Printf("Mmu::FreeRam(?,%d)",aCount)); @@ -872,20 +906,31 @@ SPageInfo* pi = SPageInfo::FromPhysAddr(pagePhys); PageFreed(pi); - // If this is an old page of a page being moved that was previously pinned - // then make sure it is freed as discardable otherwise despite DPager::DonatePages() - // having marked it as discardable it would be freed as movable. - __NK_ASSERT_DEBUG(pi->PagedState() != SPageInfo::EPagedPinnedMoved || aCount == 1); - if (pi->PagedState() == SPageInfo::EPagedPinnedMoved) - aZonePageType = EPageDiscard; - - if(ThePager.PageFreed(pi)==KErrNone) - --aCount; // pager has dealt with this page, so one less for us - else + switch (ThePager.PageFreed(pi)) { - // All paged pages should have been dealt with by the pager above. - __NK_ASSERT_DEBUG(pi->PagedState() == SPageInfo::EUnpaged); - *pagesOut++ = pagePhys; // store page address for freeing later + case KErrNone: + --aCount; // pager has dealt with this page, so one less for us + break; + case KErrCompletion: + // This was a pager controlled page but it is no longer required. + __NK_ASSERT_DEBUG(aZonePageType == EPageMovable || aZonePageType == EPageDiscard); + __NK_ASSERT_DEBUG(pi->PagedState() == SPageInfo::EUnpaged); + if (aZonePageType == EPageMovable) + {// This page was donated to the pager so have to free it here + // as aZonePageType is incorrect for this page but aPages may + // contain a mixture of movable and discardable pages. + MmuLock::Unlock(); + iRamPageAllocator->FreeRamPages(&pagePhys, 1, EPageDiscard); + aCount--; // We've freed this page here so one less to free later + flash = 0; // reset flash count as we released the mmulock. + MmuLock::Lock(); + break; + } + // fall through.. + default: + // Free this page.. + __NK_ASSERT_DEBUG(pi->PagedState() == SPageInfo::EUnpaged); + *pagesOut++ = pagePhys; // store page address for freeing later } } MmuLock::Unlock(); @@ -904,21 +949,15 @@ __KTRACE_OPT(KMMU,Kern::Printf("Mmu::AllocContiguousRam returns simulated OOM %d",KErrNoMemory)); return KErrNoMemory; } - // Only the page sets EAllocNoPagerReclaim and it shouldn't allocate contiguous ram. + // Only the pager sets EAllocNoPagerReclaim and it shouldn't allocate contiguous ram. __NK_ASSERT_DEBUG(!(aFlags&EAllocNoPagerReclaim)); #endif - TInt r = iRamPageAllocator->AllocContiguousRam(aCount, aPhysAddr, EPageFixed, aAlign+KPageShift); - if(r==KErrNoMemory && aCount > KMaxFreeableContiguousPages) - { - // flush paging cache and retry... - ThePager.FlushAll(); - r = iRamPageAllocator->AllocContiguousRam(aCount, aPhysAddr, EPageFixed, aAlign+KPageShift); - } + TInt r = iRamPageAllocator->AllocContiguousRam(aCount, aPhysAddr, aAlign+KPageShift); if(r!=KErrNone) iRamAllocFailed = ETrue; else PagesAllocated((TPhysAddr*)(aPhysAddr|1), aCount, aFlags); - __KTRACE_OPT(KMMU,Kern::Printf("AllocContiguouseRam returns %d and aPhysAddr=0x%08x",r,aPhysAddr)); + __KTRACE_OPT(KMMU,Kern::Printf("AllocContiguousRam returns %d and aPhysAddr=0x%08x",r,aPhysAddr)); return r; } @@ -963,19 +1002,7 @@ return r; // update page infos... - TPhysAddr* pages = aPages; - TPhysAddr* pagesEnd = pages+aCount; - MmuLock::Lock(); - TUint flash = 0; - while(pagesSetPhysAlloc(); - } - MmuLock::Unlock(); + SetAllocPhysRam(aPages, aCount); return KErrNone; } @@ -1004,6 +1031,19 @@ MmuLock::Unlock(); iRamPageAllocator->FreeRamPages(aPages,aCount, EPageFixed); + +#ifdef BTRACE_KERNEL_MEMORY + if (BTrace::CheckFilter(BTrace::EKernelMemory)) + {// Only loop round each page if EKernelMemory tracing is enabled + pages = aPages; + pagesEnd = aPages + aCount; + while (pages < pagesEnd) + { + BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysFree, KPageSize, *pages++); + Epoc::DriverAllocdPhysRam -= KPageSize; + } + } +#endif } @@ -1015,17 +1055,7 @@ return r; // update page infos... - SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr); - SPageInfo* piEnd = pi+aCount; - TUint flash = 0; - MmuLock::Lock(); - while(piSetPhysAlloc(); - ++pi; - } - MmuLock::Unlock(); + SetAllocPhysRam(aPhysAddr, aCount); return KErrNone; } @@ -1050,7 +1080,25 @@ } MmuLock::Unlock(); - iRamPageAllocator->FreePhysicalRam(aPhysAddr, aCount << KPageShift); + TUint bytes = aCount << KPageShift; + iRamPageAllocator->FreePhysicalRam(aPhysAddr, bytes); + +#ifdef BTRACE_KERNEL_MEMORY + BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysFree, bytes, aPhysAddr); + Epoc::DriverAllocdPhysRam -= bytes; +#endif + } + + +TInt Mmu::FreeRamZone(TUint aZoneId) + { + TPhysAddr zoneBase; + TUint zonePages; + TInt r = iRamPageAllocator->GetZoneAddress(aZoneId, zoneBase, zonePages); + if (r != KErrNone) + return r; + FreePhysicalRam(zoneBase, zonePages); + return KErrNone; } @@ -1058,25 +1106,11 @@ { __KTRACE_OPT(KMMU,Kern::Printf("Mmu::ClaimPhysicalRam(0x%08x,0x%x,0x%08x)",aPhysAddr,aCount,aFlags)); aPhysAddr &= ~KPageMask; - TInt r = iRamPageAllocator->ClaimPhysicalRam(aPhysAddr,(aCount << KPageShift)); - if(r!=KErrNone) + TInt r = iRamPageAllocator->ClaimPhysicalRam(aPhysAddr, aCount << KPageShift); + if(r != KErrNone) return r; - PagesAllocated((TPhysAddr*)(aPhysAddr|1), aCount, aFlags); - - // update page infos... - SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr); - SPageInfo* piEnd = pi+aCount; - TUint flash = 0; - MmuLock::Lock(); - while(piSetPhysAlloc(); - ++pi; - } - MmuLock::Unlock(); - + AllocatedPhysicalRam(aPhysAddr, aCount, aFlags); return KErrNone; } @@ -1088,17 +1122,59 @@ PagesAllocated((TPhysAddr*)(aPhysAddr|1), aCount, aFlags); // update page infos... + SetAllocPhysRam(aPhysAddr, aCount); + } + + +void Mmu::SetAllocPhysRam(TPhysAddr aPhysAddr, TUint aCount) + { SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr); SPageInfo* piEnd = pi+aCount; TUint flash = 0; MmuLock::Lock(); while(piSetPhysAlloc(); ++pi; } MmuLock::Unlock(); + +#ifdef BTRACE_KERNEL_MEMORY + TUint bytes = aCount << KPageShift; + BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, bytes, aPhysAddr); + Epoc::DriverAllocdPhysRam += bytes; +#endif + } + + +void Mmu::SetAllocPhysRam(TPhysAddr* aPageList, TUint aNumPages) + { + TPhysAddr* page = aPageList; + TPhysAddr* pageEnd = aPageList + aNumPages; + TUint flash = 0; + MmuLock::Lock(); + while (page < pageEnd) + { + MmuLock::Flash(flash, KMaxPageInfoUpdatesInOneGo / 2); + TPhysAddr pagePhys = *page++; + __NK_ASSERT_DEBUG(pagePhys != KPhysAddrInvalid); + SPageInfo::FromPhysAddr(pagePhys)->SetPhysAlloc(); + } + MmuLock::Unlock(); + +#ifdef BTRACE_KERNEL_MEMORY + if (BTrace::CheckFilter(BTrace::EKernelMemory)) + {// Only loop round each page if EKernelMemory tracing is enabled + TPhysAddr* pAddr = aPageList; + TPhysAddr* pAddrEnd = aPageList + aNumPages; + while (pAddr < pAddrEnd) + { + BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, KPageSize, *pAddr++); + Epoc::DriverAllocdPhysRam += KPageSize; + } + } +#endif } @@ -1187,20 +1263,10 @@ __NK_ASSERT_DEBUG(iSize>=1); __NK_ASSERT_DEBUG(iCount==0); - TUint colour = aColour&KPageColourMask; - TLinAddr addr = iLinAddr+(colour<=1); __NK_ASSERT_DEBUG(iCount==0); - - TUint colour = aColour&KPageColourMask; - TLinAddr addr = iLinAddr+(colour<SetPagedState(SPageInfo::EUnpaged); // Must be unpaged before returned to free pool. - return KErrNotFound; + return KErrCompletion; default: __NK_ASSERT_DEBUG(0); @@ -365,6 +366,14 @@ SetClean(*aPageInfo); } + if (iNumberOfFreePages > 0) + {// The paging cache is not at the minimum size so safe to let the + // ram allocator free this page. + iNumberOfFreePages--; + aPageInfo->SetPagedState(SPageInfo::EUnpaged); + return KErrCompletion; + } + // Need to hold onto this page as have reached the page cache limit. // add as oldest page... aPageInfo->SetPagedState(SPageInfo::EPagedOldestClean); iOldestCleanList.Add(&aPageInfo->iLink); @@ -413,8 +422,8 @@ #ifdef _DEBUG if (!IsPageTableUnpagedRemoveAllowed(aPageInfo)) __NK_ASSERT_DEBUG(0); +#endif break; -#endif default: __NK_ASSERT_DEBUG(0); return; @@ -803,6 +812,20 @@ } +TInt DPager::DiscardAndAllocPage(SPageInfo* aPageInfo, TZonePageType aPageType) + { + TInt r = DiscardPage(aPageInfo, KRamZoneInvalidId, EFalse); + if (r == KErrNone) + { + TheMmu.MarkPageAllocated(aPageInfo->PhysAddr(), aPageType); + } + // Flash the ram alloc lock as we may have had to write a page out to swap. + RamAllocLock::Unlock(); + RamAllocLock::Lock(); + return r; + } + + static TBool DiscardCanStealPage(SPageInfo* aOldPageInfo, TBool aBlockRest) { // If the page is pinned or if the page is dirty and a general defrag is being performed then @@ -1002,6 +1025,9 @@ __NK_ASSERT_DEBUG(iNumberOfFreePages>0); --iNumberOfFreePages; + // The page must be unpaged, otherwise it wasn't successfully removed + // from the live list. + __NK_ASSERT_DEBUG(aPageInfo.PagedState() == SPageInfo::EUnpaged); MmuLock::Unlock(); TPhysAddr pagePhys = aPageInfo.PhysAddr(); @@ -2068,6 +2094,7 @@ } +// WARNING THIS METHOD MAY HOLD THE RAM ALLOC LOCK FOR EXCESSIVE PERIODS. DON'T USE THIS IN ANY PRODUCTION CODE. void DPager::FlushAll() { NKern::ThreadEnterCS(); @@ -2108,7 +2135,9 @@ } ++pi; if(((TUint)pi&(0xf<RamAllocFlags(), EPageFixed); + +#ifdef BTRACE_KERNEL_MEMORY + if (r == KErrNone) + { + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscAlloc, KPageSize); + ++Epoc::KernelMiscPages; + } +#endif } RamAllocLock::Unlock(); @@ -241,7 +245,14 @@ if(aDemandPaged) ThePager.PageInFreePages(&pagePhys,1); else + { TheMmu.FreeRam(&pagePhys, 1, EPageFixed); + +#ifdef BTRACE_KERNEL_MEMORY + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscFree, KPageSize); + --Epoc::KernelMiscPages; +#endif + } r = 1; } @@ -362,11 +373,8 @@ { iReserveCount = aReserveCount; iDemandPaged = aDemandPaged; - while(iFreeCountAllocReserve(*this)) - { - __NK_ASSERT_ALWAYS(0); - } + while(iFreeCount < aReserveCount) + __NK_ASSERT_ALWAYS(aAllocator->AllocReserve(*this)); } diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/memmodel/epoc/mmubase/mmubase.cpp --- a/kernel/eka/memmodel/epoc/mmubase/mmubase.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/memmodel/epoc/mmubase/mmubase.cpp Mon May 10 11:40:53 2010 +0100 @@ -483,7 +483,7 @@ TInt MmuBase::AllocPhysicalRam(TInt aSize, TPhysAddr& aPhysAddr, TInt aAlign) { __KTRACE_OPT(KMMU,Kern::Printf("Mmu::AllocPhysicalRam() size=%x align=%d",aSize,aAlign)); - TInt r=AllocContiguousRam(aSize, aPhysAddr, EPageFixed, aAlign); + TInt r=AllocContiguousRam(aSize, aPhysAddr, aAlign); if (r!=KErrNone) { iAllocFailed=ETrue; @@ -516,7 +516,7 @@ TInt MmuBase::ZoneAllocPhysicalRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aSize, TPhysAddr& aPhysAddr, TInt aAlign) { __KTRACE_OPT(KMMU,Kern::Printf("Mmu::ZoneAllocPhysicalRam() size=0x%x align=%d", aSize, aAlign)); - TInt r = ZoneAllocContiguousRam(aZoneIdList, aZoneIdCount, aSize, aPhysAddr, EPageFixed, aAlign); + TInt r = ZoneAllocContiguousRam(aZoneIdList, aZoneIdCount, aSize, aPhysAddr, aAlign); if (r!=KErrNone) { iAllocFailed=ETrue; @@ -725,20 +725,19 @@ } -TInt MmuBase::AllocContiguousRam(TInt aSize, TPhysAddr& aPhysAddr, TZonePageType aPageType, TInt aAlign, TUint aBlockedZoneId, TBool aBlockRest) +TInt MmuBase::AllocContiguousRam(TInt aSize, TPhysAddr& aPhysAddr, TInt aAlign) { #ifdef _DEBUG if(K::CheckForSimulatedAllocFail()) return KErrNoMemory; #endif - __NK_ASSERT_DEBUG(aPageType == EPageFixed); TUint contigPages = (aSize + KPageSize - 1) >> KPageShift; - TInt r = iRamPageAllocator->AllocContiguousRam(contigPages, aPhysAddr, aPageType, aAlign, aBlockedZoneId, aBlockRest); + TInt r = iRamPageAllocator->AllocContiguousRam(contigPages, aPhysAddr, aAlign); if (r == KErrNoMemory && contigPages > KMaxFreeableContiguousPages) {// Allocation failed but as this is a large allocation flush the RAM cache // and reattempt the allocation as large allocation wouldn't discard pages. iRamCache->FlushAll(); - r = iRamPageAllocator->AllocContiguousRam(contigPages, aPhysAddr, aPageType, aAlign, aBlockedZoneId, aBlockRest); + r = iRamPageAllocator->AllocContiguousRam(contigPages, aPhysAddr, aAlign); } return r; } @@ -750,16 +749,15 @@ @param aZoneIdCount The number of IDs listed in aZoneIdList @param aSize The number of bytes to allocate @param aPhysAddr Will receive the physical base address of the allocated RAM -@param aPageType The type of the pages being allocated @param aAlign The log base 2 alginment required */ -TInt MmuBase::ZoneAllocContiguousRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aSize, TPhysAddr& aPhysAddr, TZonePageType aPageType, TInt aAlign) +TInt MmuBase::ZoneAllocContiguousRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aSize, TPhysAddr& aPhysAddr, TInt aAlign) { #ifdef _DEBUG if(K::CheckForSimulatedAllocFail()) return KErrNoMemory; #endif - return iRamPageAllocator->ZoneAllocContiguousRam(aZoneIdList, aZoneIdCount, aSize, aPhysAddr, aPageType, aAlign); + return iRamPageAllocator->ZoneAllocContiguousRam(aZoneIdList, aZoneIdCount, aSize, aPhysAddr, aAlign); } SPageInfo* SPageInfo::SafeFromPhysAddr(TPhysAddr aAddress) diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/memmodel/epoc/mmubase/ramalloc.cpp --- a/kernel/eka/memmodel/epoc/mmubase/ramalloc.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/memmodel/epoc/mmubase/ramalloc.cpp Mon May 10 11:40:53 2010 +0100 @@ -354,13 +354,13 @@ aZone->iAllocPages[EPageFixed], aZone->iAllocPages[EPageMovable],aZone->iAllocPages[EPageDiscard])); Panic(EZonesCountErr); } - __ASSERT_DEBUG(free == (TUint32)aZone->iBma[KBmaAllPages]->iAvail, Panic(EAllocRamPagesInconsistent)); __KTRACE_OPT(KMMU2,Kern::Printf("ZoneFreePages - aCount %x free %x, alloc %x",aCount,free,alloc)); __KTRACE_OPT(KMMU2,Kern::Printf("Alloc Unk %x Fx %x Mv %x Dis %x",aZone->iAllocPages[EPageUnknown], aZone->iAllocPages[EPageFixed], aZone->iAllocPages[EPageMovable],aZone->iAllocPages[EPageDiscard])); - if (iAllowBmaVerify) + if (!iContiguousReserved) { + __ASSERT_DEBUG(free == (TUint32)aZone->iBma[KBmaAllPages]->iAvail, Panic(EAllocRamPagesInconsistent)); TBitMapAllocator& bmaType = *(aZone->iBma[(aType != EPageUnknown)? aType : EPageFixed]); TUint allocPages; if (aType == EPageFixed || aType == EPageUnknown) @@ -495,13 +495,13 @@ aZone->iAllocPages[EPageFixed], aZone->iAllocPages[EPageMovable],aZone->iAllocPages[EPageDiscard])); Panic(EZonesCountErr); } - __ASSERT_DEBUG(free == (TUint32)aZone->iBma[KBmaAllPages]->iAvail, Panic(EAllocRamPagesInconsistent)); __KTRACE_OPT(KMMU2,Kern::Printf("ZoneFreePages - aCount %x free %x, alloc %x",aCount,free,alloc)); __KTRACE_OPT(KMMU2,Kern::Printf("Alloc Unk %x Fx %x Mv %x Dis %x",aZone->iAllocPages[EPageUnknown], aZone->iAllocPages[EPageFixed], aZone->iAllocPages[EPageMovable],aZone->iAllocPages[EPageDiscard])); - if (iAllowBmaVerify) + if (!iContiguousReserved) { + __ASSERT_DEBUG(free == (TUint32)aZone->iBma[KBmaAllPages]->iAvail, Panic(EAllocRamPagesInconsistent)); TBitMapAllocator& bmaType = *(aZone->iBma[(aType != EPageUnknown)? aType : EPageFixed]); TUint allocPages; if (aType == EPageFixed || aType == EPageUnknown) @@ -968,7 +968,7 @@ // Temporarily fill preference list so SetPhysicalRamState can succeed #ifdef _DEBUG // Block bma verificaitons as bma and alloc counts aren't consistent yet. - iAllowBmaVerify = EFalse; + iContiguousReserved = 1; #endif const SZone* const lastZone = iZones + iNumZones; zone = iZones; @@ -984,7 +984,7 @@ } #ifdef _DEBUG // Only now is it safe to enable bma verifications - iAllowBmaVerify = ETrue; + iContiguousReserved = 0; #endif /////////////////////////////////////////////////////////////////////////// @@ -1135,6 +1135,7 @@ } } + TInt DRamAllocator::MarkPageAllocated(TPhysAddr aAddr, TZonePageType aType) { __KTRACE_OPT(KMMU,Kern::Printf("DRamAllocator::MarkPageAllocated %08x",aAddr)); @@ -1160,7 +1161,12 @@ return KErrAlreadyExists; // page is already allocated } bmaAll.Alloc(n,1); - bmaType.Alloc(n,1); + if (bmaType.NotAllocated(n,1)) + bmaType.Alloc(n,1); +#ifdef _DEBUG + else // Allow this page to already be reserved in bmaType as AllocContiguousRam() may have done this. + __NK_ASSERT_DEBUG(aType == EPageFixed); +#endif --iTotalFreeRamPages; ZoneAllocPages(z, 1, aType); __KTRACE_OPT(KMMU,Kern::Printf("Total free RAM pages now = %d",iTotalFreeRamPages)); @@ -1171,6 +1177,7 @@ return KErrNone; } + TInt DRamAllocator::FreeRamPage(TPhysAddr aAddr, TZonePageType aType) { __KTRACE_OPT(KMMU,Kern::Printf("FreeRamPage %08x",aAddr)); @@ -1201,17 +1208,27 @@ __KTRACE_OPT(KMMU2,Kern::Printf("Zone index %d page index %04x",z-iZones,n)); TBitMapAllocator& bmaAll = *(z->iBma[KBmaAllPages]); TBitMapAllocator& bmaType = *(z->iBma[aType]); - bmaAll.Free(n); + bmaType.Free(n); - ++iTotalFreeRamPages; - ZoneFreePages(z, 1, aType); - + if (iContiguousReserved && aType != EPageFixed && z->iBma[EPageFixed]->NotFree(n, 1)) + {// This page has been reserved by AllocContiguous() so don't free it + // but allocate it as fixed. + ZoneFreePages(z, 1, aType); + ZoneAllocPages(z, 1, EPageFixed); + } + else + { + bmaAll.Free(n); + ++iTotalFreeRamPages; + ZoneFreePages(z, 1, aType); + } #ifdef BTRACE_RAM_ALLOCATOR BTrace8(BTrace::ERamAllocator, BTrace::ERamAllocFreePage, aType, aAddr); #endif return KErrNone; } + void DRamAllocator::FreeRamPages(TPhysAddr* aPageList, TInt aNumPages, TZonePageType aType) { __KTRACE_OPT(KMMU,Kern::Printf("FreeRamPages count=%08x",aNumPages)); @@ -1259,11 +1276,37 @@ pa += KPageSize; } __KTRACE_OPT(KMMU2,Kern::Printf("%d consecutive pages, zp_rem=%x, %d remaining pages",n,zp_rem,aNumPages)); - bmaAll.Free(ix,n); TBitMapAllocator& bmaType = *(z->iBma[aType]); bmaType.Free(ix,n); - iTotalFreeRamPages += n; - ZoneFreePages(z, n, aType); + + if (iContiguousReserved && aType != EPageFixed) + {// See if a page has been reserved by AllocContiguous() in this range. + TUint pagesFreed = 0; + TUint allocStart = ix; + TUint freeOffset = ix; + TUint endOffset = ix + n - 1; + while (freeOffset <= endOffset) + { + TUint runLength = NextAllocatedRun(z, allocStart, endOffset, EPageFixed); + if (allocStart > freeOffset) + { + TUint freed = allocStart - freeOffset; + bmaAll.Free(freeOffset, freed); + pagesFreed += freed; + } + allocStart += runLength; + freeOffset = allocStart; + } + iTotalFreeRamPages += pagesFreed; + ZoneFreePages(z, n, aType); + ZoneAllocPages(z, n - pagesFreed, EPageFixed); + } + else + { + bmaAll.Free(ix,n); + iTotalFreeRamPages += n; + ZoneFreePages(z, n, aType); + } #ifdef BTRACE_RAM_ALLOCATOR BTrace12(BTrace::ERamAllocator, BTrace::ERamAllocFreePages, aType, n, first_pa); #endif @@ -1273,6 +1316,7 @@ #endif } + /** Attempt to clear upto the required amount of discardable or movable pages from the RAM zone. @@ -1464,7 +1508,7 @@ {// Allocating as part of a general defragmentation and // can't allocate without using a RAM zone less preferable than // the current least prefeable RAM zone with movable and/or - //discardable. + // discardable. __NK_ASSERT_DEBUG(numMissing); goto exit; } @@ -1679,29 +1723,173 @@ return r; } + +#if !defined(__MEMMODEL_MULTIPLE__) && !defined(__MEMMODEL_MOVING__) +void DRamAllocator::BlockContiguousRegion(TPhysAddr aAddrBase, TUint aNumPages) + { + // Shouldn't be asked to block zero pages, addrEndPage would be wrong if we did. + __NK_ASSERT_DEBUG(aNumPages); + TPhysAddr addr = aAddrBase; + TPhysAddr addrEndPage = aAddrBase + ((aNumPages - 1) << KPageShift); + TInt tmpOffset; + SZone* endZone = GetZoneAndOffset(addrEndPage, tmpOffset); + SZone* tmpZone; + do + { + tmpZone = GetZoneAndOffset(addr, tmpOffset); + __NK_ASSERT_DEBUG(tmpZone != NULL); + TUint runLength = (addrEndPage < tmpZone->iPhysEnd)? + ((addrEndPage - addr) >> KPageShift) + 1: + tmpZone->iPhysPages - tmpOffset; + TUint reserved = tmpZone->iBma[KBmaAllPages]->SelectiveAlloc(tmpOffset, runLength); + if (reserved) + { +#ifdef _DEBUG + TUint runEnd = tmpOffset + runLength; + TUint free = 0; + for (TUint i = tmpOffset; i < runEnd; i++) + if (tmpZone->iBma[EPageMovable]->NotAllocated(i,1) && tmpZone->iBma[EPageDiscard]->NotAllocated(i,1)) + free++; + __NK_ASSERT_DEBUG(free == reserved); +#endif + ZoneAllocPages(tmpZone, reserved, EPageFixed); + iTotalFreeRamPages -= reserved; + } + tmpZone->iBma[EPageFixed]->Alloc(tmpOffset, runLength); + addr = tmpZone->iPhysEnd + 1; + } + while (tmpZone != endZone); + } + + +FORCE_INLINE void DRamAllocator::UnblockSetAllocRuns( TUint& aOffset1, TUint& aOffset2, + TUint aRunLength1, TUint aRunLength2, + TUint& aAllocLength, TUint& aAllocStart) + { + aAllocStart = aOffset1; + aAllocLength = aRunLength1; + aOffset1 += aAllocLength; + if (aOffset1 == aOffset2) + { + aAllocLength += aRunLength2; + aOffset2 += aRunLength2; + aOffset1 = aOffset2; + } + } + + +void DRamAllocator::UnblockContiguousRegion(TPhysAddr aAddrBase, TUint aNumPages) + { + // Shouldn't be asked to unblock zero pages, addrEndPage would be wrong if we did. + __NK_ASSERT_DEBUG(aNumPages); + TPhysAddr addr = aAddrBase; + TPhysAddr addrEndPage = aAddrBase + ((aNumPages - 1) << KPageShift); + TInt tmpOffset; + SZone* endZone = GetZoneAndOffset(addrEndPage, tmpOffset); + SZone* tmpZone; + do + { + tmpZone = GetZoneAndOffset(addr, tmpOffset); + __NK_ASSERT_DEBUG(tmpZone != NULL); + TUint runLength = (addrEndPage < tmpZone->iPhysEnd)? + ((addrEndPage - addr) >> KPageShift) + 1: + tmpZone->iPhysPages - tmpOffset; + TUint unreserved = 0; + TUint runEnd = tmpOffset + runLength - 1; + TUint freeOffset = tmpOffset; + TUint discardOffset = freeOffset; + TUint movableOffset = freeOffset; + __KTRACE_OPT(KMMU2, Kern::Printf("freeOff %d, runEnd %d", freeOffset, runEnd)); + while (freeOffset <= runEnd) + { + TUint discardRun; + TUint movableRun; + discardRun = NextAllocatedRun(tmpZone, discardOffset, runEnd, EPageDiscard); + movableRun = NextAllocatedRun(tmpZone, movableOffset, runEnd, EPageMovable); + TUint allocLength; + TUint allocStart; + __KTRACE_OPT(KMMU2, Kern::Printf("disOff %d len %d movOff %d len %d", discardOffset, discardRun, movableOffset, movableRun)); + if (discardOffset < movableOffset) + UnblockSetAllocRuns(discardOffset, movableOffset, discardRun, movableRun, allocLength, allocStart); + else + UnblockSetAllocRuns(movableOffset, discardOffset, movableRun, discardRun, allocLength, allocStart); + + if (allocStart > freeOffset) + { + unreserved += allocStart - freeOffset; + tmpZone->iBma[KBmaAllPages]->Free(freeOffset, allocStart - freeOffset); + __NK_ASSERT_DEBUG( !tmpZone->iBma[EPageMovable]->NotFree(freeOffset, allocStart - freeOffset) && + !tmpZone->iBma[EPageDiscard]->NotFree(freeOffset, allocStart - freeOffset)); + } + __KTRACE_OPT(KMMU2, Kern::Printf("disOff %d len %d movOff %d len %d start %d len %d", discardOffset, discardRun, movableOffset, movableRun, allocStart, allocLength)); + freeOffset = allocStart + allocLength; + __KTRACE_OPT(KMMU2, Kern::Printf("freeOff %d", freeOffset)); + } + tmpZone->iBma[EPageFixed]->Free(tmpOffset, runLength); + ZoneFreePages(tmpZone, unreserved, EPageFixed); + iTotalFreeRamPages += unreserved; + addr = tmpZone->iPhysEnd + 1; + } + while (tmpZone != endZone); + } + + +TBool DRamAllocator::ClearContiguousRegion(TPhysAddr aAddrBase, TPhysAddr aZoneBase, TUint aNumPages, TInt& aOffset) + { + TPhysAddr addr = aAddrBase; + TPhysAddr addrEnd = aAddrBase + (aNumPages << KPageShift); + TInt contigOffset = 0; + SZone* contigZone = GetZoneAndOffset(addr, contigOffset); + for (; addr != addrEnd; addr += KPageSize, contigOffset++) + { + if (contigZone->iPhysEnd < addr) + { + contigZone = GetZoneAndOffset(addr, contigOffset); + __NK_ASSERT_DEBUG(contigZone != NULL); + } + + __NK_ASSERT_DEBUG(contigZone != NULL); + __NK_ASSERT_DEBUG(contigZone->iBma[EPageFixed]->NotFree(contigOffset, 1)); + __NK_ASSERT_DEBUG(SPageInfo::SafeFromPhysAddr(addr) != NULL); + + // WARNING - This may flash the ram alloc mutex. + TInt exRet = M::MoveAndAllocPage(addr, EPageFixed); + if (exRet != KErrNone) + {// This page couldn't be moved or discarded so + // restart the search the page after this one. + __KTRACE_OPT(KMMU2, Kern::Printf("ContigMov fail contigOffset 0x%x exRet %d", contigOffset, exRet)); + aOffset = (addr < aZoneBase)? 0 : contigOffset + 1; + break; + } + } + return addr == addrEnd; + } + + /** Search through the zones for the requested contiguous RAM, first in preference order then, if that fails, in address order. +No support for non-fixed pages as this will discard and move pages if required. + @param aNumPages The number of contiguous pages to find @param aPhysAddr Will contain the base address of any contiguous run if found -@param aType The page type of the memory to be allocated @param aAlign Alignment specified as the alignment shift -@param aBlockedZoneId The ID of a zone that can't be allocated into, by default this has no effect -@param aBlockRest Set to ETrue to stop allocation as soon as aBlockedZoneId is reached in preference ordering. EFalse otherwise. @return KErrNone on success, KErrNoMemory otherwise */ -TInt DRamAllocator::AllocContiguousRam(TUint aNumPages, TPhysAddr& aPhysAddr, TZonePageType aType, TInt aAlign, TUint aBlockedZoneId, TBool aBlockRest) +TInt DRamAllocator::AllocContiguousRam(TUint aNumPages, TPhysAddr& aPhysAddr, TInt aAlign) { __KTRACE_OPT(KMMU,Kern::Printf("AllocContiguousRam size %08x align %d",aNumPages,aAlign)); M::RamAllocIsLocked(); - // No support for non-fixed pages as this will discard and move - // pages if required. - __NK_ASSERT_DEBUG(aType == EPageFixed); + if ((TUint)aNumPages > iTotalFreeRamPages + M::NumberOfFreeDpPages()) + {// Not enough free space and not enough freeable pages. + return KErrNoMemory; + } + TInt alignWrtPage = Max(aAlign - KPageShift, 0); TUint32 alignmask = (1u << alignWrtPage) - 1; @@ -1716,7 +1904,124 @@ TInt offset = 0; iZoneTmpAddrIndex = -1; iZoneTmpPrefLink = iZonePrefList.First(); - while (NextAllocZone(zone, searchState, aType, aBlockedZoneId, aBlockRest)) + while (NextAllocZone(zone, searchState, EPageFixed, KRamZoneInvalidId, EFalse)) + { + // Be sure to start from scratch if zone not contiguous with previous zone + if (prevZone && (zone->iPhysBase == 0 || (zone->iPhysBase - 1) != prevZone->iPhysEnd)) + { + carryAll = 0; + carryImmov = 0; + } + prevZone = zone; + TBitMapAllocator& bmaAll = *(zone->iBma[KBmaAllPages]); + base = TInt(zone->iPhysBase >> KPageShift); + TInt runLength; + __KTRACE_OPT(KMMU,Kern::Printf("AllocAligned: base=%08x carryAll=%08x offset=%08x", base, carryAll, offset)); + offset = bmaAll.AllocAligned(aNumPages, alignWrtPage, base, EFalse, carryAll, runLength); + __KTRACE_OPT(KMMU,Kern::Printf("AllocAligned: offset=%08x", offset)); + + if (offset >= 0) + { + // Have found enough contiguous pages so return address of physical page + // at the start of the region + aPhysAddr = TPhysAddr((base + offset - carryAll + alignmask) & ~alignmask) << KPageShift; + MarkPagesAllocated(aPhysAddr, aNumPages, EPageFixed); + + __KTRACE_OPT(KMMU,Kern::Printf("AllocContiguousRam returns %08x",aPhysAddr)); +#ifdef BTRACE_RAM_ALLOCATOR + BTrace12(BTrace::ERamAllocator, BTrace::ERamAllocContiguousRam, EPageFixed, aNumPages, aPhysAddr); +#endif + return KErrNone; + } + // No run found when looking in just the free pages so see if this + // RAM zone could be used if pages where moved or discarded. + TBitMapAllocator& bmaImmov = *(zone->iBma[EPageFixed]); + offset = 0; // Clear so searches whole of fixed BMA on the first pass. + do + { + __KTRACE_OPT(KMMU,Kern::Printf("AllocAligned: base=%08x carryImmov=%08x offset=%08x", base, carryImmov, offset)); + offset = bmaImmov.AllocAligned(aNumPages, alignWrtPage, base, EFalse, carryImmov, runLength, offset); + __KTRACE_OPT(KMMU,Kern::Printf("AllocAligned: offset=%08x", offset)); + if (offset >= 0) + {// Have found a run in immovable page bma so attempt to clear + // it for the allocation. + TPhysAddr addrBase = TPhysAddr((base + offset - carryImmov + alignmask) & ~alignmask) << KPageShift; + __KTRACE_OPT(KMMU2, Kern::Printf(">AllocContig fix run 0x%08x - 0x%08x 0x%x", addrBase, addrBase + (aNumPages << KPageShift), TheCurrentThread)); + + // Block the contiguous region from being allocated. + iContiguousReserved++; + BlockContiguousRegion(addrBase, aNumPages); + if (ClearContiguousRegion(addrBase, zone->iPhysBase, aNumPages, offset)) + {// Cleared all the required pages. + // Return address of physical page at the start of the region. + iContiguousReserved--; + aPhysAddr = addrBase; + __KTRACE_OPT(KMMU,Kern::Printf("AllocContiguousRam returns %08x",aPhysAddr)); +#ifdef BTRACE_RAM_ALLOCATOR + BTrace12(BTrace::ERamAllocator, BTrace::ERamAllocContiguousRam, EPageFixed, aNumPages, aPhysAddr); +#endif + __KTRACE_OPT(KMMU2, Kern::Printf("= 0 && (TUint)offset < zone->iPhysPages); + } + return KErrNoMemory; + } + +#else + +/** +Search through the zones for the requested contiguous RAM, first in preference +order then, if that fails, in address order. + +No support for non-fixed pages as this will discard and move pages if required. + +@param aNumPages The number of contiguous pages to find +@param aPhysAddr Will contain the base address of any contiguous run if found +@param aAlign Alignment specified as the alignment shift + +@return KErrNone on success, KErrNoMemory otherwise +*/ +TInt DRamAllocator::AllocContiguousRam(TUint aNumPages, TPhysAddr& aPhysAddr, TInt aAlign) + { + __KTRACE_OPT(KMMU,Kern::Printf("AllocContiguousRam size %08x align %d",aNumPages,aAlign)); + + M::RamAllocIsLocked(); + + TInt alignWrtPage = Max(aAlign - KPageShift, 0); + TUint32 alignmask = (1u << alignWrtPage) - 1; + + // Attempt to find enough pages searching in preference order first then + // in address order + TZoneSearchState searchState = EZoneSearchPref; + SZone* zone; + SZone* prevZone = NULL; + TInt carryAll = 0; // Carry for all pages bma, clear to start new run. + TInt carryImmov = 0; // Carry for immovable pages bma, clear to start new run. + TInt base = 0; + TInt offset = 0; + iZoneTmpAddrIndex = -1; + iZoneTmpPrefLink = iZonePrefList.First(); + while (NextAllocZone(zone, searchState, EPageFixed, KRamZoneInvalidId, EFalse)) { // Be sure to start from scratch if zone not contiguous with previous zone if (prevZone && (zone->iPhysBase == 0 || (zone->iPhysBase - 1) != prevZone->iPhysEnd)) @@ -1736,11 +2041,11 @@ {// Have found enough contiguous pages so return address of physical page // at the start of the region aPhysAddr = TPhysAddr((base + offset - carryAll + alignmask) & ~alignmask) << KPageShift; - MarkPagesAllocated(aPhysAddr, aNumPages, aType); + MarkPagesAllocated(aPhysAddr, aNumPages, EPageFixed); __KTRACE_OPT(KMMU,Kern::Printf("AllocContiguousRam returns %08x",aPhysAddr)); #ifdef BTRACE_RAM_ALLOCATOR - BTrace12(BTrace::ERamAllocator, BTrace::ERamAllocContiguousRam, aType, aNumPages, aPhysAddr); + BTrace12(BTrace::ERamAllocator, BTrace::ERamAllocContiguousRam, EPageFixed, aNumPages, aPhysAddr); #endif return KErrNone; } @@ -1788,12 +2093,11 @@ contigZone = GetZoneAndOffset(addr, contigOffset); __NK_ASSERT_DEBUG(contigZone != NULL); } -#ifdef _DEBUG // This page shouldn't be allocated as fixed, only movable or discardable. + // This page shouldn't be allocated as fixed, only movable or discardable. __NK_ASSERT_DEBUG(contigZone != NULL); __NK_ASSERT_DEBUG(contigZone->iBma[EPageFixed]->NotAllocated(contigOffset, 1)); - SPageInfo* pageInfo = SPageInfo::SafeFromPhysAddr(addr); - __NK_ASSERT_DEBUG(pageInfo != NULL); -#endif + __NK_ASSERT_DEBUG(SPageInfo::SafeFromPhysAddr(addr) != NULL); + TPhysAddr newAddr; TInt moveRet = M::MovePage(addr, newAddr, contigZone->iId, EFalse); if (moveRet != KErrNone && moveRet != KErrNotFound) @@ -1827,11 +2131,11 @@ {// Cleared all the required pages so allocate them. // Return address of physical page at the start of the region. aPhysAddr = addrBase; - MarkPagesAllocated(aPhysAddr, aNumPages, aType); + MarkPagesAllocated(aPhysAddr, aNumPages, EPageFixed); __KTRACE_OPT(KMMU,Kern::Printf("AllocContiguousRam returns %08x",aPhysAddr)); #ifdef BTRACE_RAM_ALLOCATOR - BTrace12(BTrace::ERamAllocator, BTrace::ERamAllocContiguousRam, aType, aNumPages, aPhysAddr); + BTrace12(BTrace::ERamAllocator, BTrace::ERamAllocContiguousRam, EPageFixed, aNumPages, aPhysAddr); #endif return KErrNone; } @@ -1844,6 +2148,7 @@ } return KErrNoMemory; } +#endif // !defined(__MEMODEL_MULTIPLE__) || !defined(__MEMODEL_MOVING__) /** @@ -1858,19 +2163,17 @@ @param aZoneIdCount The number of the IDs listed by aZoneIdList. @param aSize The number of contiguous bytes to find @param aPhysAddr Will contain the base address of the contiguous run if found -@param aType The page type of the memory to be allocated @param aAlign Alignment specified as the alignment shift @return KErrNone on success, KErrNoMemory if allocation couldn't succeed or the RAM zone has the KRamZoneFlagNoAlloc flag set. KErrArgument if a zone of aZoneIdList exists or if aSize is larger than the size of the zone. */ -TInt DRamAllocator::ZoneAllocContiguousRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aSize, TPhysAddr& aPhysAddr, TZonePageType aType, TInt aAlign) +TInt DRamAllocator::ZoneAllocContiguousRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aSize, TPhysAddr& aPhysAddr, TInt aAlign) { __KTRACE_OPT(KMMU,Kern::Printf("ZoneAllocContiguousRam zones 0x%x size 0x%08x align %d",aZoneIdCount, aSize, aAlign)); M::RamAllocIsLocked(); - __NK_ASSERT_DEBUG(aType == EPageFixed); TUint numPages = (aSize + KPageSize - 1) >> KPageShift; @@ -1930,11 +2233,11 @@ // Have found enough contiguous pages so mark the pages allocated and // return address of physical page at the start of the region. aPhysAddr = TPhysAddr((base + offset - carry + alignmask) & ~alignmask) << KPageShift; - MarkPagesAllocated(aPhysAddr, numPages, aType); + MarkPagesAllocated(aPhysAddr, numPages, EPageFixed); __KTRACE_OPT(KMMU,Kern::Printf("ZoneAllocContiguousRam returns %08x",aPhysAddr)); #ifdef BTRACE_RAM_ALLOCATOR - BTrace12(BTrace::ERamAllocator, BTrace::ERamAllocZoneContiguousRam, aType, numPages, aPhysAddr); + BTrace12(BTrace::ERamAllocator, BTrace::ERamAllocZoneContiguousRam, EPageFixed, numPages, aPhysAddr); #endif return KErrNone; } @@ -2106,34 +2409,34 @@ // Makes things simpler for bma selection. __NK_ASSERT_DEBUG(aType != EPageUnknown); - if (aOffset >= aZone->iPhysPages) + TUint zoneEndOffset = aZone->iPhysPages - 1; + if (aOffset > zoneEndOffset) {// Starting point is outside the zone return KErrArgument; } - TUint offset = aOffset; - TUint endOffset = aZone->iPhysPages; - TUint endOffsetAligned = endOffset & KWordAlignMask; + TUint wordIndex = aOffset >> 5; + TUint endWordIndex = zoneEndOffset >> 5; // Select the BMA to search, TUint bmaIndex = (aType == EPageTypes)? KBmaAllPages : aType; - TUint32* map = &(aZone->iBma[bmaIndex]->iMap[offset >> 5]); - TUint32 bits = *map++; + TUint32* map = &(aZone->iBma[bmaIndex]->iMap[wordIndex]); + TUint32* mapEnd = &(aZone->iBma[bmaIndex]->iMap[endWordIndex]); + TUint32 bits = *map; // Set bits for pages before 'offset' (i.e. ones we want to ignore)... - bits |= ~(KMaxTUint32 >> (offset & ~KWordAlignMask)); + bits |= ~(KMaxTUint32 >> (aOffset & ~KWordAlignMask)); // Find the first bit map word from aOffset in aZone with allocated pages - while (bits == KMaxTUint32 && offset < endOffsetAligned) + while (bits == KMaxTUint32 && map < mapEnd) { - bits = *map++; - offset = (offset + 32) & KWordAlignMask; + bits = *++map; } - if (offset >= endOffsetAligned && endOffset != endOffsetAligned) + if (map == mapEnd) {// Have reached the last bit mask word so set the bits that are // outside of the zone so that they are ignored. - bits |= KMaxTUint32 >> (endOffset - endOffsetAligned); + bits |= (KMaxTUint32 >> (zoneEndOffset & ~KWordAlignMask)) >> 1; } if (bits == KMaxTUint32) @@ -2143,25 +2446,104 @@ // Now we have bits with allocated pages in it so determine the exact // offset of the next allocated page - TUint32 mask = 0x80000000 >> (offset & ~KWordAlignMask); - while (bits & mask) - { - mask >>= 1; - offset++; - } - - if (offset >= endOffset) - {// Reached the end of the zone without finding an allocated page after aOffset - return KErrNotFound; - } - - // Should definitely have found an allocated page within aZone's pages - __NK_ASSERT_DEBUG(mask != 0 && !(bits & mask) && offset < aZone->iPhysPages); - - aOffset = offset; + TInt msOne = __e32_find_ms1_32(~bits); + __NK_ASSERT_DEBUG(msOne >= 0); // Must have at least one allocated page in the word. + TUint msOneOffset = 31 - msOne; + aOffset = ((map - aZone->iBma[bmaIndex]->iMap) << 5) + msOneOffset; return KErrNone; } + +/** +Get the next run of pages in this zone that are allocated after aOffset. + +@param aZone The zone to find the next allocated page in. +@param aOffset On entry this is the offset from which the next allocated + page in the zone should be found, on return it will be the offset + of the next allocated page. +@param aEndOffset The last offset within this RAM zone to check for allocated runs. +@return The length of any run found, KErrNotFound if no more pages in +the zone after aOffset are allocated, KErrArgument if aOffset is outside the zone. +*/ +TInt DRamAllocator::NextAllocatedRun(SZone* aZone, TUint& aOffset, TUint aEndOffset, TZonePageType aType) const + { + const TUint KWordAlignMask = KMaxTUint32 << 5; + + M::RamAllocIsLocked(); + + __NK_ASSERT_DEBUG(aZone - iZones < (TInt)iNumZones); + // Makes things simpler for bma selection. + __NK_ASSERT_DEBUG(aType != EPageUnknown); + + if (aOffset > aEndOffset) + {// UnblockContiguous() has already searched the whole range for this page type. + return 0; + } + + TUint wordIndex = aOffset >> 5; + TUint endWordIndex = aEndOffset >> 5; + + // Select the BMA to search, + TUint bmaIndex = (aType == EPageTypes)? KBmaAllPages : aType; + TUint32* map = &(aZone->iBma[bmaIndex]->iMap[wordIndex]); + TUint32* mapEnd = &(aZone->iBma[bmaIndex]->iMap[endWordIndex]); + TUint32 bits = *map; + + // Set bits for pages before 'offset' (i.e. ones we want to ignore)... + bits |= ~(KMaxTUint32 >> (aOffset & ~KWordAlignMask)); + + // Find the first bit map word from aOffset in aZone with allocated pages + while (bits == KMaxTUint32 && map < mapEnd) + { + bits = *++map; + } + + if (map == mapEnd) + {// Have reached the last bit mask word so set the bits that are + // outside of the range so that they are ignored. + bits |= (KMaxTUint32 >> (aEndOffset & ~KWordAlignMask)) >> 1; + } + + if (bits == KMaxTUint32) + {// No allocated pages found in the range. + aOffset = aEndOffset + 1; + return 0; + } + + // Now we have bits with allocated pages in it so determine the exact + // offset of the next allocated page + TInt msOne = __e32_find_ms1_32(~bits); + __NK_ASSERT_DEBUG(msOne >= 0); // Must have at least one allocated page in the word. + TUint msOneOffset = 31 - msOne; + aOffset = ((map - aZone->iBma[bmaIndex]->iMap) << 5) + msOneOffset; + TUint32* runWord = map; + + if (map < mapEnd && __e32_bit_count_32(~bits) == msOne + 1) + {// The whole of the region in this word is allocated. + // Find the next word which isn't completely allocated within the range. + do + { + bits = *++map; + } + while (!bits && map < mapEnd); + } + + // Clear any bits before the run so can get next free from __e32_find_msl_32(). + if (runWord == map) + bits &= KMaxTUint32 >> (aOffset & ~KWordAlignMask); + TInt msFree = __e32_find_ms1_32(bits); + __NK_ASSERT_DEBUG(msFree >= 0 || map == mapEnd); + TUint msFreeOffset = (msFree >= 0)? 31 - msFree : 32; + TUint endIndex = map - aZone->iBma[bmaIndex]->iMap; + TUint runEnd = (endIndex << 5) + msFreeOffset; + if (runEnd > aEndOffset + 1) // Ensure we don't go past the range. + runEnd = aEndOffset + 1; + __NK_ASSERT_DEBUG(runEnd > aOffset); + + return runEnd - aOffset; + } + + /** See if any of the least preferable RAM zones can be emptied. If they can then initialise the allocator for a general defragmentation operation. @@ -2852,7 +3234,7 @@ It outputs the zone configuration and the base addresses of any contiguous block of allocated pages. */ -void DRamAllocator::SendInitialBtraceLogs(void) +void DRamAllocator::DoBTracePrime(void) { M::RamAllocIsLocked(); CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL, "DRamAllocator::SendInitialBtraceLogs"); diff -r e880629062dd -r e4a7b1cbe40c kernel/eka/memmodel/epoc/moving/mchunk.cpp --- a/kernel/eka/memmodel/epoc/moving/mchunk.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kernel/eka/memmodel/epoc/moving/mchunk.cpp Mon May 10 11:40:53 2010 +0100 @@ -467,7 +467,8 @@ { // Allocate a block of contiguous RAM from the free pool TInt numPages=(endOffset-offset)>>m.iPageShift; - r=m.AllocContiguousRam(numPages<1) { TInt align=aSeparateGlobal ? KPageDirectoryShift : KPageDirectoryShift-1; - r=AllocContiguousRam(aNumPages<>m.iPageShift; - r=m.AllocContiguousRam(numPages<Avail()==aSize); + // Allocate whole free bma + test_Equal(aSize, pA->SelectiveAlloc(0, aSize)); + test_Equal(0,pA->Avail()); + // Allocate whole full bma + test_Equal(0, pA->SelectiveAlloc(0, aSize)); + test_Equal(0,pA->Avail()); + TInt i; + TInt j; + TInt l; + for (i=2; i<8; ++i) + { + for (l=1; l<=aSize; ++l) + { + new (pA) TBitMapAllocator(aSize, ETrue); + for (j=0; jAlloc(j,1); + TInt orig=pA->Avail(); + test_Equal(aSize-(aSize+i-1)/i, orig); + TUint newAllocs = pA->SelectiveAlloc(0,l); + TInt allocated = orig - pA->Avail(); + test_Equal(allocated, newAllocs); + test_Equal(l - (l+i-1)/i, allocated); + Check(*pA); + } + } + for (i=0; i<=Min(32,aSize-1); ++i) + { + for (l=1; l<=aSize-i; ++l) + { + for (j=1; j<=aSize; ++j) + { + new (pA) TBitMapAllocator(aSize, ETrue); + pA->Alloc(i,l); + test_Equal(aSize-l, pA->Avail()); + TUint newAllocs = pA->SelectiveAlloc(0,j); + TUint allocated = j - Max(0,Min(i+l,j)-i); + test_Equal(allocated, newAllocs); + test_Equal(pA->Avail(), aSize-l-allocated); + test(!pA->NotAllocated(0,j)); + if (j>=i && jNotAllocated(0,j+1)); + Check(*pA); + } + } + } + delete pA; + } + + TBitMapAllocator* DoSetupBMA(TInt aSize, VA_LIST aList) { TBitMapAllocator* pA=TBitMapAllocator::New(aSize, EFalse); @@ -1246,6 +1302,11 @@ TestSelectiveFree(128); TestSelectiveFree(149); + TestSelectiveAlloc(3); + TestSelectiveAlloc(31); + TestSelectiveAlloc(128); + TestSelectiveAlloc(149); + TestAllocConsecutive(); TestChain(); diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/buffer/t_tbma.h --- a/kerneltest/e32test/buffer/t_tbma.h Wed May 05 05:11:16 2010 +0100 +++ b/kerneltest/e32test/buffer/t_tbma.h Mon May 10 11:40:53 2010 +0100 @@ -39,6 +39,7 @@ IMPORT_C void Free(TInt aPos); IMPORT_C void Alloc(TInt aStart, TInt aLength); IMPORT_C void Free(TInt aStart, TInt aLength); + IMPORT_C TUint SelectiveAlloc(TInt aStart, TInt aLength); IMPORT_C void SelectiveFree(TInt aStart, TInt aLength); IMPORT_C TBool NotFree(TInt aStart, TInt aLength) const; IMPORT_C TBool NotAllocated(TInt aStart, TInt aLength) const; diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/defrag/t_ramdefrag.cpp --- a/kerneltest/e32test/defrag/t_ramdefrag.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kerneltest/e32test/defrag/t_ramdefrag.cpp Mon May 10 11:40:53 2010 +0100 @@ -33,6 +33,7 @@ #include #include #include "testdefs.h" +#include "..\mmu\mmudetect.h" #include @@ -128,6 +129,7 @@ LOCAL_D TInt* gCandList1; // Array of zones that have the same preference and the same LOCAL_D TInt* gCandList2; // amount of free pages const TInt KInvalidCandIndex = -1; +LOCAL_D TUint gMemModel; // // GetDrive @@ -489,6 +491,8 @@ currentCacheSize >> gPageShift)); } + // Get the memory model of the kernel that this test is running on. + gMemModel = MemModelType(); return KErrNone; } @@ -1536,7 +1540,7 @@ } if (totalMorePrefInUse > requiredMovDis) - {// There enough allocatable pages in the RAM zones below the currently + {// There are enough allocatable pages in the RAM zones below the currently // least preferable RAM in use. test.Printf(_L("Memory is spread out totalMorePref 0x%x required 0x%x\n"), totalMorePrefInUse, requiredMovDis); if (verifySpread) @@ -7073,16 +7077,20 @@ //! @SYMPREQ PREQ308 //! @SYMTestPriority High //! @SYMTestActions -//! 1. Allocate fixed pages and call function to free all fixed pages allocated. +//! 1. Allocate fixed pages and call function to free all fixed pages allocated. +//! 2. Claim a RAM zone and then free it via Epoc::FreeRamZone(). +//! 3. Invoke Epoc::FreeRamZone() with an invalid RAM zone ID. //! //! @SYMTestExpectedResults //! 1. KErrNone +//! 2. KErrNone +//! 3. KErrArgument //--------------------------------------------------------------------------------------------------------------------- TInt TestFreeZone() { TInt r = 0; TUint zoneID = 0; - test.Start(_L("Test1: Free allocated pages")); + test.Start(_L("Test1: Freeing allocated pages")); TestStart(); TInt pages = 50; @@ -7128,7 +7136,58 @@ } } TestEnd(); - + test.End(); + + test.Start(_L("Test2: Epoc::FreeRamZone() on a claimed RAM zone")); + TestStart(); + GetAllPageInfo(); + TUint zoneIndex = 0; + while (zoneIndex < gZoneCount) + { + if (gZoneUtilArray[zoneIndex].iFreePages == gZoneUtilArray[zoneIndex].iPhysPages) + break; + zoneIndex++; + } + if (zoneIndex >= gZoneCount) + { + test.Printf(_L("Cannot find zone to perform test, Skipping test step...\n")); + goto Test2End; + } + zoneID = gZoneConfigArray[zoneIndex].iZoneId; + r = Ldd.CallDefrag(DEFRAG_TYPE_CLAIM, DEFRAG_VER_SYNC, zoneID); + if (r != KErrNone) + { + test.Printf(_L("Fail: r = %d, expected = %d\n"), r, KErrNone); + TEST_FAIL; + } + GetAllPageInfo(); + if (gZoneUtilArray[zoneIndex].iPhysPages != gZoneUtilArray[zoneIndex].iAllocFixed) + { + test.Printf(_L("Fail: RAM zone ID %d not claimed successfully"), zoneID); + TEST_FAIL; + } + r = Ldd.FreeZoneId(zoneID); + GetAllPageInfo(); + if (r != KErrNone || + gZoneUtilArray[zoneIndex].iPhysPages != gZoneUtilArray[zoneIndex].iFreePages) + { + test.Printf(_L("Fail: RAM zone ID %d not freed successfully r=%d"), zoneID, r); + TEST_FAIL; + } +Test2End: + TestEnd(); + test.End(); + + test.Start(_L("Test2: Epoc::FreeRamZone() on an invalid RAM zone")); + TestStart(); + r = Ldd.FreeZoneId(KInvalidZoneID); + if (r != KErrArgument) + { + test.Printf(_L("Fail: Error RAM zone ID %d r=%d"), KInvalidZoneID, r); + TEST_FAIL; + } + + TestEnd(); test.End(); return KErrNone; } @@ -9384,6 +9443,14 @@ test.Next(_L("Test5: Filling the FS Cache and allocating more than 16 contiguous fixed pages")); TestStart(); + + if (gMemModel >= EMemModelTypeFlexible) + {// The flexible memory model won't flush the whole paging cache for + // contiguous allocations >16 pages so skip the next test. + test.Printf(_L("This memory model won't flush the cache - Skipping...\n")); + goto SkipTest5; + } + // TestEnd() will have reduced any cache pages to minimum so just get current // count of discardable pages. GetAllPageInfo(); diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/demandpaging/t_datapaging.cpp --- a/kerneltest/e32test/demandpaging/t_datapaging.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kerneltest/e32test/demandpaging/t_datapaging.cpp Mon May 10 11:40:53 2010 +0100 @@ -236,7 +236,7 @@ CLOSE_AND_WAIT(thread); } CLOSE_AND_WAIT(gChunk); - User::After(1000000); + UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0); __KHEAP_MARKEND; } @@ -783,6 +783,9 @@ test_KErrNone(timeoutStatus.Int()); CLOSE_AND_WAIT(gChunk); + + UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0); + __KHEAP_MARKEND; } diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/device/t_usbapi.cpp --- a/kerneltest/e32test/device/t_usbapi.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kerneltest/e32test/device/t_usbapi.cpp Mon May 10 11:40:53 2010 +0100 @@ -1849,6 +1849,29 @@ { test.Start(_L("Test Endpoint Stall Status")); +#ifdef BSW_USB_DRC + // The MACRO comes from ncp adaptation to indicate that otg is built in. + // Newly added code for defect ou1cimx1#267421. When otg is built in and the device is not + // in peripheral role, the ncp adaptation will return a dummy endpoint for the stall operation. + // The solution is to check if the device is in peripheral mode, if not, skip the stall + // operation. A problem is now we can't find a good solution to check the current role of the device. + // For the test environement, it's ok to use the USB state to confirm and from the test result, + // it works fine. Later when we find accurate method, we will change the confirmation logic. + TInt ret = KErrNone; + + TUsbcDeviceState devstate = EUsbcDeviceStateUndefined; + ret = gPort.DeviceStatus(devstate); + test(ret == KErrNone); + + if( EUsbcDeviceStateUndefined==devstate ) + { + test.Printf( _L("Device not connected, state EUsbcDeviceStateUndefined.\n") ); + test.Printf( _L("Skipping endpoint stall status tests.\n") ); + test.End(); + return; + } +#endif + if (!SupportsEndpointStall()) { test.Printf(_L("*** Not supported - skipping endpoint stall status tests\n")); diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/digitiser/digi.auto.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/digitiser/digi.auto.bat Mon May 10 11:40:53 2010 +0100 @@ -0,0 +1,19 @@ +rem +rem Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +rem All rights reserved. +rem This component and the accompanying materials are made available +rem under the terms of the License "Eclipse Public License v1.0" +rem which accompanies this distribution, and is available +rem at the URL "http://www.eclipse.org/legal/epl-v10.html". +rem +rem Initial Contributors: +rem Nokia Corporation - initial contribution. +rem +rem Contributors: +rem +rem Description: +rem + +t_userdigitisertest +t_userdigitisernocap +t_ldddigitisertest diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/digitiser/digitiser.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/digitiser/digitiser.inf Mon May 10 11:40:53 2010 +0100 @@ -0,0 +1,44 @@ +// 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: +// Digitiser Driver Tests +// Convienence INF file to build just Digitiser tests "bldmake -f digitiser.inf bldfiles" +// Test MMPs also part of the offical ../group/bld.inf e32test component. +// + +/** +@file + +@SYMPurpose Kernel and User library test code +*/ + +PRJ_PLATFORMS + +BASEDEFAULT + +PRJ_TESTEXPORTS + +digitiser_tests.iby /epoc32/rom/include/digitiser_tests.iby +tshell_digitisertests.oby ../../../kernel/eka/rombuild/tshell_digitisertests.oby + +digi.auto.bat /epoc32/rom/include/digi.auto.bat + +PRJ_TESTMMPFILES + +..\group\d_ldddigitisertest support + +#ifndef SMP +..\group\t_userdigitisertest +..\group\t_userdigitisernocaps +..\group\t_ldddigitisertest +#endif diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/digitiser/digitiser_tests.iby --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/digitiser/digitiser_tests.iby Mon May 10 11:40:53 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: +// Digitiser Driver Test Application +// + +#ifndef __DIGITISER_TEST_IBY__ +#define __DIGITISER_TEST_IBY__ + +device[VARID]=\Epoc32\Release\##KMAIN##\##BUILD##\d_ldddigitisertest.ldd \sys\bin\d_ldddigitisertest.ldd +file=\Epoc32\Release\##MAIN##\##BUILD##\t_ldddigitisertest.exe \sys\bin\t_ldddigitisertest.exe +file=\Epoc32\Release\##MAIN##\##BUILD##\t_userdigitisertest.exe \sys\bin\t_userdigitisertest.exe +file=\Epoc32\Release\##MAIN##\##BUILD##\t_userdigitisernocaps.exe \sys\bin\t_userdigitisernocaps.exe + +data=\epoc32\rom\include\digi.auto.bat \digi.auot.bat + +#endif // __DIGITISER_TEST_IBY__ diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/digitiser/t_traweventdigitiser.cpp --- a/kerneltest/e32test/digitiser/t_traweventdigitiser.cpp Wed May 05 05:11:16 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). -// All rights reserved. -// This component and the accompanying materials are made available -// under the terms of the License "Eclipse Public License v1.0" -// which accompanies this distribution, and is available -// at the URL "http://www.eclipse.org/legal/epl-v10.html". -// -// Initial Contributors: -// Nokia Corporation - initial contribution. -// -// Contributors: -// -// Description: -// e32test\digitiser\t_traweventdigitiser.cpp -// Overview: -// Test the TRawEvent APIS and events associated with the Digitiser and also verify the BTRACEs (manually) -// API Information: -// UserSvr -// Details: -// - Test the following 6 Events types -// 1. EPointerMove -// 2. EPointer3DInRange, -// 3. EPointer3DOutOfRange, -// 4. EPointer3DTilt, -// 5. EPointer3DRotation, -// 6. EPointer3DTiltAndMove, -// Platforms/Drives/Compatibility: -// All. -// Assumptions/Requirement/Pre-requisites: -// Failures and causes: -// -// - -#include -#include -#include -#include - -LOCAL_D RTest test(_L("t_TRawEventDigitiser")); - -class TestTRawDigitiserEvent - { -public: - TestTRawDigitiserEvent(TRawEvent::TType aType,TInt aX,TInt aY,TInt aZ,TInt aScanCode,TInt aPhi,TInt aTheta,TInt aAlpha,TUint8 aPointerNumber,TUint8 iTip); - void TestEvents(); -private: - TRawEvent::TType iType; - TInt iX; - TInt iY; - TInt iZ; - TInt iScanCode; - TInt iPhi; - TInt iTheta; - TInt iAlpha; - TUint8 iPointerNumber; - TUint8 iTip; - TRawEvent iDigitiser3DEvent; - }; - - -TestTRawDigitiserEvent::TestTRawDigitiserEvent(TRawEvent::TType aType,TInt aX,TInt aY,TInt aZ,TInt aScanCode,TInt aPhi,TInt aTheta,TInt aAlpha,TUint8 aPointerNumber,TUint8 aTip):iType(aType),iX(aX),iY(aY),iZ(aZ),iScanCode(aScanCode),iPhi(aPhi),iTheta(aTheta),iAlpha(aAlpha),iPointerNumber(aPointerNumber),iTip(aTip) - {} - - -void TestTRawDigitiserEvent::TestEvents() - { - - test(iDigitiser3DEvent.Type()==0); - iDigitiser3DEvent.Set(iType); - test(iDigitiser3DEvent.Type()==iType); - iDigitiser3DEvent.SetPointerNumber(iPointerNumber); - test(iPointerNumber == iDigitiser3DEvent.PointerNumber()); - iDigitiser3DEvent.Set(iType,iScanCode); - //Set the Type temporarily to get through the assertion - iDigitiser3DEvent.Set(TRawEvent::EKeyDown); - test(iScanCode==iDigitiser3DEvent.ScanCode()); - iDigitiser3DEvent.Set(iType,iX,iY); - //Set the Type temporarily to get through the assertion - iDigitiser3DEvent.Set(TRawEvent::EPointerMove); - test(TPoint(iX,iY)==iDigitiser3DEvent.Pos()); - iDigitiser3DEvent.Set(iType,iX,iY,iZ); - //Set the Type temporarily to get through the assertion - iDigitiser3DEvent.Set(TRawEvent::EPointerMove); - test(TPoint3D(iX,iY,iZ)==iDigitiser3DEvent.Pos3D()); - iDigitiser3DEvent.SetTip(iTip); - test(TBool(iTip) == iDigitiser3DEvent.IsTip()); - iDigitiser3DEvent.SetTilt(iType,iPhi,iTheta); - //Set the Type temporarily to get through the assertion - iDigitiser3DEvent.Set(TRawEvent::EPointer3DTilt); - TAngle3D rawEventAnge3D=iDigitiser3DEvent.Tilt(); - test((rawEventAnge3D.iPhi==iPhi) && (rawEventAnge3D.iTheta==iTheta)) ; - - - iDigitiser3DEvent.SetRotation(iType,iAlpha); - //Set the Type temporarily to get through the assertion - iDigitiser3DEvent.Set(TRawEvent::EPointer3DRotation); - test(iAlpha == iDigitiser3DEvent.Rotation()); - iDigitiser3DEvent.Set(iType,iX+1,iY+1,iZ+1,iPhi+1,iTheta+1,iAlpha+1); - //Set the Type temporarily to get through the assertion - iDigitiser3DEvent.Set(TRawEvent::EPointer3DTiltAndMove); - test(TPoint3D(iX+1,iY+1,iZ+1)==iDigitiser3DEvent.Pos3D()); - rawEventAnge3D=iDigitiser3DEvent.Tilt(); - test((rawEventAnge3D.iPhi==iPhi+1) &&(rawEventAnge3D.iTheta==iTheta+1)); - test((iAlpha+1) == iDigitiser3DEvent.Rotation()); - iDigitiser3DEvent.Set(iType,iX+2,iY+2,iZ+2,static_cast(iPointerNumber+1)); - //Set the Type temporarily to get through the assertion - iDigitiser3DEvent.Set(TRawEvent::EPointer3DTiltAndMove); - test(TPoint3D(iX+2,iY+2,iZ+2)==iDigitiser3DEvent.Pos3D()); - test((iPointerNumber+1) == iDigitiser3DEvent.PointerNumber()); - - UserSvr::AddEvent(iDigitiser3DEvent); - } - - -GLDEF_C TInt E32Main() -// -// - { - - test.Title(); - test.Start(_L("Testing Digitiser Events")); - - TestTRawDigitiserEvent digitiserEvent1(TRawEvent::EPointerMove, -890,-123, -823,455,2563,156,62,3,1); - TestTRawDigitiserEvent digitiserEvent2(TRawEvent::EPointer3DInRange, 23,45,23,1,2,6,4,2,1); - TestTRawDigitiserEvent digitiserEvent3(TRawEvent::EPointer3DOutOfRange, 23,45,23,1,2,6,4,2,0); - TestTRawDigitiserEvent digitiserEvent4(TRawEvent::EPointer3DTilt, 23,45,23,1,2,6,4,2,1); - TestTRawDigitiserEvent digitiserEvent5(TRawEvent::EPointer3DRotation, 23,45,23,1,2,6,4,2,1); - TestTRawDigitiserEvent digitiserEvent6(TRawEvent::EPointer3DTiltAndMove, 23,45,23,1,2,6,4,2,0); - - digitiserEvent1.TestEvents(); - digitiserEvent2.TestEvents(); - digitiserEvent3.TestEvents(); - digitiserEvent4.TestEvents(); - digitiserEvent5.TestEvents(); - digitiserEvent6.TestEvents(); - test.Printf(_L("T_TRAWEVENTDIGITISER: TEST Successfully Completed\n")); - test.End(); - test.Close(); - - return KErrNone; - - } - diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/digitiser/t_userdigitisertest.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/digitiser/t_userdigitisertest.cpp Mon May 10 11:40:53 2010 +0100 @@ -0,0 +1,267 @@ +// 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\digitiser\t_userdigitisertest.cpp +// Overview: +// Test the TRawEvent APIS and events associated with the Digitiser and also verify the BTRACEs (manually) +// Test HAL digitiser orientation attribute +// API Information: +// UserSvr +// Details: +// - Test the following 6 Events types +// 1. EPointerMove +// 2. EPointer3DInRange, +// 3. EPointer3DOutOfRange, +// 4. EPointer3DTilt, +// 5. EPointer3DRotation, +// 6. EPointer3DTiltAndMove, +// Platforms/Drives/Compatibility: +// All. +// Assumptions/Requirement/Pre-requisites: +// Failures and causes: +// +// + +#define __E32TEST_EXTENSION__ +#include +#include +#include +#include +#include + +#ifndef E32TEST_NOCAPS +LOCAL_D RTest test(_L("T_UserDigitiserTest")); +#else +LOCAL_D RTest test(_L("T_UserDigitiserNoCaps")); +#endif + +class TestTRawDigitiserEvent + { +public: + TestTRawDigitiserEvent(TRawEvent::TType aType,TInt aX,TInt aY,TInt aZ,TInt aScanCode,TInt aPhi,TInt aTheta,TInt aAlpha,TUint8 aPointerNumber,TUint8 iTip); + void TestEvents(); +private: + TRawEvent::TType iType; + TInt iX; + TInt iY; + TInt iZ; + TInt iScanCode; + TInt iPhi; + TInt iTheta; + TInt iAlpha; + TUint8 iPointerNumber; + TUint8 iTip; + TRawEvent iDigitiser3DEvent; + }; + + +TestTRawDigitiserEvent::TestTRawDigitiserEvent(TRawEvent::TType aType,TInt aX,TInt aY,TInt aZ,TInt aScanCode,TInt aPhi,TInt aTheta,TInt aAlpha,TUint8 aPointerNumber,TUint8 aTip):iType(aType),iX(aX),iY(aY),iZ(aZ),iScanCode(aScanCode),iPhi(aPhi),iTheta(aTheta),iAlpha(aAlpha),iPointerNumber(aPointerNumber),iTip(aTip) + {} + + +void TestTRawDigitiserEvent::TestEvents() + { + static TInt count = 0; + count++; + test.Printf(_L("TestTRawDigitiserEvent test case %2d\n"), count); + + test(iDigitiser3DEvent.Type()==0); + iDigitiser3DEvent.Set(iType); + test(iDigitiser3DEvent.Type()==iType); + iDigitiser3DEvent.SetPointerNumber(iPointerNumber); + test(iPointerNumber == iDigitiser3DEvent.PointerNumber()); + iDigitiser3DEvent.Set(iType,iScanCode); + //Set the Type temporarily to get through the assertion + iDigitiser3DEvent.Set(TRawEvent::EKeyDown); + test(iScanCode==iDigitiser3DEvent.ScanCode()); + iDigitiser3DEvent.Set(iType,iX,iY); + //Set the Type temporarily to get through the assertion + iDigitiser3DEvent.Set(TRawEvent::EPointerMove); + test(TPoint(iX,iY)==iDigitiser3DEvent.Pos()); + iDigitiser3DEvent.Set(iType,iX,iY,iZ); + //Set the Type temporarily to get through the assertion + iDigitiser3DEvent.Set(TRawEvent::EPointerMove); + test(TPoint3D(iX,iY,iZ)==iDigitiser3DEvent.Pos3D()); + iDigitiser3DEvent.SetTip(iTip); + test(TBool(iTip) == iDigitiser3DEvent.IsTip()); + iDigitiser3DEvent.SetTilt(iType,iPhi,iTheta); + //Set the Type temporarily to get through the assertion + iDigitiser3DEvent.Set(TRawEvent::EPointer3DTilt); + TAngle3D rawEventAnge3D=iDigitiser3DEvent.Tilt(); + test((rawEventAnge3D.iPhi==iPhi) && (rawEventAnge3D.iTheta==iTheta)) ; + + + iDigitiser3DEvent.SetRotation(iType,iAlpha); + //Set the Type temporarily to get through the assertion + iDigitiser3DEvent.Set(TRawEvent::EPointer3DRotation); + test(iAlpha == iDigitiser3DEvent.Rotation()); + iDigitiser3DEvent.Set(iType,iX+1,iY+1,iZ+1,iPhi+1,iTheta+1,iAlpha+1); + //Set the Type temporarily to get through the assertion + iDigitiser3DEvent.Set(TRawEvent::EPointer3DTiltAndMove); + test(TPoint3D(iX+1,iY+1,iZ+1)==iDigitiser3DEvent.Pos3D()); + rawEventAnge3D=iDigitiser3DEvent.Tilt(); + test((rawEventAnge3D.iPhi==iPhi+1) &&(rawEventAnge3D.iTheta==iTheta+1)); + test((iAlpha+1) == iDigitiser3DEvent.Rotation()); + iDigitiser3DEvent.Set(iType,iX+2,iY+2,iZ+2,static_cast(iPointerNumber+1)); + //Set the Type temporarily to get through the assertion + iDigitiser3DEvent.Set(TRawEvent::EPointer3DTiltAndMove); + test(TPoint3D(iX+2,iY+2,iZ+2)==iDigitiser3DEvent.Pos3D()); + test((iPointerNumber+1) == iDigitiser3DEvent.PointerNumber()); + + UserSvr::AddEvent(iDigitiser3DEvent); + } + + +struct HalAttribute_TestCase + { + HALData::TAttribute iAttr; + TInt iValueIn; + TInt iSetRC; // Set to KMaxTInt to skip set test case + TInt iGetRC; // Set to KMaxTInt to skip get test case + + }; + +static HalAttribute_TestCase gHalAttributeTests[] = + { +#ifndef E32TEST_NOCAPS + // Normal all pass tests + { HALData::EDigitiserOrientation, HALData::EDigitiserOrientation_000, KErrNone, KErrNone}, + { HALData::EDigitiserOrientation, HALData::EDigitiserOrientation_090, KErrNone, KErrNone}, + { HALData::EDigitiserOrientation, HALData::EDigitiserOrientation_180, KErrNone, KErrNone}, + { HALData::EDigitiserOrientation, HALData::EDigitiserOrientation_270, KErrNone, KErrNone}, + { HALData::EDigitiserOrientation, HALData::EDigitiserOrientation_default, KErrNone, KErrNone}, + + // Negative tests + { HALData::EDigitiserOrientation, -1, KErrArgument, KMaxTInt}, + { HALData::EDigitiserOrientation, 100, KErrArgument, KMaxTInt}, + +#else + // Platsec tests for no capabilities executable. + { HALData::EDigitiserOrientation, HALData::EDigitiserOrientation_default, KMaxTInt, KErrNone}, // Get, No caps needed + { HALData::EDigitiserOrientation, HALData::EDigitiserOrientation_default, KErrPermissionDenied, KMaxTInt}, // Set WDD cap needed +#endif + }; + +static TInt gNumHalAttributeTests = sizeof(gHalAttributeTests)/sizeof(HalAttribute_TestCase); + +void DoTestDigitiserHalAttributes() + { + __UHEAP_MARK; +#ifndef E32TEST_NOCAPS + test.Start(_L("DoTestDigitiserHalAttributes tests")); +#else + test.Start(_L("DoTestDigitiserHalAttributes NO CAPS tests")); + + // Skip No Caps testing for WDD caps when enforcement is not enabled on the + // platform i.e. when a emulator epoc.ini is missing. + if (!PlatSec::IsCapabilityEnforced(ECapabilityWriteDeviceData)) + { + test.Printf(_L("Platform security enforcement off, skipping\n")); + test.End(); + __UHEAP_MARKEND; + return; + } +#endif + + TInt i = 0; + TInt origValue = -1; + TInt r = HAL::Get(HALData::EDigitiserOrientation, origValue); + if (r == KErrNotSupported) + { + test.Printf(_L("Platform doesn't support EDigitiserOrientation, skipping\n")); + test.End(); + __UHEAP_MARKEND; + return; + } + test_KErrNone(r); + + // Attribute supported on platform, proceed with test. + TInt value = -1; + for (i=0; i < gNumHalAttributeTests; i++) + { + test.Printf(_L("DoTestDigitiserHalAttributes - step/row %2d\n"), i+1); + + if (gHalAttributeTests[i].iSetRC != KMaxTInt) // Skip set test? + { + r = HAL::Set(gHalAttributeTests[i].iAttr, gHalAttributeTests[i].iValueIn); + test_Equal( gHalAttributeTests[i].iSetRC, r); + } + + if (gHalAttributeTests[i].iGetRC != KMaxTInt) // Skip get test? + { + r = HAL::Get(gHalAttributeTests[i].iAttr, value); + test_Equal(gHalAttributeTests[i].iGetRC, r); + test_Equal(gHalAttributeTests[i].iValueIn, value); + } + } + +#ifndef E32TEST_NOCAPS + // Return system state back to before the test + r = HAL::Set(HALData::EDigitiserOrientation, origValue); + test_KErrNone(r); +#endif + + test.Printf(_L("DoTestDigitiserHalAttributes - complete\n")); + test.End(); + __UHEAP_MARKEND; + } + +#ifndef E32TEST_NOCAPS +void DoTestRawDigitiserEvent() + { + __UHEAP_MARK; + test.Start(_L("DoTestRawDigitiserEvent tests")); + + TestTRawDigitiserEvent digitiserEvent1(TRawEvent::EPointerMove, -890,-123, -823,455,2563,156,62,3,1); + TestTRawDigitiserEvent digitiserEvent2(TRawEvent::EPointer3DInRange, 23,45,23,1,2,6,4,2,1); + TestTRawDigitiserEvent digitiserEvent3(TRawEvent::EPointer3DOutOfRange, 23,45,23,1,2,6,4,2,0); + TestTRawDigitiserEvent digitiserEvent4(TRawEvent::EPointer3DTilt, 23,45,23,1,2,6,4,2,1); + TestTRawDigitiserEvent digitiserEvent5(TRawEvent::EPointer3DRotation, 23,45,23,1,2,6,4,2,1); + TestTRawDigitiserEvent digitiserEvent6(TRawEvent::EPointer3DTiltAndMove, 23,45,23,1,2,6,4,2,0); + + digitiserEvent1.TestEvents(); + digitiserEvent2.TestEvents(); + digitiserEvent3.TestEvents(); + digitiserEvent4.TestEvents(); + digitiserEvent5.TestEvents(); + digitiserEvent6.TestEvents(); + + test.End(); + __UHEAP_MARKEND; + } +#endif + + +GLDEF_C TInt E32Main() +// +// + { + __UHEAP_MARK; + + test.Title(); + test.Start(_L("User-side Digitiser Testing Events/HAL")); + + DoTestDigitiserHalAttributes(); + +#ifndef E32TEST_NOCAPS + DoTestRawDigitiserEvent(); +#endif + + test.Printf(_L("\n")); + test.End(); + test.Close(); + + __UHEAP_MARKEND; + return KErrNone; + } + diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/digitiser/tshell_digitisertests.oby --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/digitiser/tshell_digitisertests.oby Mon May 10 11:40:53 2010 +0100 @@ -0,0 +1,29 @@ +/* +* 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: +* +*/ + +#define BASE_ROM +#include + + +files= + +#include +#include "user.iby" +#include +#include + +#include diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/group/bld.inf --- a/kerneltest/e32test/group/bld.inf Wed May 05 05:11:16 2010 +0100 +++ b/kerneltest/e32test/group/bld.inf Mon May 10 11:40:53 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 1999-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" @@ -387,7 +387,8 @@ t_newldd t_lddpowerseqtest t_ldddigitisertest -t_traweventdigitiser +t_userdigitisertest +t_userdigitisernocaps t_persistrestart manual halsettings support @@ -506,6 +507,11 @@ t_heap t_heap2 t_heapdb +t_heapdl +t_heapslab +t_heapstress manual +t_heapcheck +t_heappagealloc t_kheap // Secure RNG tests @@ -867,7 +873,7 @@ t_logtofile manual t_eventtracker manual t_traceredirect support -t_heapcorruption support +t_heapcorruption support t_btrace t_perflogger diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/group/t_ramall.mmp --- a/kerneltest/e32test/group/t_ramall.mmp Wed May 05 05:11:16 2010 +0100 +++ b/kerneltest/e32test/group/t_ramall.mmp Mon May 10 11:40:53 2010 +0100 @@ -19,7 +19,7 @@ targettype exe sourcepath ../mmu source t_ramall.cpp -library euser.lib +library euser.lib dptest.lib OS_LAYER_SYSTEMINCLUDE_SYMBIAN diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/group/t_traweventdigitiser.mmp --- a/kerneltest/e32test/group/t_traweventdigitiser.mmp Wed May 05 05:11:16 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* -* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -* All rights reserved. -* This component and the accompanying materials are made available -* under the terms of 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: -* -*/ - -TARGET t_traweventdigitiser.exe -TARGETTYPE EXE -SOURCEPATH ../digitiser -SOURCE t_traweventdigitiser.cpp -LIBRARY euser.lib -OS_LAYER_SYSTEMINCLUDE_SYMBIAN - - -capability all - -VENDORID 0x70000001 - -SMPSAFE diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/group/t_userdigitisernocaps.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/group/t_userdigitisernocaps.mmp Mon May 10 11:40:53 2010 +0100 @@ -0,0 +1,36 @@ +/* +* 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: +* +*/ + +TARGET t_userdigitisernocaps.exe +TARGETTYPE EXE + +CAPABILITY None +MACRO E32TEST_NOCAPS + +VENDORID 0x70000001 +SMPSAFE + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +SOURCEPATH ../digitiser +SOURCE t_userdigitisertest.cpp + +LIBRARY euser.lib +LIBRARY hal.lib + + + diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/group/t_userdigitisertest.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/group/t_userdigitisertest.mmp Mon May 10 11:40:53 2010 +0100 @@ -0,0 +1,34 @@ +/* +* 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" +* 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: +* +*/ + +TARGET t_userdigitisertest.exe +TARGETTYPE EXE + +CAPABILITY SwEvent WriteDeviceData +VENDORID 0x70000001 +SMPSAFE + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +SOURCEPATH ../digitiser +SOURCE t_userdigitisertest.cpp + +LIBRARY euser.lib +LIBRARY hal.lib + + + diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/mmu/t_cachechunk.cpp --- a/kerneltest/e32test/mmu/t_cachechunk.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kerneltest/e32test/mmu/t_cachechunk.cpp Mon May 10 11:40:53 2010 +0100 @@ -98,7 +98,7 @@ TInt PageSize; TInt NoFreeRam; RTimer Timer; - +TBool gFmm; void FillPage(TUint aOffset) @@ -308,18 +308,44 @@ test_KErrNone(r); test.Next(_L("Check Decommit on unlocked pages")); + // Get orignal page cache size + TUint minCache = 0; + TUint maxCache = 0; + TUint oldCache = 0; + TUint newCache = 0; + if (gFmm) + { + r = DPTest::CacheSize(minCache, maxCache, oldCache); + test_KErrNone(r); + } r = TestChunk.Unlock(aOffset,PageSize*4); test_KErrNone(r); + + TUint spareCache = maxCache - oldCache; + if (gFmm && spareCache) + {// Cache wasn't at maximum so should have grown when unlocked pages were added. + r = DPTest::CacheSize(minCache, maxCache, newCache); + test_KErrNone(r); + TUint extraCache = (spareCache > (TUint)PageSize*4)? PageSize*4 : spareCache; + test_Equal(oldCache + extraCache, newCache); + } test(FreeRam() >= NoFreeRam+PageSize*4); r=TestChunk.Decommit(aOffset, PageSize*4); test_KErrNone(r); freeRam = FreeRam(); test_Compare(freeRam, >=, NoFreeRam+PageSize*4); test_Equal(origChunkSize - PageSize*4, TestChunk.Size()); + + if (gFmm) + {// Cache should have shrunk after pages were decommited. + r = DPTest::CacheSize(minCache, maxCache, newCache); + test_KErrNone(r); + test_Equal(oldCache, newCache); + } // Restore chunk back to original state r = TestChunk.Commit(aOffset, PageSize*4); test_KErrNone(r); - test(FreeRam() == NoFreeRam); + test_Equal(NoFreeRam, FreeRam()); test.Next(_L("Check Decommit on unlocked and reclaimed pages")); r = TestChunk.Unlock(aOffset,PageSize*4); @@ -351,6 +377,44 @@ test(freeRam==NoFreeRam); test_Equal(origChunkSize, TestChunk.Size()); + test.Next(_L("Check Decommit on a mixture of locked and unlocked pages")); + // Get orignal page cache size + if (gFmm) + { + r = DPTest::CacheSize(minCache, maxCache, oldCache); + test_KErrNone(r); + } + r = TestChunk.Unlock(aOffset,PageSize); + test_KErrNone(r); + r = TestChunk.Unlock(aOffset + PageSize*2, PageSize); + test_KErrNone(r); + + spareCache = maxCache - oldCache; + if (gFmm && spareCache) + {// Cache wasn't at maximum so should have grown when unlocked pages were added. + r = DPTest::CacheSize(minCache, maxCache, newCache); + test_KErrNone(r); + TUint extraCache = (spareCache > (TUint)PageSize*2)? PageSize*2 : spareCache; + test_Equal(oldCache + extraCache, newCache); + } + test(FreeRam() >= NoFreeRam+PageSize*2); + r=TestChunk.Decommit(aOffset, PageSize*4); + test_KErrNone(r); + freeRam = FreeRam(); + test_Compare(freeRam, >=, NoFreeRam+PageSize*4); + test_Equal(origChunkSize - PageSize*4, TestChunk.Size()); + + if (gFmm) + {// Cache should have shrunk after pages were decommited. + r = DPTest::CacheSize(minCache, maxCache, newCache); + test_KErrNone(r); + test_Equal(oldCache, newCache); + } + // Restore chunk back to original state + r = TestChunk.Commit(aOffset, PageSize*4); + test_KErrNone(r); + test_Equal(NoFreeRam, FreeRam()); + test.End(); } @@ -450,6 +514,10 @@ test.Printf(_L("This test requires an MMU\n")); return KErrNone; } + // See if were running on the Flexible Memory Model or newer. + TUint32 memModelAttrib = (TUint32)UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL); + gFmm = (memModelAttrib & EMemModelTypeMask) >= EMemModelTypeFlexible; + test.Start(_L("Initialise test")); test.Next(_L("Load gobbler LDD")); TInt r = User::LoadLogicalDevice(KGobblerLddFileName); diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/mmu/t_ramall.cpp --- a/kerneltest/e32test/mmu/t_ramall.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kerneltest/e32test/mmu/t_ramall.cpp Mon May 10 11:40:53 2010 +0100 @@ -20,6 +20,7 @@ #include #include #include +#include #include "d_shadow.h" #include "mmudetect.h" #include "freeram.h" @@ -32,6 +33,18 @@ TInt PageShift; RShadow Shadow; TInt InitFreeRam; +RChunk Chunk; +TUint ChunkCommitEnd; +RThread TouchThread; +TRequestStatus TouchStatus; +TBool TouchDataStop; +RThread FragThread; +TRequestStatus FragStatus; +TBool FragThreadStop; +TBool ManualTest; +TBool CacheSizeAdjustable; +TUint OrigMinCacheSize; +TUint OrigMaxCacheSize; TInt AllocPhysicalRam(TUint32& aAddr, TInt aSize, TInt aAlign) { @@ -118,6 +131,334 @@ } + +struct SPhysAllocData + { + TUint iSize; + TUint iAlign; + TBool iCheckMaxAllocs; + TBool iCheckFreeRam; + }; + + +TInt FillPhysicalRam(TAny* aArgs) + { + SPhysAllocData& allocData = *((SPhysAllocData*)aArgs); + TUint maxAllocs = FreeRam() / allocData.iSize; + TUint32* physAddrs = new TUint32[maxAllocs + 1]; + if (!physAddrs) + return KErrNoMemory; + TUint32* pa = physAddrs; + TUint32 alignMask = (1 << allocData.iAlign) - 1; + TUint initialFreeRam = FreeRam(); + TInt r = KErrNone; + TUint allocations = 0; + for(; allocations <= maxAllocs; ++allocations) + { + TUint freeRam = FreeRam(); + r = AllocPhysicalRam(*pa, allocData.iSize, allocData.iAlign); + if (r != KErrNone) + break; + if (*pa++ & alignMask) + { + r = KErrGeneral; + RDebug::Printf("Error alignment phys addr 0x%08x", *(pa - 1)); + break; + } + if (allocData.iCheckFreeRam && freeRam - allocData.iSize != (TUint)FreeRam()) + { + r = KErrGeneral; + RDebug::Printf("Error in free ram 0x%08x orig 0x%08x", FreeRam(), freeRam); + break; + } + } + + TUint32* physEnd = pa; + TBool failFrees = EFalse; + for (pa = physAddrs; pa < physEnd; pa++) + { + if (FreePhysicalRam(*pa, allocData.iSize) != KErrNone) + failFrees = ETrue; + } + if (failFrees) + r = KErrNotFound; + if (allocData.iCheckMaxAllocs && allocations > maxAllocs) + { + r = KErrOverflow; + RDebug::Printf("Error able to allocate too many pages"); + } + if (allocData.iCheckFreeRam && initialFreeRam != (TUint)FreeRam()) + { + r = KErrGeneral; + RDebug::Printf("Error in free ram 0x%08x initial 0x%08x", FreeRam(), initialFreeRam); + } + delete[] physAddrs; + if (r != KErrNone && r != KErrNoMemory) + return r; + TUint possibleAllocs = initialFreeRam / allocData.iSize; + if (allocData.iCheckMaxAllocs && possibleAllocs != allocations) + { + RDebug::Printf("Error in number of allocations possibleAllocs %d allocations %d", possibleAllocs, allocations); + return KErrGeneral; + } + return allocations; + } + + +void TestMultipleContiguousAllocations(TUint aNumThreads, TUint aSize, TUint aAlign) + { + test.Printf(_L("TestMultiContig threads %d size 0x%x, align %d\n"), aNumThreads, aSize, aAlign); + SPhysAllocData allocData; + allocData.iSize = aSize; + allocData.iAlign = aAlign; + allocData.iCheckMaxAllocs = EFalse; + allocData.iCheckFreeRam = EFalse; + // Start several threads all contiguous allocating memory. + RThread* threads = new RThread[aNumThreads]; + TRequestStatus* status = new TRequestStatus[aNumThreads]; + TUint i = 0; + for (; i < aNumThreads; i++) + {// Need enough heap to store addr of every possible allocation + 1. + TUint requiredHeapMax = Max(PageSize, ((InitFreeRam / aSize) / sizeof(TUint32)) + sizeof(TUint32)); + TInt r = threads[i].Create(KNullDesC, FillPhysicalRam, KDefaultStackSize, PageSize, requiredHeapMax, (TAny*)&allocData); + test_KErrNone(r); + threads[i].Logon(status[i]); + } + for (i = 0; i < aNumThreads; i++) + { + threads[i].Resume(); + } + for (i = 0; i < aNumThreads; i++) + { + User::WaitForRequest(status[i]); + test_Equal(EExitKill, threads[i].ExitType()); + TInt exitReason = threads[i].ExitReason(); + test_Value(exitReason, exitReason >= 0 || exitReason == KErrNoMemory); + threads[i].Close(); + } + delete[] status; + delete[] threads; + } + +struct STouchData + { + TUint iSize; + TUint iFrequency; + }TouchData; + + +TInt TouchMemory(TAny*) + { + while (!TouchDataStop) + { + TUint8* p = Chunk.Base(); + TUint8* pEnd = p + ChunkCommitEnd; + TUint8* fragPEnd = p + TouchData.iFrequency; + for (TUint8* fragP = p + TouchData.iSize; fragPEnd < pEnd;) + { + TUint8* data = fragP; + for (; data < fragPEnd; data += PageSize) + { + *data = (TUint8)(data - fragP); + } + for (data = fragP; data < fragPEnd; data += PageSize) + { + if (*data != (TUint8)(data - fragP)) + { + RDebug::Printf("Error unexpected data 0x%x read from 0x%08x", *data, data); + return KErrGeneral; + } + } + fragP = fragPEnd + TouchData.iSize; + fragPEnd += TouchData.iFrequency; + } + } + return KErrNone; + } + +struct SFragData + { + TUint iSize; + TUint iFrequency; + TUint iDiscard; + TBool iFragThread; + }FragData; + +void FragmentMemoryFunc() + { + ChunkCommitEnd = 0; + TInt r; + while(KErrNone == (r = Chunk.Commit(ChunkCommitEnd,PageSize)) && !FragThreadStop) + { + ChunkCommitEnd += PageSize; + } + if (FragThreadStop) + return; + test_Equal(KErrNoMemory, r); + TUint freeBlocks = 0; + for ( TUint offset = 0; + (offset + FragData.iSize) < ChunkCommitEnd; + offset += FragData.iFrequency, freeBlocks++) + { + test_KErrNone(Chunk.Decommit(offset, FragData.iSize)); + } + if (!FragData.iFragThread) + test_Equal(FreeRam(), freeBlocks * FragData.iSize); + + if (FragData.iDiscard && CacheSizeAdjustable && !FragThreadStop) + { + TUint minCacheSize = FreeRam(); + TUint maxCacheSize = minCacheSize; + TUint currentCacheSize; + test_KErrNone(DPTest::CacheSize(OrigMinCacheSize, OrigMaxCacheSize, currentCacheSize)); + test_KErrNone(DPTest::SetCacheSize(minCacheSize, maxCacheSize)); + test_KErrNone(DPTest::SetCacheSize(OrigMinCacheSize, maxCacheSize)); + } + } + + +void UnfragmentMemoryFunc() + { + if (FragData.iDiscard && CacheSizeAdjustable) + test_KErrNone(DPTest::SetCacheSize(OrigMinCacheSize, OrigMaxCacheSize)); + Chunk.Decommit(0, Chunk.MaxSize()); + } + + +TInt FragmentMemoryThreadFunc(TAny*) + { + while (!FragThreadStop) + { + FragmentMemoryFunc(); + UnfragmentMemoryFunc(); + } + return KErrNone; + } + + +void FragmentMemory(TUint aSize, TUint aFrequency, TBool aDiscard, TBool aTouchMemory, TBool aFragThread) + { + test_Value(aTouchMemory, !aTouchMemory || !aFragThread); + test_Value(aSize, aSize < aFrequency); + FragData.iSize = aSize; + FragData.iFrequency = aFrequency; + FragData.iDiscard = aDiscard; + FragData.iFragThread = aFragThread; + + TChunkCreateInfo chunkInfo; + chunkInfo.SetDisconnected(0, 0, FreeRam()); + chunkInfo.SetPaging(TChunkCreateInfo::EUnpaged); + test_KErrNone(Chunk.Create(chunkInfo)); + + if (aFragThread) + { + TInt r = FragThread.Create(KNullDesC, FragmentMemoryThreadFunc, KDefaultStackSize, PageSize, PageSize, NULL); + test_KErrNone(r); + FragThread.Logon(FragStatus); + FragThreadStop = EFalse; + FragThread.Resume(); + } + else + { + FragmentMemoryFunc(); + } + if (aTouchMemory && !ManualTest) + { + TouchData.iSize = aSize; + TouchData.iFrequency = aFrequency; + TInt r = TouchThread.Create(KNullDesC, TouchMemory, KDefaultStackSize, PageSize, PageSize, NULL); + test_KErrNone(r); + TouchThread.Logon(TouchStatus); + TouchDataStop = EFalse; + TouchThread.Resume(); + } + } + + +void UnfragmentMemory(TBool aDiscard, TBool aTouchMemory, TBool aFragThread) + { + test_Value(aTouchMemory, !aTouchMemory || !aFragThread); + if (aTouchMemory && !ManualTest) + { + TouchDataStop = ETrue; + User::WaitForRequest(TouchStatus); + test_Equal(EExitKill, TouchThread.ExitType()); + test_KErrNone(TouchThread.ExitReason()); + CLOSE_AND_WAIT(TouchThread); + } + if (aFragThread) + { + FragThreadStop = ETrue; + User::WaitForRequest(FragStatus); + test_Equal(EExitKill, FragThread.ExitType()); + test_KErrNone(FragThread.ExitReason()); + CLOSE_AND_WAIT(FragThread); + } + else + UnfragmentMemoryFunc(); + CLOSE_AND_WAIT(Chunk); + } + + +void TestFillPhysicalRam(TUint aFragSize, TUint aFragFreq, TUint aAllocSize, TUint aAllocAlign, TBool aDiscard, TBool aTouchMemory) + { + test.Printf(_L("TestFillPhysicalRam aFragSize 0x%x aFragFreq 0x%x aAllocSize 0x%x aAllocAlign %d dis %d touch %d\n"), + aFragSize, aFragFreq, aAllocSize, aAllocAlign, aDiscard, aTouchMemory); + FragmentMemory(aFragSize, aFragFreq, aDiscard, aTouchMemory, EFalse); + SPhysAllocData allocData; + // Only check free all ram could be allocated in manual tests as fixed pages may be fragmented. + allocData.iCheckMaxAllocs = (ManualTest && !aTouchMemory && !aAllocAlign)? ETrue : EFalse; + allocData.iCheckFreeRam = ETrue; + allocData.iSize = aAllocSize; + allocData.iAlign = aAllocAlign; + FillPhysicalRam(&allocData); + UnfragmentMemory(aDiscard, aTouchMemory, EFalse); + } + + +void TestFragmentedAllocation() + { + // Test every other page free. + TestFillPhysicalRam(PageSize, PageSize * 2, PageSize, 0, EFalse, EFalse); + if (ManualTest) + { + TestFillPhysicalRam(PageSize, PageSize * 2, PageSize * 2, 0, EFalse, EFalse); + TestFillPhysicalRam(PageSize, PageSize * 2, PageSize, 0, EFalse, ETrue); + } + TestFillPhysicalRam(PageSize, PageSize * 2, PageSize * 2, 0, EFalse, ETrue); + // Test every 2 pages free. + TestFillPhysicalRam(PageSize * 2, PageSize * 4, PageSize * 8, 0, EFalse, EFalse); + if (ManualTest) + TestFillPhysicalRam(PageSize * 2, PageSize * 4, PageSize * 8, 0, EFalse, ETrue); + // Test 10 pages free then 20 pages allocated, allocate 256 pages (1MB in most cases). + if (ManualTest) + TestFillPhysicalRam(PageSize * 10, PageSize * 30, PageSize * 256, 0, EFalse, EFalse); + TestFillPhysicalRam(PageSize * 10, PageSize * 30, PageSize * 256, 0, EFalse, ETrue); + + if (CacheSizeAdjustable) + {// It is possible to adjust the cache size so test phyiscally contiguous + // allocations discard and move pages when required. + test.Next(_L("TestFragmentedAllocations with discardable data no true free memory")); + // Test every other page free. + TestFillPhysicalRam(PageSize, PageSize * 2, PageSize, 0, ETrue, EFalse); + if (ManualTest) + { + TestFillPhysicalRam(PageSize, PageSize * 2, PageSize, 0, ETrue, ETrue); + TestFillPhysicalRam(PageSize, PageSize * 2, PageSize * 2, 0, ETrue, EFalse); + } + TestFillPhysicalRam(PageSize, PageSize * 2, PageSize * 2, 0, ETrue, ETrue); + // Test every 2 pages free. + TestFillPhysicalRam(PageSize * 2, PageSize * 4, PageSize * 8, 0, ETrue, EFalse); + if (ManualTest) + TestFillPhysicalRam(PageSize * 2, PageSize * 4, PageSize * 8, 0, ETrue, ETrue); + // Test 10 pages free then 20 pages allocated, allocate 256 pages (1MB in most cases). + if (ManualTest) + TestFillPhysicalRam(PageSize * 10, PageSize * 30, PageSize * 256, 0, ETrue, EFalse); + TestFillPhysicalRam(PageSize * 10, PageSize * 30, PageSize * 256, 0, ETrue, ETrue); + } + } + + GLDEF_C TInt E32Main() // // Test RAM allocation @@ -135,6 +476,28 @@ PageShift=-1; for (; psz; psz>>=1, ++PageShift); + TUint currentCacheSize; + CacheSizeAdjustable = DPTest::CacheSize(OrigMinCacheSize, OrigMaxCacheSize, currentCacheSize) == KErrNone; + + TUint memodel = UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL) & EMemModelTypeMask; + + TInt cmdLineLen = User::CommandLineLength(); + if(cmdLineLen) + { + _LIT(KManual, "manual"); + RBuf cmdLine; + test_KErrNone(cmdLine.Create(cmdLineLen)); + User::CommandLine(cmdLine); + cmdLine.LowerCase(); + ManualTest = cmdLine.Find(KManual) != KErrNotFound; + } + + // Turn off lazy dll unloading so the free ram checking isn't affected. + RLoader l; + test(l.Connect()==KErrNone); + test(l.CancelLazyDllUnload()==KErrNone); + l.Close(); + InitFreeRam=FreeRam(); test.Printf(_L("Free RAM=%08x, Page size=%x, Page shift=%d\n"),InitFreeRam,PageSize,PageShift); @@ -148,8 +511,54 @@ test.Next(_L("TestClaimPhys")); TestClaimPhys(); + if (memodel >= EMemModelTypeFlexible) + { + test.Next(_L("TestFragmentedAllocation")); + TestFragmentedAllocation(); + + test.Next(_L("TestMultipleContiguousAllocations")); + TestMultipleContiguousAllocations(20, PageSize * 16, 0); + TestMultipleContiguousAllocations(20, PageSize * 16, PageShift + 1); + TestMultipleContiguousAllocations(20, PageSize * 128, PageShift + 2); + + FragmentMemory(PageSize, PageSize * 2, EFalse, EFalse, EFalse); + TestMultipleContiguousAllocations(20, PageSize * 128, PageShift + 2); + UnfragmentMemory(EFalse, EFalse, EFalse); + + test.Next(_L("TestMultipleContiguousAllocations while accessing memory")); + FragmentMemory(PageSize, PageSize * 2, EFalse, ETrue, EFalse); + TestMultipleContiguousAllocations(20, PageSize * 128, PageShift + 2); + UnfragmentMemory(EFalse, ETrue, EFalse); + FragmentMemory(PageSize, PageSize * 2, ETrue, ETrue, EFalse); + TestMultipleContiguousAllocations(50, PageSize * 256, PageShift + 5); + UnfragmentMemory(ETrue, ETrue, EFalse); + FragmentMemory(PageSize * 16, PageSize * 32, ETrue, ETrue, EFalse); + TestMultipleContiguousAllocations(10, PageSize * 512, PageShift + 8); + UnfragmentMemory(ETrue, ETrue, EFalse); + FragmentMemory(PageSize * 32, PageSize * 64, ETrue, ETrue, EFalse); + TestMultipleContiguousAllocations(10, PageSize * 1024, PageShift + 10); + UnfragmentMemory(ETrue, ETrue, EFalse); + + test.Next(_L("TestMultipleContiguousAllocations with repeated movable and discardable allocations")); + FragmentMemory(PageSize, PageSize * 2, EFalse, EFalse, ETrue); + TestMultipleContiguousAllocations(20, PageSize * 2, PageShift); + UnfragmentMemory(EFalse, EFalse, ETrue); + FragmentMemory(PageSize, PageSize * 2, EFalse, EFalse, ETrue); + TestMultipleContiguousAllocations(20, PageSize * 128, PageShift + 2); + UnfragmentMemory(EFalse, EFalse, ETrue); + FragmentMemory(PageSize, PageSize * 2, ETrue, EFalse, ETrue); + TestMultipleContiguousAllocations(50, PageSize * 256, PageShift + 5); + UnfragmentMemory(ETrue, EFalse, ETrue); + FragmentMemory(PageSize * 16, PageSize * 32, ETrue, EFalse, ETrue); + TestMultipleContiguousAllocations(20, PageSize * 512, PageShift + 8); + UnfragmentMemory(ETrue, EFalse, ETrue); + FragmentMemory(PageSize * 32, PageSize * 64, ETrue, EFalse, ETrue); + TestMultipleContiguousAllocations(20, PageSize * 1024, PageShift + 10); + UnfragmentMemory(ETrue, EFalse, ETrue); + } + Shadow.Close(); + test.Printf(_L("Free RAM=%08x at end of test\n"),FreeRam()); test.End(); return(KErrNone); } - diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/prime/t_semutx.cpp --- a/kerneltest/e32test/prime/t_semutx.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kerneltest/e32test/prime/t_semutx.cpp Mon May 10 11:40:53 2010 +0100 @@ -38,7 +38,10 @@ // // +#define __E32TEST_EXTENSION__ #include +#include +#include const TInt KMaxBufferSize=10; const TInt KMaxArraySize=10; @@ -221,7 +224,7 @@ void StartWaitSemThread(RThread& aT, SWaitSem& aW, TThreadPriority aP=EPriorityLess) { TInt r = aT.Create(KNullDesC, &WaitSemThread, 0x1000, 0x1000, 0x1000, &aW); - test(r==KErrNone); + test_KErrNone(r); aT.SetPriority(aP); aT.Resume(); } @@ -231,9 +234,9 @@ TRequestStatus s; aT.Logon(s); User::WaitForRequest(s); - test(aT.ExitType()==EExitKill); - test(aT.ExitReason()==aResult); - test(s.Int()==aResult); + test_Equal(EExitKill, aT.ExitType()); + test_Equal(aResult, aT.ExitReason()); + test_Equal(aResult, s.Int()); CLOSE_AND_WAIT(aT); } @@ -251,7 +254,7 @@ TTime final; TInt elapsed=0; TInt r = ws.iSem.CreateLocal(0); - test(r==KErrNone); + test_KErrNone(r); RThread().SetPriority(EPriorityAbsoluteVeryLow); TInt threadcount=0; @@ -259,7 +262,7 @@ while (elapsed<1000000) { r = t.Create(KNullDesC, &DummyThread, 0x1000, NULL, NULL); - test(r==KErrNone); + test_KErrNone(r); t.SetPriority(EPriorityMore); t.Resume(); t.Close(); @@ -307,7 +310,7 @@ User::After(200000); t.Resume(); WaitForWaitSemThread(t, KErrTimedOut); - test(ws.iSem.Wait(1)==KErrNone); + test_KErrNone(ws.iSem.Wait(1)); ws.iTimeout=100000; StartWaitSemThread(t, ws, EPriorityMore); @@ -316,7 +319,7 @@ User::After(50000); t.Resume(); WaitForWaitSemThread(t, KErrNone); - test(ws.iSem.Wait(1)==KErrTimedOut); + test_Equal(KErrTimedOut, ws.iSem.Wait(1)); RThread t2; ws.iTimeout=100000; @@ -324,12 +327,12 @@ StartWaitSemThread(t2, ws, EPriorityMore); t.Suspend(); ws.iSem.Signal(); - test(t2.ExitType()==EExitKill); - test(t.ExitType()==EExitPending); + test_Equal(EExitKill, t2.ExitType()); + test_Equal(EExitPending, t.ExitType()); t.Resume(); WaitForWaitSemThread(t, KErrTimedOut); WaitForWaitSemThread(t2, KErrNone); - test(ws.iSem.Wait(1)==KErrTimedOut); + test_Equal(KErrTimedOut, ws.iSem.Wait(1)); ws.iTimeout=1000000; initial.HomeTime(); @@ -376,11 +379,11 @@ initial.HomeTime(); StartWaitSemThread(t, ws, EPriorityMore); StartWaitSemThread(t2, ws, EPriorityMuchMore); - test(t.ExitType()==EExitPending); - test(t2.ExitType()==EExitPending); + test_Equal(EExitPending, t.ExitType()); + test_Equal(EExitPending, t2.ExitType()); ws.iSem.Close(); - test(t.ExitType()==EExitKill); - test(t2.ExitType()==EExitKill); + test_Equal(EExitKill, t.ExitType()); + test_Equal(EExitKill, t2.ExitType()); WaitForWaitSemThread(t2, KErrGeneral); WaitForWaitSemThread(t, KErrGeneral); final.HomeTime(); @@ -414,23 +417,23 @@ test.Next(_L("Producer/Consumer scenario")); // Test Rsemaphore with the producer/consumer scenario RThread thread1, thread2; TRequestStatus stat1, stat2; - test(mutex.CreateLocal()==KErrNone); - test(slotAvailable.CreateLocal(KMaxBufferSize)==KErrNone); - test(itemAvailable.CreateLocal(0)==KErrNone); - test(thread1.Create(_L("Thread1"),Producer,KDefaultStackSize,0x200,0x200,NULL)==KErrNone); - test(thread2.Create(_L("Thread2"),Consumer,KDefaultStackSize,0x200,0x200,NULL)==KErrNone); + test_KErrNone(mutex.CreateLocal()); + test_KErrNone(slotAvailable.CreateLocal(KMaxBufferSize)); + test_KErrNone(itemAvailable.CreateLocal(0)); + test_KErrNone(thread1.Create(_L("Thread1"),Producer,KDefaultStackSize,0x200,0x200,NULL)); + test_KErrNone(thread2.Create(_L("Thread2"),Consumer,KDefaultStackSize,0x200,0x200,NULL)); thread1.Logon(stat1); thread2.Logon(stat2); - test(stat1==KRequestPending); - test(stat2==KRequestPending); + test_Equal(KRequestPending, stat1.Int()); + test_Equal(KRequestPending, stat2.Int()); thread1.Resume(); thread2.Resume(); User::WaitForRequest(stat1); User::WaitForRequest(stat2); - test(stat1==KErrNone); - test(stat2==KErrNone); + test_KErrNone(stat1.Int()); + test_KErrNone(stat2.Int()); for(TInt jj=0;jj>1)); + test_Equal(thread1Count, thread1ActualCount); + test_Equal(thread2Count, thread2ActualCount); + test_Equal(thread2Count, thread1Count); + test_Equal((KMaxArraySize>>1), thread1Count); test.Next(_L("Close")); CLOSE_AND_WAIT(thread1); @@ -521,7 +524,7 @@ { test.Start(_L("Create")); - test(criticalSn.CreateLocal()==KErrNone); + test_KErrNone(criticalSn.CreateLocal()); /***************** TO DO *********************** @@ -551,19 +554,19 @@ // arrayIndex=0; RThread thread1,thread2; - test(thread1.Create(_L("Thread1"),CriticalSnThreadEntryPoint1,KDefaultStackSize,0x2000,0x2000,NULL)==KErrNone); - test(thread2.Create(_L("Thread2"),CriticalSnThreadEntryPoint2,KDefaultStackSize,0x2000,0x2000,NULL)==KErrNone); + test_KErrNone(thread1.Create(_L("Thread1"),CriticalSnThreadEntryPoint1,KDefaultStackSize,0x2000,0x2000,NULL)); + test_KErrNone(thread2.Create(_L("Thread2"),CriticalSnThreadEntryPoint2,KDefaultStackSize,0x2000,0x2000,NULL)); TRequestStatus stat1,stat2; thread1.Logon(stat1); thread2.Logon(stat2); - test(stat1==KRequestPending); - test(stat2==KRequestPending); + test_Equal(KRequestPending, stat1.Int()); + test_Equal(KRequestPending, stat2.Int()); thread1.Resume(); thread2.Resume(); User::WaitForRequest(stat1); User::WaitForRequest(stat2); - test(stat1==KErrNone); - test(stat2==KErrNone); + test_KErrNone(stat1.Int()); + test_KErrNone(stat2.Int()); TInt thread1ActualCount=0; TInt thread2ActualCount=0; TInt ii=0; @@ -575,10 +578,10 @@ thread2ActualCount++; ii++; } - test(thread1ActualCount==thread1Count); - test(thread2ActualCount==thread2Count); - test(thread1Count==thread2Count); - test(thread1Count==(KMaxArraySize>>1)); + test_Equal(thread1Count, thread1ActualCount); + test_Equal(thread2Count, thread2ActualCount); + test_Equal(thread2Count, thread1Count); + test_Equal((KMaxArraySize>>1), thread1Count); test.Next(_L("Close")); CLOSE_AND_WAIT(thread1); @@ -590,6 +593,16 @@ GLDEF_C TInt E32Main() { + TInt cpus = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); + if (cpus != 1) + { + test(cpus>1); + // This test will require compatibility mode (and probably other changes) + // to work on SMP - it depends on explicit scheduling order. + test.Printf(_L("T_SEMUTX skipped, does not work on SMP\n")); + return KErrNone; + } + test.Title(); __UHEAP_MARK; diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/prime/t_semutx2.cpp --- a/kerneltest/e32test/prime/t_semutx2.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kerneltest/e32test/prime/t_semutx2.cpp Mon May 10 11:40:53 2010 +0100 @@ -37,7 +37,10 @@ // // +#define __E32TEST_EXTENSION__ #include +#include +#include RMutex M1; RMutex M2; @@ -62,8 +65,8 @@ //#define MCOUNT(m,c) test((m).Count() ==(c)) // mutex count value is not visible for user any more #define MCOUNT(m,c) (void)(1) -#define IDCHECK(x) test(GetNextId()==(x)) -#define NUMCHECK(x) test(NumIdsPending()==(x)) +#define IDCHECK(x) test_Equal((x), GetNextId()) +#define NUMCHECK(x) test_Equal((x), NumIdsPending()) #define id0 id[0] #define id1 id[1] @@ -153,38 +156,38 @@ TInt count=0; TRequestStatus s; TInt r=t.Create(_L("Test0"),Test0Thread,0x1000,NULL,&count); - test(r==KErrNone); + test_KErrNone(r); t.Logon(s); - test(r==KErrNone); + test_KErrNone(r); User::After(10000); // make sure we have a full timeslice t.Resume(); - test(count==0); // t shouldn't have run yet + test_Equal(0, count); // t shouldn't have run yet RThread().SetPriority(EPriorityMuchMore); // shouldn't reschedule (priority unchanged) - test(count==0); + test_Equal(0, count); RThread().SetPriority(EPriorityMore); // shouldn't reschedule (priority decreasing, but not enough) - test(count==0); + test_Equal(0, count); RThread().SetPriority(EPriorityMuchMore); // shouldn't reschedule (priority increasing) - test(count==0); + test_Equal(0, count); RThread().SetPriority(EPriorityNormal); // should reschedule (we go behind t) - test(count==1); + test_Equal(1, count); RThread().SetPriority(EPriorityLess); // should reschedule (priority decreasing to below t) - test(count==2); + test_Equal(2, count); t.SetPriority(EPriorityMuchMore); // shouldn't reschedule (round-robin, timeslice not expired) - test(count==2); + test_Equal(2, count); t.SetPriority(EPriorityNormal); // shouldn't reschedule (t's priority decreasing) - test(count==2); + test_Equal(2, count); t.SetPriority(EPriorityNormal); // shouldn't reschedule (t's priority unchanged) - test(count==2); + test_Equal(2, count); BusyWait(100000); // use up our timeslice t.SetPriority(EPriorityMuchMore); // should reschedule (round-robin, timeslice expired) - test(count==3); - test(s==KRequestPending); - test(t.ExitType()==EExitPending); + test_Equal(3, count); + test_Equal(KRequestPending, s.Int()); + test_Equal(EExitPending, t.ExitType()); t.SetPriority(EPriorityRealTime); // should reschedule (t increases above current) - test(count==4); - test(s==KErrNone); // t should have exited - test(t.ExitType()==EExitKill); + test_Equal(4, count); + test_KErrNone(s.Int()); // t should have exited + test_Equal(EExitKill, t.ExitType()); User::WaitForRequest(s); RThread().SetPriority(EPriorityMuchMore); t.Close(); @@ -201,11 +204,11 @@ { test.Start(_L("Test signalling from wrong thread")); TInt r=M1.CreateLocal(); - test(r==KErrNone); + test_KErrNone(r); M1.Wait(); RThread t; r=t.Create(_L("Test1"),Test1Thread,0x1000,NULL,NULL); - test(r==KErrNone); + test_KErrNone(r); TRequestStatus s; t.Logon(s); t.Resume(); @@ -213,9 +216,9 @@ User::SetJustInTime(EFalse); User::WaitForRequest(s); User::SetJustInTime(jit); - test(s==EAccessDenied); - test(t.ExitType()==EExitPanic); - test(t.ExitReason()==EAccessDenied); + test_Equal(EAccessDenied, s.Int()); + test_Equal(EExitPanic, t.ExitType()); + test_Equal(EAccessDenied, t.ExitReason()); test(t.ExitCategory()==_L("KERN-EXEC")); t.Close(); M1.Close(); @@ -273,13 +276,13 @@ test.Next(_L("Create mutex")); TInt r=M1.CreateLocal(); - test(r==KErrNone); + test_KErrNone(r); test.Next(_L("Create low priority thread")); TInt lowcount=0; RThread low; r=low.Create(_L("low"),LowThread,0x1000,NULL,&lowcount); - test(r==KErrNone); + test_KErrNone(r); low.SetPriority(EPriorityMuchLess); test(Exists(_L("low"))); @@ -287,42 +290,42 @@ TInt medcount=0; RThread med; r=med.Create(_L("med"),MedThread,0x1000,NULL,&medcount); - test(r==KErrNone); + test_KErrNone(r); med.SetPriority(EPriorityNormal); test(Exists(_L("med"))); test.Next(_L("Start low priority thread")); low.Resume(); User::AfterHighRes(KTestDelay/10); - test(lowcount==1); + test_Equal(1, lowcount); // MCOUNT(M1,0); test.Next(_L("Start medium priority thread")); med.Resume(); User::AfterHighRes(KTestDelay/10); - test(medcount==1); + test_Equal(1, medcount); Kick(med); User::AfterHighRes(KTestDelay/10); - test(medcount==2); + test_Equal(2, medcount); Kick(med); M1.Wait(); - test(lowcount==1); - test(medcount==2); + test_Equal(1, lowcount); + test_Equal(2, medcount); test.Next(_L("Wait, check medium runs")); User::AfterHighRes(KTestDelay/10); - test(medcount==3); + test_Equal(3, medcount); M1.Signal(); test.Next(_L("Create mutex 2")); r=M2.CreateLocal(); - test(r==KErrNone); + test_KErrNone(r); test.Next(_L("Create high priority thread")); TInt highcount=0; RThread high; r=high.Create(_L("high"),HighThread,0x1000,NULL,&highcount); - test(r==KErrNone); + test_KErrNone(r); high.SetPriority(EPriorityMore); test(Exists(_L("high"))); @@ -336,15 +339,15 @@ User::AfterHighRes(KTestDelay/10); // MCOUNT(M2,0); // MCOUNT(M1,-1); - test(highcount==1); + test_Equal(1, highcount); M2.Wait(); - test(lowcount==2); - test(medcount==3); - test(highcount==2); + test_Equal(2, lowcount); + test_Equal(3, medcount); + test_Equal(2, highcount); test.Next(_L("Wait, check medium runs")); User::AfterHighRes(KTestDelay/10); - test(medcount==4); + test_Equal(4, medcount); M2.Signal(); test.Next(_L("Kill threads")); @@ -401,7 +404,7 @@ TBuf<4> b; b.Num(n); TInt r=t.Create(b,ThreadFunction,0x1000,NULL,aPtr); - test(r==KErrNone); + test_KErrNone(r); t.Resume(); TUint id=t.Id(); test.Printf(_L("id=%d\n"),id); @@ -516,7 +519,7 @@ Count=0; test.Next(_L("Create mutex")); TInt r=M1.CreateLocal(); - test(r==KErrNone); + test_KErrNone(r); MCOUNT(M1,1); MutexWait(); MCOUNT(M1,0); @@ -624,7 +627,7 @@ User::After(50000); // let threads claim mutex MutexWait(); MCOUNT(M1,0); // check no threads waiting - test(t[2].ExitType()==EExitKill); // check t2 has exited + test_Equal(EExitKill, t[2].ExitType()); // check t2 has exited t[2].Close(); test(!Exists(2)); IDCHECK(id2); // check they ran in order t2,t3,t4,t5,t1 @@ -942,12 +945,12 @@ { if (i==3 || i==6 || i==7) { - test(t[i].ExitType()==EExitPending); + test_Equal(EExitPending, t[i].ExitType()); } else { - test(t[i].ExitType()==EExitPanic); - test(t[i].ExitReason()==EBadHandle); + test_Equal(EExitPanic, t[i].ExitType()); + test_Equal(EBadHandle, t[i].ExitReason()); test(t[i].ExitCategory()==_L("KERN-EXEC")); t[i].Close(); test(!Exists(i)); @@ -963,8 +966,8 @@ { if (i==3 || i==6 || i==7) { - test(t[i].ExitType()==EExitPanic); - test(t[i].ExitReason()==EBadHandle); + test_Equal(EExitPanic, t[i].ExitType()); + test_Equal(EBadHandle, t[i].ExitReason()); test(t[i].ExitCategory()==_L("KERN-EXEC")); t[i].Close(); test(!Exists(i)); @@ -1008,11 +1011,11 @@ test.Start(_L("Test mutex speed")); TInt count=0; TInt r=M1.CreateLocal(); - test(r==KErrNone); + test_KErrNone(r); RThread t; r=t.Create(_L("Speed"),MutexSpeed,0x1000,NULL,&count); - test(r==KErrNone); + test_KErrNone(r); t.SetPriority(EPriorityRealTime); t.Resume(); User::AfterHighRes(1000000); @@ -1023,7 +1026,7 @@ TInt count2=0; r=t.Create(_L("Speed2"),MutexSpeed2,0x1000,NULL,&count2); - test(r==KErrNone); + test_KErrNone(r); t.SetPriority(EPriorityRealTime); t.Resume(); User::AfterHighRes(1000000); @@ -1074,7 +1077,7 @@ TBuf<4> b; b.Num(n); TInt r=t.Create(b,SemThreadFunction,0x1000,NULL,aPtr); - test(r==KErrNone); + test_KErrNone(r); t.Resume(); TUint id=t.Id(); return id; @@ -1147,7 +1150,7 @@ Count=0; test.Next(_L("Create semaphore")); TInt r=S.CreateLocal(2); - test(r==KErrNone); + test_KErrNone(r); MCOUNT(S,2); SemWait(); MCOUNT(S,1); @@ -1312,20 +1315,20 @@ { if (i==3 || i==7 || i==10) { - test(t[i].ExitType()==EExitPending); + test_Equal(EExitPending, t[i].ExitType()); } else if (i!=5) { - test(t[i].ExitType()==EExitPanic); - test(t[i].ExitReason()==EBadHandle); + test_Equal(EExitPanic, t[i].ExitType()); + test_Equal(EBadHandle, t[i].ExitReason()); test(t[i].ExitCategory()==_L("KERN-EXEC")); t[i].Close(); test(!Exists(i)); } else { - test(t[i].ExitType()==EExitKill); - test(t[i].ExitReason()==0); + test_Equal(EExitKill, t[i].ExitType()); + test_Equal(0, t[i].ExitReason()); t[i].Close(); test(!Exists(i)); } @@ -1340,8 +1343,8 @@ { if (i==3 || i==7 || i==10) { - test(t[i].ExitType()==EExitPanic); - test(t[i].ExitReason()==EBadHandle); + test_Equal(EExitPanic, t[i].ExitType()); + test_Equal(EBadHandle, t[i].ExitReason()); test(t[i].ExitCategory()==_L("KERN-EXEC")); t[i].Close(); test(!Exists(i)); @@ -1371,11 +1374,11 @@ test.Start(_L("Test semaphore speed")); TInt count=0; TInt r=S.CreateLocal(1); - test(r==KErrNone); + test_KErrNone(r); RThread t; r=t.Create(_L("SemSpeed"),SemSpeed,0x1000,NULL,&count); - test(r==KErrNone); + test_KErrNone(r); t.SetPriority(EPriorityRealTime); t.Resume(); User::AfterHighRes(1000000); @@ -1391,12 +1394,22 @@ GLDEF_C TInt E32Main() { + TInt cpus = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); + if (cpus != 1) + { + test(cpus>1); + // This test will require compatibility mode (and probably other changes) + // to work on SMP - it depends on explicit scheduling order. + test.Printf(_L("T_SEMUTX2 skipped, does not work on SMP\n")); + return KErrNone; + } + test.Title(); test.Start(_L("Test mutexes and semaphores")); RThread().SetPriority(EPriorityMuchMore); TInt r=Main.Duplicate(RThread()); - test(r==KErrNone); + test_KErrNone(r); Test0(); Test1(); diff -r e880629062dd -r e4a7b1cbe40c kerneltest/e32test/system/t_condvar.cpp --- a/kerneltest/e32test/system/t_condvar.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kerneltest/e32test/system/t_condvar.cpp Mon May 10 11:40:53 2010 +0100 @@ -1,820 +1,831 @@ -// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). -// All rights reserved. -// This component and the accompanying materials are made available -// under the terms of the License "Eclipse Public License v1.0" -// which accompanies this distribution, and is available -// at the URL "http://www.eclipse.org/legal/epl-v10.html". -// -// Initial Contributors: -// Nokia Corporation - initial contribution. -// -// Contributors: -// -// Description: -// e32test\system\t_condvar.cpp -// Overview: -// Test the use of the RCondVar & RMutex classes. -// API Information: -// RCondVar, RMutex -// Details: -// - Create some local conditional variables and mutexes and verify results -// are as expected. -// - Create a test thread that waits on conditional variables and mutexes, -// append some items on an array, signal the conditional variable and mutex, -// the thread then counts the number of items on the array and passes the -// result back to the main process. Verify results are as expected. Repeat -// with different array data. -// - Verify that a RCondVar::Wait() panics when the thread does not hold the -// specified mutex (mutex not locked). -// - Test using two mutexes with 1 conditional variable, append some items to -// an array, verify results from the thread are as expected. -// - Create a second thread with higher priority, perform tests similar to -// above, verify results are as expected. -// - Verify the thread timeout values are as expected. -// - Create global conditional variables and global mutexes, using two threads -// test the RCondVar::Signal() and RMutex::Wait() results are as expected. -// - Test various combinations of creating a thread, suspending and killing it -// and signalling a conditional variable and mutex. Verify results are as -// expected. -// - Create a secondary process along with a global chunk, conditional variable -// and mutex. Signal the conditional variable and verify the results are as -// expected. -// - Using two threads, benchmark the number of conditional variable/mutex Signal -// and Wait iterations that can be completed per second. -// Platforms/Drives/Compatibility: -// All. -// Assumptions/Requirement/Pre-requisites: -// Failures and causes: -// Base Port information: -// -// - -#include -#include -#include -#include -#include -#include -#include - -RTest test(_L("T_CONDVAR")); -RMutex M1; -RMutex M2; -RCondVar CV1; -RCondVar CV2; - -#define __TRACE_LINE__ test.Printf(_L("Line %d\n"),__LINE__) - -struct SThreadData - { - SThreadData(); - RMutex iM; - RCondVar iV; - RArray* iA; - TInt iTotal; - TInt iInnerLoops; - TInt iOuterLoops; - TInt iTimeoutMs; - TInt iTimeouts; - TInt iBadCount; - }; - -struct SThreadData2 - { - SThreadData2(); - const TText* iMutexName; - const TText* iCondVarName; - TInt iInnerLoops; - }; - -SThreadData::SThreadData() - { - memset(this, 0, sizeof(*this)); - } - -SThreadData2::SThreadData2() - { - memset(this, 0, sizeof(*this)); - } - -TInt Thread0(TAny*) - { - return CV1.Wait(M1); - } - -TInt Thread1(TAny* a) - { - TUint32 t1, t2; - SThreadData& d = *(SThreadData*)a; - TInt r = KErrNone; - TInt i = 0; - d.iM.Wait(); - FOREVER - { - while (d.iA->Count()<=i && r==KErrNone) - { - t1 = User::NTickCount(); - if (d.iTimeoutMs) - r = d.iV.TimedWait(d.iM, d.iTimeoutMs*1000); - else - r = d.iV.Wait(d.iM); - t2 = User::NTickCount(); - ++d.iInnerLoops; - if (r == KErrTimedOut) - { - ++d.iTimeouts; - TInt iv = (TInt)(t2-t1); - if (ivCount(); - for (; i=0) - { - test(aD.iA->Append(VA_ARG(list,TInt))==KErrNone); - } - aD.iV.Signal(); - aD.iM.Signal(); - } - -void AppendToArrayB(SThreadData& aD, TInt aCount, ...) - { - VA_LIST list; - VA_START(list,aCount); - aD.iM.Wait(); - while(--aCount>=0) - { - test(aD.iA->Append(VA_ARG(list,TInt))==KErrNone); - } - aD.iV.Broadcast(); - aD.iM.Signal(); - } - -void AppendToArrayB2(SThreadData& aD, TInt aCount, ...) - { - VA_LIST list; - VA_START(list,aCount); - aD.iM.Wait(); - while(--aCount>=0) - { - test(aD.iA->Append(VA_ARG(list,TInt))==KErrNone); - } - aD.iM.Signal(); - aD.iV.Broadcast(); - } - -void Thread2Test() - { - test.Next(_L("Thread2Test")); - RCondVar cv2; - RMutex m3; - TInt r = cv2.CreateLocal(); - test(r==KErrNone); - r = m3.CreateLocal(); - test(r==KErrNone); - SThreadData d1; - d1.iM = m3; - d1.iV = cv2; - RThread t1; - - CreateThread2(t1, d1, EPriorityLess); - cv2.Signal(); - m3.Signal(); - User::After(100000); - test(d1.iInnerLoops == 1); - KillThread2(t1); - - CreateThread2(t1, d1, EPriorityLess); - KillThread2(t1); - m3.Signal(); - test(d1.iInnerLoops == 1); - - CreateThread2(t1, d1, EPriorityLess); - m3.Signal(); - User::After(10000); - KillThread2(t1); - test(d1.iInnerLoops == 1); - - CreateThread2(t1, d1, EPriorityLess); - cv2.Signal(); - User::After(10000); - KillThread2(t1); - m3.Signal(); - test(d1.iInnerLoops == 1); - - CreateThread2(t1, d1, EPriorityLess); - t1.Suspend(); - KillThread2(t1); - m3.Signal(); - test(d1.iInnerLoops == 1); - - CreateThread2(t1, d1, EPriorityLess); - User::After(10000); - t1.Suspend(); - KillThread2(t1); - m3.Signal(); - test(d1.iInnerLoops == 1); - - CreateThread2(t1, d1, EPriorityLess); - cv2.Signal(); - t1.Suspend(); - KillThread2(t1); - m3.Signal(); - test(d1.iInnerLoops == 1); - - CreateThread2(t1, d1, EPriorityLess); - cv2.Signal(); - User::After(10000); - t1.Suspend(); - KillThread2(t1); - m3.Signal(); - test(d1.iInnerLoops == 1); - - cv2.Close(); - m3.Close(); - } - -const TText* KMutex1Name = _S("mtx1"); -const TText* KMutex2Name = _S("mtx2"); -const TText* KCondVar1Name = _S("cv1"); -const TText* KCondVar2Name = _S("cv2"); - -void TestGlobal() - { - test.Next(_L("Test Global")); - RMutex mg1, mg2; - RCondVar cvg1, cvg2; - TInt r = mg1.CreateGlobal(TPtrC(KMutex1Name)); - test(r==KErrNone); - r = mg2.CreateGlobal(TPtrC(KMutex2Name)); - test(r==KErrNone); - r = cvg1.CreateGlobal(TPtrC(KCondVar1Name)); - test(r==KErrNone); - r = cvg2.CreateGlobal(TPtrC(KCondVar2Name)); - test(r==KErrNone); - SThreadData2 d1, d2; - d1.iMutexName = KMutex1Name; - d1.iCondVarName = KCondVar1Name; - d2.iMutexName = KMutex2Name; - d2.iCondVarName = KCondVar2Name; - - RThread t1, t2; - r = t1.Create(KNullDesC, &Thread3, 0x1000, 0x1000, 0x1000, &d1); - test(r==KErrNone); - t1.SetPriority(EPriorityMore); - TRequestStatus s1; - t1.Logon(s1); - t1.Resume(); - r = t2.Create(KNullDesC, &Thread3, 0x1000, 0x1000, 0x1000, &d2); - test(r==KErrNone); - t2.SetPriority(EPriorityMore); - TRequestStatus s2; - t2.Logon(s2); - t2.Resume(); - - test(s1==KRequestPending); - test(s2==KRequestPending); - test(d1.iInnerLoops == 0); - test(d2.iInnerLoops == 0); - cvg1.Signal(); - test(d1.iInnerLoops == 1); - test(d2.iInnerLoops == 0); - cvg2.Signal(); - test(d1.iInnerLoops == 1); - test(d2.iInnerLoops == 1); - - cvg1.Close(); - cvg2.Close(); - test(s1==KRequestPending); - test(s2==KRequestPending); - test(d1.iInnerLoops == 1); - test(d2.iInnerLoops == 1); - - t1.Kill(0); - t2.Kill(0); - User::WaitForRequest(s1); - User::WaitForRequest(s2); - test(t1.ExitType()==EExitKill); - test(t1.ExitReason()==0); - test(t2.ExitType()==EExitKill); - test(t2.ExitReason()==0); - CLOSE_AND_WAIT(t1); - CLOSE_AND_WAIT(t2); - r = cvg1.OpenGlobal(TPtrC(KCondVar1Name)); - test(r==KErrNotFound); - test(cvg1.Handle()==0); - mg1.Close(); - mg2.Close(); - } - -void TestSecondaryProcess() - { - test.Next(_L("Test Secondary Process")); - - RProcess p; - RChunk c; - RMutex m; - RCondVar cv; - - //cancel lazy dll unloading - RLoader loader; - TInt r = loader.Connect(); - test(r==KErrNone); - r = loader.CancelLazyDllUnload(); - test(r==KErrNone); - loader.Close(); - - r = c.CreateGlobal(KNullDesC, 0x1000, 0x1000); - test(r==KErrNone); - volatile TInt& x = *(volatile TInt*)c.Base(); - x = 0; - r = m.CreateGlobal(KNullDesC); - test(r==KErrNone); - r = cv.CreateGlobal(KNullDesC); - test(r==KErrNone); - r = p.Create(RProcess().FileName(), KNullDesC); - test(r==KErrNone); - p.SetPriority(EPriorityHigh); - r = p.SetParameter(1, cv); - test(r==KErrNone); - r = p.SetParameter(2, m); - test(r==KErrNone); - r = p.SetParameter(3, c); - test(r==KErrNone); - TRequestStatus s; - p.Logon(s); - p.Resume(); - test(s==KRequestPending); - test(x==0); - TInt i; - for (i=0; i<10; ++i) - { - cv.Signal(); - test(x == i+1); - } - cv.Close(); - test(s==KRequestPending); - test(x==10); - p.Terminate(0); - User::WaitForRequest(s); - test(p.ExitType()==EExitTerminate); - test(p.ExitReason()==0); - CLOSE_AND_WAIT(p); - m.Close(); - c.Close(); - } - -TInt SecondaryProcess(RCondVar aCV) - { - RDebug::Print(_L("SecProc")); - RMutex mp; - RChunk cp; - TInt r = mp.Open(2); - if (r!=KErrNone) - return r; - r = cp.Open(3); - if (r!=KErrNone) - return r; - volatile TInt& x = *(volatile TInt*)cp.Base(); - mp.Wait(); - r = KErrNone; - while (r==KErrNone) - { - r = aCV.Wait(mp); - ++x; - RDebug::Print(_L("SecProc r=%d x=%d"), r, x); - } - return r; - } - -TInt E32Main() - { - __KHEAP_MARK; - __UHEAP_MARK; - - TInt r; - RCondVar cvp; - r = cvp.Open(1); - if (r==KErrNone) - return SecondaryProcess(cvp); - test.Title(); - test.Start(_L("Create condition variable")); - r = CV1.CreateLocal(); - test(r==KErrNone); - r = CV2.CreateLocal(); - test(r==KErrNone); - - test.Next(_L("Signal with no-one waiting")); - CV1.Signal(); - - test.Next(_L("Broadcast with no-one waiting")); - CV1.Broadcast(); - - test.Next(_L("Create mutexes")); - r = M1.CreateLocal(); - test(r==KErrNone); - r = M2.CreateLocal(); - test(r==KErrNone); - - RArray array; - SThreadData d0; - d0.iM = M2; - d0.iV = CV1; - d0.iA = &array; - test.Next(_L("Create thread to use mutex 2")); - RThread t0; - r = t0.Create(KNullDesC, &Thread1, 0x1000, 0x1000, 0x1000, &d0); - test(r==KErrNone); - t0.SetPriority(EPriorityMore); - TRequestStatus s0; - t0.Logon(s0); - t0.Resume(); - __TRACE_LINE__; - AppendToArray(d0, 1, 4); - test(d0.iTotal==4); - __TRACE_LINE__; - AppendToArray(d0, 2, -3, 17); - test(d0.iTotal==18); - t0.Terminate(11); - User::WaitForRequest(s0); - test(t0.ExitType()==EExitTerminate); - test(t0.ExitReason()==11); - CLOSE_AND_WAIT(t0); - array.Reset(); - - SThreadData d; - d.iM = M1; - d.iV = CV1; - d.iA = &array; - test.Next(_L("Create thread to use mutex 1")); - RThread t; - r = t.Create(KNullDesC, &Thread1, 0x1000, 0x1000, 0x1000, &d); - test(r==KErrNone); - t.SetPriority(EPriorityMore); - TRequestStatus s; - t.Logon(s); - t.Resume(); - - test.Next(_L("Test wait with mutex unlocked")); - r = t0.Create(KNullDesC, &Thread0, 0x1000, 0x1000, 0x1000, NULL); - test(r==KErrNone); - t0.SetPriority(EPriorityMore); - t0.Logon(s0); - TBool jit = User::JustInTime(); - User::SetJustInTime(EFalse); - t0.Resume(); - User::WaitForRequest(s0); - User::SetJustInTime(jit); - test(t0.ExitType()==EExitPanic); - test(t0.ExitCategory()==_L("KERN-EXEC")); - test(t0.ExitReason()==ECondVarWaitMutexNotLocked); - CLOSE_AND_WAIT(t0); - - test.Next(_L("Test trying to use two mutexes with 1 condition variable")); - M2.Wait(); - r = CV1.Wait(M2); - M2.Signal(); - test(r==KErrInUse); - - test(d.iTotal==0); - __TRACE_LINE__; - AppendToArray(d, 1, 3); - test(d.iTotal==3); - __TRACE_LINE__; - AppendToArray(d, 2, 3, 19); - test(d.iTotal==25); - __TRACE_LINE__; - AppendToArray(d, 4, 15, -1, -2, -30); - test(d.iTotal==7); - test(d.iInnerLoops==3); - test(d.iOuterLoops==3); - __TRACE_LINE__; - t.Suspend(); - __TRACE_LINE__; - t.Resume(); - test(d.iTotal==7); - test(d.iInnerLoops==4); - test(d.iOuterLoops==3); - __TRACE_LINE__; - t.SetPriority(EPriorityLess); - test(d.iTotal==7); - test(d.iInnerLoops==4); - test(d.iOuterLoops==3); - __TRACE_LINE__; - t.SetPriority(EPriorityMore); - test(d.iTotal==7); - test(d.iInnerLoops==5); - test(d.iOuterLoops==3); - __TRACE_LINE__; - t.Suspend(); - __TRACE_LINE__; - AppendToArray(d, 1, 4); - test(d.iTotal==7); - test(d.iInnerLoops==5); - test(d.iOuterLoops==3); - __TRACE_LINE__; - t.Resume(); - test(d.iTotal==11); - test(d.iInnerLoops==6); - test(d.iOuterLoops==4); - - SThreadData d2; - d2.iM = M1; - d2.iV = CV1; - d2.iA = &array; - - test.Next(_L("Create 2nd thread")); - RThread t2; - r = t2.Create(KNullDesC, &Thread1, 0x1000, NULL, &d2); - test(r==KErrNone); - t2.SetPriority(EPriorityMuchMore); - TRequestStatus s2; - t2.Logon(s2); - __TRACE_LINE__; - t2.Resume(); - - test(d2.iTotal == 11); - test(d2.iInnerLoops == 0); - test(d2.iOuterLoops == 1); - __TRACE_LINE__; - AppendToArray(d, 2, 9, 10); - test(d2.iTotal == 30); - test(d2.iInnerLoops == 1); - test(d2.iOuterLoops == 2); - test(d.iTotal==11); - test(d.iInnerLoops==6); - test(d.iOuterLoops==4); - __TRACE_LINE__; - AppendToArrayB(d, 2, 20, 30); - test(d2.iTotal == 80); - test(d2.iInnerLoops == 2); - test(d2.iOuterLoops == 3); - test(d.iTotal == 80); - test(d.iInnerLoops == 7); - test(d.iOuterLoops == 5); - __TRACE_LINE__; - AppendToArrayB2(d, 2, -10, -6); - test(d2.iTotal == 64); - test(d2.iInnerLoops == 3); - test(d2.iOuterLoops == 4); - test(d.iTotal == 64); - test(d.iInnerLoops == 8); - test(d.iOuterLoops == 6); - __TRACE_LINE__; - t2.Suspend(); - __TRACE_LINE__; - AppendToArray(d, 2, -8, -8); - test(d2.iTotal == 64); - test(d2.iInnerLoops == 3); - test(d2.iOuterLoops == 4); - test(d.iTotal == 48); - test(d.iInnerLoops == 9); - test(d.iOuterLoops == 7); - __TRACE_LINE__; - t2.Resume(); - test(d2.iTotal == 48); - test(d2.iInnerLoops == 4); - test(d2.iOuterLoops == 5); - test(d.iTotal == 48); - test(d.iInnerLoops == 9); - test(d.iOuterLoops == 7); - - // test timeouts - d.iTimeoutMs = 1000; - __TRACE_LINE__; - t.Suspend(); - __TRACE_LINE__; - t.Resume(); - test(d2.iTotal == 48); - test(d2.iInnerLoops == 4); - test(d2.iOuterLoops == 5); - test(d2.iTimeouts == 0); - test(d.iTotal == 48); - test(d.iInnerLoops == 10); - test(d.iOuterLoops == 7); - test(d.iTimeouts == 0); - test(array.Append(1)==0); - TInt nt = 0; - do { - if (d.iTimeouts > nt) - { - test(d.iTimeouts-nt == 1); - nt = d.iTimeouts; - test.Printf(_L("Timeout %d\n"), nt); - test(d2.iTotal == 48); - test(d2.iInnerLoops == 4); - test(d2.iOuterLoops == 5); - test(d2.iTimeouts == 0); - test(d.iTotal == 48+nt); - test(d.iInnerLoops == 10+nt); - test(d.iOuterLoops == 7+nt); - test(array.Append(1)==0); - } - } while (nt<10); - - d.iTimeoutMs = 0; - AppendToArrayB(d, 0); - test(d2.iTotal == 59); - test(d2.iInnerLoops == 5); - test(d2.iOuterLoops == 6); - test(d2.iTimeouts == 0); - test(d.iTotal == 59); - test(d.iInnerLoops == 21); - test(d.iOuterLoops == 18); - test(d.iTimeouts == 10); - - __TRACE_LINE__; - t.SetPriority(EPriorityLess); - __TRACE_LINE__; - AppendToArrayB(d, 1, 11); - test(d2.iTotal == 70); - test(d2.iInnerLoops == 6); - test(d2.iOuterLoops == 7); - test(d2.iTimeouts == 0); - test(d.iTotal == 59); - test(d.iInnerLoops == 21); - test(d.iOuterLoops == 18); - test(d.iTimeouts == 10); - User::After(50000); - test(d2.iTotal == 70); - test(d2.iInnerLoops == 6); - test(d2.iOuterLoops == 7); - test(d2.iTimeouts == 0); - test(d.iTotal == 70); - test(d.iInnerLoops == 22); - test(d.iOuterLoops == 19); - test(d.iTimeouts == 10); - - - - __TRACE_LINE__; - CV1.Close(); - User::WaitForRequest(s); - test(t.ExitType()==EExitKill); - test(t.ExitReason()==KErrGeneral); - User::WaitForRequest(s2); - test(t2.ExitType()==EExitKill); - test(t2.ExitReason()==KErrGeneral); - CLOSE_AND_WAIT(t); - CLOSE_AND_WAIT(t2); - - - M1.Close(); - - TestGlobal(); - - Thread2Test(); - - TestSecondaryProcess(); - - RunBench(); - M2.Close(); - CV2.Close(); - array.Close(); - - test.End(); - test.Close(); - - __UHEAP_MARKEND; - __KHEAP_MARKEND; - return KErrNone; - } - +// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\system\t_condvar.cpp +// Overview: +// Test the use of the RCondVar & RMutex classes. +// API Information: +// RCondVar, RMutex +// Details: +// - Create some local conditional variables and mutexes and verify results +// are as expected. +// - Create a test thread that waits on conditional variables and mutexes, +// append some items on an array, signal the conditional variable and mutex, +// the thread then counts the number of items on the array and passes the +// result back to the main process. Verify results are as expected. Repeat +// with different array data. +// - Verify that a RCondVar::Wait() panics when the thread does not hold the +// specified mutex (mutex not locked). +// - Test using two mutexes with 1 conditional variable, append some items to +// an array, verify results from the thread are as expected. +// - Create a second thread with higher priority, perform tests similar to +// above, verify results are as expected. +// - Verify the thread timeout values are as expected. +// - Create global conditional variables and global mutexes, using two threads +// test the RCondVar::Signal() and RMutex::Wait() results are as expected. +// - Test various combinations of creating a thread, suspending and killing it +// and signalling a conditional variable and mutex. Verify results are as +// expected. +// - Create a secondary process along with a global chunk, conditional variable +// and mutex. Signal the conditional variable and verify the results are as +// expected. +// - Using two threads, benchmark the number of conditional variable/mutex Signal +// and Wait iterations that can be completed per second. +// Platforms/Drives/Compatibility: +// All. +// Assumptions/Requirement/Pre-requisites: +// Failures and causes: +// Base Port information: +// +// + +#include +#include +#include +#include +#include +#include +#include +#include + +RTest test(_L("T_CONDVAR")); +RMutex M1; +RMutex M2; +RCondVar CV1; +RCondVar CV2; + +#define __TRACE_LINE__ test.Printf(_L("Line %d\n"),__LINE__) + +struct SThreadData + { + SThreadData(); + RMutex iM; + RCondVar iV; + RArray* iA; + TInt iTotal; + TInt iInnerLoops; + TInt iOuterLoops; + TInt iTimeoutMs; + TInt iTimeouts; + TInt iBadCount; + }; + +struct SThreadData2 + { + SThreadData2(); + const TText* iMutexName; + const TText* iCondVarName; + TInt iInnerLoops; + }; + +SThreadData::SThreadData() + { + memset(this, 0, sizeof(*this)); + } + +SThreadData2::SThreadData2() + { + memset(this, 0, sizeof(*this)); + } + +TInt Thread0(TAny*) + { + return CV1.Wait(M1); + } + +TInt Thread1(TAny* a) + { + TUint32 t1, t2; + SThreadData& d = *(SThreadData*)a; + TInt r = KErrNone; + TInt i = 0; + d.iM.Wait(); + FOREVER + { + while (d.iA->Count()<=i && r==KErrNone) + { + t1 = User::NTickCount(); + if (d.iTimeoutMs) + r = d.iV.TimedWait(d.iM, d.iTimeoutMs*1000); + else + r = d.iV.Wait(d.iM); + t2 = User::NTickCount(); + ++d.iInnerLoops; + if (r == KErrTimedOut) + { + ++d.iTimeouts; + TInt iv = (TInt)(t2-t1); + if (ivCount(); + for (; i=0) + { + test(aD.iA->Append(VA_ARG(list,TInt))==KErrNone); + } + aD.iV.Signal(); + aD.iM.Signal(); + } + +void AppendToArrayB(SThreadData& aD, TInt aCount, ...) + { + VA_LIST list; + VA_START(list,aCount); + aD.iM.Wait(); + while(--aCount>=0) + { + test(aD.iA->Append(VA_ARG(list,TInt))==KErrNone); + } + aD.iV.Broadcast(); + aD.iM.Signal(); + } + +void AppendToArrayB2(SThreadData& aD, TInt aCount, ...) + { + VA_LIST list; + VA_START(list,aCount); + aD.iM.Wait(); + while(--aCount>=0) + { + test(aD.iA->Append(VA_ARG(list,TInt))==KErrNone); + } + aD.iM.Signal(); + aD.iV.Broadcast(); + } + +void Thread2Test() + { + test.Next(_L("Thread2Test")); + RCondVar cv2; + RMutex m3; + TInt r = cv2.CreateLocal(); + test(r==KErrNone); + r = m3.CreateLocal(); + test(r==KErrNone); + SThreadData d1; + d1.iM = m3; + d1.iV = cv2; + RThread t1; + + CreateThread2(t1, d1, EPriorityLess); + cv2.Signal(); + m3.Signal(); + User::After(100000); + test(d1.iInnerLoops == 1); + KillThread2(t1); + + CreateThread2(t1, d1, EPriorityLess); + KillThread2(t1); + m3.Signal(); + test(d1.iInnerLoops == 1); + + CreateThread2(t1, d1, EPriorityLess); + m3.Signal(); + User::After(10000); + KillThread2(t1); + test(d1.iInnerLoops == 1); + + CreateThread2(t1, d1, EPriorityLess); + cv2.Signal(); + User::After(10000); + KillThread2(t1); + m3.Signal(); + test(d1.iInnerLoops == 1); + + CreateThread2(t1, d1, EPriorityLess); + t1.Suspend(); + KillThread2(t1); + m3.Signal(); + test(d1.iInnerLoops == 1); + + CreateThread2(t1, d1, EPriorityLess); + User::After(10000); + t1.Suspend(); + KillThread2(t1); + m3.Signal(); + test(d1.iInnerLoops == 1); + + CreateThread2(t1, d1, EPriorityLess); + cv2.Signal(); + t1.Suspend(); + KillThread2(t1); + m3.Signal(); + test(d1.iInnerLoops == 1); + + CreateThread2(t1, d1, EPriorityLess); + cv2.Signal(); + User::After(10000); + t1.Suspend(); + KillThread2(t1); + m3.Signal(); + test(d1.iInnerLoops == 1); + + cv2.Close(); + m3.Close(); + } + +const TText* KMutex1Name = _S("mtx1"); +const TText* KMutex2Name = _S("mtx2"); +const TText* KCondVar1Name = _S("cv1"); +const TText* KCondVar2Name = _S("cv2"); + +void TestGlobal() + { + test.Next(_L("Test Global")); + RMutex mg1, mg2; + RCondVar cvg1, cvg2; + TInt r = mg1.CreateGlobal(TPtrC(KMutex1Name)); + test(r==KErrNone); + r = mg2.CreateGlobal(TPtrC(KMutex2Name)); + test(r==KErrNone); + r = cvg1.CreateGlobal(TPtrC(KCondVar1Name)); + test(r==KErrNone); + r = cvg2.CreateGlobal(TPtrC(KCondVar2Name)); + test(r==KErrNone); + SThreadData2 d1, d2; + d1.iMutexName = KMutex1Name; + d1.iCondVarName = KCondVar1Name; + d2.iMutexName = KMutex2Name; + d2.iCondVarName = KCondVar2Name; + + RThread t1, t2; + r = t1.Create(KNullDesC, &Thread3, 0x1000, 0x1000, 0x1000, &d1); + test(r==KErrNone); + t1.SetPriority(EPriorityMore); + TRequestStatus s1; + t1.Logon(s1); + t1.Resume(); + r = t2.Create(KNullDesC, &Thread3, 0x1000, 0x1000, 0x1000, &d2); + test(r==KErrNone); + t2.SetPriority(EPriorityMore); + TRequestStatus s2; + t2.Logon(s2); + t2.Resume(); + + test(s1==KRequestPending); + test(s2==KRequestPending); + test(d1.iInnerLoops == 0); + test(d2.iInnerLoops == 0); + cvg1.Signal(); + test(d1.iInnerLoops == 1); + test(d2.iInnerLoops == 0); + cvg2.Signal(); + test(d1.iInnerLoops == 1); + test(d2.iInnerLoops == 1); + + cvg1.Close(); + cvg2.Close(); + test(s1==KRequestPending); + test(s2==KRequestPending); + test(d1.iInnerLoops == 1); + test(d2.iInnerLoops == 1); + + t1.Kill(0); + t2.Kill(0); + User::WaitForRequest(s1); + User::WaitForRequest(s2); + test(t1.ExitType()==EExitKill); + test(t1.ExitReason()==0); + test(t2.ExitType()==EExitKill); + test(t2.ExitReason()==0); + CLOSE_AND_WAIT(t1); + CLOSE_AND_WAIT(t2); + r = cvg1.OpenGlobal(TPtrC(KCondVar1Name)); + test(r==KErrNotFound); + test(cvg1.Handle()==0); + mg1.Close(); + mg2.Close(); + } + +void TestSecondaryProcess() + { + test.Next(_L("Test Secondary Process")); + + RProcess p; + RChunk c; + RMutex m; + RCondVar cv; + + //cancel lazy dll unloading + RLoader loader; + TInt r = loader.Connect(); + test(r==KErrNone); + r = loader.CancelLazyDllUnload(); + test(r==KErrNone); + loader.Close(); + + r = c.CreateGlobal(KNullDesC, 0x1000, 0x1000); + test(r==KErrNone); + volatile TInt& x = *(volatile TInt*)c.Base(); + x = 0; + r = m.CreateGlobal(KNullDesC); + test(r==KErrNone); + r = cv.CreateGlobal(KNullDesC); + test(r==KErrNone); + r = p.Create(RProcess().FileName(), KNullDesC); + test(r==KErrNone); + p.SetPriority(EPriorityHigh); + r = p.SetParameter(1, cv); + test(r==KErrNone); + r = p.SetParameter(2, m); + test(r==KErrNone); + r = p.SetParameter(3, c); + test(r==KErrNone); + TRequestStatus s; + p.Logon(s); + p.Resume(); + test(s==KRequestPending); + test(x==0); + TInt i; + for (i=0; i<10; ++i) + { + cv.Signal(); + test(x == i+1); + } + cv.Close(); + test(s==KRequestPending); + test(x==10); + p.Terminate(0); + User::WaitForRequest(s); + test(p.ExitType()==EExitTerminate); + test(p.ExitReason()==0); + CLOSE_AND_WAIT(p); + m.Close(); + c.Close(); + } + +TInt SecondaryProcess(RCondVar aCV) + { + RDebug::Print(_L("SecProc")); + RMutex mp; + RChunk cp; + TInt r = mp.Open(2); + if (r!=KErrNone) + return r; + r = cp.Open(3); + if (r!=KErrNone) + return r; + volatile TInt& x = *(volatile TInt*)cp.Base(); + mp.Wait(); + r = KErrNone; + while (r==KErrNone) + { + r = aCV.Wait(mp); + ++x; + RDebug::Print(_L("SecProc r=%d x=%d"), r, x); + } + return r; + } + +TInt E32Main() + { + TInt cpus = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); + if (cpus != 1) + { + test(cpus>1); + // This test will require compatibility mode (and probably other changes) + // to work on SMP - it depends on explicit scheduling order. + test.Printf(_L("T_CONDVAR skipped, does not work on SMP\n")); + return KErrNone; + } + + __KHEAP_MARK; + __UHEAP_MARK; + + TInt r; + RCondVar cvp; + r = cvp.Open(1); + if (r==KErrNone) + return SecondaryProcess(cvp); + test.Title(); + test.Start(_L("Create condition variable")); + r = CV1.CreateLocal(); + test(r==KErrNone); + r = CV2.CreateLocal(); + test(r==KErrNone); + + test.Next(_L("Signal with no-one waiting")); + CV1.Signal(); + + test.Next(_L("Broadcast with no-one waiting")); + CV1.Broadcast(); + + test.Next(_L("Create mutexes")); + r = M1.CreateLocal(); + test(r==KErrNone); + r = M2.CreateLocal(); + test(r==KErrNone); + + RArray array; + SThreadData d0; + d0.iM = M2; + d0.iV = CV1; + d0.iA = &array; + test.Next(_L("Create thread to use mutex 2")); + RThread t0; + r = t0.Create(KNullDesC, &Thread1, 0x1000, 0x1000, 0x1000, &d0); + test(r==KErrNone); + t0.SetPriority(EPriorityMore); + TRequestStatus s0; + t0.Logon(s0); + t0.Resume(); + __TRACE_LINE__; + AppendToArray(d0, 1, 4); + test(d0.iTotal==4); + __TRACE_LINE__; + AppendToArray(d0, 2, -3, 17); + test(d0.iTotal==18); + t0.Terminate(11); + User::WaitForRequest(s0); + test(t0.ExitType()==EExitTerminate); + test(t0.ExitReason()==11); + CLOSE_AND_WAIT(t0); + array.Reset(); + + SThreadData d; + d.iM = M1; + d.iV = CV1; + d.iA = &array; + test.Next(_L("Create thread to use mutex 1")); + RThread t; + r = t.Create(KNullDesC, &Thread1, 0x1000, 0x1000, 0x1000, &d); + test(r==KErrNone); + t.SetPriority(EPriorityMore); + TRequestStatus s; + t.Logon(s); + t.Resume(); + + test.Next(_L("Test wait with mutex unlocked")); + r = t0.Create(KNullDesC, &Thread0, 0x1000, 0x1000, 0x1000, NULL); + test(r==KErrNone); + t0.SetPriority(EPriorityMore); + t0.Logon(s0); + TBool jit = User::JustInTime(); + User::SetJustInTime(EFalse); + t0.Resume(); + User::WaitForRequest(s0); + User::SetJustInTime(jit); + test(t0.ExitType()==EExitPanic); + test(t0.ExitCategory()==_L("KERN-EXEC")); + test(t0.ExitReason()==ECondVarWaitMutexNotLocked); + CLOSE_AND_WAIT(t0); + + test.Next(_L("Test trying to use two mutexes with 1 condition variable")); + M2.Wait(); + r = CV1.Wait(M2); + M2.Signal(); + test(r==KErrInUse); + + test(d.iTotal==0); + __TRACE_LINE__; + AppendToArray(d, 1, 3); + test(d.iTotal==3); + __TRACE_LINE__; + AppendToArray(d, 2, 3, 19); + test(d.iTotal==25); + __TRACE_LINE__; + AppendToArray(d, 4, 15, -1, -2, -30); + test(d.iTotal==7); + test(d.iInnerLoops==3); + test(d.iOuterLoops==3); + __TRACE_LINE__; + t.Suspend(); + __TRACE_LINE__; + t.Resume(); + test(d.iTotal==7); + test(d.iInnerLoops==4); + test(d.iOuterLoops==3); + __TRACE_LINE__; + t.SetPriority(EPriorityLess); + test(d.iTotal==7); + test(d.iInnerLoops==4); + test(d.iOuterLoops==3); + __TRACE_LINE__; + t.SetPriority(EPriorityMore); + test(d.iTotal==7); + test(d.iInnerLoops==5); + test(d.iOuterLoops==3); + __TRACE_LINE__; + t.Suspend(); + __TRACE_LINE__; + AppendToArray(d, 1, 4); + test(d.iTotal==7); + test(d.iInnerLoops==5); + test(d.iOuterLoops==3); + __TRACE_LINE__; + t.Resume(); + test(d.iTotal==11); + test(d.iInnerLoops==6); + test(d.iOuterLoops==4); + + SThreadData d2; + d2.iM = M1; + d2.iV = CV1; + d2.iA = &array; + + test.Next(_L("Create 2nd thread")); + RThread t2; + r = t2.Create(KNullDesC, &Thread1, 0x1000, NULL, &d2); + test(r==KErrNone); + t2.SetPriority(EPriorityMuchMore); + TRequestStatus s2; + t2.Logon(s2); + __TRACE_LINE__; + t2.Resume(); + + test(d2.iTotal == 11); + test(d2.iInnerLoops == 0); + test(d2.iOuterLoops == 1); + __TRACE_LINE__; + AppendToArray(d, 2, 9, 10); + test(d2.iTotal == 30); + test(d2.iInnerLoops == 1); + test(d2.iOuterLoops == 2); + test(d.iTotal==11); + test(d.iInnerLoops==6); + test(d.iOuterLoops==4); + __TRACE_LINE__; + AppendToArrayB(d, 2, 20, 30); + test(d2.iTotal == 80); + test(d2.iInnerLoops == 2); + test(d2.iOuterLoops == 3); + test(d.iTotal == 80); + test(d.iInnerLoops == 7); + test(d.iOuterLoops == 5); + __TRACE_LINE__; + AppendToArrayB2(d, 2, -10, -6); + test(d2.iTotal == 64); + test(d2.iInnerLoops == 3); + test(d2.iOuterLoops == 4); + test(d.iTotal == 64); + test(d.iInnerLoops == 8); + test(d.iOuterLoops == 6); + __TRACE_LINE__; + t2.Suspend(); + __TRACE_LINE__; + AppendToArray(d, 2, -8, -8); + test(d2.iTotal == 64); + test(d2.iInnerLoops == 3); + test(d2.iOuterLoops == 4); + test(d.iTotal == 48); + test(d.iInnerLoops == 9); + test(d.iOuterLoops == 7); + __TRACE_LINE__; + t2.Resume(); + test(d2.iTotal == 48); + test(d2.iInnerLoops == 4); + test(d2.iOuterLoops == 5); + test(d.iTotal == 48); + test(d.iInnerLoops == 9); + test(d.iOuterLoops == 7); + + // test timeouts + d.iTimeoutMs = 1000; + __TRACE_LINE__; + t.Suspend(); + __TRACE_LINE__; + t.Resume(); + test(d2.iTotal == 48); + test(d2.iInnerLoops == 4); + test(d2.iOuterLoops == 5); + test(d2.iTimeouts == 0); + test(d.iTotal == 48); + test(d.iInnerLoops == 10); + test(d.iOuterLoops == 7); + test(d.iTimeouts == 0); + test(array.Append(1)==0); + TInt nt = 0; + do { + if (d.iTimeouts > nt) + { + test(d.iTimeouts-nt == 1); + nt = d.iTimeouts; + test.Printf(_L("Timeout %d\n"), nt); + test(d2.iTotal == 48); + test(d2.iInnerLoops == 4); + test(d2.iOuterLoops == 5); + test(d2.iTimeouts == 0); + test(d.iTotal == 48+nt); + test(d.iInnerLoops == 10+nt); + test(d.iOuterLoops == 7+nt); + test(array.Append(1)==0); + } + } while (nt<10); + + d.iTimeoutMs = 0; + AppendToArrayB(d, 0); + test(d2.iTotal == 59); + test(d2.iInnerLoops == 5); + test(d2.iOuterLoops == 6); + test(d2.iTimeouts == 0); + test(d.iTotal == 59); + test(d.iInnerLoops == 21); + test(d.iOuterLoops == 18); + test(d.iTimeouts == 10); + + __TRACE_LINE__; + t.SetPriority(EPriorityLess); + __TRACE_LINE__; + AppendToArrayB(d, 1, 11); + test(d2.iTotal == 70); + test(d2.iInnerLoops == 6); + test(d2.iOuterLoops == 7); + test(d2.iTimeouts == 0); + test(d.iTotal == 59); + test(d.iInnerLoops == 21); + test(d.iOuterLoops == 18); + test(d.iTimeouts == 10); + User::After(50000); + test(d2.iTotal == 70); + test(d2.iInnerLoops == 6); + test(d2.iOuterLoops == 7); + test(d2.iTimeouts == 0); + test(d.iTotal == 70); + test(d.iInnerLoops == 22); + test(d.iOuterLoops == 19); + test(d.iTimeouts == 10); + + + + __TRACE_LINE__; + CV1.Close(); + User::WaitForRequest(s); + test(t.ExitType()==EExitKill); + test(t.ExitReason()==KErrGeneral); + User::WaitForRequest(s2); + test(t2.ExitType()==EExitKill); + test(t2.ExitReason()==KErrGeneral); + CLOSE_AND_WAIT(t); + CLOSE_AND_WAIT(t2); + + + M1.Close(); + + TestGlobal(); + + Thread2Test(); + + TestSecondaryProcess(); + + RunBench(); + M2.Close(); + CV2.Close(); + array.Close(); + + test.End(); + test.Close(); + + __UHEAP_MARKEND; + __KHEAP_MARKEND; + return KErrNone; + } + diff -r e880629062dd -r e4a7b1cbe40c kerneltest/f32test/demandpaging/t_nandpaging.cpp --- a/kerneltest/f32test/demandpaging/t_nandpaging.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kerneltest/f32test/demandpaging/t_nandpaging.cpp Mon May 10 11:40:53 2010 +0100 @@ -277,7 +277,6 @@ Drive.ControlIO(KNandGetDeferStats,statsBuf,0); test.Printf(_L("PG %d PO %d(%d%%) NG %d NO %d\n"),stats.iPageGarbage, stats.iPageOther, (TInt) ((stats.iPageOther*100)/cCount), stats.iNormalGarbage, stats.iNormalOther); - test(stats.iPageOther>0); pageGarbageCount+=stats.iPageGarbage; pageOtherCount+=stats.iPageOther; normalGarbageCount+=stats.iNormalGarbage; @@ -301,6 +300,7 @@ { test.Printf(_L("\nTotals: Avg %2d %d%% CC=%4d \n"), fullTot/fullcCount, (TInt)(totChangeCount*100)/fullcCount, totChangeCount); test.Printf(_L("PG %d PO %d(%d%%) NG %d NO %d\n"),pageGarbageCount, pageOtherCount,(TInt) (pageOtherCount*100/fullcCount), normalGarbageCount, normalOtherCount ); + test(pageOtherCount > 0); // Ensure at least one paging conflict occurred during the test. } // If totChangeCount does not change, nand maybe busy waiting. @@ -511,15 +511,14 @@ TUint8* start = (TUint8*)romHeader+romHeader->iPageableRomStart; TUint size = romHeader->iPageableRomSize; TUint8* addr=NULL; - TBool flush; while (Testing) { PageSemaphore.Wait(); // wait for main thread to want paging. - flush = (PagesBeingPaged==0); addr=start+((TInt64(Random())*TInt64(size))>>32); - PageDoneSemaphore.Signal(); // Acknolage request. + PageDoneSemaphore.Signal(); // Acknowledge request. PageMutex.Wait(); + TBool flush = (PagesBeingPaged==0); // Ensure only one thread is flushing the cache at a time. PagesBeingPaged++; PageMutex.Signal(); diff -r e880629062dd -r e4a7b1cbe40c kerneltest/f32test/server/t_falsespace.cpp --- a/kerneltest/f32test/server/t_falsespace.cpp Wed May 05 05:11:16 2010 +0100 +++ b/kerneltest/f32test/server/t_falsespace.cpp Mon May 10 11:40:53 2010 +0100 @@ -1049,7 +1049,7 @@ test_KErrNone(nRes); for(i=0; icurrentPath.Left(2)); } - RFile file; + RFile64 file; r=file.Open(CShell::TheFs,aPath,EFileStream); if (r!=KErrNone) // File could not be opened { @@ -1199,11 +1199,23 @@ //-- print out cluster size that FS reported TVolumeIOParamInfo volIoInfo; nRes = aFs.VolumeIOParam(aDrvNum, volIoInfo); - if(nRes == KErrNone && volIoInfo.iClusterSize >= 512) + if(nRes == KErrNone) { - Buf.AppendFormat(_L(", Cluster Sz:%d"), volIoInfo.iClusterSize); + if(volIoInfo.iBlockSize >= 0) + { + Buf.AppendFormat(_L(", BlkSz:%d"), volIoInfo.iBlockSize); + } + + if(volIoInfo.iClusterSize >= 0) + { + Buf.AppendFormat(_L(", ClSz:%d"), volIoInfo.iClusterSize); + } + + Buf.AppendFormat(_L(", CacheFlags:0x%x"), volInfo.iFileCacheFlags); + } + if(Buf.Length()) { Buf.Append(_L("\n")); @@ -1972,7 +1984,7 @@ ShellFunction::StripQuotes(aPath); ParsePath(aPath); - RFile file; + RFile64 file; TInt r=file.Open(TheShell->TheFs,aPath,EFileStream); if (r!=KErrNone) return(r); @@ -3108,7 +3120,7 @@ TInt ShellFunction::Type(TDes& aPath,TUint aSwitches) { ParsePath(aPath); - RFile file; + RFile64 file; TInt r=file.Open(TheShell->TheFs,aPath,EFileStreamText|EFileShareReadersOnly); if (r!=KErrNone) return r; diff -r e880629062dd -r e4a7b1cbe40c userlibandfileserver/fileserver/group/release.txt --- a/userlibandfileserver/fileserver/group/release.txt Wed May 05 05:11:16 2010 +0100 +++ b/userlibandfileserver/fileserver/group/release.txt Mon May 10 11:40:53 2010 +0100 @@ -1,3 +1,22 @@ +Version 2.00.3039 +================= +(Made by vfebvre 06/05/2010) + +1. famustaf + 1. ou1cimx1#372432 CFileMan malfunctioning in copying + +2. dlyokhin + 1. ou1cimx1#372220 File server may request more free space on the volume than necessary + + +Version 2.00.3038 +================= +(Made by vfebvre 05/05/2010) + +1. niccox + 1. ou1cimx1#371028 shostmassstorage capabilities are too high + + Version 2.00.3037 ================= (Made by vfebvre 30/04/2010) diff -r e880629062dd -r e4a7b1cbe40c userlibandfileserver/fileserver/inc/f32file.h --- a/userlibandfileserver/fileserver/inc/f32file.h Wed May 05 05:11:16 2010 +0100 +++ b/userlibandfileserver/fileserver/inc/f32file.h Mon May 10 11:40:53 2010 +0100 @@ -680,6 +680,15 @@ ETrue value means that the drive is finalised */ EIsDriveFinalised, + + /** + Query the volume to ascertain whether File system extensions + are supported on this volume. + A boolean value is returned within the buffer defined as TPckgBuf. + ETrue value means that extensions are supported. + EFalse means they are not supported. + */ + EFSysExtensionsSupported, }; /** @@ -699,27 +708,28 @@ { public: /** - The size of a block in bytes. - - Reads and writes that are aligned on block boundaries are up to twice as fast as when - mis-aligned. - - Read and write operations on certain underlying media is done in blocks. - A write operation that modifies only part of a block is less efficient, in general, than - one that modifies an entire block. Data throughput degrades linearly for reads and writes in smaller - sized units. + The size of a media block in bytes. This is a physical property of a media and returned by the corresponding media driver. + This value is usually at least 512 bytes and always a power of 2. For some media types the meaning of this value is + "the min. size of the aligned data buffer which write onto the media doesn't lead to read-modify-write operation." + Therefore, reads and writes that are aligned on block boundaries and with lenght of a multiple block size can be much faster. + Read and write operations on certain underlying media is done in blocks. A write operation that modifies only part of a block is less efficient, + in general, than one that modifies an entire block. Data throughput degrades linearly for reads and writes in smaller sized units. */ TInt iBlockSize; + /** - The size in bytes of a single disk cluster. - - Read and write operations that are aligned on cluster boundaries are more efficient. - - The file system organises and allocates the file data on the disk in clusters where each cluster is - one or more blocks. Files that are not zero length occupy at least one cluster of the disk, - so large numbers of very small files use up more disk space than expected. + The size in bytes of a single file system cluster. This is a logical property of the file system. + The file system organises and allocates the data on the disk in clusters where each cluster usually consists of one or more blocks. + Cluster is a minimal unit that the file system allocates on the volume. Thus, a file of 1 byte length occupies 1 cluster. + + Read and write operations that are aligned on cluster boundaries are more efficient from the file system point of view. + In some circumstances cluster size can be less than a block size, but it is very inefficient. + + This value is reported by a file system. The value less than 0 indicates a error. */ TInt iClusterSize; + + /** The recommended buffer size for optimised reading performance. @@ -754,7 +764,7 @@ /** The maximum file size that is supported by the file system mounted on this volume. - Not all file system may provide this parameter; The value KMaxTUint64 (0xffffffffffffffff) means that this particular file system hasn't + Not all file system may report this parameter; The value KMaxTUint64 (0xffffffffffffffff) means that this particular file system hasn't provided this information. */ TUint64 iMaxSupportedFileSize; @@ -1140,7 +1150,32 @@ @internalTechnology */ - EFileBigFile =0x00040000 + EFileBigFile =0x00040000, + + /** + Using this flag implies that the client is making large sequential reads and/or writes + and it is interested in maximising the performance of the large reads and/or writes. + + The flag gives a hint to the file server and filesystem to adjust to a streaming + data pattern and try their best to make it optimal. + + Some conditions apply: + - This does not guarantee that the performance of read/write operations will increase. + - Using this flag for other purposes other than data streaming may lead to performance degradation. + - This may sacrifice user data integrity for the sake of performance. + + If a file is opened by Client A with EFileSequential, and the file is then opened + without EFileSequential by Client B, then this file mode will be disabled. + When the file handle is closed by Client B, then the EFileSequential file mode + will be enabled again. + Therefore, this mode will only be enabled if all clients set the file as such, + otherwise the file mode will be disabled. + + FAT file system specific information: + This flag improves write and file expansion performance whilst decreasing robustness + on a "Rugged-FAT" file system, which is applicable to internal non-removable drives. + */ + EFileSequential =0x00080000 }; diff -r e880629062dd -r e4a7b1cbe40c userlibandfileserver/fileserver/inc/f32ver.h --- a/userlibandfileserver/fileserver/inc/f32ver.h Wed May 05 05:11:16 2010 +0100 +++ b/userlibandfileserver/fileserver/inc/f32ver.h Mon May 10 11:40:53 2010 +0100 @@ -58,6 +58,6 @@ @see TVersion */ -const TInt KF32BuildVersionNumber=3037; +const TInt KF32BuildVersionNumber=3039; // #endif diff -r e880629062dd -r e4a7b1cbe40c userlibandfileserver/fileserver/sfile/sf_file.cpp --- a/userlibandfileserver/fileserver/sfile/sf_file.cpp Wed May 05 05:11:16 2010 +0100 +++ b/userlibandfileserver/fileserver/sfile/sf_file.cpp Mon May 10 11:40:53 2010 +0100 @@ -241,7 +241,7 @@ TUint32 mode=aRequest->Message().Int1(); if (anOpen==EFileCreate || anOpen==EFileReplace) { - r = CheckDiskSpace(0, aRequest); + r = CheckDiskSpace(KMinFsCreateObjTreshold, aRequest); if(r != KErrNone) return r; @@ -601,7 +601,7 @@ { __PRINT(_L("TFsFileTemp::DoRequestL(CFsRequest* aRequest)")); - TInt r = CheckDiskSpace(0, aRequest); + TInt r = CheckDiskSpace(KMinFsCreateObjTreshold, aRequest); if(r != KErrNone) return r; @@ -1652,7 +1652,7 @@ { __PRINT(_L("TFsFileSetAtt::DoRequestL(CSessionFs* aSession)")); - TInt r = CheckDiskSpace(0, aRequest); + TInt r = CheckDiskSpace(KMinFsCreateObjTreshold, aRequest); if(r != KErrNone) return r; @@ -1717,7 +1717,7 @@ { __PRINT(_L("TFsFileSetModified::DoRequestL(CFsRequest* aRequest)")); - TInt r = CheckDiskSpace(0, aRequest); + TInt r = CheckDiskSpace(KMinFsCreateObjTreshold, aRequest); if(r != KErrNone) return r; @@ -1757,7 +1757,7 @@ { __PRINT(_L("TFsFileSet::DoRequestL(CFsRequest* aRequest)")); - TInt r = CheckDiskSpace(0, aRequest); + TInt r = CheckDiskSpace(KMinFsCreateObjTreshold, aRequest); if(r != KErrNone) return r; @@ -1830,26 +1830,13 @@ // check if an attempt is made to change the share mode to EFileShareExclusive // while the file has multiple readers if (newMode == EFileShareExclusive && (currentMode & KFileShareMask) != EFileShareExclusive) - { - // Check no other CFileCB is reading the file. - FileShares->Lock(); - TInt count=FileShares->Count(); - TBool found=EFalse; - while(count--) - { - CFileShare* fileShare=(CFileShare*)(*FileShares)[count]; - if (&fileShare->File()==&share->File()) - { - if (found) - { - FileShares->Unlock(); - return(KErrAccessDenied); - } - found=ETrue; - } - } - FileShares->Unlock(); + { + // Check that this is the file's only fileshare/client + TDblQue& aShareList = (&share->File())->FileShareList(); + if (!(aShareList.IsFirst(share) && aShareList.IsLast(share))) + return KErrAccessDenied; } + share->iMode&=~KFileShareMask; share->iMode|=newMode; share->File().SetShare(newMode); @@ -1882,7 +1869,7 @@ { __PRINT(_L("TFsFileRename::DoRequestL(CFsRequest* aRequest)")); - TInt r = CheckDiskSpace(0, aRequest); + TInt r = CheckDiskSpace(KMinFsCreateObjTreshold, aRequest); if(r != KErrNone) return r; @@ -2451,14 +2438,18 @@ void CFileCB::PromoteShare(CFileShare* aShare) -// -// Manages share promotion after the share has been added to the FilsShares container. -// -// - Assumes the share has already been validated using ValidateShare() -// -// - The count of promoted shares (ie - non-EFileShareReadersOrWriters) is incremented -// to allow the share mode to be demoted when the last promoted share is closed. -// +/** + Manages share promotion and checks the EFileSequential file mode + after the share has been added to the FileShares container. + + It assumes the share has already been validated using ValidateShare(). + + The count of promoted shares (ie - non-EFileShareReadersOrWriters) is incremented + to allow the share mode to be demoted when the last promoted share is closed. + + Similarly, the count of non-EFileSequential file modes is incremented to allow + the file mode to be enabled when the last non-EFileSequential share is closed. + */ { TShare reqShare = (TShare)(aShare->iMode & KFileShareMask); if(reqShare != EFileShareReadersOrWriters) @@ -2466,29 +2457,48 @@ iBody->iPromotedShares++; iShare = reqShare; } + + // If the file mode is not EFileSequential, then disable the 'Sequential' flag + if(!(aShare->iMode & EFileSequential)) + { + iBody->iNonSequentialFileModes++; + SetSequentialMode(EFalse); + __PRINT(_L("CFileCB::PromoteShare - FileSequential mode is off")); + } } void CFileCB::DemoteShare(CFileShare* aShare) -// -// Manages share demotion after the share has been removed from the FileShares container. -// -// - If the share being removed is not EFileShareReadersOrWriters, then the current -// share mode may require demotion back to EFileShareReadersOrWriters. -// -// - This is determined by the iPromotedShares count, incremented in PromoteShare() -// +/** + Manages share demotion and checks the EFileSequential file mode + after the share has been removed from the FileShares container. + + If the share being removed is not EFileShareReadersOrWriters, then the current + share mode may require demotion back to EFileShareReadersOrWriters. + This is determined by the iPromotedShares count, incremented in PromoteShare(). + + Similarly, if the share being removed is non-EFileSequential, + then the EFileSequential flag may need to be enabled, + which is determined by the iNonSequentialFileModes count. + */ { - if((aShare->iMode & KFileShareMask) != EFileShareReadersOrWriters) + if((aShare->iMode & KFileShareMask) != EFileShareReadersOrWriters + && --iBody->iPromotedShares == 0) { - if(--iBody->iPromotedShares == 0) - { - // Don't worry if the file has never been opened as EFileShareReadersOrWriters - // - in this case the CFileCB object is about to be closed anyway. - iShare = EFileShareReadersOrWriters; - } + // Don't worry if the file has never been opened as EFileShareReadersOrWriters + // - in this case the CFileCB object is about to be closed anyway. + iShare = EFileShareReadersOrWriters; } - __ASSERT_DEBUG(iBody->iPromotedShares>=0,Fault(EFileShareBadPromoteCount)); + __ASSERT_DEBUG(iBody->iPromotedShares>=0, Fault(EFileShareBadPromoteCount)); + + if(!(aShare->iMode & EFileSequential) && --iBody->iNonSequentialFileModes == 0) + { + // As above, if the file has never been opened as EFileSequential, + // it implies that the CFileCB object is about to be closed anyway. + SetSequentialMode(ETrue); + __PRINT(_L("CFileCB::PromoteShare - FileSequential mode is enabled")); + } + __ASSERT_DEBUG(iBody->iNonSequentialFileModes>=0, Fault(EFileShareBadPromoteCount)); } @@ -2723,7 +2733,8 @@ /** Constructor. -Locks the mount resource to which the shared file resides. +Locks the mount resource to which the shared file resides +and adds the share to the file's FileShare List. @param aFileCB File to be shared. */ @@ -2731,12 +2742,14 @@ : iFile(aFileCB) { AddResource(iFile->Mount()); + iFile->AddShare(*this); } /** Destructor. Frees mount resource to which the shared file resides, +removes the share from the file's FileShare List, removes share status from the shared file and finally closes the file. */ @@ -2746,6 +2759,7 @@ __ASSERT_DEBUG(iCurrentRequest == NULL, Fault(ERequestQueueNotEmpty)); RemoveResource(iFile->Mount()); + iShareLink.Deque(); iFile->RemoveLocks(this); iFile->DemoteShare(this); iFile->CancelAsyncReadRequest(this, NULL); @@ -3027,6 +3041,7 @@ CFileBody::CFileBody(CFileCB* aFileCB, CFileCB::MExtendedFileInterface* aExtendedFileInterface) : iFileCB(aFileCB), iExtendedFileInterface(aExtendedFileInterface ? aExtendedFileInterface : this), + iShareList(_FOFF(CFileShare,iShareLink)), iSizeHigh(0) { iFairSchedulingLen = TFileCacheSettings::FairSchedulingLen(iFileCB->DriveNumber()); @@ -3586,6 +3601,45 @@ } +//--------------------------------------------------------------------------------------------------------------------- +/** +Gets the 'Sequential' mode of the file. + +@return ETrue, if the file is in 'Sequential' mode +*/ +EXPORT_C TBool CFileCB::IsSequentialMode() const + { + return iBody->iSequential; + } + +/** +Sets the 'Sequential' mode of the file. + */ +void CFileCB::SetSequentialMode(TBool aSequential) + { + iBody->iSequential = aSequential; + } + +//--------------------------------------------------------------------------------------------------------------------- +/** +Gets the list containing the shares associated with the file. + +@return The FileShare List +*/ +TDblQue& CFileCB::FileShareList() const + { + return iBody->iShareList; + } + +/** +Adds the share to the end of the FileShare List. +*/ +void CFileCB::AddShare(CFileShare& aFileShare) + { + iBody->iShareList.AddLast(aFileShare); + } + + //##################################################################################################################### //# TFileShareLock class implementation //##################################################################################################################### diff -r e880629062dd -r e4a7b1cbe40c userlibandfileserver/fileserver/sfile/sf_nbs.cpp --- a/userlibandfileserver/fileserver/sfile/sf_nbs.cpp Wed May 05 05:11:16 2010 +0100 +++ b/userlibandfileserver/fileserver/sfile/sf_nbs.cpp Mon May 10 11:40:53 2010 +0100 @@ -22,7 +22,7 @@ { __PRINT(_L("TFsMkDir::DoRequestL(CFsRequest* aRequest)")); - TInt r = CheckDiskSpace(0, aRequest); + TInt r = CheckDiskSpace(KMinFsCreateObjTreshold, aRequest); if(r != KErrNone) return r; @@ -143,7 +143,7 @@ // { __PRINT(_L("TFsRename::DoRequestL(CFsRequest* aRequest)")); - TInt r = CheckDiskSpace(0, aRequest); + TInt r = CheckDiskSpace(KMinFsCreateObjTreshold, aRequest); if(r != KErrNone) return r; @@ -182,7 +182,7 @@ { __PRINT(_L("TFsReplace::DoRequestL(CFsRequest* aRequest)")); - TInt r = CheckDiskSpace(0, aRequest); + TInt r = CheckDiskSpace(KMinFsCreateObjTreshold, aRequest); if(r != KErrNone) return r; @@ -261,7 +261,7 @@ { __PRINT(_L("TFsSetEntry::DoRequestL(CFsRequest* aRequest)")); - TInt r = CheckDiskSpace(0, aRequest); + TInt r = CheckDiskSpace(KMinFsCreateObjTreshold, aRequest); if(r != KErrNone) return r; @@ -892,7 +892,7 @@ // create the private path unless it already exists // { - TInt ret = CheckDiskSpace(0, aRequest); + TInt ret = CheckDiskSpace(KMinFsCreateObjTreshold, aRequest); if(ret != KErrNone) return ret; diff -r e880629062dd -r e4a7b1cbe40c userlibandfileserver/fileserver/sfile/sf_std.h --- a/userlibandfileserver/fileserver/sfile/sf_std.h Wed May 05 05:11:16 2010 +0100 +++ b/userlibandfileserver/fileserver/sfile/sf_std.h Mon May 10 11:40:53 2010 +0100 @@ -144,6 +144,13 @@ //-- absolute maximum file size that file server supports const TUint64 KMaxSupportedFileSize = KMaxTUint64; +//-- this is a speculative value of a min. amount of free space on the volume necessary to create a file, directory etc. +//-- it is used mostly in "reserve drive space" functionality, which is, actually, fundamentally flawed. +//-- the problem is that the file server can't know exactly how much space is required to create some fs object on the volume, +//-- so, it has to guess. This is a default "sector size" value; the file system can round it up internally to its cluster size if any. +const TInt KMinFsCreateObjTreshold = KDefaultVolumeBlockSize; + + //__DATA_CAGING__ const TUint SHA1_LBLOCK=16; const TUint SHA1_HASH=20; @@ -235,7 +242,7 @@ enum TFsPanic { - ELdrImportedOrdinalDoesNotExist + ELdrImportedOrdinalDoesNotExist }; // enum TFsFault @@ -443,7 +450,8 @@ ETraceLddLoadFailure, //200 ETooManyDrivesPerSocket, ENotificationFault, - EFsObjectOpen + EFsObjectOpen, + EContainerHeapCorruptionOnRemove }; @@ -1838,10 +1846,6 @@ typedef TPckgBuf TMediaPswdReplyNotifyInfoV1Buf; -#if defined(__WINS__) - TInt MapWindowsFileName(TDes& aBuffer,const TDesC& aFileName); -#endif - enum TDllFindMethod {EFindInPath, EFindInSystemLibs, EFindInSystemBin, EFindExhausted}; //--------------------------------------------------------------------------------------------------------------------- @@ -1867,6 +1871,7 @@ TInt iFairSchedulingLen; TBool iNotifyAsyncReadersPending; TBool iDeleteOnClose; + TDblQue iShareList; // A list containing the CFileShare objects associated with the file protected: TInt iPromotedShares; @@ -1876,11 +1881,14 @@ /** maximum file size supported by the filesystem that instantiates the CFileCB, associated with this object. - For example, FAT32 supports files not larger than 4GB-1. Other file systems can support larger files. + For example, FAT32 supports files not larger than 4GB-1. Other file systems can support larger files. This member allows file server to know maximum allowed position in the file. The default value is KMaxTUint64 */ - TUint64 iMaxSupportedFileSize; + TUint64 iMaxSupportedFileSize; + + TInt iNonSequentialFileModes; // Count of clients without the 'Sequential' mode enabled + TBool iSequential; // Indicates whether the file is in 'Sequential' mode public: // Provides support for large file size ( file size > 4GB - 1) diff -r e880629062dd -r e4a7b1cbe40c userlibandfileserver/fileserver/sfile/sf_svr.cpp --- a/userlibandfileserver/fileserver/sfile/sf_svr.cpp Wed May 05 05:11:16 2010 +0100 +++ b/userlibandfileserver/fileserver/sfile/sf_svr.cpp Mon May 10 11:40:53 2010 +0100 @@ -590,7 +590,7 @@ // Set the volume name. // { - TInt r = CheckDiskSpace(0, aRequest); + TInt r = CheckDiskSpace(KMinFsCreateObjTreshold, aRequest); if(r != KErrNone) return r; @@ -1314,8 +1314,13 @@ return KErrNone; } - - + case EFSysExtensionsSupported: + { + TBool supported = pDrive->GetFSys()->IsExtensionSupported(); + TPckgBuf data(supported); + aRequest->WriteL(KMsgPtr2,data); + return KErrNone; + } default: { return KErrNotSupported; diff -r e880629062dd -r e4a7b1cbe40c userlibandfileserver/fileserver/sfile/sf_utl.cpp --- a/userlibandfileserver/fileserver/sfile/sf_utl.cpp Wed May 05 05:11:16 2010 +0100 +++ b/userlibandfileserver/fileserver/sfile/sf_utl.cpp Mon May 10 11:40:53 2010 +0100 @@ -1067,6 +1067,8 @@ if(KReservedSpace == 0 || KDriveNumber == EDriveZ) return KErrNone; + ASSERT(aThreshold); + //-- if the drive has a reserved space, take it into account CSessionFs* session=aRequest->Session(); @@ -1074,8 +1076,7 @@ aThreshold += KReservedSpace; //-- ask the corresponding file system if there is aThreshold bytes available. - //-- for some reason it's required to be strictly > than aThreshold - return aRequest->Drive()->RequestFreeSpaceOnMount(aThreshold+1); + return aRequest->Drive()->RequestFreeSpaceOnMount(aThreshold); } diff -r e880629062dd -r e4a7b1cbe40c userlibandfileserver/fileserver/sfsrv/cl_fman.cpp --- a/userlibandfileserver/fileserver/sfsrv/cl_fman.cpp Wed May 05 05:11:16 2010 +0100 +++ b/userlibandfileserver/fileserver/sfsrv/cl_fman.cpp Mon May 10 11:40:53 2010 +0100 @@ -1089,6 +1089,31 @@ including any directories in the path specified by aNew which do not already exist. +If the source (anOld) is a FILE and the recursive operation is set, +then all the files with the same name as anOld in the source directory +including those in subdirectories will be copied to the destination. + +For example, the initial directory structure is as follows: +C:\dir1\file.txt +C:\dir1\subdirA\file.txt +C:\dir1\subdirB\file.txt + +@code +CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle +fm->Copy(_L("C:\\dir1\\file.txt"), _L("C:\\dir2\\file.txt"), CFileMan::ERecurse); +// OR without specifying the filename in aNew: +fm->Copy(_L("C:\\dir1\\file.txt"), _L("C:\\dir2\\"), CFileMan::ERecurse); +@endcode + +Because of the recursive behaviour, the final directory structure after +either one of the copy operations above will be as follows: +C:\dir1\file.txt +C:\dir1\subdirA\file.txt +C:\dir1\subdirB\file.txt +C:\dir2\file.txt +C:\dir2\subdirA\file.txt +C:\dir2\subdirB\file.txt + If recursive operation is not set, only the matching files located in the single directory specified in anOld are copied. No intermediate directories will be created; if any directories in @@ -1122,13 +1147,13 @@ 1.2 If there is no file to operate on i.e. if source directory is empty, the function will do nothing and return error code KErrNotFound. - 2. Files can be copied across drives. - - 3. Open files can be copied if they have been opened using - the EFileShareReadersOnly file share mode. - - 4. Read-only, hidden and system files can be copied and - the source file's attributes are preserved in the target file. + 2. Files can be copied across drives. + + 3. Open files can be copied if they have been opened using + the EFileShareReadersOnly file share mode. + + 4. Read-only, hidden and system files can be copied and + the source file's attributes are preserved in the target file. @param anOld Path indicating the file(s) to be copied. Any path components which are not specified here will be @@ -1393,7 +1418,7 @@ recursively by default and moves both the last directory level and all of its content. Notice that no trailing backslash ("\") implies moving files recursively automatically. -For example, if the directory level "b" contains the files F1,F2 and F3, then: +For example, if the directory level "b" contains the files F1, F2 and F3, then: @code CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle ... @@ -1421,7 +1446,7 @@ 0 is passed as an argument, the operation behaves the same way as by passing CFileMan::ERecurse flag. -for example: +For example: @code CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle ... @@ -1436,6 +1461,31 @@ fm->Move(_L("C:\\a\\b"), _L("C:\\x\\y\\"), CFileMan::ERecurse); @endcode +If the source (anOld) is a FILE and the recursive operation is set, +then all the files with the same name as anOld in the source directory +including those in subdirectories will be moved to the destination. + +For example, the initial directory structure is as follows: +C:\src\file.txt +C:\src\subdirA\file.txt +C:\src\subdirB\file.txt + +@code +CFileMan* fm(CFileMan::NewL(iFs)); // Where iFs is an RFs handle +fm->Move(_L("C:\\src\\file.txt"), _L("C:\\dest\\file.txt"), CFileMan::ERecurse); +// OR without specifying the filename in aNew: +fm->Move(_L("C:\\src\\file.txt"), _L("C:\\dest\\"), CFileMan::ERecurse); +@endcode + +Because of the recursive behaviour, the final directory structure after +either one of the move operations above will be as follows: +C:\src\ +C:\src\subdirA\ +C:\src\subdirB\ +C:\dest\file.txt +C:\dest\subdirA\file.txt +C:\dest\subdirB\file.txt + Notes: -# Read-only, hidden and system files can be moved and the source file's @@ -1443,7 +1493,7 @@ be moved. Attempting to move an open file will return an error for that file, as retrieved by CFileBase::GetLastError(). -@param anOld Path indicating the files to be moved. May be either a full path, or +@param anOld Path indicating the directory/files to be moved. May be either a full path, or relative to the session path. Note that if you specify a directory level, then the behaviour of the move operation is sensitive to the presence (or absence) of a trailing backslash ("\") character. Any path components diff -r e880629062dd -r e4a7b1cbe40c userlibandfileserver/fileserver/shostmassstorage/client/hostmsclient.mmp --- a/userlibandfileserver/fileserver/shostmassstorage/client/hostmsclient.mmp Wed May 05 05:11:16 2010 +0100 +++ b/userlibandfileserver/fileserver/shostmassstorage/client/hostmsclient.mmp Mon May 10 11:40:53 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2008-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" @@ -30,7 +30,7 @@ LIBRARY efsrv.lib euser.lib hal.lib usbdescriptors.lib usbdi_utils.lib -CAPABILITY ALL +CAPABILITY TCB ProtServ DiskAdmin AllFiles PowerMgmt CommDD NetworkControl WriteDeviceData //MACRO _USBMS_DEBUG_PRINT_ diff -r e880629062dd -r e4a7b1cbe40c userlibandfileserver/fileserver/shostmassstorage/server/hostmsserver.mmp --- a/userlibandfileserver/fileserver/shostmassstorage/server/hostmsserver.mmp Wed May 05 05:11:16 2010 +0100 +++ b/userlibandfileserver/fileserver/shostmassstorage/server/hostmsserver.mmp Mon May 10 11:40:53 2010 +0100 @@ -1,4 +1,4 @@ -// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2008-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" @@ -62,7 +62,7 @@ BASEADDRESS 0x61000000 END -CAPABILITY ALL -Tcb +CAPABILITY AllFiles CommDD UID 0 0x10286A83