Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase.
Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.
// memsamplerdd.cpp
//
// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//
#include <fshell/extrabtrace.h>
#include <platform.h>
#include <kern_priv.h>
#include "memsamplerdd.h"
#include <fshell/common.mmh>
const TInt KMinRate = 10;
const TInt KMaxRate = 10000;
const TInt KMajorVersionNumber = 1;
const TInt KMinorVersionNumber = 0;
const TInt KBuildVersionNumber = 0;
const TInt KArrayGranularity = 32;
const TInt KDfcThreadPriority = 26;
_LIT(KDfcThreadName, "MemSamplerDD");
class DDeviceMemSampler : public DLogicalDevice
{
public:
DDeviceMemSampler();
virtual TInt Install();
virtual void GetCaps(TDes8& aDes) const;
virtual TInt Create(DLogicalChannelBase*& aChannel);
};
class TChunkInfo
{
public:
TChunkInfo(DChunk& aChunk);
TBool operator==(const TChunkInfo& aChunkInfo);
public:
DChunk* iAddress;
TInt iSize;
TInt iHighWaterMark;
TBool iSeen;
};
TChunkInfo::TChunkInfo(DChunk& aChunk)
: iAddress(&aChunk), iSize(aChunk.Size()), iHighWaterMark(aChunk.Size()), iSeen(ETrue)
{
}
TBool TChunkInfo::operator==(const TChunkInfo& aChunkInfo)
{
return (iSize == aChunkInfo.iSize);
}
class DMemSamplerChannel : public DLogicalChannel
{
public:
DMemSamplerChannel();
~DMemSamplerChannel();
protected:
virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
virtual void HandleMsg(TMessageBase* aMsg);
private:
TInt StartSampling(TInt aRate);
TInt StopSampling();
TInt ResetSampling();
TInt ReadChunks();
void TraceNewChunk(const TChunkInfo& aChunkInfo) const;
void TraceChangedChunk(const TChunkInfo& aChunkInfo) const;
void TraceDeletedChunk(const TChunkInfo& aChunkInfo) const;
void TraceNewSample() const;
#if FSHELL_PLATFORM_SYMTB >= 92
inline TBool Running()
{return iTimer.IsPending();}
#else
inline TBool Running()
{return iTimer.iState!=NTimer::EIdle;}
#endif
private:
static void Sample(TAny*);
static void DoSample(TAny*);
static void ExitDfcThread(TAny*);
private:
RArray<TChunkInfo> iChunkInfo;
NTimer iTimer;
TInt iPeriod;
TInt iPeriodNumber;
TDfcQue iPrivateDfcQ;
TDfc iDoSampleDfc;
TDfc iExitDfc;
DThread* iClient;
mutable TBool iNewSampleTraced;
};
DECLARE_STANDARD_LDD()
{
return new DDeviceMemSampler;
}
DDeviceMemSampler::DDeviceMemSampler()
{
iVersion=TVersion(KMajorVersionNumber, KMinorVersionNumber, KBuildVersionNumber);
}
TInt DDeviceMemSampler::Install()
{
TInt r = SetName(&KMemSamplerName);
return r;
}
void DDeviceMemSampler::GetCaps(TDes8&) const
{
}
TInt DDeviceMemSampler::Create(DLogicalChannelBase*& aChannel)
{
aChannel = new DMemSamplerChannel;
return aChannel ? KErrNone : KErrNoMemory;
}
DMemSamplerChannel::DMemSamplerChannel()
: iChunkInfo(KArrayGranularity, _FOFF(TChunkInfo, iAddress)), iTimer(Sample, this), iPeriodNumber(-1), iDoSampleDfc(DoSample, this, 1), iExitDfc(ExitDfcThread, this, 0), iNewSampleTraced(EFalse)
{
}
DMemSamplerChannel::~DMemSamplerChannel()
{
Kern::SafeClose((DObject*&)iClient, NULL);
iExitDfc.Enque();
}
void DMemSamplerChannel::ExitDfcThread(TAny*)
{
Kern::Exit(KErrNone);
}
TInt DMemSamplerChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
{
if (!Kern::QueryVersionSupported(TVersion(1,0,0),aVer))
{
return KErrNotSupported;
}
iClient=&Kern::CurrentThread();
iClient->Open();
TInt err = Kern::DfcQInit(&iPrivateDfcQ, KDfcThreadPriority, &KDfcThreadName);
if (err == KErrNone)
{
SetDfcQ(&iPrivateDfcQ);
iDoSampleDfc.SetDfcQ(&iPrivateDfcQ);
iExitDfc.SetDfcQ(&iPrivateDfcQ);
iMsgQ.Receive();
}
return err;
}
TInt DMemSamplerChannel::StartSampling(TInt aRate)
{
DEBUG_MEMSAMPLER(Kern::Printf("START");)
ReadChunks();
aRate = Min(KMaxRate, Max(KMinRate, aRate));
iPeriod = NKern::TimerTicks(aRate);
if (!Running())
{
iTimer.OneShot(iPeriod, EFalse);
}
DEBUG_MEMSAMPLER(Kern::Printf("START end");)
return KErrNone;
}
TInt DMemSamplerChannel::StopSampling()
{
DEBUG_MEMSAMPLER(Kern::Printf("STOP");)
if (Running())
{
iTimer.Cancel();
}
DEBUG_MEMSAMPLER(Kern::Printf("STOP end");)
return KErrNone;
}
TInt DMemSamplerChannel::ResetSampling()
{
DEBUG_MEMSAMPLER(Kern::Printf("RESET");)
iChunkInfo.Reset();
DEBUG_MEMSAMPLER(Kern::Printf("RESET end");)
return KErrNone;
}
TInt DMemSamplerChannel::ReadChunks()
{
++iPeriodNumber;
iNewSampleTraced = EFalse;
for (TInt i = (iChunkInfo.Count() - 1); i >= 0; --i)
{
iChunkInfo[i].iSeen = EFalse;
}
DObjectCon* const * containers = Kern::Containers();
DObjectCon& container = *containers[EChunk];
container.Wait();
for (TInt i = (container.Count() - 1); i >= 0; --i)
{
TChunkInfo thisChunk(*(DChunk*)container[i]);
TInt pos;
TInt err = iChunkInfo.FindInUnsignedKeyOrder(thisChunk, pos);
if (err == KErrNotFound)
{
if (pos < iChunkInfo.Count())
{
iChunkInfo.Insert(thisChunk, pos);
}
else
{
TInt err = iChunkInfo.Append(thisChunk);
if (err)
{
container.Signal();
return err;
}
}
TraceNewChunk(thisChunk);
}
else
{
if (thisChunk == iChunkInfo[pos])
{
// Chunk size hasn't changed - ignore.
iChunkInfo[pos].iSeen = ETrue;
}
else
{
TChunkInfo& c = iChunkInfo[pos];
if (thisChunk.iSize > c.iHighWaterMark)
{
c.iHighWaterMark = thisChunk.iSize;
}
c.iSize = thisChunk.iSize;
c.iSeen = ETrue;
TraceChangedChunk(c);
}
}
}
container.Signal();
for (TInt i = (iChunkInfo.Count() - 1); i >= 0; --i)
{
const TChunkInfo& chunkInfo = iChunkInfo[i];
if (!chunkInfo.iSeen)
{
TraceDeletedChunk(chunkInfo);
iChunkInfo.Remove(i);
}
}
return KErrNone;
}
void DMemSamplerChannel::TraceNewChunk(const TChunkInfo& aChunkInfo) const
{
TraceNewSample();
TFullName nameBuf;
aChunkInfo.iAddress->FullName(nameBuf);
BTraceN(RMemSampler::EBtraceCategory, RMemSampler::ENewChunk, aChunkInfo.iAddress, aChunkInfo.iAddress->MaxSize(), nameBuf.Ptr(), nameBuf.Size());
TraceChangedChunk(aChunkInfo);
}
void DMemSamplerChannel::TraceChangedChunk(const TChunkInfo& aChunkInfo) const
{
TraceNewSample();
BTraceContext12(RMemSampler::EBtraceCategory, RMemSampler::EChangedChunk, aChunkInfo.iAddress, aChunkInfo.iSize, aChunkInfo.iHighWaterMark);
}
void DMemSamplerChannel::TraceDeletedChunk(const TChunkInfo& aChunkInfo) const
{
TraceNewSample();
BTraceContext4(RMemSampler::EBtraceCategory, RMemSampler::EDeletedChunk, aChunkInfo.iAddress);
}
void DMemSamplerChannel::TraceNewSample() const
{
if (!iNewSampleTraced)
{
iNewSampleTraced = ETrue;
BTraceContext8(RMemSampler::EBtraceCategory, RMemSampler::ENewSample, iPeriod, iPeriodNumber);
}
}
void DMemSamplerChannel::HandleMsg(TMessageBase* aMsg)
{
TInt r=KErrNone;
TThreadMessage& m=*(TThreadMessage*)aMsg;
TInt id=m.iValue;
if (id==(TInt)ECloseMsg)
{
DEBUG_MEMSAMPLER(Kern::Printf("CLOSE");)
iTimer.Cancel();
m.Complete(KErrNone,EFalse);
iMsgQ.CompleteAll(KErrServerTerminated);
DEBUG_MEMSAMPLER(Kern::Printf("CLOSE end");)
return;
}
else
{
switch(id)
{
case RMemSampler::EControlStartProfile:
r = StartSampling(m.Int0());
break;
case RMemSampler::EControlStopProfile:
r = StopSampling();
break;
case RMemSampler::EControlResetProfile:
r = ResetSampling();
break;
default:
r = KErrNotSupported;
break;
}
}
m.Complete(r,ETrue);
}
void DMemSamplerChannel::Sample(TAny* aPtr)
{
DMemSamplerChannel& d = *(DMemSamplerChannel*)aPtr;
d.iTimer.Again(d.iPeriod);
d.iDoSampleDfc.Add();
}
void DMemSamplerChannel::DoSample(TAny* aPtr)
{
DMemSamplerChannel& d = *(DMemSamplerChannel*)aPtr;
d.ReadChunks();
}