Tidying up obsolete guicons commands.
(comm.script handles a lot of the cases, the rest are covered by the applauncher icons)
// undertaker.cpp
//
// Copyright (c) 2005 - 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/iocli.h>
#include "undertaker.h"
TInt CCmdUndertaker::Queue()
{
TInt err = iUndertaker.Logon(iStatus, iDeadThreadHandle);
if (err == KErrNone)
{
SetActive();
}
return err;
}
void CCmdUndertaker::DoCancel()
{
iUndertaker.LogonCancel();
}
void CCmdUndertaker::RunL()
{
TInt handle = iDeadThreadHandle;
Queue(); // Queue early, to try and avoid missing notifications
// We don't use the RunL if we're in paranoid mode - the undertaker notifications are serviced directly in DoWork() without an active scheduler
ProcessHandle(handle);
}
void CCmdUndertaker::ProcessHandle(TInt aDeadThreadHandle)
{
RThread deadThread;
deadThread.SetHandle(aDeadThreadHandle);
TFullName name(deadThread.FullName());
TExitType type = deadThread.ExitType();
if (type != EExitKill || deadThread.ExitReason() != 0 || iAll)
{
Write(_L("Thread "));
Write(name);
Printf(_L(" (tid=%d) "), (TUint)deadThread.Id());
}
if (type == EExitPanic)
{
TExitCategoryName cat = deadThread.ExitCategory();
Printf(_L("panicked with %S %d\r\n"), &cat, deadThread.ExitReason());
}
else if (type == EExitTerminate)
{
Printf(_L("terminated with reason %d\r\n"), deadThread.ExitReason());
}
else if (deadThread.ExitReason() != 0)
{
// We'll consider a kill with non-zero exit code as counting as abnormal
Printf(_L("killed with reason %d\r\n"), deadThread.ExitReason());
}
else if (iAll)
{
Printf(_L("exited cleanly\r\n"));
}
if (!iLeakThreads)
{
deadThread.Close();
}
}
CCommandBase* CCmdUndertaker::NewLC()
{
CCmdUndertaker* self = new(ELeave) CCmdUndertaker();
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
CCmdUndertaker::~CCmdUndertaker()
{
Cancel();
if (iWorkerThread.Id() != RThread().Id()) iWorkerThread.Kill(KErrAbort);
iHandles.Close();
CloseProcessOwnedHandles();
}
CCmdUndertaker::CCmdUndertaker()
: CMemoryAccessCommandBase(EManualComplete)
{
}
void CCmdUndertaker::ConstructL()
{
BaseConstructL();
}
const TDesC& CCmdUndertaker::Name() const
{
_LIT(KName, "undertaker");
return KName;
}
void CCmdUndertaker::DoRunL()
{
User::LeaveIfError(iUndertaker.Create());
if (iParanoid)
{
User::LeaveIfError(iMainThread.Open(RThread().Id()));
User::LeaveIfError(iLock.CreateLocal());
iHandles.ReserveL(10);
TFullName threadName(RThread().Name());
threadName.Append(_L("_worker"));
LeaveIfErr(iWorkerThread.Create(threadName, &WorkerThreadFn, 8192, NULL, this), _L("Couldn't create worker thread"));
#ifdef FSHELL_MEMORY_ACCESS_SUPPORT
LoadMemoryAccessL();
LeaveIfErr(iMemAccess.SetThreadPriority(iWorkerThread, 31), _L("Couldn't set worker thread priority with memoryaccess"));
#else
iWorkerThread.SetPriority(EPriorityMuchMore); // Best we can do
#endif
iWorkerThread.Resume();
}
else
{
User::LeaveIfError(Queue());
}
if (Stdin().IsForeground() > 0)
{
Write(iAll ? _L("Waiting for any thread exit...\r\n") : _L("Waiting for panicked thread exit...\r\n"));
}
if (iParanoid)
{
// We've spawned off our worker thread, which is the client of the RUndertaker. We now wait for it to signal us back again.
// It's easier to balance the requests if we don't go through the active scheduler (so long as nothing else signals this thread!)
for (;;)
{
User::WaitForRequest(iMainThreadStat);
if (iMainThreadStat.Int() != KErrNone) User::Leave(iMainThreadStat.Int());
iLock.Wait();
TInt handle = iHandles[0];
iHandles.Remove(0);
iLock.Signal();
ProcessHandle(handle);
}
}
}
void CCmdUndertaker::OptionsL(RCommandOptionList& aOptions)
{
_LIT(KOptAll, "all");
_LIT(KOptNoClose, "noclose");
_LIT(KOptParanoid, "paranoid");
aOptions.AppendBoolL(iAll, KOptAll);
aOptions.AppendBoolL(iLeakThreads, KOptNoClose);
aOptions.AppendBoolL(iParanoid, KOptParanoid);
}
TInt CCmdUndertaker::WorkerThreadFn(TAny* aSelf)
{
CCmdUndertaker* self = static_cast<CCmdUndertaker*>(aSelf);
return self->DoWork();
}
TInt CCmdUndertaker::DoWork()
{
TRequestStatus mainThreadDeadStat;
iMainThread.Logon(mainThreadDeadStat);
TRequestStatus stat;
TInt deadThreadHandle;
TInt err = KErrNone;
for (;;)
{
err = iUndertaker.Logon(stat, deadThreadHandle);
TRequestStatus* s = &iMainThreadStat;
if (err)
{
iMainThread.RequestComplete(s, err);
break;
}
else
{
User::WaitForRequest(stat, mainThreadDeadStat);
if (mainThreadDeadStat.Int() != KRequestPending)
{
// We're dead
err = mainThreadDeadStat.Int();
// Have to clean up our process-owned handles here...
CloseProcessOwnedHandles();
break;
}
// Have to duplicate the thread handle so the main thread can see it. Can't seem to persuade RUndertaker to give us a process-owned handle in the first place
RThread origHandle;
origHandle.SetHandle(deadThreadHandle);
RThread newHandle(origHandle);
err = newHandle.Duplicate(RThread(), EOwnerProcess);
origHandle.Close();
if (!err)
{
iLock.Wait();
err = iHandles.Append(newHandle.Handle());
iLock.Signal();
}
iMainThread.RequestComplete(s, err);
}
}
return err;
}
void CCmdUndertaker::CloseProcessOwnedHandles()
{
iMainThread.Close();
iWorkerThread.Close();
iUndertaker.Close();
iLock.Close();
}
#ifdef EXE_BUILD
EXE_BOILER_PLATE(CCmdUndertaker)
#endif